CONFIG LIB 1.5
Configuration Files Library (by TGG 2020)
Loading...
Searching...
No Matches
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
34double NACA_PROFILE::xcoord(double angle)
35{
36 return 0.5 + cos(angle)/2.0;
37}
38
39double 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
54void 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
67void 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
101void 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
136void 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
195void NACA_PROFILE::draw_surface(int ndiv, const struct NACA_AIRFOIL_DATA *data, FILE *fp)
196{
197 double ainc = M_PI / (ndiv-1);
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 {
212 i--; // to avoid doubled LE points
213 inc = -1;
214 }
215 else
216 i += inc;
217 }
218}
219
220/*
221 * Check to see if this is a valid name for an NACA section
222 */
223char* NACA_PROFILE::check_name(char *name)
224{
225 int len;
226
227 /* Trim off a leading NACA or naca */
228 if(!strncmp(name, "NACA", 4) || !strncmp(name, "naca", 4))
229 name += 4;
230
231 len = strlen(name);
232
233 if(len < 4 || len > 5) {
234 return 0;
235 }
236
237 if(len == 4) {
238 /* Need to all be numeric */
239 int i;
240 for(i = 0; i < 4; i++)
241 if(!isdigit(name[i]))
242 return 0;
243 }
244 else {
245 /* Ok, first digit has to be 2, 3, 4, 6 */
246 if(!strchr("2346", name[0]))
247 return 0;
248
249 /* Second digit has to be 12345, except if the first digit is [346]
250 // then the second can only be [234] */
251 if(name[1] < '1' || name[1] > '5')
252 return 0;
253 if(strchr("346", name[0]))
254 if(!strchr("234", name[1]))
255 return 0;
256
257 /* Third digit has to be 0 or 1 */
258 if(name[2] < '0' || name[2] > '1')
259 return 0;
260
261 /* last two need to be numeric */
262 if(!isdigit(name[3]) || !isdigit(name[4]))
263 return 0;
264 }
265 return name;
266}
267
268int NACA_PROFILE::generate_naca(char* cNACA, int NN)
269{
270 N = 2*NN - 1; // must be odd
271 CreateTabs( N );
272
273 char *cname;
274
275 if(!(cname = check_name(cNACA)))
276 {
277 fprintf(stderr, "%s is not a valid NACA section name.\n", cNACA );
278 return -1;
279 }
280 else
281 {
282 fprintf( stderr, "NACA %s - cname %s\n", cNACA, cname );
283 }
284
285 iWrite = 0;
286 iLicz = 0;
287
288 get_params(&data, cname);
289
290 draw_surface(NN, &data, stderr);
291
292 return 0;
293}
294
295int NACA_PROFILE::generate_naca(char *file_name, char* cNACA)
296{
297 FILE *fp = fopen( file_name, "w" );
298
299 char *cname;
300
301 if(!(cname = check_name(cNACA)))
302 {
303 fprintf(stderr, "%s is not a valid NACA section name.\n", cNACA );
304 return -1;
305 }
306 else
307 {
308 fprintf( stderr, "NACA %s - cname %s\n", cNACA, cname );
309 }
310
311 return generate_naca(cname, 160, fp);
312}
313
314int NACA_PROFILE::generate_naca(char *name, int num, FILE *fp)
315{
316 iWrite = 1;
317
318 get_params(&data, name);
319
320 fprintf(fp, "NACA %s\n", name);
321
322#ifdef Debug
323 fprintf(stderr, "%s:\n camber: %g\n thickness: %g\n max_camber_pos: %g\n series: %s\n",
324 data.name, data.maxor, data.thmax, data.posmax,
325 ((data.serie == four_digit)? "four digit" : "five digit"));
326#endif
327
328 draw_surface(num, &data, fp);
329
330 fclose (fp);
331
332 return 0;
333}
334
335void NACA_PROFILE::ClearTabs( void )
336{
337 DELETE_TAB( X );
338 DELETE_TAB( Z );
339}
340
341void NACA_PROFILE::CreateTabs( int nn )
342{
343 ClearTabs();
344 X = new double[nn];
345 Z = new double[nn];
346}
347
348NACA_PROFILE::~NACA_PROFILE(void)
349{
350 ClearTabs();
351}
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:314
double * Z
z coordinates vecotr
Definition naca.h:111
int N
coordiantes vectors' size
Definition naca.h:112
double * X
x coordinates vector
Definition naca.h:110
#define DELETE_TAB(OBJ)
Macro for safe deleteing the array and sets the pointer to zero.
Definition memfun.h:97
A struct containing airfoil data.
Definition naca.h:46
double posmax
the location of maximum camber
Definition naca.h:49
int ireflex
reflex flag - if ireflex = 1, Cm should be close to 0 (5-digit serie)
Definition naca.h:53
double thmax
the maximum thickness
Definition naca.h:50
enum series serie
type of serie - 4- or 5-digit
Definition naca.h:52
double maxor
the maximum camber
Definition naca.h:48
double k1
constant to determine the desired lift coefficient (5-digit serie)
Definition naca.h:51
int iTE0
trailing edge flag, 1 - TE thickness equal to zero
Definition naca.h:54
const char * name
4- or 5-digit airfoil code
Definition naca.h:47