001/*
002*   NACA4ModCambered -- An arbitrary cambered NACA 4 digit modified 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 NACA
031*      modified 4 digit airfoil section with 2 digit camber
032*      such as a NACA 2512-34 airfoil.
033*      The 1st digit is the maximum camber in percent chord.
034*      The 2nd digit is the chordwise location of maximum
035*      camber in tenths of chord.  The next two digits are
036*      the airfoil thickness in percent chord.  The 1st digit
037*      after the hyphen is the leading edge radius index and
038*      the last digit after the hyphen is the position of
039*      maximum thickness in tenths of chord.
040*  </p>
041*
042*  <p> Ported from FORTRAN "NACA4.FOR" to Java by:
043*                Joseph A. Huwaldt, October 20, 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 20, 2000
072*  @version February 22, 2025
073*/
074public class NACA4ModCambered extends NACA4ModUncambered {
075
076        /**
077        *  The amount of camber in terms of maximum ordinate-to-chord ratio.
078        */
079        private double CMB;
080        
081        /**
082        *  The position in x/c of the maximum camber.
083        */
084        private double xCM = 0.50;
085        
086        
087        /**
088        *  Create a cambered NACA modified 4 digit airfoil with the
089        *  specified parameters.  For example:  a NACA 2512-34 airfoil
090        *  translates to:  thickness = 0.12, camber = 0.02, xcamber = 0.50,
091        *                  Rle = 0.003967, and xThickness = 0.40.
092        *
093        *  @param  thickness  The thickness to chord ratio (e.g.: 0.09 == 9% t/c).
094        *  @param  camber     The maximum camber ordinate-to-chord ratio
095        *                     (e.g.:  0.06 == 6% camber/c).
096        *  @param  xcamber    The position of maximum camber in tenths of chord
097        *                     (e.g.:  0.40 == max camber at 4% chord).
098        *  @param  Rle        The radius of the leading edge of the airfoil in
099        *                     percent chord.
100        *  @param  xThickness The position of maximum thickness in percent chord
101        *                     (e.g.:  0.40 == 40% t/c).
102        *  @param  length     The chord length.
103        */
104        public NACA4ModCambered(double thickness, double camber, double xcamber,
105                                                                double Rle, double xThickness, double length) {
106                super(thickness, Rle, xThickness, length);
107                
108                CMB = camber;
109                xCM = xcamber;
110        }
111        
112
113        /**
114        *  Create a cambered NACA modified 4 digit airfoil with the
115        *  specified parameters.  For example:  a NACA 2512-34 airfoil
116        *  translates to:  thickness = 0.12, camber = 0.02, xcamber = 0.50,
117        *                  LEindex = 3, xThickness = 0.40..
118        *
119        *  @param  thickness  The thickness to chord ratio (e.g.: 0.09 == 9% t/c).
120        *  @param  camber     The maximum camber ordinate-to-chord ratio
121        *                     (e.g.:  0.06 == 6% camber/c).
122        *  @param  xcamber    The position of maximum camber in tenths of chord
123        *                     (e.g.:  0.40 == max camber at 4% chord).
124        *  @param  LEindex    The leading edge radius index for this airfoil.  Should
125        *                     be a number from 1 to 8.
126        *  @param  xThickness The position of maximum thickness in percent chord
127        *                     (e.g.:  0.40 == 40% t/c).
128        *  @param  length     The chord length.
129        */
130        public NACA4ModCambered(double thickness, double camber, double xcamber,
131                                                                int LEindex, double xThickness, double length) {
132                super(thickness, LEindex, xThickness, length);
133                
134                CMB = camber;
135                xCM = xcamber;
136        }
137        
138        /**
139        *  Returns a string representation of this airfoil
140        *  (the NACA designation of this airfoil).
141        */
142    @Override
143        public String toString() {
144                StringBuilder buffer = new StringBuilder("NACA ");
145                
146                buffer.append((int)(CMB*100));
147                buffer.append((int)(xCM*10));
148                
149                if (TOC < 0.1)
150                        buffer.append("0");
151                buffer.append((int)(TOC*100));
152                
153                buffer.append("-");
154                
155                if (leIndex == 0)
156                        buffer.append("?");
157                else
158                        buffer.append(leIndex);
159                
160                buffer.append((int)(xMaxT*10));
161                
162                if (chord != 1.0) {
163                        buffer.append(" c=");
164                        buffer.append(chord);
165                }
166                return buffer.toString();
167        }
168        
169        //-----------------------------------------------------------------------------------
170
171        /**
172        *  Method to determine the local slope of the airfoil at
173        *  the leading edge.  This implementation sets the LE
174        *  slope to a very large number and sets the tanth
175        *  parameter to 2*CMB/xCM just as the NACA 4 digit
176        *  uncambered implementation does.
177        *  This method sets the class variables:  tanth, yp, ypp.
178        *
179        *  @param  o  The ordinate data structure.  The following are set:  tanth, yp, ypp.
180        */
181    @Override
182        protected void calcLESlope(Ordinate o) {
183                if (CMB < EPS)
184                        o.tanth = EPS;
185                else
186                        o.tanth = 2*CMB/xCM;
187                o.yp = BIG;
188                o.ypp = BIG;
189        }
190        
191        /**
192        *  Method to calculate the camber distribution for the airfoil.
193        *  This implementation computes a camber distribution that is
194        *  appropriate for a modified, NACA 4 digit, cambered airfoil.
195        *  This method sets the class variables:  yCMB, tanth, thp.
196        *
197        *  @param  x  The x/c location currently being calculated.
198        *  @param  o  The ordinate data structure. The following are set: yCMB, tanth, thp.
199        *  @return The following function value is returned: sqrt(1 + tanth^2).
200        */
201    @Override
202        protected double calcCamber(double x, Ordinate o) {
203                if (x > xCM) {
204                        double OneMxCM = 1 - xCM;
205                        double OneMxCM2 = OneMxCM*OneMxCM;
206                        o.yCMB = CMB*(1 - 2*xCM + 2*xCM*x - x*x)/OneMxCM2;
207                        o.tanth = (2*xCM - 2*x)*CMB/OneMxCM2;
208                        
209                } else {
210                        o.yCMB = CMB*(2*xCM*x - x*x)/(xCM*xCM);
211                        o.tanth = 2*CMB*(1 - x/xCM)/xCM;
212                }
213                
214                double func = Math.sqrt(1 + o.tanth*o.tanth);
215                
216                if (x > xCM) {
217                        double OneMxCM = 1 - xCM;
218                        o.thp = -2*CMB/(OneMxCM*OneMxCM)/(func*func);
219                        
220                } else 
221                        o.thp = -2*CMB/(xCM*xCM)/(func*func);
222                
223                return func;
224        }
225        
226        //-----------------------------------------------------------------------------------
227
228        /**
229        *  Simple method to test this class.
230        *
231        * @param args the command-line arguments.
232        */
233        public static void main(String[] args) {
234        
235                DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance();
236                nf.setMaximumFractionDigits(5);
237                nf.setMinimumFractionDigits(5);
238                
239                System.out.println("Start NACA4ModCambered...");
240                
241                System.out.println("Creating a NACA 6409-34 airfoil...");
242                Airfoil af = new NACA4ModCambered(0.09, 0.06, 0.4, 3, 0.4, 1);
243                
244                System.out.println("Airfoil = " + af.toString());
245                
246                //      Output the upper surface of the airfoil.
247                List<Point2D> upper = af.getUpper();
248                List<Double> ypArr = af.getUpperYp();
249                
250                System.out.println("        X    \t    Y    \t    dy/dx");
251                int length = upper.size();
252                for (int i=0; i < length; ++i) {
253                        Point2D o = upper.get(i);
254                        System.out.println("    " + nf.format(o.getX()) + "\t" + nf.format(o.getY()) +
255                                                                        "\t" + nf.format(ypArr.get(i)));
256                }
257                
258                System.out.println("# ordinates = " + length);
259                System.out.println("Done!");
260        }
261}
262
263