CONFIG LIB  1.5
Configuration Files Library (by TGG 2020)
naca.cpp
1 /*********************************************************************/
2 /* */
3 /* Panukl package - (C) TGG 2002 */
4 /* Config files library - (C) TGG 2015 */
5 /* */
6 /*********************************************************************/
7 /* Warszawa, 2020 */
8 /*********************************************************************/
9 /* */
10 /* File: naca.cpp */
11 /* */
12 /* Author: T.Grabowski */
13 /* */
14 /* Contents - NACA_PROFILE class - definition */
15 /* */
16 /* Last update: 21.11.2020 */
17 /* */
18 /*********************************************************************/
19 /* */
20 
21 /*
22  * naca.cpp
23  *
24  * Created by Alexandre Naaman (hoser@step.polymtl.ca) 30-08-1995
25  * Code clean-up, modifications to include more 5-digit sections:
26  * Shamim Mohamed (shamim@synopsys.com) Sept. 8 95
27  * corrected & modified to encapsulate into C++ class
28  * by Tomasz Grabowski (tgrab@meil.pw.edu.pl) Jan. 2012
29  * included to PanuklConfigLib 20.11.2020
30  */
31 
32 #include "naca.h"
33 
34 double NACA_PROFILE::xcoord(double angle)
35 {
36  return 0.5 + cos(angle)/2.0;
37 }
38 
39 double NACA_PROFILE::ytfunc(double x, double thmax)
40 {
41  if (x == 1.0) return 0.0;
42 
43  double y = A[4];
44  for( int i=1; i<4; i++ )
45  y = y*x + A[4-i];
46  y = y*x + A[0] * sqrt(x);
47 
48  return 5. * thmax * y;
49 
50 // return thmax * (1.4845*sqrt(x) - 0.63*x - 1.758*sqr(x)+
51 // 1.4215*cube(x) - 0.5075*sqr(sqr(x)));
52 }
53 
54 void NACA_PROFILE::camber_four(double *yc, double *slope,
55  double x, double maxor, double posmax)
56 {
57  if (x < posmax) {
58  *yc = maxor/sqr(posmax) * (2.0*posmax*x - sqr(x));
59  *slope = 2*(maxor/posmax) * (1.0-(x/posmax));
60  }
61  else {
62  *yc = maxor/sqr(1.0-posmax) * ( 1 - 2*posmax + 2*posmax*x - sqr(x));
63  *slope = 2*(maxor/sqr(1-posmax))*(posmax-x);
64  }
65 }
66 
67 void NACA_PROFILE::camber_five(double *yc, double *slope,
68  double x, double maxor, double posmax, double k1, int iReflex )
69 {
70  double d16 = 1.0/6.0;
71 
72  if( iReflex )
73  {
74  double k21 = (3.*sqr(maxor-posmax)-cube(maxor))/(1-maxor);
75  if (x < maxor)
76  {
77  *yc = d16*k1*(cube(x-maxor) - k21*sqr(1-maxor)*x - cube(maxor)*(x-1) );
78  *slope = d16*k1*(3*sqr(x-maxor) - k21*sqr(1-maxor) - cube(maxor) );
79  }
80  else
81  {
82  *yc = d16*k1*(k21*cube(x-maxor) - k21*sqr(1-maxor)*x - cube(maxor)*(x-1));
83  *slope = d16*k1*(3*k21*sqr(x-maxor) - k21*sqr(1-maxor) - cube(maxor) );
84  }
85  }
86  else
87  {
88  if (x < maxor)
89  {
90  *yc = d16*k1*(cube(x) - 3.0*maxor*sqr(x) + sqr(maxor)*(3.0-maxor)*x);
91  *slope = d16*k1*( 3.0*sqr(x) - 6.0*maxor*x + sqr(maxor)*(3.0-maxor) );
92  }
93  else
94  {
95  *yc = d16*k1*cube(maxor)*(1.0-x);
96  *slope = d16*k1*cube(maxor);
97  }
98  }
99 }
100 
101 void NACA_PROFILE::out_point(double x, double yc, double yt, double slope, int is_upper, FILE *fp)
102 {
103  double xloc, yloc, h;
104 
105 #ifdef Debug
106  fprintf(stderr, " >>> x: %.4g\tcamber: %.3g\tthickness: %.3g\n", x, yc, yt);
107 #endif
108 
109  h = sqrt(1+sqr(slope));
110  if (is_upper) {
111  xloc = x - yt*slope/h;
112  yloc = yc + yt/h;
113  }
114  else {
115  xloc = x + yt*slope/h;
116  yloc = yc - yt/h;
117  }
118  /* Save results into file */
119  if( iWrite )
120  fprintf(fp,"%5.5f %5.5f\n", xloc, yloc);
121  else
122  {
123  if( iLicz < N )
124  {
125  X[iLicz] = xloc;
126  Z[iLicz] = yloc;
127  }
128  else
129  fprintf(stderr, "%5.5f %5.5f %d\n", xloc, yloc, iLicz);
130  iLicz++;
131  }
132 }
133 
134 #define dig(c) ((c)-'0')
135 
136 void NACA_PROFILE::get_params(struct NACA_AIRFOIL_DATA *data, const char *name)
137 {
138  A[0] = 0.2969;
139  A[1] = -0.126;
140  A[2] = -0.3516;
141  A[3] = 0.2843;
142 
143  if( data->iTE0 == 0 )
144  A[4] = -0.1015;
145  else
146  A[4] = -0.1036;
147 
148  data->name = name;
149  if(strlen(name) == 4)
150  {
151  data->serie = four_digit;
152  data->maxor = dig(name[0])/100.0;
153  data->posmax = dig(name[1])/10.0;
154  data->thmax = atoi(name+2)/100.0;
155  }
156  else
157  {
158  int d1, d2, d3;
159 
160  data->serie = five_digit;
161  data->thmax = atoi(name+3)/100.0;
162  d1 = dig(name[0]);
163  d2 = dig(name[1]);
164  d3 = dig(name[2]);
165  data->posmax = d2/20.0;
166  data->ireflex = d3;
167 
168  if( d3 == 0 || d3 == 1 )
169  {
170  int code = d1*100 + d2*10 + d3;
171  switch (code)
172  {
173  case 210: data->maxor=0.0580; data->k1=361.4; break;
174  case 220: data->maxor=0.1260; data->k1=51.64; break;
175  case 230: data->maxor=0.2025; data->k1=15.957;break;
176  case 240: data->maxor=0.2900; data->k1=6.643; break;
177  case 250: data->maxor=0.3910; data->k1=3.23; break;
178 
179  case 211: data->maxor=0.0621; data->k1=28.51; break; // approximated data from www.pdas.com
180  case 221: data->maxor=0.1300; data->k1=51.99; break;
181  case 231: data->maxor=0.2170; data->k1=15.793;break;
182  case 241: data->maxor=0.3180; data->k1=6.52; break;
183  case 251: data->maxor=0.4410; data->k1=3.191; break;
184 
185  default: break;
186  }
187  }
188  else
189  {
190  fprintf(stderr, "wrong number ireflex = %d\n", d3 );
191  }
192  }
193 }
194 
195 void NACA_PROFILE::draw_surface(int ndiv, const struct NACA_AIRFOIL_DATA *data, FILE *fp)
196 {
197  double ainc = M_PI / ndiv;
198  int i=0, inc=1;
199  double x, yt, yc, slope;
200 
201  while (i >= 0)
202  {
203  x = xcoord(i * ainc);
204  yt = ytfunc(x, data->thmax);
205  if (data->serie == four_digit)
206  camber_four(&yc, &slope, x, data->maxor, data->posmax);
207  else
208  camber_five(&yc, &slope, x, data->maxor, data->posmax, data->k1, data->ireflex);
209  out_point(x, yc, yt, slope, inc==1, fp);
210  if (i >= ndiv-1 && inc == 1)
211  inc = -1;
212  else
213  i += inc;
214  }
215 }
216 
217 /*
218  * Check to see if this is a valid name for an NACA section
219  */
220 char* NACA_PROFILE::check_name(char *name)
221 {
222  int len;
223 
224  /* Trim off a leading NACA or naca */
225  if(!strncmp(name, "NACA", 4) || !strncmp(name, "naca", 4))
226  name += 4;
227 
228  len = strlen(name);
229 
230  if(len < 4 || len > 5) {
231  return 0;
232  }
233 
234  if(len == 4) {
235  /* Need to all be numeric */
236  int i;
237  for(i = 0; i < 4; i++)
238  if(!isdigit(name[i]))
239  return 0;
240  }
241  else {
242  /* Ok, first digit has to be 2, 3, 4, 6 */
243  if(!strchr("2346", name[0]))
244  return 0;
245 
246  /* Second digit has to be 12345, except if the first digit is [346]
247  // then the second can only be [234] */
248  if(name[1] < '1' || name[1] > '5')
249  return 0;
250  if(strchr("346", name[0]))
251  if(!strchr("234", name[1]))
252  return 0;
253 
254  /* Third digit has to be 0 or 1 */
255  if(name[2] < '0' || name[2] > '1')
256  return 0;
257 
258  /* last two need to be numeric */
259  if(!isdigit(name[3]) || !isdigit(name[4]))
260  return 0;
261  }
262  return name;
263 }
264 
265 int NACA_PROFILE::generate_naca(char* cNACA, int NN)
266 {
267  N = 2*NN;
268  CreateTabs( N );
269 
270  char *cname;
271 
272  if(!(cname = check_name(cNACA)))
273  {
274  fprintf(stderr, "%s is not a valid NACA section name.\n", cNACA );
275  return -1;
276  }
277  else
278  {
279  fprintf( stderr, "NACA %s - cname %s\n", cNACA, cname );
280  }
281 
282  iWrite = 0;
283  iLicz = 0;
284 
285  get_params(&data, cname);
286 
287  draw_surface(NN, &data, stderr);
288 
289  return 0;
290 }
291 
292 int NACA_PROFILE::generate_naca(char *file_name, char* cNACA)
293 {
294  FILE *fp = fopen( file_name, "w" );
295 
296  char *cname;
297 
298  if(!(cname = check_name(cNACA)))
299  {
300  fprintf(stderr, "%s is not a valid NACA section name.\n", cNACA );
301  return -1;
302  }
303  else
304  {
305  fprintf( stderr, "NACA %s - cname %s\n", cNACA, cname );
306  }
307 
308  return generate_naca(cname, 160, fp);
309 }
310 
311 int NACA_PROFILE::generate_naca(char *name, int num, FILE *fp)
312 {
313  iWrite = 1;
314 
315  get_params(&data, name);
316 
317  fprintf(fp, "NACA %s\n", name);
318 
319 #ifdef Debug
320  fprintf(stderr, "%s:\n camber: %g\n thickness: %g\n max_camber_pos: %g\n series: %s\n",
321  data.name, data.maxor, data.thmax, data.posmax,
322  ((data.serie == four_digit)? "four digit" : "five digit"));
323 #endif
324 
325  draw_surface(num, &data, fp);
326 
327  fclose (fp);
328 
329  return 0;
330 }
331 
332 void NACA_PROFILE::ClearTabs( void )
333 {
334  DELETE_TAB( X );
335  DELETE_TAB( Z );
336 }
337 
338 void NACA_PROFILE::CreateTabs( int nn )
339 {
340  ClearTabs();
341  X = new double[nn];
342  Z = new double[nn];
343 }
344 
345 NACA_PROFILE::~NACA_PROFILE(void)
346 {
347  ClearTabs();
348 }
NACA_AIRFOIL_DATA::iTE0
int iTE0
trailing edge flag, 1 - TE thickness equal to zero
Definition: naca.h:54
NACA_AIRFOIL_DATA::thmax
double thmax
the maximum thickness
Definition: naca.h:50
NACA_PROFILE::generate_naca
int generate_naca(char *name, int num, FILE *fp)
generates naca airfoil coordinates (NN points) and stores it in file defined by stream "fp"
Definition: naca.cpp:311
NACA_PROFILE::N
int N
coordiantes vectors' size
Definition: naca.h:112
NACA_AIRFOIL_DATA::serie
enum series serie
type of serie - 4- or 5-digit
Definition: naca.h:52
NACA_AIRFOIL_DATA::maxor
double maxor
the maximum camber
Definition: naca.h:48
NACA_PROFILE::Z
double * Z
z coordinates vecotr
Definition: naca.h:111
NACA_AIRFOIL_DATA::posmax
double posmax
the location of maximum camber
Definition: naca.h:49
NACA_PROFILE::X
double * X
x coordinates vector
Definition: naca.h:108
NACA_AIRFOIL_DATA::k1
double k1
constant to determine the desired lift coefficient (5-digit serie)
Definition: naca.h:51
NACA_AIRFOIL_DATA
A struct containing airfoil data.
Definition: naca.h:46
NACA_AIRFOIL_DATA::ireflex
int ireflex
reflex flag - if ireflex = 1, Cm should be close to 0 (5-digit serie)
Definition: naca.h:53
DELETE_TAB
#define DELETE_TAB(OBJ)
Macro for safe deleteing the array and sets the pointer to zero.
Definition: memfun.h:97
NACA_AIRFOIL_DATA::name
const char * name
4- or 5-digit airfoil code
Definition: naca.h:47