Aerofoil

GEVfoil: NACA 4 Series Update

TIt’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.

GEVfoil: DHMTU aerofoil implementation in GEVfoil

Introduction

Following on from the previous post, on the definition of the DHMTU aerofoil, an initial implementation of this ground-effect specific aerofoil type has been created for GEVfoil. Through the Wing In Ground Effect group on groups.io, a Matlab script was discovered. This Matlab code was created by Martin Hepperl (of JavaFoil [1] fame), in 2012. Thankfully, the Matlab script is open-source, and thus could be translated directly into Python without fear of breaching copyright.

DHMTU Aerofoil Definition

The DHMTU and their aerofoils

Without doubt, the nation that has progressed ground-effect-vehicles the furthest is Russia. More specifically, this was the USSR from the 1960s through to the late 1980s with their Ekranoplan aircraft. These GEVs (Ground Effect Vehicles) were designed by the Central Hydrofoil Design Bureau, at the heart of the aerodynamic design was the Department of Hydromechanics of the Marine Technical University (DHMTU) in Saint Petersburg.

Caspian Sea Monster

GEVfoil: Ramer–Douglas–Peucker algorithm

Generally speaking, for low-speed flow around an aerofoil, the largest gradients in the flow-properties coincide with the greatest curvature of the aerofoil, and thus are the region that requires the greatest concentration of cells (or nodes) in the computational domain.

Many of the simplified treatments for spacing points along an aerofoil use a logarithmic spacing biased towards the leading edge. This of course can create issues if spaced in the chord-wise direction (x/c). The surface-normal at the leading edge of a symmetric aerofoil is perpendicular to the stream-wise direction, and thus can become under-resolved, and even faceted, with a simple linear or logarithmic chord-wise spacing.

GEVfoil: NACA 4 Series Part 2 and CSV Reading

Previously I had made a simple function that will generate a number of points/coordinates for any specified NACA 4 series aerofoil. The limitation with this approach was that it did a fairly poor job at capturing the leading-edge. The leading edge is of critical importance to the aerodynamic performance and characteristics of the aerofoil. After some consideration, I have decided not to modify this technique. I am designing the GEVfoil tools to be as modular, generic and extendable as possible. This isn’t to say I am neglecting the importance of the leading edge, or that the method is flawed.

GEVfoil: NACA 4 Series

The intention behind GEVfoil is to establish an open-source set of Python classes to handle aerofoils (American English: airfoils). The intention is that these can be used for anything from generating simple point clouds, analytical representations all the way to STL files for CFD meshing and OpenFOAM BlockMesh output.

The first step is starting with something basic, in this case a simple class to generate NACA 4 series aerofoils:

import numpy as np
import matplotlib.pyplot as plt
 
class NACA4(object):
    """A class for generating  NACA 4 series aerofoils
        TO-DO - linspace not good at LE capture """
    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
        x = np.linspace(0, chord, 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)
        y1 = yc + yt
        y2 = yc - yt
 
        self.y = y1
 
        plt.plot(self.x, yc)
        plt.plot(self.x, y1, '.')
        plt.plot(self.x, y2, '.')
        plt.axis('equal')
        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')

For now, Matplotlib has been built into the class for visual reference. For example, 2412 generates: NACA 2412