001/*
002*   NACA5Cambered -- An arbitrary cambered NACA 5 digit unreflexed airfoil.
003*
004*   Copyright (C) 2000-2025, by Joseph A. Huwaldt. All rights reserved.
005*   
006*   This library is free software; you can redistribute it and/or
007*   modify it under the terms of the GNU Lesser General Public
008*   License as published by the Free Software Foundation; either
009*   version 2.1 of the License, or (at your option) any later version.
010*   
011*   This library is distributed in the hope that it will be useful,
012*   but WITHOUT ANY WARRANTY; without even the implied warranty of
013*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014*   Lesser General Public License for more details.
015*
016*   You should have received a copy of the GNU Lesser General Public License
017*   along with this program; if not, write to the Free Software
018*   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
019*   Or visit:  http://www.gnu.org/licenses/lgpl.html
020*/
021package jahuwaldt.aero.airfoils;
022
023import java.util.List;
024import java.awt.geom.Point2D;
025import java.text.DecimalFormat;
026import java.text.NumberFormat;
027
028
029/**
030*  <p>  This class represents an arbitrary cambered unreflexed
031*       NACA 5 digit airfoil section with 3 digit camber such
032*       as a NACA 23012 airfoil.
033*       The 1st digit is defined as 2/3 of the design lift
034*       coefficient (in tenths, i.e.: 2 denotes cl = 0.3).
035*       The 2nd digit is twice the chordwise location of maximum
036*       camber in tenths of chord.  The 3rd digit of zero
037*       indicates a non-reflexed trailing edge and the
038*       last two digits indicate the thickness ratio in
039*       percent chord.
040*  </p>
041*
042*  <p> Ported from FORTRAN "NACA4.FOR" to Java by:
043*                Joseph A. Huwaldt, October 9, 2000     </p>
044*
045*  <p> Original FORTRAN "NACA4" code had the following note:  </p>
046*
047*  <pre>
048*         AUTHORS - Charles L.Ladson and Cuyler W. Brooks, NASA Langley
049*                   Liam Hardy, NASA Ames
050*                   Ralph Carmichael, Public Domain Aeronautical Software
051*         Last FORTRAN version:  8Aug95  1.7   RLC
052*
053*         NOTES - This program has been known by the names ANALIN, FOURDIGIT and NACA4.
054*         REFERENCES-  NASA Technical Memorandum TM X-3284 (November, 1975),
055*                      "Development of a Computer Program to Obtain Ordinates for
056*                      NACA 4-Digit, 4-Digit Modified, 5-Digit and 16-Digit Airfoils",
057*                      by Charles L. Ladson and Cuyler W. Brooks, Jr.,
058*                      NASA Langley Research Center.
059*
060*                      NASA Technical Memorandum TM 4741 (December 1996),
061*                      "Computer Program to Obtain Ordinates for NACA Airfoils",
062*                      by Charles L. Ladson, Cuyler W. Brooks, Jr., and Acquilla S. Hill,
063*                      NASA Langley Research Center and
064*                      Darrell W. Sproles, Computer Sciences Corporation, Hampton, VA.
065*
066*                      "Theory of Wing Sections", by Ira Abbott and Albert Von Doenhoff.
067*  </pre>
068*
069*  <p>  Modified by:  Joseph A. Huwaldt  </p>
070*
071*  @author  Joseph A. Huwaldt   Date:  October 9, 2000
072*  @version February 22, 2025
073*/
074public class NACA5Cambered extends NACA4Uncambered {
075
076        /**
077        *  The camber function K factor.
078        */
079        private double k1;
080        
081        /**
082        *  The camber function "r" factor.
083        */
084        private double rFactor;
085        
086        /**
087        *  The position in x/c of the maximum camber.
088        */
089        private double xCM;
090        
091        
092        /**
093        *  Create a cambered unreflexed NACA 5 digit airfoil with the
094        *  specified parameters.  For example:  a NACA 23012 airfoil
095        *  translates to:  thickness = 0.12, cl*2/3 = 2, xcamber*2 = 0.30.
096        *  The 3rd digit must be 0 for an unreflexed airfoil.
097        *  This constructor requires the user to specify the 5 digit airfoil
098        *  k and r factors and position of max camber explicitly.
099        *  See NASA TM X-3284.
100        *
101        *  @param  thickness  The thickness to chord ratio (e.g.: 0.09 == 9% t/c).
102        *  @param  k1         The airfoil camber k factor as described in
103        *                     NASA TM X-3284.
104        *  @param  r          The airfoil camber r factor as described in
105        *                     NASA TM X-3284.
106        *  @param  xcamber    The position of maximum camber in tenths of chord
107        *                     (e.g.:  0.40 == max camber at 4% chord).
108        *  @param  length     The chord length.
109        */
110        public NACA5Cambered(double thickness, double k1, double r, double xcamber, double length) {
111                super(thickness, length);
112                
113                this.k1 = k1;
114                rFactor = r;
115                xCM = xcamber;
116        }
117        
118        /**
119        *  Create a cambered unreflexed NACA 5 digit airfoil with the
120        *  specified parameters.  For example:  a NACA 23012 airfoil
121        *  translates to:  thickness = 0.12, cl*2/3 = 2, xcamber*2 = 0.30.
122        *  The 3rd digit must be 0 for an unreflexed airfoil.
123        *  This constructor requires the thickness and camber code (the
124        *  1st 2 digits of the airfoil designation).
125        *
126        *  @param  thickness  The thickness to chord ratio (e.g.: 0.09 == 9% t/c).
127        *  @param  code       The 1st 2 digits of the airfoil designation.
128        *                     Acceptable values are:  21, 22, 23, 24, and 25.
129        *  @param  length     The chord length.
130        */
131        public NACA5Cambered(double thickness, int code, double length) {
132                super(thickness, length);
133                
134                switch (code) {
135                        case 21:
136                                xCM = 0.05;
137                                rFactor = 0.0580;
138                                k1 = 361.400;
139                                break;
140                        
141                        case 22:
142                                xCM = 0.10;
143                                rFactor = 0.1260;
144                                k1 = 51.640;
145                                break;
146                        
147                        case 23:
148                                xCM = 0.15;
149                                rFactor = 0.2025;
150                                k1 = 15.957;
151                                break;
152                        
153                        case 24:
154                                xCM = 0.20;
155                                rFactor = 0.2900;
156                                k1 = 6.643;
157                                break;
158                        
159                        case 25:
160                                xCM = 0.25;
161                                rFactor = 0.3910;
162                                k1 = 3.230;
163                                break;
164                        
165                        default:
166                                throw new IllegalArgumentException("Unknown camber code.");
167                }
168                
169                
170        }
171        
172
173        /**
174        *  Returns a string representation of this airfoil
175        *  (the NACA designation of this airfoil).
176        */
177    @Override
178        public String toString() {
179                StringBuilder buffer = new StringBuilder("NACA 2");
180                
181                buffer.append((int)(xCM*20));
182                buffer.append("0");
183                
184                if (TOC < 0.1)
185                        buffer.append("0");
186                buffer.append((int)(TOC*100));
187                
188                if (chord != 1.0) {
189                        buffer.append(" c=");
190                        buffer.append(chord);
191                }
192                return buffer.toString();
193        }
194        
195        /**
196        *  Method to determine the local slope of the airfoil at
197        *  the leading edge.  This implementation sets the LE
198        *  slope to a very large number and sets the value for
199        *  tanth to k1*rFactor*rFactor*(3 - rFactor)/6.
200        *  This method sets the class variables:  tanth, yp, ypp.
201        *
202        *  @param  o  The ordinate data structure.  The following are set:  tanth, yp, ypp.
203        */
204    @Override
205        protected void calcLESlope(Ordinate o) {
206                if (k1 < EPS)
207                        o.tanth = EPS;
208                else
209                        o.tanth = k1*rFactor*rFactor*(3 - rFactor)/6;
210                o.yp = BIG;
211                o.ypp = BIG;
212        }
213        
214        /**
215        *  Method to calculate the camber distribution for the airfoil.
216        *  This implementation computes a camber distribution that is
217        *  appropriate for an unreflexed NACA 5 digit cambered airfoil.
218        *  This method sets the class variables:  yCMB, tanth, thp.
219        *
220        *  @param  x  The x/c location currently being calculated.
221        *  @param  o  The ordinate data structure. The following are set: yCMB, tanth, thp.
222        *  @return The following function value is returned: sqrt(1 + tanth^2).
223        */
224    @Override
225        protected double calcCamber(double x, Ordinate o) {
226        
227                double r2 = rFactor*rFactor;
228                
229                if (x > rFactor) {
230                        double r3 = r2*rFactor;
231                        o.yCMB = k1*r3*(1 - x)/6;
232                        o.tanth = -k1*r3/6;
233                        
234                } else {
235                        double x2 = x*x;
236                        double x3 = x2*x;
237                        o.yCMB = k1*(x3 - 3*rFactor*x2 + r2*(3 - rFactor)*x)/6;
238                        o.tanth = k1*(3*x2 - 6*rFactor*x + r2*(3 - rFactor))/6;
239                }
240                
241                double func = Math.sqrt(1 + o.tanth*o.tanth);
242                
243                if (x > rFactor) {
244                        o.thp = 0;
245                        
246                } else 
247                        o.thp = k1*(x - rFactor)/(func*func);
248                
249                return func;
250        }
251        
252        /**
253        *  Simple method to test this class.
254        *
255        * @param args the command-line arguments
256        */
257        public static void main(String[] args) {
258        
259                DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance();
260                nf.setMaximumFractionDigits(5);
261                nf.setMinimumFractionDigits(5);
262                
263                System.out.println("Start NACA5Cambered...");
264                
265                System.out.println("Creating a NACA 23012 airfoil...");
266                Airfoil af = new NACA5Cambered(0.12, 23, 1);
267                
268                System.out.println("Airfoil = " + af.toString());
269                
270                //      Output the upper surface of the airfoil.
271                List<Point2D> upper = af.getUpper();
272                List<Double> ypArr = af.getUpperYp();
273                
274                System.out.println("        X    \t    Y    \t    dy/dx");
275                int length = upper.size();
276                for (int i=0; i < length; ++i) {
277                        Point2D o = upper.get(i);
278                        System.out.println("    " + nf.format(o.getX()) + "\t" + nf.format(o.getY()) +
279                                                                        "\t" + nf.format(ypArr.get(i)));
280                }
281                
282                System.out.println("# ordinates = " + length);
283                System.out.println("Done!");
284        }
285}
286
287