https://badge.fury.io/py/ADRpy.svg https://travis-ci.com/sobester/ADRpy.svg?branch=master

Aircraft Design Recipes in Python – User’s Guide

by Andras Sobester

Welcome to ADRpy, a free library of aircraft design and performance analysis tools suitable for rapid sizing calculations. The models implemented in ADRpy are largely analytical, enabling fast explorations of large design spaces. Most of the methods can already be used in the earliest phases of the design process, even before a geometry model is built. In fact, ADRpy can serve as the basis of sensitivity analyses and uncertainty quantification (UQ) exercises as part of the analysis of the feasibility of the design requirements.

The classes, methods and functions of the library fall into three broad categories:

1. Models of the operating environment. These live in the Atmospheres module and include virtual atmospheres (ISA, MIL-HDBK-310, etc.), runway models (suitable for take-off and landing performance modelling using a ‘real world’ runway database) and models of propulsion performance response to variations in ambient conditions.

2. Conceptual sizing methods for fixed wing aircraft sizing (wing area and thrust/power requirements), given a set of constraints, such as take-off distance, climb rate, etc. These can be found in the Constraint Analysis Module.

3. Utilities, including a module for Unit Conversions and a set of Miscellaneous Utilities.

This document contains numerous usage examples and details on the inputs and outputs of each class, method and function. You can copy and paste these into .py files and execute those in a development environment or from Python’s command prompt, you can copy and paste them line by line into a Python terminal or (perhaps most usefully) into a Jupyter notebook. Any problems, issues, questions, please raise an issue on GitHub. Happy designing!

Installing and running ADRpy

ADRpy is written in Python 3 and tested in Python 3.4, 3.5, 3.5-dev, 3.6, 3.6-dev and 3.7-dev. It is not available for Python 2.

First and foremost, you will need to have Python installed - you can get the latest version here or as part of a number of alternative packages.

Once you have Python, on most systems you should be able to simply open an operating system terminal and at the command prompt type python -m pip install ADRpy or just pip install ADRpy (pip is a Python package; in the unlikely event that it is not available on your system, download get-pip.py and run it by entering python get-pip.py at the operating system prompt).

For the ADRpy source code, license conditions (GPLv3), and alternative installation instructions see the ADRpy GitHub repository.

Notebooks

ADRpy includes a library of examples recorded in Jupyter notebooks. You can play with these ‘live’ in Binder:

https://mybinder.org/badge_logo.svg

…or you can click File / Download as / … to create your own local copy in any number of formats. [Note: if you don’t want to wait for Binder to generate the library, you can still access the ‘static’ versions of the notebooks through nbviewer - click on the required notebook in the lower half of the holding page.]

ADRpy Modules

Atmospheres

This module contains tools for defining the environment in which aircraft performance analyses, trade-off studies, conceptual sizing and other aircraft engineering calculations can be carried out.

The module contains the following class definitions:

Runway

Definition of a runway object, including the capability to instantiate a runway from a ‘real world’ database of the world’s airports.

Atmosphere

Definition of a virtual atmosphere object. This includes a number of methods that allow the user to query parameters of the atmosphere.

Obsprofile

Definition of an atmospheric observation (sounding) object. This allows the user to create bespoke atmospheres and any other atmospheres derived from specified temperature, pressure, etc. profiles (such as the MIL HDBK 310 atmospheres).

See, in what follows, detailed descriptions of these classes, their methods, functions, as well as usage examples.

class atmospheres.Atmosphere(offset_deg=0, profile=None)

Standard or off-standard/custom atmospheres.

Available atmosphere types

1. The International Standard Atmosphere (ISA) model. Based on ESDU Data Item 77022, “Equations for calculation of International Standard Atmosphere and associated off-standard atmospheres”, published in 1977, amended in 2008. It covers the first 50km of the atmosphere.

  1. Off-standard, temperature offset versions of the above.

3. Extremely warm/cold, and low/high density atmospheres from US MIL HDBK 310

  1. User-defined atmospheres based on interpolated data.

Example

from ADRpy import atmospheres as at
from ADRpy import unitconversions as co

# Instantiate an atmosphere object: an off-standard ISA
# with a -10C offset
isa_minus10 = at.Atmosphere(offset_deg=-10)

# Query altitude
altitude_ft = 38000
altitude_m = co.feet2m(altitude_ft)

# Query the ambient density in this model at the specified altitude
print("ISA-10C density at", str(altitude_ft), "feet (geopotential):",
    isa_minus10.airdens_kgpm3(altitude_m), "kg/m^3")

# Query the speed of sound in this model at the specified altitude
print("ISA-10C speed of sound at", str(altitude_ft), "feet (geopotential):",
    isa_minus10.vsound_mps(altitude_m), "m/s")

Output:

ISA-10C density at 38000 feet (geopotential): 0.348049478999 kg/m^3
ISA-10C speed of sound at 38000 feet (geopotential): 288.1792251702055 m/s

Note

The unit tests (found in tests/t_atmospheres.py in the GitHub repository) compare the atmosphere outputs against data from the 1976 US Standard Atmosphere, NASA-TM-X-74335. ESDU 77022 describes its ISA model as being identical for all practical purposes with the US Standard Atmospheres.

Methods

airdens_kgpm3(altitudes_m=0)

Ambient density in the current atmosphere in \(\mathrm{kg/m}^3\).

airpress_mbar(altitudes_m=0)

Air pressure in mbar.

airpress_pa(altitudes_m=0)

Pressures in the selected atmosphere, in Pa.

airtemp_c(altitudes_m=0)

Air temperature in Celsius.

airtemp_k(altitudes_m=0)

Temperatures in the selected atmosphere, in K.

Parameter:

altitudes_m

altitudes at which the temperature is to be interrogated (float or array of floats)

Output:

Ambient temperature (Static Air Temperature) in Kelvin.

Example

from ADRpy import atmospheres as at

isa = at.Atmosphere()

print("ISA temperatures at SL, 5km, 10km (geopotential):",
    isa.airtemp_k([0, 5000, 10000]), "K")

Output:

ISA temperatures at SL, 5km, 10km (geopotential): [ 288.15  255.65  223.15] K
dynamicpressure_pa(airspeed_mps=0, altitudes_m=0)

Dynamic pressure in the current atmosphere at a given true airspeed and altitude

Parameters

airspeed_mps

float, true airspeed in m/s (MPSTAS)

altitudes_m

float array, altitudes in m where the dynamic pressure is to be computed

Returns

float or array of floats, dynamic pressure values

Example

from ADRpy import atmospheres as at
from ADRpy import unitconversions as co

ISA = at.Atmosphere()

altitudelist_m = [0, 500, 1000, 1500]

MPSTAS = 20

q_Pa = ISA.dynamicpressure_pa(MPSTAS, altitudelist_m)

q_mbar = co.pa2mbar(q_Pa)

print(q_mbar)

Output:

[ 2.44999974  2.33453737  2.22328473  2.11613426]
eas2tas(eas, altitude_m)

Converts EAS to TAS at a given altitude.

The method first calculates the density ratio \(\sigma\) (as the ratio of the ambient density at altitude_m and at the ambient density at sea level); the true airspeed is then calculated as:

\[\mathrm{TAS}=\frac{\mathrm{EAS}}{\sqrt{\sigma}}\]

Parameters

eas

Float or numpy array of floats. Equivalent airspeed (any unit, returned TAS value will be in the same unit).abs

altitude_m

Float. Flight altitude in metres.

Returns

True airspeed in the same units as the EAS input.

keas2kcas(keas, altitude_m)

Converts equivalent airspeed into calibrated airspeed.

The relationship between the two depends on the Mach number \(M\) and the ratio \(\delta\) of the pressure at the current altitude \(P_\mathrm{alt}\) and the sea level pressure \(P_\mathrm{0}\). We approximate this relationship with the expression:

\[\mathrm{CAS}\approx\mathrm{EAS}\left[1 + \frac{1}{8}(1-\delta)M^2 + \frac{3}{640}\left(1-10\delta+9\delta^2 \right)M^4 \right]\]

Parameters

keas

float or numpy array, equivalent airspeed in knots.

altitude_m

float, altitude in metres.

Returns

kcas

float or numpy array, calibrated airspeed in knots.

mach

float, Mach number.

See also mpseas2mpscas

Notes

The reverse conversion is slightly more complicated, as their relationship depends on the Mach number. This, in turn, requires the computation of the true airspeed and that can only be computed from EAS, not CAS. The unit- specific nature of the function is also the result of the need for computing the Mach number.

Example

import numpy as np
from ADRpy import atmospheres as at
from ADRpy import unitconversions as co

isa = at.Atmosphere()

keas = np.array([100, 200, 300])
altitude_m = co.feet2m(40000)

kcas, mach = isa.keas2kcas(keas, altitude_m)

print(kcas)

Output:

[ 101.25392563  209.93839073  333.01861569]
mach(airspeed_mps, altitude_m=0)

Mach number at a given speed (m/s) and altitude (m)

mpseas2mpscas(mpseas, altitude_m)

Convert EAS (m/s) to CAS (m/s) at a given altitude (m)

tas2eas(tas, altitude_m)

Convert TAS to EAS at a given altitude

vsound_kts(altitudes_m=0)

Speed of sound in knots.

vsound_mps(altitudes_m=0)

Speed of sound in m/s at an altitude given in m.

class atmospheres.Obsprofile(alt_m=None, temp_k=None, rho_kgpm3=None, p_pa=None)

Observed atmosphere profile data.

hialt()

The maximum valid altitude (in m) of the interpolators.

loalt()

The minimum valid altitude (in m) of the interpolators.

class atmospheres.Runway(icao_code=None, rwyno=0, elevation_ft=0, heading=0, surf='ASP', length_ft=10000, width_ft=100)

Runway model to be used for take-off/landing performance calculations.

Parameters (all optional):

icao_code

String. International Civil Aviation Organisation code of the airport. Required if the user wishes to equip this object with the attributes of a specific, existing runway, e.g., ‘EGLL’ (London Heathrow airport). Runway data is obtained from an off-line image of the ourairports.com database.

rwyno

Integer. Specifies which of the runways at the airport specified by the ICAO code above we want to associate with the runway object. A ValueError will be thrown if rwyno exceeds the number of runways at the airport specified by the icao_code. The number of runways can be found in the nrways attribute of the runway object:

runway = at.Runway('KDEN')
runway.nrways

Output:

6
elevation_ft, heading, surf, length_ft, width_ft

Parameters of bespoke, user-defined runways. The recommended use of these is as indicated by their names, though the user may wish to adopt their own definitions to suit particular applications (for example, surf can be any string describing the runway surface).

Example - creating and querying a Runway class object:

from ADRpy import atmospheres as at

runway = at.Runway('EGLL', 0)

print('Runway: ', runway.le_ident, '/', runway.he_ident)

print('True headings: ',
    runway.le_heading_degt, '/',
    runway.he_heading_degt, 'degrees')

print('Elevation (low end): ', runway.le_elevation_ft, 'ft')

print('Length: ', runway.length_ft, 'ft')

Outputs:

Runway:  09L / 27R
True headings:  89.6 / 269.6 degrees
Elevation (low end):  79.0 ft
Length:  12799.0 ft
windcomponents(wind_dirs_deg, wind_speeds)

Resolves list of wind speeds and directions into runway/cross components on the current runway.

Parameters:

wind_dirs_deg

List of floats. Wind directions expressed in degrees true (e.g., directions specified in a METAR).

wind_speeds

List of floats. Wind_speeds (in the units in which the output is desired).

Outputs:

runway_component

Scalar or numpy array. The runway direction component of the wind (sign convention: headwinds are positive).

crosswind_component

Scalar or numpy array. The cross component of the wind (sign convention: winds from the right are positive).

Example

# Given a METAR, calculate the wind components on Rwy 09 at Yeovilton

from ADRpy import atmospheres as at
from metar import Metar

runway = at.Runway('EGDY', 1)

egdywx = Metar.Metar('EGDY 211350Z 30017G25KT 9999 FEW028 BKN038 08/01 Q1031')

direction_deg = egdywx.wind_dir.value()
windspeed_kts = egdywx.wind_speed.value()

rwy_knots, cross_knots = runway.windcomponents(direction_deg, windspeed_kts)

print("Runway component:", rwy_knots)
print("Cross component:", cross_knots)

Output:

Runway component: -13.5946391943
Cross component: -10.2071438305
atmospheres.geom2geop45m(altitude_m)

Convert geometric height to geopotential (m) assuming 45deg lat

atmospheres.geop2geom45m(altitude_m)

Convert geometric height to geopotential (m) assuming 45deg lat

atmospheres.idealgasdens_kgm3(p_pa, temp_k)

Density from pressure and temperature, on ideal gas assumption

atmospheres.idealgaspress_pa(rho_kgpm3, temp_k)

Pressure from density and temperature, on ideal gas assumption

atmospheres.mil_hdbk_310(high_or_low, temp_or_dens, alt_km)

Load an atmospheric data set from US Military Handbook 310

atmospheres.pistonpowerfactor(density_kgpm3)

Gagg-Ferrar model. Multiply by this to get power at given density.

atmospheres.pressratio(pressure_pa, mach)

Ratio of total pressure and the standard SL pressure

atmospheres.reciprocalhdg(heading_deg)

The reciprocal of a heading in degrees

atmospheres.tatbysat(mach, recfac=1.0)

Ratio of total and static air temperature at a given Mach no

atmospheres.tempratio(temp_c, mach)

Ratio of total temperature and the standard SL temperature

atmospheres.turbofanthrustfactor(temp_c, pressure_pa, mach, throttleratio=1, ptype='highbpr')

Multiply SL static thrust by this to get thrust at specified conditions

atmospheres.turbojetthrustfactor(temp_c, pressure_pa, mach, throttleratio=1, afterburner=False)

Multiply SL static thrust by this to get thrust at specified conditions

atmospheres.turbopropthrustfactor(temp_c, pressure_pa, mach, throttleratio=1)

Multiply SL static thrust by this to get thrust at specified conditions

Constraint Analysis Module

This module contains tools for the constraint analysis of fixed wing aircraft.

class constraintanalysis.AircraftConcept(brief, design, performance, designatm)

Definition of a basic aircraft concept. This is the most important class in ADRpy. An object of this class defines an aircraft design in terms of the brief it is aiming to meet, high level design variables that specify it, key parameters that describe its performance, as well as the atmosphere it operates in. These are the four arguments that define an object of the AircraftConcept class. The first three are dictionaries, as described below, the last is an object of Atmosphere class.

Parameters:

brief

Dictionary. Definition of the design brief, that is, the requirements the design seeks to meet. Contains the following key names:

rwyelevation_m

Float. The elevation (in metres) of the runway againts which the take-off constraint is defined. Optional, defaults to zero (sea level).

groundrun_m

Float. Length (in metres) of take-off ground run in meters at the elevation defined by the rwyelevation_m entry of the dictionary. This is a basic, 100% N1, no wind, zero runway gradient ground run.

stloadfactor

Float. Load factor to be sustained by the aircraft in a steady, level turn.

turnalt_m

Float. Altitude (in metres) where the turn requirement is defined. Optional, defaults to zero (sea level).

turnspeed_ktas

Float. True airspeed (in knots) at which the turn requirement (above) has to be met. Since the dynamics of turning flight is dominated by inertia, which depends on ground speed, the turn speed is specified here as TAS (on the zero wind assumption). If you’d rather specify this as IAS/CAS/EAS, use eas2tas first to obtain the TAS value.

climbalt_m

Float. The altitude (in metres) where the climb rate requirement is specified. Optional, defaults to zero (sea level).

climbspeed_kias

Float. The airspeed (in knots, indicated) at which the required climb rate has to be achieved.

climbrate_fpm

Float. Required climb rate (in feet per minute) at the altitude specified in the climbalt_m entry (above).

cruisealt_m

Float. The altitude at which the cruise speed requirement will be defined.

cruisespeed_ktas

Float. The required cruise speed (in knots, true airspeed) at the altitude specified in the cruisealt_m entry (above).

cruisethrustfact

Float. The fraction (nondimensional) of the maximum available thrust at which the cruise speed requirement must be achieved.

servceil_m

Float. The required service ceiling in meters (that is, the altitude at which the maximum rate of climb drops to 100 feet per minute).

secclimbspd_kias

Float. The speed (knots indicated airspeed) at which the service ceiling must be reached. This should be an estimate of the best rate of climb speed.

vstallclean_kcas

Float. The maximum acceptable stall speed (in knots, indicated/calibrated).

Example design brief:

brief = {'rwyelevation_m':0, 'groundrun_m':313,
         'stloadfactor': 1.5, 'turnalt_m': 1000, 'turnspeed_ktas': 100,
         'climbalt_m': 0, 'climbspeed_kias': 101, 'climbrate_fpm': 1398,
         'cruisealt_m': 3048, 'cruisespeed_ktas': 182, 'cruisethrustfact': 1.0,
         'servceil_m': 6580, 'secclimbspd_kias': 92,
         'vstallclean_kcas': 69}
design

Dictionary. Definition of key, high level design variables that define the future design.

aspectratio

Float. Wing aspect ratio.

sweep_le_deg

Float. Main wing leading edge sweep angle (in degrees). Optional, defaults to zero (no sweep).

sweep_mt_deg

Float. Main wing sweep angle measured at the maximum thickness point. Optional, defaults to zero.

bpr

Float. Specifies the propulsion system type. For jet engines (powered by axial gas turbines) this should be the bypass ratio (hence ‘bpr’). Set to -1 for piston engines, -2 for turboprops and -3 if no power/thrust corrections are needed (e.g., for electric motors).

weightfractions

Dictionary, specifying at what fraction of the maximum take-off weight do various constraints have to be met. It should contain the following keys: take-off, climb, cruise, turn, servceil. Optional, each defaults to 1.0 if not specified.

performance

Dictionary. Definition of key, high level design performance estimates.

CDTO

Float. Take-off drag coefficient.

CLTO

Float. Take-off lift coefficient.

CLmaxTO

Float. Maximum lift coefficient in take-off conditions.

CLmaxclean

Float. Maximum lift coefficient in flight, in clean configuration.

mu_R

Float. Coefficient of rolling resistance on the wheels.

CDminclean

Float. Zero lift drag coefficient in clean configuration.

etaprop

Dictionary. Propeller efficiency in various phases of the mission. It should contain the following keys: take-off, climb, cruise, turn, servceil. Optional, unspecified entries in the dictionary default to the following values:

etap = {'take-off': 0.45, 'climb': 0.75, 'cruise': 0.85,
        'turn': 0.85, 'servceil': 0.65}
designatm

Atmosphere class object. Specifies the virtual atmosphere in which all the design calculations within the AircraftConcept class will be performed.

bank2turnradius(bankangle_deg)

Calculates the turn radius in m, given the turn TAS and the bank angle

bestclimbspeedprop(wingloading_pa, altitude_m)

The best rate of climb speed for a propeller aircraft

induceddragfact(whichoswald=1)

Lift induced drag factor k estimate (Cd = Cd0 + k.Cl^2)

map2static()

Maps the average take-off thrust to static thrust. If a bypass ratio is not specified, it returns a value of 1.

oswaldspaneff1()

Raymer’s Oswald span efficiency estimate, sweep < 30, moderate AR

oswaldspaneff2()

Oswald span efficiency estimate due to Brandt et al.

oswaldspaneff3()

Raymer’s Oswald span efficiency estimate, swept wings

powerrequired(wingloadinglist_pa, tow_kg, feasibleonly=True)

Calculate the power (in HP) required for t/o, trn, clm, crs, sec.

smincleanstall_m2(weight_kg)

Minimum wing area defined by the clean stall CLmax and the weight

thrusttoweight_sustainedturn(wingloading_pa)

Baseline T/W req’d for sustaining a given load factor at a certain altitude

thrusttoweight_takeoff(wingloading_pa)

The thrust to weight ratio required for take-off. This function is an implementation of the following simple, analytical model:

\[\frac{\overline{T}}{W} = 1.21\frac{W/S}{\rho C_\mathrm{Lmax}^\mathrm{TO}gd_ \mathrm{G}}+\frac{1}{2}\frac{C_\mathrm{D}^\mathrm{TO}}{C_\mathrm{L}^\mathrm{TO}} +\frac{1}{2}\mu_\mathrm{R}\]

where \(\overline{T}\) is the average thrust during the take-off run, \(W/S\) is the wing loading, \(d_\mathrm{G}\) is the required ground roll, \(C_\mathrm{D}^\mathrm{TO}\) and \(C_\mathrm{L}^\mathrm{TO}\) are the ‘all wheels on the runway’ drag and lift coefficient respectively in the take-off configuration, \(C_\mathrm{Lmax}^\mathrm{TO}\) is the maximum lift coefficient achieved during the take-off run (during rotation), \(\rho\) is the ambient density and \(\mu_\mathrm{R}\) is the coefficient of rolling resistance on the wheels.

This is a function exposed to the user for clarity and added flexibility. If you need to calculate the trust to weight ratio required for take-off, use twrequired_to. This corrects the output of this function to account for the environmental conditions (including their impact on engine performance) and includes a mapping to static thrust. thrusttoweight_takeoff should only be used if you would like to perform these corrections in a different way than implemented in twrequired_to.

If a full constraint analysis is required, twrequired should be used. A similar ‘full constraint set’ function is available for calculating the power demanded of the engine of a propeller-driven engine or electric motor (to satisfy the constraint set) - this is called powerrequired.

twrequired(wingloadinglist_pa, feasibleonly=True)

Calculate the T/W required for t/o, trn, clm, crs, sec.

This method integrates the full set of constraints and it gives the user a compact way of performing a full constraint analysis. If a specific constraint is required only, the individual methods can be called separately: twrequired_to (take-off), twrequired_trn (turn), twrequired_clm (climb), twrequired_trn (turn), twrequired_crs (cruise), twrequired_sec (service ceiling).

Parameters

wingloading_pa

float or numpy array, list of wing loading values in Pa.

Returns

twreq

dictionary variable, wherein each entry contains vectors related to one of the constraints: twreq['take-off'] (T/W required for take-off), twreq['liftoffspeed_mps'] (liftoff speed in m/s), twreq['avspeed_mps'] (average speed of the take-off run, in m/s), twreq['turn'] (T/W required for the turn), twreq['turnfeasible'] (same as twreq['turn'], but with NaN where the maximum lift coefficient is exceeded), twreq['turncl'] (lift coefficient required in the turn), twreq['climb'] (T/W required for climb), twreq['cruise'] (T/W required for cruise), twreq['servceil'] (T/W required for the service ceiling constraint), twreq['combined'] (the T/W required to meet all of the above).

twrequired_clm(wingloading_pa)

Calculates the T/W required for climbing for a range of wing loadings.

Parameters

wingloading_pa

float or numpy array, list of wing loading values in Pa.

Returns

twratio

array, thrust to weight ratio required for the given wing loadings.

See also twrequired

Notes

1. Use twrequired if a full constraint analysis is desired, as this integrates the take-off, turn, climb, cruise, and service ceiling constraints, as well as computing the combined constraint boundary.

2. The calculation currently approximates climb performance on the constant TAS assumption (though note that the design brief dictionary variable must specify the climb speed as IAS, which is the operationally relevant figure) - a future version of the code will remove this approximation and assume constant IAS.

Example

Given a climb rate (in feet per minute) and a climb speed (KIAS), as well as an altitude (in a given atmosphere) where these must be achieved, as well as a set of basic geometrical and aerodynamic performance parameters, compute the necessary T/W ratio to hold the specified climb rate.

from ADRpy import atmospheres as at
from ADRpy import constraintanalysis as ca

designbrief = {'climbalt_m': 0, 'climbspeed_kias': 101,
            'climbrate_fpm': 1398}

etap = {'climb': 0.8}

designperformance = {'CDminclean': 0.0254, 'etaprop' :etap}

designdef = {'aspectratio': 10.12, 'sweep_le_deg': 2,
            'sweep_mt_deg': 0, 'bpr': -1}

TOW_kg = 1542.0

designatm = at.Atmosphere()

concept = ca.AircraftConcept(designbrief, designdef,
                            designperformance, designatm)

wingloadinglist_pa = [1250, 1500, 1750]

twratio = concept.twrequired_clm(wingloadinglist_pa)

print('T/W: ', twratio)

Output:

T/W:  [ 0.20249491  0.2033384   0.20578177]
twrequired_crs(wingloading_pa)

Calculate the T/W required for cruise for a range of wing loadings

twrequired_sec(wingloading_pa)

T/W required for a service ceiling for a range of wing loadings

twrequired_to(wingloading_pa)

Calculate the T/W required for take-off for a range of wing loadings

Parameters

wingloading_pa

float or numpy array, list of wing loading values in Pa.

Returns

twratio

array, thrust to weight ratio required for the given wing loadings.

liftoffspeed_mpstas

array, liftoff speeds (TAS - true airspeed) in m/s.

avspeed_mps

average speed (TAS) during the take-off run, in m/s.

See also twrequired

Notes

1. The calculations here assume a ‘no wind’ take-off, conflating ground speed (GS) and true airspeed (TAS).

2. Use twrequired if a full constraint analysis is desired, as this integrates the take-off, turn, climb, cruise, and service ceiling constraints, as well as computing the combined constraint boundary.

Example

from ADRpy import atmospheres as at
from ADRpy import constraintanalysis as ca

designbrief = {'rwyelevation_m':1000, 'groundrun_m':1200}
designdefinition = {'aspectratio':7.3, 'bpr':3.9, 'tr':1.05}
designperformance = {'CDTO':0.04, 'CLTO':0.9, 'CLmaxTO':1.6, 'mu_R':0.02}

wingloadinglist_pa = [2000, 3000, 4000, 5000]

atm = at.Atmosphere()
concept = ca.AircraftConcept(designbrief, designdefinition,
                            designperformance, atm)

tw_sl, liftoffspeed_mpstas, _ = concept.twrequired_to(wingloadinglist_pa)

print(tw_sl)
print(liftoffspeed_mpstas)

Output:

[ 0.19397876  0.26758006  0.33994772  0.41110154]
[ 52.16511207  63.88895348  73.77260898  82.48028428]
twrequired_trn(wingloading_pa)

Calculates the T/W required for turning for a range of wing loadings

Parameters

wingloading_pa

float or numpy array, list of wing loading values in Pa.

Returns

twratio

array, thrust to weight ratio required for the given wing loadings.

clrequired

array, lift coefficient values required for the turn (see notes).

feasibletw

as twratio, but contains NaNs in lieu of unachievable (CLmax exceeded) values.

See also twrequired

Notes

1. Use twrequired if a full constraint analysis is desired, as this integrates the take-off, turn, climb, cruise, and service ceiling constraints, as well as computing the combined constraint boundary.

2. At the higher end of the wing loading range (low wing area values) the CL required to achieve the required turn rate may exceed the maximum clean CL (as specified in the CLmaxclean entry in the performance dictionary argument of the AircraftConcept class object being used). This means that, whatever the T/W ratio, the wings will stall at this point. The basic T/W value will still be returned in twratio, but there is another output, feasibletw, which is an array of the same T/W values, with those values blanked out (replaced with NaN) that cannot be achieved due to CL exceeding the maximum clean lift coefficient.

Example

Given a load factor, an altitude (in a given atmosphere) and a true airspeed, as well as a set of basic geometrical and aerodynamic performance parameters, compute the necessary T/W ratio to hold that load factor in the turn.

from ADRpy import atmospheres as at
from ADRpy import constraintanalysis as ca
from ADRpy import unitconversions as co

designbrief = {'stloadfactor': 2, 'turnalt_m': co.feet2m(10000),
            'turnspeed_ktas': 140}

etap = {'turn': 0.85}

designperformance = {'CLmaxclean': 1.45, 'CDminclean':0.02541,
                    'etaprop': etap}

designdef = {'aspectratio': 10.12, 'sweep_le_deg': 2,
            'sweep_mt_deg': 0, 'bpr': -1}

designatm = at.Atmosphere()

concept = ca.AircraftConcept(designbrief, designdef,
designperformance, designatm)

wingloadinglist_pa = [1250, 1500, 1750]

twratio, clrequired, feasibletw = concept.twrequired_trn(wingloadinglist_pa)

print('T/W:               ', twratio)
print('Only feasible T/Ws:', feasibletw)
print('CL required:       ', clrequired)
print('CLmax clean:       ', designperformance['CLmaxclean'])

Output:

T/W:                [ 0.19920641  0.21420513  0.23243016]
Only feasible T/Ws: [ 0.19920641  0.21420513         nan]
CL required:        [ 1.06552292  1.2786275   1.49173209]
CLmax clean:        1.45
vstall_kias(wingloadinglist_pa, clmax)

Calculates the stall speed (indicated) for a given wing loading in a specified cofiguration.

Parameters:

wingloading_pa

float or numpy array, list of wing loading values in Pa.

clmax

maximum lift coefficient (float) or the name of a standard configuration (string) for which a maximum lift coefficient was specified in the performance dictionary (currently implemented: ‘take-off’).

Returns:

stall speed in knots (float or numpy array)

Note:

The calculation is performed assuming standard day ISA sea level conditions (not in the consitions specified in the atmosphere used when instantiating the AircraftConcept object!) so the speed returned is an indicated (IAS) / calibrated (CAS) value.

Example:

from ADRpy import constraintanalysis as ca

designperformance = {'CLmaxTO':1.6}

concept = ca.AircraftConcept({}, {}, designperformance, {})

wingloading_pa = 3500

print("VS1(take-off):",
    concept.vstall_kias(wingloading_pa, 'take-off'))
wigfactor()

Wing-in-ground-effect factor to account for the change in induced drag as a result of the wing being in close proximity of the ground. Specify the entry wingheightratio in the design dictionary variable you instantiated the AircraftConcept object with in order to compute this - if unspecified, a call to this method will result in a value practically equal to 1 being returned.

The factor, following McCormick (“Aerodynamics, Aeronautics, and Flight Mechanics”, Wiley, 1979) and Gudmundsson (2013) is calculated as:

\[\Phi = \frac{(16\,h/b)^2}{1+(16\,h/b)^2}\]

where \(h/b\) is design[‘wingheightratio’]: the ratio of the height of the wing above the ground (when the aircraft is on the runway) and the span of the main wing.

The induced drag coefficient adjusted for ground effect thus becomes:

\[C_\mathrm{Di} = \Phi C_\mathrm{Di}^\mathrm{oge},\]

where the ‘oge’ superscript denotes the ‘out of ground effect’ value.

Example:

import math
from ADRpy import constraintanalysis as co

designdef = {'aspectratio':8}
wingarea_m2 = 10
wingspan_m = math.sqrt(designdef['aspectratio'] * wingarea_m2)

for wingheight_m in [0.6, 0.8, 1.0]:

    designdef['wingheightratio'] = wingheight_m / wingspan_m

    aircraft = co.AircraftConcept({}, designdef, {}, {})

    print('h/b: ', designdef['wingheightratio'],
        ' Phi: ', aircraft.wigfactor())

Output:

h/b:  0.06708203932499368  Phi:  0.5353159851301115
h/b:  0.08944271909999159  Phi:  0.6719160104986877
h/b:  0.11180339887498948  Phi:  0.761904761904762
wsmaxcleanstall_pa()

Maximum wing loading defined by the clean stall Clmax

constraintanalysis.tw2pw(thrusttoweight, speed, etap)

Converts thrust to weight to power to weight (propeller-driven aircraft)

Parameters

thrusttoweight

thrust to weight ratio (non-dimensional)

speed

ground speed (in m/s if output in Watts / Newton is required)

etap

propeller efficiency (non-dimensional), float

Returns

power to weight ratio (in W/N if speed is in m/s)

See also powerrequired

Notes

1. A note on units. If the input speed is in m/s, the other two inputs being non-dimensional, the output product is also in m/s, which is equal to W/N (W / N = (J/s) / N = (Nm/s) / N = m/s).

2. The speed input is a kinematic quantity, not an airspeed, so it is generally a ground speed (GS) or a true airspeed (TAS) if we are assuming zero wind.

3. The inputs to the function are scalars or a mix of scalars and numpy arrays.

Example:

from ADRpy import constraintanalysis as ca
from ADRpy import atmospheres as at
from ADRpy import unitconversions as co

designbrief = {'stloadfactor': 2, 'turnalt_m': 3050, 'turnspeed_ktas': 140}

etap = {'turn': 0.85}

designperformance = {'CLmaxclean': 1.45, 'CDminclean': 0.02541,
                        'etaprop': etap}

designdef = {'aspectratio': 10, 'sweep_le_deg': 2,
                'sweep_mt_deg': 0, 'bpr': -1}

TOW_kg = 1500

designatm = at.Atmosphere()
concept = ca.AircraftConcept(designbrief, designdef,
                                designperformance, designatm)

wingloading_pa = 1000

twreq, _, _ = concept.twrequired_trn(wingloading_pa)

turnspeed_mpstas = co.kts2mps(designbrief['turnspeed_ktas'])

pw_trn_wpn = ca.tw2pw(twreq, turnspeed_mpstas, etap['turn'])
pw_trn_hpkg = co.wn2hpkg(pw_trn_wpn)
p_trn_hp = pw_trn_hpkg * TOW_kg

print(p_trn_hp)

Output:

318.691213406

Unit Conversions

This module contains tools for converting between units commonly used in aircraft design.

unitconversions.c2f(temp_c)

Convert temperature value from Celsius to Fahrenheit

unitconversions.c2k(temp_c)

Convert temperature value from Celsius to Kelvin

unitconversions.c2r(temp_c)

Convert temperature value from Celsius to Rankine

unitconversions.feet22m2(area_ft2)

Converts area value from feet squared to meters squared

unitconversions.feet2m(length_feet)

Converts length value from feet to meters

unitconversions.fpm2mps(speed_fpm)

Convert speed value from feet/min to m/s

unitconversions.hp2kw(power_hp)

Convert power from HP to kW

unitconversions.inhg2mbar(press_inhg)

Convert pressure value from inHg to mbar

unitconversions.k2c(temp_k)

Convert temperature value from Kelvin to Celsius

unitconversions.k2r(temp_k)

Convert temperature value from Kelvin to Rankine

unitconversions.kg2lbs(mass_kg)

Convert mass value from kg to lbs

unitconversions.kg2n(mass_kg)

Converts mass in kg to weight in N

unitconversions.kgm22pa(pressure_kgm2)

Convert pressure value from kg/m^2 to Pa

unitconversions.kgm32sft3(density_kgm3)

Convert density from kg/m^3 to slugs/ft^3

unitconversions.km2m(length_km)

Converts length value from kilometres to metres

unitconversions.kts2mps(speed_kts)

Convert speed value knots to mps

unitconversions.kw2hp(power_kw)

Convert power from kW to HP

unitconversions.lbf2n(force_lbf)

Convert force from lbf to N

unitconversions.lbfft22mbar(press_lbfft2)

Convert pressure value from lb/ft^2 to mbar

unitconversions.lbs2kg(mass_lbs)

Convert mass value from lbs to kg

unitconversions.m22feet2(area_m2)

Converts area value from meters squared to feet squared

unitconversions.m2feet(length_m)

Convert length value from meters to feet

unitconversions.m2km(length_m)

Converts length value from meters to kilometres

unitconversions.mbar2inhg(press_mbar)

Convert pressure value from mbar to inHg

unitconversions.mbar2lbfft2(press_mbar)

Convert pressure value from mbar to lb/ft^2

unitconversions.mbar2pa(press_mbar)

Convert pressure value from mbar to Pascal

unitconversions.mps2kts(speed_mps)

Convert speed value from m/s to knots

unitconversions.n2kg(force_n)

Converts force in N to mass in kg

unitconversions.n2lbf(force_n)

Convert force from N to lbf

unitconversions.pa2kgm2(pressure_pa)

Convert pressure value from Pa to kg/m^2

unitconversions.pa2mbar(press_pa)

Convert pressure value from Pascal to mbar

unitconversions.r2c(temp_r)

Convert temperature value from Rankine to Celsius

unitconversions.r2k(temp_r)

Convert temperature value from Rankine to Kelvin

unitconversions.sft32kgm3(density_slft3)

Convert density from slugs/ft^3 to kg/m^3

unitconversions.wn2hpkg(powertoweight_wn)

Convert power to weight (Watt/N) to hp/kg

unitconversions.wn2kwkg(powertoweight_wn)

Convert power to weight (Watt/N) to kW/kg

unitconversions.wn2wkg(powertoweight_wn)

Convert power to weight (Watt/N) to W/kg

Miscellaneous Utilities

This module contains miscellaneous tools to support aircraft engineering calculations.

mtools4acdc.panelplot_with_shared_y(vaxis, haxes, hlimits, vlabel, hlabels, hlines, hlinecols, figpar=[10, 6, 100], tex=False, fam='sans-serif')

Multi-panel plots with a shared y-axis, e.g., for atmosphere profiles. See the Jupyter notebook Introduction_to_Modelling_the_Atmosphere… in the docs/ADRpy directory for usage examples.

mtools4acdc.polyblend(time, time_f, signal_i, signal_f)

A smooth blend between two levels of a signal. Suitable for approximating thrust variations associated with spool-up and spool-down, etc.

mtools4acdc.recastasnpfloatarray(scalarorvec)

Recasts an arbitrary argument as a numpy float array. Used internally by some of the constraint calculations to increase robustness, though the use of numpy arrays as inputs is the recommended approach in most cases.