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