It’s been nearly a decade since I wrote the original NACA 4 series aerofoil script, with a ‘to-do’ that I had assumed I would address in days, not years… That post is available here: GEVfoil – NACA 4 Series

I have, finally, made the small adjustments to the code to address to the ‘to-do’. Hooray, it is done! Hopefully, the motivation is clear when comparing the original and updated script. Previously, I had used linear spacing and despite my confidence in the RDP algorithm (Ramer–Douglas–Peucker algorithm) implementation, there have been deficiencies at the leading edge.

This is an image of a NACA 2412 with the original linear spacing, that leading edge would make any worthy aerodynamicist raise an eyebrow:

By simply transitioning to cosine spacing, we can cluster more points at the leading edge, the region in which the curvature changes most rapidly. This is the same NACA 2414 in the new implementation:

It’s clear to see the leading edge capture is markedly improved, with just a small modification to the script. In full, the updates are:

```
#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
class NACA4(object):
"""A class for generating NACA 4 series aerofoils
Improved LE capture with cosine spacing of points """
def __init__(self, foil, points=200, chord=1):
super(NACA4, self).__init__()
m = float(foil[0])/100 # max camber
p = float(foil[1])/10 # chordwise position of max camber
t = float(foil[2:])/100 # thickness
# Cosine-spaced points for better LE resolution
beta = np.linspace(0, np.pi, points)
x = chord * (0.5 * (1 - np.cos(beta))) # Cosine spacing of points
self.x = x
yt = self.thickness(x, t)
yc = []
for coord in x:
if m:
yc.append(self.camber(m, p, coord))
else:
# No camber
yc.append(0)
yc = np.array(yc)
y1 = yc + yt
y2 = yc - yt
self.y = y1
plt.plot(self.x, yc, label="Camber Line")
plt.plot(self.x, y1, '.', label="Upper Surface")
plt.plot(self.x, y2, '.', label="Lower Surface")
plt.axis('equal')
plt.legend()
plt.show()
def thickness(self, x, t):
# Y thickness at given x point
return t / 0.2 * \
(0.2969*np.sqrt(x)-0.126*x-0.3516*x**2+0.2843*x**3-0.1015*x**4)
def camber(self, m, p, x):
# Return the camber of the aerofoil
if x <= p:
return m/p**2 * (2*p*x - x**2)
return m/(1-p)**2 * ((1-2*p) + 2*p*x - x**2)
if __name__ == "__main__":
test = NACA4('2412')
```