001/*
002*   NACA4Cambered -- An arbitrary cambered NACA 4 digit 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 4
031*      digit airfoil section with 2 digit camber such as a
032*      NACA 6409 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 last two digits are
036*      the airfoil thickness in percent chord.
037*  </p>
038*
039*  <p> Ported from FORTRAN "NACA4.FOR" to Java by:
040*                Joseph A. Huwaldt, October 8, 2000     </p>
041*
042*  <p> Original FORTRAN "NACA4" code had the following note:  </p>
043*
044*  <pre>
045*         AUTHORS - Charles L.Ladson and Cuyler W. Brooks, NASA Langley
046*                   Liam Hardy, NASA Ames
047*                   Ralph Carmichael, Public Domain Aeronautical Software
048*         Last FORTRAN version:  8Aug95  1.7   RLC
049*
050*         NOTES - This program has been known by the names ANALIN, FOURDIGIT and NACA4.
051*         REFERENCES-  NASA Technical Memorandum TM X-3284 (November, 1975)
052*                      "Development of a Computer Program to Obtain Ordinates for
053*                      NACA 4-Digit, 4-Digit Modified, 5-Digit and 16-Digit Airfoils",
054*                      by Charles L. Ladson and Cuyler W. Brooks, Jr.,
055*                      NASA Langley Research Center.
056*
057*                      NASA Technical Memorandum TM 4741 (December 1996),
058*                      "Computer Program to Obtain Ordinates for NACA Airfoils",
059*                      by Charles L. Ladson, Cuyler W. Brooks, Jr., and Acquilla S. Hill,
060*                      NASA Langley Research Center and
061*                      Darrell W. Sproles, Computer Sciences Corporation, Hampton, VA.
062*
063*                      "Theory of Wing Sections", by Ira Abbott and Albert Von Doenhoff.
064*  </pre>
065*
066*  <p>  Modified by:  Joseph A. Huwaldt  </p>
067*
068*  @author  Joseph A. Huwaldt   Date:  October 8, 2000
069*  @version February 22, 2025
070*/
071public class NACA4Cambered extends NACA4Uncambered {
072
073        /**
074        *  The amount of camber in terms of maximum ordinate-to-chord ratio.
075        */
076        private double CMB;
077        
078        /**
079        *  The position in x/c of the maximum camber.
080        */
081        private double xCM;
082        
083        
084        /**
085        *  Create a cambered NACA 4 digit airfoil with the
086        *  specified parameters.  For example:  a NACA 6409 airfoil
087        *  translates to:  thickness = 0.09, camber = 0.06, xcamber = 0.40.
088        *
089        *  @param  thickness  The thickness to chord ratio (e.g.: 0.09 == 9% t/c).
090        *  @param  camber     The maximum camber ordinate-to-chord ratio
091        *                     (e.g.:  0.06 == 6% camber/c).
092        *  @param  xcamber    The position of maximum camber in tenths of chord
093        *                     (e.g.:  0.40 == max camber at 4% chord).
094        *  @param  length     The chord length.
095        */
096        public NACA4Cambered(double thickness, double camber, double xcamber, double length) {
097                super(thickness, length);
098                
099                CMB = camber;
100                xCM = xcamber;
101        }
102        
103
104        /**
105        *  Returns a string representation of this airfoil
106        *  (the NACA designation of this airfoil).
107        */
108    @Override
109        public String toString() {
110                StringBuilder buffer = new StringBuilder("NACA ");
111                
112                buffer.append((int)(CMB*100));
113                buffer.append((int)(xCM*10));
114                
115                if (TOC < 0.1)
116                        buffer.append("0");
117                buffer.append((int)(TOC*100));
118                
119                if (chord != 1.0) {
120                        buffer.append(" c=");
121                        buffer.append(chord);
122                }
123                return buffer.toString();
124        }
125        
126        /**
127        *  Method to determine the local slope of the airfoil at
128        *  the leading edge.  This implementation sets the
129        *  slope of the leading edge to a very large number and
130        *  sets tanth to 2*CMB/xCM.
131        *  This method sets the class variables:  tanth, yp, ypp.
132        *
133        *  @param  o  The ordinate data structure.  The following are set:  tanth, yp, ypp.
134        */
135    @Override
136        protected void calcLESlope(Ordinate o) {
137                if (CMB < EPS)
138                        o.tanth = EPS;
139                else
140                        o.tanth = 2*CMB/xCM;
141                o.yp = BIG;
142                o.ypp = BIG;
143        }
144        
145        /**
146        *  Method to calculate the camber distribution for the airfoil.
147        *  This implementation computes a camber distribution that is
148        *  appropriate for a cambered NACA 4 digit airfoil.
149        *
150        *  @param  x  The x/c location currently being calculated.
151        *  @param  o  The ordinate data structure. The following are set: yCMB, tanth, thp.
152        *  @return The following function value is returned: sqrt(1 + tanth^2).
153        */
154    @Override
155        protected double calcCamber(double x, Ordinate o) {
156                if (x > xCM) {
157                        double OneMxCM = 1 - xCM;
158                        double OneMxCM2 = OneMxCM*OneMxCM;
159                        o.yCMB = CMB*(1 - 2*xCM + 2*xCM*x - x*x)/OneMxCM2;
160                        o.tanth = (2*xCM - 2*x)*CMB/OneMxCM2;
161                        
162                } else {
163                        o.yCMB = CMB*(2*xCM*x - x*x)/(xCM*xCM);
164                        o.tanth = 2*CMB*(1 - x/xCM)/xCM;
165                }
166                
167                double func = Math.sqrt(1 + o.tanth*o.tanth);
168                
169                if (x > xCM) {
170                        double OneMxCM = 1 - xCM;
171                        o.thp = -2*CMB/(OneMxCM*OneMxCM)/(func*func);
172                        
173                } else 
174                        o.thp = -2*CMB/(xCM*xCM)/(func*func);
175                
176                return func;
177        }
178
179        
180        /**
181        *  Simple method to test this class.
182        *
183        * @param args the command line arguments.
184        */
185        public static void main(String[] args) {
186        
187                DecimalFormat nf = (DecimalFormat)NumberFormat.getInstance();
188                nf.setMaximumFractionDigits(5);
189                nf.setMinimumFractionDigits(5);
190                
191                System.out.println("Start NACA4Cambered...");
192                
193                System.out.println("Creating a NACA 6409 airfoil...");
194                Airfoil af = new NACA4Cambered(0.09, 0.06, 0.4, 1);
195                
196                System.out.println("Airfoil = " + af.toString());
197                
198                //      Output the upper surface of the airfoil.
199                List<Point2D> upper = af.getUpper();
200                List<Double> ypArr = af.getUpperYp();
201                
202                System.out.println("        X    \t    Y    \t    dy/dx");
203                int length = upper.size();
204                for (int i=0; i < length; ++i) {
205                        Point2D o = upper.get(i);
206                        System.out.println("    " + nf.format(o.getX()) + "\t" + nf.format(o.getY()) +
207                                                                        "\t" + nf.format(ypArr.get(i)));
208                }
209                
210                System.out.println("# ordinates = " + length);
211                System.out.println("Done!");
212        }
213}
214
215