Generating components

Rotor

FLOWunsteady uses a database of airfoil and rotor geometries to automate the generation of rotors. A prepopulated database is found in the directory under FLOWUnsteady.default_database. Alternatively, users can define their own database with custom rotors and airfoils.

The following slides describe the structure of the database, using the DJI 9443 rotor as an example:

Rotors can then be generated calling any of following functions:

FLOWUnsteady.generate_rotorMethod
generate_rotor(rotor_file::String;
                    data_path=FLOWUnsteady.default_database, optargs...)

Generates a FLOWVLM.Rotor reading the full rotor geometry from the rotor file rotor_file found in the database data_path.

source
FLOWUnsteady.generate_rotorMethod
generate_rotor(Rtip, Rhub, B, blade_file::String;
                    data_path=FLOWUnsteady.default_database, optargs...)

Generates a FLOWVLM.Rotor reading the blade geometry from the blade file blade_file found in the database data_path.

source
FLOWUnsteady.generate_rotorMethod
generate_rotor(Rtip, Rhub, B,
                    chorddist, twistdist, sweepdist, heightdist,
                    airfoil_contours;

                    # MORE ROTOR PARAMETERS
                    pitch=0.0,
                    CW=true,

                    # DISCRETIZATION SETTINGS
                    n=10, blade_r=1.0,
                    rediscretize_airfoils=true,
                    rfl_n_lower=15, rfl_n_upper=15,
                    spline_k=5, spline_s=0.001, spline_bc="extrapolate",

                    # AIRFOIL PROCESSING
                    data_path=FLOWUnsteady.default_database,
                    read_polar=vlm.ap.read_polar,
                    xfoil=false,
                    alphas=[i for i in -20:1.0:20], ncrit=9,
                    ReD=5e5, altReD=nothing, Matip=0.0,

                    # OUTPUT OPTIONS
                    verbose=false, verbose_xfoil=false, v_lvl=1,
                    plot_disc=true, save_polars=nothing)

Generates a FLOWVLM.Rotor from direct inputs.

ARGUMENTS

  • Rtip::Real : (m) rotor radius (from centerline to blade tip)
  • Rhub::Real : (m) hub radius (from centerline to blade root)
  • B::Int : Number of blades
  • chorddist::Matrix : Chord distribution (chorddist[:, 1] = r/R, chorddist[:, 2] = c/R
  • twistdist::Matrix : Twist distribution (twistdist[:, 1] = r/R, twistdist[:, 2] = degs
  • sweepdist::Matrix : LE sweep distribution (sweepdist[:, 1] = r/R, sweepdist[:, 2] = x/R
  • heightdist::Matrix : LE height distribution (heightdist[:, 1] = r/R, heightdist[:, 2] = z/R
  • airfoil_contours::Array{ Tuple{Float64, Array{Float64, 2}, String} } : Airfoil contours along the span. It must follow the pattern (pos, contour, polarfile) = airfoil_contours[i], where pos = (r-Rhub)/(Rtip-Rhub) is the spanwise position (with root=0, tip=1), contour is the airfoil profile (contour[:, 1] = x/c, contour[:, 2] = y/c), and polarfile is any file from airfoiltools.com with the airfoil lookup table (airfoil polar).

The function allows airfoil_contours::Array{ Tuple{Float64, String, String} }, following the pattern (pos, contourfile, polarfile) = airfoil_contours[i] where contourfile is a CSV file with columns x/c and y/c.

KEYWORD ARGUMENTS

Extra rotor parameters

  • pitch::Real : (deg) rotor collective pitch
  • CW::Bool : Whether the rotor rotates in the clockwise (true) or counter-clockwise (false)

Discretization

  • n::Int : Number of blade elements per blade.
  • r::Real : Spacing between elements at the tip, divided by the spacing between elements at the root.
  • spline_k::Int, spline_s::Real, spline_bc::String : To discretize the blade, the blade distributions are splined and re-discretize into n elements. These splines are done through the Dierckx package, with spline_k the order of the spline, spline_s the smoothing parameter, and spline_bc the boundary condition.
  • rediscretize_airfoils : If true, it will spline the airfoil contours and re-discretize them. It will discretize the lower side of the contour into rfl_n_lower panels, and the upper side into rfl_n_upper panels. This is necessary unless all the airfoil contours already have the same number of points.

Airfoil processing

  • data_path::String : Path to database where to read the airfoil polars from.
  • read_polar::Function : Function used for parsing the airfoil files. Use vlm.ap.read_polar for files that are direct outputs from XFOIL. Use vlm.ap.read_polar2 for CSV files.
  • xfoil::Bool : If true, the polar files will be ignored and XFOIL will be used to generate the polars instead. This will be done sweeping AOA as in alphas (in degrees) and ncrit for inflow turbulence parameter.
  • ReD::Real, Matip::Real, altReD::Tuple{Real, Real, Real}

ReD is the diameter Reynolds number based on rotational speed calculated as ReD = (omega*R)*(2*R)/nu, and Matip is the rotational+freestream Mach number at the tip. These number will be used for running XFOIL to compute airfoil polars, and will be ignored if airfoil polars are prescribed.

Give it altReD = (RPM, J, nu), and it will calculate the chord-based Reynolds accounting for the effective velocity at every station, ignoring ReD (this is more accurate, but not needed).

NOTE: If Matip is different than zero while running XFOIL, you must deactive compressibility corrections in run_simulation by using sound_spd=nothing. Otherwise, compressibility effects will be double accounted for.

Outputs

  • verbose::Bool : Whether to verbose while generating the rotor
  • verbose_xfoil::Bool : Whether to verbose while running XFOIL
  • v_lvl::Int : Indentation level for printing the verbose
  • plot_disc : If true, it will plot the discretization process of the blade, which is useful for verification and debugging. It will also plot the airfoil polars.
  • save_polars::String : Give it a path to a directory and it will save the polars plot in that directory
source
FLOWVLM.rotateFunction
rotate(rotor::Rotor, degs::Real)

Rotates the rotor by degs degrees in the direction of rotation (rotor.CW).

VLM Wing

FLOWVLM.simpleWingFunction
simpleWing(b, ar, tr, twist, lambda, gamma; twist_tip=twist, n=20, r=2.0)

Generates a simple wing with constant twist, sweep, dihedral, and taper ratio.

Arguments

  • b : (float) span
  • ar : (float) aspect ratio (span / tip chord)
  • tr : (float) taper ratio (tip chord / root chord)
  • twist : (float) twist of the root in degrees
  • lambda : (float) sweep in degrees
  • gamma : (float) dihedral in degrees
  • twist_tip : (float) twist of the tip (if different than root)
  • n : (int) number of horseshoes per semi-span
  • r : (float) horseshoes' expansion ratio
FLOWVLM.complexWingFunction
complexWing(b, AR, tr, n, pos, twist, sweep, dihed; symmetric=true)

Generates a wing with an abritrary distribution of twist, sweep, dihedral, and chord length.

Arguments

  • b::Float64 : Span
  • AR::Float64 : Reference aspect ratio (span / tip chord)
  • n::Int64 : Number of horseshoes per semi-span
  • pos::Array{Float64,1} : Position of stations along the semi-span
  • clen::Array{Float64,1} : Chord length at each station (normalized by tip chord)
  • twist::Array{Float64,1} : (deg) twist at each station
  • sweep::Array{Float64,1} : (deg) sweep between each station
  • dihed::Array{Float64,1} : (deg) dihedral between each station

Optional Arguments

  • symmetric::Bool=true : If false, generates only a half-span
  • chordalign::Float64=0.0 : Indicate position along chord length to align chords. Give it 0 for alignment about leading edge, 0.25 for alignment about quarter chord, and 1.0 for alignment about trailing edge.

Example

# Wing dimensions
b = 1.0                     # (m) span
AR = 12.0                   # Span over tip chord
n = 50                      # Horseshoes per semi-span

# Define chord, twist, sweep, and dihedral distributions
pos = [0, 0.25, 0.75, 1]    # Position of stations along semi-span
clen = [2.0, 1.5, 1.5, 1]   # Normalized chord length at each station
twist = [0.0, 0.0, -2.0, -4.0]    # (deg) twist at each station
sweep = [10.0, 15.0, 35.0]  # (deg) sweep between stations
dihed = [2.0, 5.0, 7.5]     # (deg) dihedral between stations

# Generate the wing
wing = vlm.complexWing(b, AR, n, pos, clen, twist, sweep, dihed)

FLOWVLM Systems

FLOWVLM.WingSystemType
WingSystem(wings::Array{Union{Wing, WingSystem}}, wing_names::Array{String})

Initiates a system of wings. All methods applicable to a Wing object are applicable to a WingSystem. When solved, it will calculate the interaction between wings.

FLOWVLM.addwingFunction
addwing(self::WingSystem, wing_name::String, wing::Union{Wing, Rotor})

Adds a wing (or rotor) to the system. The local reference frame of the wing then is then in relation to the local reference frame of the System.

FLOWVLM.get_wingFunction
get_wing(self::WingSystem, wing_name::String)

Returns the wing of name wing_name.

get_wing(self::WingSystem, wing_i::Int)

Returns the i-th wing.

FLOWVLM.setcoordsystemFunction
setcoordsystem(wing::Wing, O::Vector, Oaxis::Matrix)

Redefines the local coordinate system of the wing, where O is the new origin and Oaxis is the matrix of unit vectors

setcoordsystem(system::WingSystem, O::Vector, Oaxis::Matrix; wings=String[])

Redefines the local coordinate system of the system, where O is the new origin and Oaxis is the matrix of unit vectors. It transforms the coordinates of all wings in the system accordingly.

To change the local coordinate system of a specific wing relative to the system's coordinate system, give the name of the wing in an array under argument wings.

setcoordsystem(rotor::Rotor, O::Vector, Oaxis::Matrix; user=false)

Redefines the local coordinate system of the rotor, where O is the new origin and Oaxis is the matrix of unit vectors. If the user is calling this function, give user=true, otherwise it will not do the automatic translation to blade coordinate system.

FLOWVLM.get_mFunction
get_m(wing::Wing)

Returns the number of horseshoes in the wing

get_m(system::WingSystem)

Returns the total number of horseshoes in the system

get_m(rotor::Rotor)

Returns the total number of horseshoes in the rotor

FLOWVLM.get_mBladeFunction
get_mBlade(rotor::Rotor)

Returns the number of horseshoes per blade