Airfoil Geometry Manipulation Tools

Here we include the variety of methods for manipulating airfoil geometries in useful ways implemented in AirfoilTools.

Deconstruction

It is often convenient to deconstruct an airfoil into its upper and lower halves. The split_upper_lower function makes this process straightforward.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = naca4()

xl, xu, yl, yu = split_upper_lower(x, y)

plot(xl, yl; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Lower Side")
plot!(xu, yu; label="Upper Side")
Example block output
FLOWFoil.AirfoilTools.split_upper_lowerFunction
split_upper_lower(x, y; idx::Integer=nothing)

Split the upper and lower halves of the airfoil coordinates.

Assumes leading edge point is at first minimum x value if idx is not provided. Returns the upper and lower coordinates each with the leading edge point. Assumes airfoil is defined clockwise starting at the trailing edge.

Arguments

  • x::AbstractArray{Float} : Vector of x coordinates
  • y::AbstractArray{Float} : Vector of y coordinates

Keyword Arguments

  • idx::Integer : optional index at which to split the coordinates

Returns

  • xl::AbstractArray{Float} : Vector of lower half of x coordinates
  • xu::AbstractArray{Float} : Vector of upper half of x coordinates
  • yl::AbstractArray{Float} : Vector of lower half of y coordinates
  • yu::AbstractArray{Float} : Vector of upper half of y coordinates
source
split_upper_lower(coordaintes; idx::Integer=nothing)

Split the upper and lower halves of the airfoil coordinates.

Assumes leading edge point is at first minimum x value if idx is not provided. Returns the upper and lower coordinates each with the leading edge point. Assumes airfoil is defined clockwise starting at the trailing edge.

Arguments

  • coordinates::Matrix{Float} : Matrix of [x y] coordinates

Keyword Arguments

  • idx::Integer : optional index at which to split the coordinates

Returns

  • xl::AbstractArray{Float} : View of lower half of x coordinates
  • xu::AbstractArray{Float} : View of upper half of x coordinates
  • yl::AbstractArray{Float} : View of lower half of y coordinates
  • yu::AbstractArray{Float} : View of upper half of y coordinates
source

Translation

There are various transformation functions that can also be helpful in various situations.

We can flip an airfoil.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = naca4()

plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Nominal")
plot!(flip!(copy(x)), y; label="x Flipped")
Example block output
Note

Note that this function both flips and translates. It's primarily useful for flipping the x coordinates. If you want to flip the y coordinate, applying a simple negative would be best

plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Nominal")
plot!(x, flip!(copy(y)); label="y Flipped")
plot!(x, -y; label="y Negated")
Example block output

Another thing we could do is translate the airfoil so that the trailing edge is at y=0.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = naca4()
y .+= 0.2

plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Nominal")

xy = [x y]
zero_y_te!(xy)
plot!(xy[:,1], xy[:,2]; label="TE zeroed")
Example block output
Note

This only vertically translates the geometry, it does not rotate things to put the leading edge on the axis as well if the geometry is rotated.

FLOWFoil.AirfoilTools.zero_y_te!Function
zero_y_te!(coordinates)

Places trailing edge on the x-axis.

Arguments

  • coordinates::Array{Float} : Array of [x y] coordinates to be updated in place.
source

Rotation

We can also rotate airfoils about arbitrary points.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = naca4()

plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Nominal")

xy = [x y]
angle = 10.0 # degrees

# rotate by angle about default point: (0,0)
rotate_coordinates!(xy, angle)

plot!(xy[:,1], xy[:,2], label="rotated about (0,0)")

# rotate again but about the trailing edge
xy2 = [x y]
rotate_coordinates!(xy2, angle; rotation_point=[1.0,0.0])

plot!(xy2[:,1], xy2[:,2], label="rotated about (1,0)")
Example block output
FLOWFoil.AirfoilTools.rotate_coordinates!Function
rotate_coordinates!(coordinates, angle; rotation_point=[0.0; 0.0])

Rotate coordinates clockwise about rotation_point by angle in degrees.

Arguments

  • coordinates::Array{Float} : Array of [x y] coordinates to be updated in place.
  • angle::Float=0.0 : Angles, in degrees, by which to rotate the coordinates clockwise (positive angle will pitch airfoil up).

Keyword Arguments

  • rotation_point::AbstractArray{Float}=[0.0; 0.0] : Array of [x y] position of point about which to perform rotation.
source

Normalization

It can also be convenient to normalize coordinates to have a chord length of one.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = 2.0.*naca4()

plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Nominal")

normalize_coordinates!(x, y)

plot!(x, y; label="Normalized")
Example block output
Note

This function is designed to go from a nominal airfoil (length 1, leading edge and trailing edges on the axis, etc.) to something else. The operations are in the order: scale, rotate, then translate.

FLOWFoil.AirfoilTools.normalize_coordinates!Function
normalize_coordinates!(coordinates)

Normalize airfoil to unit chord and shift leading edge to zero. Adjusts coordinates in place.

Arguments

  • coordinates::AbstractArray{Float} : Array of [x y] coordinates
source
normalize_coordinates!(x, y)

Normalize airfoil to unit chord and shift leading edge to zero. Adjusts coordinates in place.

Arguments

  • x::Array{Float} : Array of x coordinates
  • y::Array{Float} : Array of y coordinates
source

Scale, Rotate, and Translate

Sometimes, we might want do several operations together, which we can with the position_coordinates! function.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = naca4()
plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Unscaled")

xy = [x y]
position_coordinates!(
    xy; scale=0.8, angle=3.0, location=[-0.2; 0.1], rotation_point=[0.0; 0.0], flipped=true
)

plot!(xy[:, 1], xy[:, 2]; label="Re-positioned")
Example block output
FLOWFoil.AirfoilTools.position_coordinates!Function
position_coordinates!(coordinates, scale, angle, location)

Scale, Rotate, and Transform (in that order) airfoil coordinates.

Arguments

  • coordinates::Array{Float} : Array of [x y] coordinates to be updated in place.

Keyword Arguments

  • scale::Float=1.0 : Value by which to scale coordinates.
  • angle::Float=0.0 : Angles, in degrees, by which to rotate the coordinates clockwise (positive angle will pitch airfoil up).
  • location::AbstractArray{Float}=[0.0; 0.0] : Array of [x y] position of leading edge location.
  • rotation_point::AbstractArray{Float}=[0.0; 0.0] : Array of [x y] position of point about which to perform rotation.
  • flipped::Bool : flag whether to flip airfoil upside down.

Returns

  • x::Array{Float} : array of x-coordinates
  • y::Array{Float} : array of y-coordinates
source
position_coordinates!(
    coordinates::Vector{AbstractArray{TF}};
    scales=[1.0],
    angles=[0.0],
    locations=[[0.0; 0.0],],
    rotation_points=[[0.0; 0.0],],
    flipped=[false],
) where {TF}

Multi-airfoil version of position_coordinates!.

If keyword arguments are give as single valued vectors, the same values are used for all coordinate sets. If keyword arguments are provided as vectors of length greater than 1, they must have the same length as the set of coordinates. For example, if scaling 3 airfoils, there will be a vector of 3 airfoil coordinate sets input and scales must either be a one element vector or a vector of length 3.

source

Re-definition

Sometimes, we may want to "re-panel" an airfoil, (a good example is the PANE command in Xfoil). The repanel_airfoil method splines the provided geometry and then resamples it using cosine spacing to give a higher density of coordinates at the leading and trailing edges.

using FLOWFoil.AirfoilTools
using Plots
using LaTeXStrings

x, y = naca4(; x = range(0.0,1.0,30))
plot(x, y; aspectratio=1, xlabel=L"x", ylabel=L"y", label="Linear Spaced", marker=true, markersize=4)

x_rp, y_rp = repanel_airfoil(x,y; N=161)

scatter!(x_rp, y_rp; label="Cosine Spaced", markersize=1.5)
Example block output
Note

Note that if you simply have too few coordinates to begin with, repaneling the airfoil isn't going to smooth out an inaccurate leading edge. In such a case you should consider fitting the geometry with one of the airfoil parameterizazation methods, which will ensure a round leading edge.

FLOWFoil.AirfoilTools.repanel_airfoilFunction
repanel_airfoil(x, y; N=160)

Repanels airfoil coordinates using Akima splines with N coordinate points.

Arguments

  • x::AbstractArray{Float} : vector containing the x coordinates of the airfoil
  • y::AbstractArray{Float} : vector containing the y coordinates of the airfoil

Keyword Arguements

  • N::Int : Number of data points to be returned after repaneling. Will only return odd numbers, if N is even, N+1 points will be returned.

Returns

  • repaneled_x::AbstractArray{Float} : Repaneled, cosine spaced x corrdinates of the airfoil
  • repaneled_y::AbstractArray{Float} : y coordinates of the repaneled airfoil obtained using an akima spline
source
repanel_airfoil(coordinates; N=160)

Repanels airfoil coordinates using Akima splines with N coordinate points.

Arguments

  • coordinates::Array{Float} : Array of [x y] coordinates

Keyword Arguements

  • N::Int=160 : Number of data points to be returned after repaneling. Will only return odd numbers, if N is even, N+1 points will be returned.

Returns

  • repaneled_coordinates::Array{Float} : new coordinate array.
source
FLOWFoil.AirfoilTools.repanel_revolutionFunction
repanel_revolution(coordinates; N=160)

Repanels body of revolution coordinates using Akima splines with N coordinate points.

Arguments

  • coordinates::Array{Float} : Array of [x y] coordinates

Keyword Arguements

  • N::Int=160 : Number of data points to be returned after repaneling. Will only return odd numbers, if N is even, N+1 points will be returned.

Returns

  • repaneled_coordinates::Array{Float} : new coordinate array.
source

Contributing

We welcome the addition of more convenience functions for airfoil geometry manipulation.