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