# 3D printing NACA airfoil profiles

12 Jun 2020 - tsp
Last update 05 Jul 2020
4 mins

Note: This blog post is the product of a 3 AM idea. If you spot any errors comments are welcome.

## What are NACA profiles?

NACA profiles are well known airfoil shapes for wings. They’ve been developed by the National Advisory Committee for Aeronautics in the United States. All NACA profiles are identified either by 4 or 5 digits - called 4 or 5 digit series.

The four digit series identifies:

• First digit is the maximum camber as percentage of the chord.
• Second digit is the distance of maximum camber from the airfoil leading edge in tenths of the chord.
• The last two digits describe the maximum thickness of the airfoil as percent of the chord.

An NACA 4318 profile would have a maximum camber of 4% located at 30% from the leading edge with a maximum thickness of 18% of the chord.

### Are 3D printed wings flyable?

I’m going to do some experiments on this but currently it seems that they normally require some additional post processing to get a smooth surface if one uses FDM printing - for example sanding or painting. This seems to reduces vortexes on the surface of the wings and produce much more laminar flow till the tail edge (where vortexes of course occur and provide a major contribution to lift)

## Basic symmetric profiles (00xx series)

The basic symmetric 00xx airfoil is generated by

[ y_t = 5*t*(0.2969*\sqrt(x) - 0.1260*x - 0.3516*x^2 + 0.2843*x^3 - 0.1015*x^4) \\ x \in (0;1) ]

The variable $x$ is the position along the chord and runs from zero to one, $y_t$ is the half thickness at the given center-line position - to generate a symmetric airfoil this can simply be extended in both directions of the $z$ axis. The $t$ value is the maximum thickness in relation to the chord (i.e. the last two digits divided by hundred)

As one can see this has been derived as a polynomial fit.

To generate such a profile using OpenJSCAD we can simply use a polynomial and extrude from that shape:


function naca00_YT(maxThickness, x) {
return 5 * (maxThickness/100.0) * (0.2969*Math.sqrt(x) - 0.1260*x - 0.3516*x*x + 0.2843*x*x*x - 0.1015*x*x*x*x);
}

function naca00_CAG(length, maxThickness, fn) {
let pnts = [];
let step = length / fn;

pnts.push([0,0]);

// Upper half
for(let i = 1; i < fn; i++) {
pnts.push([i*step, naca00_YT(maxThickness, (i*step)/length)]);
}

// Trailing edge
pnts.push([length, 0]);

// Lower half
for(let i = fn-1; i > 0; i--) {
pnts.push([i*step, -1*naca00_YT(maxThickness, (i*step)/length)]);
}

return CAG.fromPoints(pnts);
}

function naca00(length, width, maxThickness, fn) {
return linear_extrude({ height : width }, naca00_CAG(length, maxThickness, fn));
}

function main() {
return naca00(5, 10, 60, 100);
}


These airfoils have their maximum thickness at about 30% of the airfoil.

## Cambered airfoils

If one wants a cambered airfoil one has to modify the equation a little bit. First one has to calculate the mean camber, then profile thickness as well as the direction of thickness measurement due to bent camber line:

function nacaYC(x, maxCamber, maxPosition, maxThickness) {
let m = (maxCamber / 100.0);
let p = (maxPosition / 10.0);
let t = (maxThickness / 100.0);

if(x < p) {
return m / (p*p) * (2 * p * x - x * x);
} else {
return m / ((1-p)*(1-p)) * ((1-2*p) + 2*p*x - x*x);
}
}

function nacaYCDiff(x, maxCamber, maxPosition, maxThickness) {
let m = (maxCamber / 100.0);
let p = (maxPosition / 10.0);
let t = (maxThickness / 100.0);

if(x < p) {
return m / (p*p) * (2 * p - 2 * x);
} else {
return m / ((1-p)*(1-p)) * (2*p - 2 * x);
}
}

function nacaYT(x, maxThickness) {
let t = (maxThickness / 100.0);

return t / 0.2 * (0.2969 * Math.sqrt(x) - 0.1260 * x - 0.3516 * x * x + 0.2843 * x * x * x - 0.1015 * x * x * x * x);
}

function nacaCAG(length, maxCamber, maxPositon, maxThickness, fn) {
let pnts = [];
let step = length / fn;

for(let i = 0; i <= fn; i=i+1) {
let x = (i*step) / length;
let yt = nacaYT(x, maxThickness);

let theta = Math.atan(nacaYCDiff(x, maxCamber, maxPositon, maxThickness));

let xu = x - yt * Math.sin(theta);
let yu = nacaYC(x, maxCamber, maxPositon, maxThickness) + yt * Math.cos(theta);

pnts.push([xu*length, yu*length]);
}

for(let i = fn-1; i > 0; i--) {
let x = (i*step) / length;
let yt = nacaYT(x, maxThickness);
let theta = Math.atan(nacaYCDiff(x, maxCamber, maxPositon, maxThickness));

let xl = x + yt * Math.sin(theta);
let yl = nacaYC(x, maxCamber, maxPositon, maxThickness) - yt * Math.cos(theta);

pnts.push([xl*length, yl*length]);
}

return CAG.fromPoints(pnts);
}

function naca(length, width, maxCamber, maxPositon, maxThickness, fn) {
return linear_extrude({ height : width }, nacaCAG(length, maxCamber, maxPositon, maxThickness, fn));
}

function main() {
return naca(5, 10, 2, 4, 15, 100);
}