# Does anyone have a script to generate an Airfoil ?

Options
Member, Employee Posts: 260
✭✭✭

Has anyone developed a script to generate the Airfoil based on input parameters like Max camber, Camber position etc. and worked on parameterization of the Airfoil? (e.g.: NACA 4-digit airfoil generator)

Tagged:

• Member, Employee Posts: 260
✭✭✭
Options

```#!/usr/bin/env python
# -*- coding: utf-8 -*-

class NACA_Profile:

"""
Generate NACA 4-digit profiles
(refer to https://en.wikipedia.org/wiki/NACA_airfoil for details)
"""

def __init__(self, thickness=15, chord_length=1.0, num_pts=50,
camber=0, pos_max_camber=30, # Percent values
closed_trailing_edge=False):

import math

self.profile = [(0.0, 0.0)]
self.num_pts = num_pts

# Percent values

self.chord_length = chord_length
self.thickness = thickness / 100
self.camber = camber / 100

if camber:
self.pos_max_camber = max(min(pos_max_camber,99),1)/100
else:
self.pos_max_camber = 0

self.closed_trailing_edge = closed_trailing_edge

delta_x = 1.0/(self.num_pts-1)
x = 0.0

if self.closed_trailing_edge:
coeffs = (0.2969, -0.1260, -0.3516, +0.2843, -0.1036)
else:
coeffs = (0.2969, -0.1260, -0.3516, +0.2843, -0.1015)

for i in range(1,self.num_pts):

x += delta_x

y = coeffs[0] * math.sqrt(x)
y += coeffs[1] * x
x2 = x*x
y += coeffs[2] * x2
x3 = x2*x
y += coeffs[3] * x3
x4 = x3*x
y += coeffs[4] * x4

self.profile.append((x, 5*y*self.thickness))

self.upper_profile = [(0.0, 0.0)]
self.lower_profile = [(0.0, 0.0)]
self.camber_line = [(0.0, 0.0)]

for x,y in self.profile[1:]:

cost = 1/math.sqrt(1 + dyc_dx*dyc_dx)
sint = dyc_dx * cost

y_sint = y * sint
y_cost = y * cost

self.upper_profile.append((x - y_sint, yc + y_cost))
self.lower_profile.append((x + y_sint, yc - y_cost))
self.camber_line.append((x, yc))

if x < self.pos_max_camber:
xc = x
mx = self.pos_max_camber
mx2 = mx*mx
else:
xc = 1 - x
mx = 1 - self.pos_max_camber
mx2 = -mx*mx

yc = self.camber*(2*mx*xc - xc*xc)/(mx*mx)

dyc_dx = 2*self.camber*(mx-xc)/mx2

return yc, dyc_dx

def get_points_upper_profile(self):

for x,y in self.upper_profile:
yield x*self.chord_length, y*self.chord_length

def get_points_lower_profile(self):

for x,y in self.lower_profile:
yield x*self.chord_length, y*self.chord_length

def get_points_te_to_te(self, upper_profile_first=False):

# Points from trailing edge to leading edge.

profile = self.upper_profile if upper_profile_first else self.lower_profile

for x,y in profile[:0:-1]:  # Excluding the leading edge point
yield x*self.chord_length, y*self.chord_length

# Points from leading edge to trailing edge

profile = self.lower_profile if upper_profile_first else self.upper_profile

for x,y in profile:
yield x*self.chord_length, y*self.chord_length

def get_camberline_circles(self, limit_circles=False):
# Returns x, y of camberline and circle radii to fill profile.

import math

for (x,y),r in zip(self.camber_line, [p[1] for p in self.profile]):

if limit_circles:
# r could make circle go outside of chord, so limit r here if it looks better
rl = math.sqrt(x*x+y*y)
rt = math.sqrt((1-x)*(1-x)+(1-y)*(1-y))
r = min(r,rl,rt)

yield x*self.chord_length, y*self.chord_length, r*self.chord_length

def get_profile_name(self, basename="NACA"):

# Return NACA standard name
return "{0}{1:1d}{2:1d}{3:02d}".format(basename,
round(self.camber*100),
round(self.pos_max_camber*10),
round(self.thickness*100))

def write_te_to_te(self, filename, upper_profile_first=False):

with open(filename, "w") as f:

for x,y in self.get_points_te_to_te(upper_profile_first=upper_profile_first):
f.write(f"{x} {y}\n")

def write_upper_lower(self, filename):
# Leading edge to trailing edge

with open(filename, "w") as f:

for x,y in self.get_points_upper_profile():
f.write(f"{x} {y}\n")

f.write("\n")

for x,y in self.get_points_lower_profile():
f.write(f"{x} {y}\n")

def write_lower_upper(self, filename):
# Leading edge to trailing edge

with open(filename, "w") as f:

for x,y in self.get_points_lower_profile():
f.write(f"{x} {y}\n")

f.write("\n")

for x,y in self.get_points_upper_profile():
f.write(f"{x} {y}\n")

def write_circles(self, filename, limit_circles=True):

with open(filename, "w") as f:

# Points on the camber line with profile as radius
for x,y,r in self.get_camberline_circles(limit_circles=limit_circles):

f.write(f"{x} {y} {r}\n")
```