Professional Documents
Culture Documents
Release 2.5.1
1 Introduction 1
2 Installation 3
2.1 Prerequisites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.2 Getting Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.3 Getting the Source Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.4 Installing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.5 Testing the Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
2.6 FreeCAD for Exporting STEP Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
3 User Interface 7
3.1 Command Line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
3.2 Python Interpreter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
4 Input Files 9
4.1 JSON Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.2 Units . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
4.3 Coordinate Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.4 Scene Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
4.5 Aircraft Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5 Scene Class 29
7 Common Issues 49
7.1 Poor Nonlinear Convergence . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.2 DatabaseBoundsError Message . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.3 Trailing Vortex Impingement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
8 Error Handling 51
i
9.2 Version 2.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
10 Support 55
11 Developer Notes 57
11.1 Numerical Lifting-Line Implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
11.2 Multiple Aircraft . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
11.3 API to Aircraft . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
11.4 Wing Segment Tree Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
11.5 Mean Aerodynamic Chord (MAC) Calculation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
11.6 Definition of Sideforce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
11.7 Differences in Implementation between MachUpX and MachUp Pro . . . . . . . . . . . . . . . . . . 59
11.8 Correcting Section Properties for Sweep . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
11.9 Coordinate Systems . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
Index 65
ii
CHAPTER 1
Introduction
MachUpX is an implementation of Phillips’ numerical lifting-line algorithm with some small modifications to increase
its accuracy and versatility. For reference on numerical lifting-line, see Phillips and Snyder “Modern Adaptation of
Classic Lifting-Line Theory”. The purpose of numerical lifting-line is to quickly and accurately model the aerody-
namics of fixed-wing aircraft. Within the limitations of potential flow theory, this algorithm produces very accurate
results without the computational overhead of higher-order methods, such as vortex lattice method or CFD.
MachUpX is significantly improved from previous versions of MachUp because it incorporates updates developed by
Jackson Reid to appropriately handle singularities introduced in the governing equations when sweep or sideslip are
modeled. More can be read about this in Reid and Hunsaker “A General Approach to Lifting-Line Theory, Applied
to Wings with Sweep” and Goates and Hunsaker “A Practical Implementation of General Numerical Lifting-Line
Theory”.
Examples of using MachUpX and comparisons of data obtained can be found in the following sources:
• Atotu, N. E., McCarthy, M., “Comparison of AAA and DATCOM for Stability Derivatives Calculation,” MS
Research Project, August 2020.
• Fortin, F., Goates, C., “Extraction of Geometric Twist for Given Spanwise Load Using Low-Order Methods,”
AIAA SciTech Forum, January 2021.
Those users already familiar with previous versions of MachUp (Pro/4/5/Py) will find the interface with MachUpX to
be similar. However, attempts have not been made to ensure compatibility between previous versions of MachUp and
MachUpX. If the user wishes to use analysis scripts/input files from previous versions of MachUp with MachUpX,
modifications will have to be made. For this reason, significant effort has been made to provide clear and thorough
documentation for MachUpX.
Examples for using the MachUpX API/command line interface can be found in the examples/ directory of the source
code.
Help on using MachUpX can be found at the MachUp discussion forum on Google Groups. We have a very active
user base eager to answer questions and give advice.
1
MachUpX, Release 2.5.1
2 Chapter 1. Introduction
CHAPTER 2
Installation
2.1 Prerequisites
Version 2 of MachUpX is dependent upon the AirfoilDatabase package, also distributed by the USU AeroLab. The
source code for AirfoilDatabase can be found on our Github page. Before installing MachUpX, you will need to
download and install AirfoilDatabase manually.
If you do not have Python installed on your machine, it can be downloaded from a number of locations. We use
https://www.anaconda.com/distribution/. Please be sure you have Python 3.6 or later.
You can either download the source as a ZIP file and extract the contents, or clone the MachUpX repository using Git.
If your system does not already have a version of Git installed, you will not be able to use this second option unless
you first download and install Git. If you are unsure, you can check by typing git --version into a command
prompt.
3
MachUpX, Release 2.5.1
1. From the command prompt navigate to the directory where MachUpX will be installed. Note: git will automati-
cally create a folder within this directory called MachUpX. Keep this in mind if you do not want multiple nested
folders called MachUpX.
2. Execute
$ git clone https://github.com/usuaero/MachUpX
We recommend cloning from the repository, as this will allow you to most easily download and install periodic updates
(because we will always be updating MachUpX!). This can be done using the following command
$ git pull
2.4 Installing
Once you have the source code downloaded, navigate to the root (MachUpX/) directory and execute
$ pip install .
Please note that any time you update the source code (e.g. after executing a git pull), MachUpX will need to be
reinstalled by executing the above command.
$ py.test
to verify MachUpX is working properly on your machine. Some warnings and depreciation notices are normal.
MachUpX is able to generate CAD models of the airframe data provided using the STEP exchange format (.stp).
These can be opened by any CAD package. In order to do this, MachUpX uses the FreeCAD Python API. As such,
FreeCAD needs to be installed on your machine for this to work. FreeCAD can be downloaded from https://www.
freecadweb.org/ or on Linux systems using
You will then need to add the FreeCAD modules to the Python path. This can be done using Conda (comes with
Anaconda python). On Linux, you will need to add the following directories using the command conda-develop,
i.e.
$ conda-develop /usr/lib/freecad/lib
$ conda-develop /usr/lib/freecad/bin
$ conda-develop /usr/lib/freecad/bin/lib
$ conda-develop /usr/lib/freecad/Ext
(continues on next page)
4 Chapter 2. Installation
MachUpX, Release 2.5.1
The location of these directories will vary depending on your machine’s configuration. When you call the air-
craft_export_step() function, you may see No modules found in /usr/lib/freecad-python3/Mod or
a similar error message in yellow or red text. This means the libraries were found. Any other error message or a STEP
file not being generated indicate that you have not properly configured FreeCAD for Python to recognize the FreeCAD
modules.
6 Chapter 2. Installation
CHAPTER 3
User Interface
MachUpX is a Python module and so can be used in one of two ways, either through the command line or the Python
interpreter. Examples of the interface can be found in the examples/ directory of the source code.
MachUpX is run from the command line using the “-m” option. For example
python -m machupX example_input.json
will run the analyses listed under “run” in the file example_input.json. The various results are saved as files to
be accessed by the user. For creating the input file, see Input Files.
MachUpX can also be imported through the Python interpreter and its functionality can then be accessed through the
Scene class. For example
import machupX as MX
input_file = "traditional_input.json"
# Initialize scene
my_scene = MX.Scene(input_file)
7
MachUpX, Release 2.5.1
For more information on using the Scene class, see Scene Class.
Input Files
The basic input for MachUp contains a JSON object which describes the scene and which aircraft are in the scene,
along with the state of those aircraft in the scene. A separate JSON object is used to specify the geometry and controls
of each aircraft. These aircraft objects can reference other files that store information on airfoil properties, chord
distributions, sweep, etc., as will be discussed. At a minimum, two JSON objects will be created by the user, a scene
object and an aircraft object. These objects can be passed to MachUpX either as a .json file (this is the only way if
MachUpX is being used through the command line) or as a Python dictionary, which is directly analagous to a .json
file.
The basic structure of a JSON object is a set of key-value pairs, analogous to a Python dictionary. Examples can be
found in the examples/ directory. The following sections describe the structure of the JSON objects used to interface
with MachUp. Only one JSON object is specified per .json file. When using the JSON objects, only the scene object is
passed to MachUp. As long as the paths to all other JSON objects are properly specified in the scene object, MachUp
will automatically load all other required objects.
4.2 Units
MachUp allows the user to specify the units for each value if they desire. For float values, this is done by making
the value a list where the first element is the actual value and the second element is a string specifying the units. For
example:
For vector inputs, such as position and velocity, the units are simply appended to the vector:
For array inputs, such as a density profile or chord distribution, the units are appended as another row in the array:
9
MachUpX, Release 2.5.1
When specifying column units in files, these are also appended as another row:
# File: density_profile.csv
0.0, 1.225
2000.0, 1.0066
4000.0, 0.81935
"m", "kg/m^3"
MachUpX can accept inputs and output certain information in the wind and stability frames, along with the body
frame. An aircraft’s angular rate vector can be specified in the body, stability, or wind frame. In conjunction with this,
MachUpX will calculate damping derivatives with respect to the frame the angular rates were originally specified in.
Also, MachUpX can output forces an moments in any of these three frames.
The following are keys which can be specified in the scene JSON object. NOTE: all keys not marked as optional are
required. Key names typed in all capitals between carats (e.g. <KEY_VALUE>) are to be deterimined by the user.
“tag” : string, optional
A note on the specific input. Does not affect execution.
“run” : dict, optional
Gives the analyses MachUp is to run. This must be specified if the input file is being passed
as a command line argument to MachUp. Otherwise, MachUp will return without performing
any calculations. If the input file is used to initialize the Scene class within a script, rather
than being passed as a command line argument, this set of run commands will be ignored.
The outputs from the analyses will be stored in files automatically.If no filename is given by
the user, MachUpX will automatically specify a filename based on the name of the input file.
This means that all output files will be stored in the same directory as the input file, with the
exception of .stp and .dxf files.
Please note that each of these run commands corresponds to a Scene class method. Thus, for
more information on each, please see the Scene class page.
“solve_forces” : dict, optional
Calculates the aerodynamic forces and moments on the aircraft at the current state.
“filename” : string, optional
File to store the results in. Defaults to the input filename + “_forces”.
“dimensional” : boolean, optional
Whether results should include dimensional forces and moments. Defaults
to true.
“non_dimensional” : boolean, optional
Whether results should include nondimensional coefficients. Defaults to
true.
“body_frame” : boolean, optional
Whether to output results in the body-fixed frame. Defaults to true.
“stab_frame” : boolean, optional
Whether to output results in the stability frame. Defaults to false.
“wind_frame” : boolean, optional
Whether to output results in the wind frame. Defaults to true.
“verbose” : boolean, optional
Defaults to false.
“display_wireframe” : dict, optional
Displays a wireframe of the geometry of the scene/aircraft.
“show_legend” : boolean, optional
If set to true, a legend will be included with the wireframe detailing which
color corresponds to which wing segment. Defaults to false.
“filename” : str, optional
File to save an image of the wireframe to. If specified, the wireframe will
not be automatically displayed. If not specified, the wireframe will display
to the user, after which it can be manually saved.
“derivatives” : dict, optional
Calculates the stability, damping, and control derivatives at the current state.
“aircraft” : list, optional
The aircraft to calculate the derivatives of. Defaults to all aircraft in the
scene.
“filename” : string, optional
File to store the results in. Defaults to the input filename + “_derivatives”.
“distributions” : dict, optional
Gives the distribution of various parameters across each lifting surface.
“filename” : string, optional
File to store the results in. Defaults to the input filename + “_distributions”.
“make_plots” : list, optional
Name of the JSON file to write the model to. Must be “.json”. Defaults
to “<AIRCRAFT_NAME>_linearized.json”.
“inertia” : dict, optional
Moments of inertia for the aircraft, formatted as
{
“Ixx” : , “Iyy” : , “Izz” : , “Ixy” : , “Ixz” : , “Iyz” : }
If not specified, this will be left blank for the user to specify after the
fact. Alternatively, if “inertia” was already part of the aircraft input, it
will remain the same as inputted.
“angular_momentum” : list, optional
Angular momentum vector. Defaults to [0.0, 0.0, 0.0]. Alternatively,
if “angular_momentum” was already part of the aircraft input, it will
remain the same as inputted.
“stall_angle_of_attack” : float, optional
Angle of attack in degrees at which the aircraft stalls.
“stall_sideslip_angle” : float, optional
Sideslip angle in degrees at which the aircraft stalls laterally.
“controller_type” : str, optional
The controller that will be used with the exported model. Can be
“keyboard”, “joystick”, “user_defined”, or “time_sequence”. This
affects whether certain inputs unknown to MachUpX are marked
“<PLEASE_SPECIFY>”. If not given, all such keys will be marked
“<PLEASE_SPECIFY>”.
“velocity” : float, optional
Velocity at which to evaluate the model. Should not have any effect
unless Mach and Reynolds number effects are included. Defaults to
100.
“set_accel_derivs” : bool, optional
Whether to set derivatives with respect to vertical and lateral acceler-
ation to zero. Defaults to False, in which case the user must specify
these.
“set_err_state” : dict, optional
Describes how custom exceptions within MachUpX are to be handled. Each
can be set to “raise”, “warn”, or “ignore”.
“not_converged” : str, optional
Behavior for SolverNotConvergedError. Defaults to “raise”.
“database_bounds” : str, optional
Behavior for DatabaseBoundsError. Defaults to “raise”.
“solver” : dict, optional
Specifies parameters regarding how the lifting-line equation is solved.
“type” : string, optional
“scene” : dict
“atmosphere” : dict, optional
Specifies the atmosphere the aircraft exist in. If this dictionary is empty, the air-
craft is assumed to be at sea-level in a standard Earth atmosphere. If you take
the time to specify these keys, you can put your aircraft anywhere, even on Mars!
Note that while viscosity and speed of sound are specified here, they will have no
effect on computations unless the airfoil section properties are given as functions
of Mach and Reynolds numbers. However, for many applications, it is appropriate
to ignore Mach and Reynolds effects.
“rho” : float, array, or string, optional
If a float, the atmospheric density is assumed constant. If an array is
given, this is assumed to be either a density profile or a density field.
MachUp will interpret a 2 column array as a profile where the first col-
umn is heights and the second column is densities. A 4 column array is
a field where the first three columns are the position in earth-fixed co-
ordinates and the fourth column is the density. MachUp will linearly
interpolate these data. These arrays can alternatively be stored as a csv
file, in which case, this value should be the path to the file. NOTE:
Since MachUpX uses earth-fixed coordinates for position, altitude val-
ues should be negative (i.e. 1000 ft above sea level would be -1000 ft).
If “rho” is a string, it is assumed the density is determined using an ana-
lytically defined atmosphere profile. The following profiles can be spec-
ified:
“standard” - Standard atmosphere profile.
Defaults to density at sea-level.
“V_wind” : vector, array, or string, optional
If a vector is given, this is assumed to be the wind velocity vector given
in earth-fixed coordinates which is constant throughout the scene. If an
array is given, this is assumed to be either a wind profile or a wind field.
MachUp will interpret a 4 column array as a velocity profile where the
first column is heights and the last three columns are velocity compo-
nents in earth-fixed coordinates. A 6 column array is a field where the
first three columns are positions in earth-fixed coordinates and the fourth
through sixth columns are velocity components in earth-fixed coordi-
nates. These arrays can alternatively be stored as a csv file, in which
case, this value should be the path to the file. Defaults to no wind.
“viscosity” : float or string
Kinematic viscosity of the atmosphere. If a float, the viscosity is assumed
to be constant. If a string, it is assumed the viscosity is determined using
an analytically defined atmosphere profile. The following profiles can be
specified:
“standard” - Standard atmosphere profile.
Defaults to standard viscosity at sea-level.
“speed_of_sound” : float or string
Speed of sound in the atmosphere. If a float, the speed of sound is as-
sumed to be constant. If a string, it is assumed the speed of sound is
Defines the controls of the aircraft. The number and names of controls are arbitrary and
may be specified by the user. A simple aircraft, such as a chuck glider may have no con-
trols, whereas a more complex aircraft may have controls for aileron, elevator, rudder, and
multiple flaps. Defining the controls here can be thought of as deciding which control
knobs/switches/sticks you want to make available to the pilot.
“<CONTROL_NAME>” : dict
“is_symmetric” : bool
Specifies whether this control causes symmetric or asymmetric control
surface deflections (e.g. for a typical aircraft, the elevator control causes
symmetric deflections whereas the aileron causes asymmetric deflec-
tions).
“airfoils” : dict or str
Defines the airfoils used on the aircraft. Any number of airfoils can be defined for the aircraft
and MachUpX will pull from these airfoil definitions as needed, depending on which airfoils
are specified for each wing segment. If no airfoils are listed here MachUp will automatically
generate a default airfoil and use it on all lifting surfaces. The default values listed are for a
flat plate as predicted by thin airfoil theory. Do not expect these to give you accurate results.
This may also be the path to a JSON object containing the airfoils.
MachUpX uses the AirfoilDatabase package (link) to calculate section properties. This pack-
age allows for generating nonlinear coefficient databases for a given airfoil. It’s full capa-
bilities are explained in the documentation. Please note that MachUpX does not have the
capability to generate these databases. It can only read in a previously generated database.
IMPORTANT: If you are using multiple nonlinear databases for multiple spanwise airfoils,
then the nonlinear databases must be generated for the range of Reynolds number seen by
the whole wing. E.g. if you have a tapered wing, then the root will see a higher Reynolds
number than the tip; despite this fact, the root airfoil database must span the range of Reynolds
numbers expected at the tip and vice versa. Please also note that the Reynolds number used to
extract coefficients from the database is calculated using the total (freestream plus induced)
velocity. Thus it is a good rule of thumb to generate a database which goes a little above and
a little below the expected freestream Reynolds numbers.
The input for a single airfoil has the following structure:
“<AIRFOIL_NAME>” : dict or str
Input for a given airfoil. As a dictionary, it should have the following keys. If this
is a string, it should be the path to a JSON object containing the same information.
The name of the airfoil should not be repeated in the file; only the coefficients and
geometry information should be listed.
“type” : string
The type of data used to calculate section properties for the airfoil. Can
be “linear”, “database”, or “poly_fit”. For a “database” or “poly_fit” air-
foil, “input_file” must be specified. A “linear” airfoil assumes linear lift
and moment curves and a quadratic drag polar. In this case, the follow-
ing keys must be defined. UNITS MAY NOT BE SPECIFIED BY THE
USER FOR ANY AIRFOIL PARAMETERS. THESE VALUES MUST
BE SPECIFIED IN THE UNITS GIVEN HERE.
“aL0” : float, optional
The zero-lift angle of attack in radians. Defaults to 0.0.
“both”, changing this value will shift both sides of the wing seg-
ment in the SAME direction. The effect is not mirrored. De-
faults to 0.
“dz” : float, optional
Displacement of the origin from the selected reference point in
the body-fixed z- direction. Defaults to 0.
“y_offset” : float, optional
Distance the origin should be shifted from the centerline (posi-
tive offset corresponds to outward from the x-z plane). If “side”
is specified as “both”, this effect is mirrored. Defaults to 0.
“semispan” : float
Length of the wing segment in the y-direction (i.e. discounting sweep).
If “side” is specified as “both”, the total span of the segment is twice this
value. May not be specified if “quarter_chord_locs” is specified.
“twist” : float, array, string, or func, optional
Gives the geometric twist of the wing, meaning the angle of the chord
line of each airfoil section relative to the body x-axis in degrees. If spec-
ified as a float, then all sections will make that angle with the horizontal
and it will be as if the wing is untwisted but mounted at that angle. If
specified as an array, the array gives the local twist as a function of span.
The first column gives the span location as a fraction of the total span.
This column must have values going from 0.0 to 1.0. The second column
gives the twist at that span location. If specified as a string, this string
must contain the path to a csv file containing the twist data formatted in
columns, as with the array. For properties as a function of span, MachUp
will linearly interpolate intermediate values. If a step change in distri-
bution is needed, this can be done by specifying the span location where
the step change occurs twice, once with each value, as below:
“twist” : [[0.0, 0.0], [0.5, 0.0], [0.5, 2.0], [1.0, 2.0]]
In the above example, the twist will be 0 degrees for the inner half of
the wing and 2 degrees for the outer half of the wing. Note that this
parameter also determines the mounting angle and washout of the wing
segment. Defaults to 0.
Alternatively, if MachUpX is being used as a module imported into a
script, this value can be a function which accepts an array of span frac-
tions and returns the corresponding twist angles in radians.
“dihedral” : float, array, string, or func optional
Gives the dihedral of the wing segment in degrees. Defined the same as
“twist”. If defined as a distribution, this specifies the local dihedral angle
at each point along the wing. Defaults to 0.
“shear_dihedral” : bool, optional
Whether the dihedral should be viewed as a solid-body rotation (stan-
dard) or a shear transformation (nonstandard), similar to sweep, for the
purpose of exporting 3D models. Has no effect on aerodynamics. De-
faults to False, corresponding to a solid-body rotation.
“sweep” : float, array, string, or func optional
Gives the sweep angle of the wing segment in degrees. Sweeping the
wing is a shear transformation, rather than a solid-body rotation. This
means the amount of sweep will not affect the distance of the wingtip
from thex-z plane. Defined the same as “twist”. Defaults to 0.
“chord” : float, array, string, or func optional
Gives the chord length of the wing segment. Defined the same as “twist”,
except that it can also be specified as elliptic using the following defini-
tion:
“chord” : [“elliptic”, 1.0]
Where the second list element is the root chord length. Units can be
specified using:
“chord” : [“elliptic”, 1.0, “ft”]
Defaults to 1.0.
“quarter_chord_locs” : array or string, optional
Gives locations of the wing quarter chord relative to the wing root, as
opposed to relative to the aircraft origin. The first column should be
body-x coordinates, the second column should be body-y coordinates,
and the third column should be body-z coordinates. MachUpX will lin-
early interpolate between the given points to determine the locations of
control points and vortex nodes. Points should be given progressing from
root to tip. If only one point is given, this will be taken as the tip location
relative to the root, and the wing will be straight. Not that the corre-
sponding span fraction for each point does not need to be specified here.
MachUpX will automatically calculate that from the point locations.
If “quarter_chord_locs” is given, “sweep”, “dihedral”, and “semispan”
may not be specified.
These locations should only be given for the right half of the wing and
MachUpX will mirror them for the left half, even for a wing where
“side” is “left”.
“ll_offset” : float, array, string, or func optional
Gives the offset of the lifting-line from the locus of quarter-chord points.
By default, MachUpX assumes the lifting-line for a given wing segment
falls on the quarter chord line. This parameter allows shifting the lifting-
line along the chord line, if desired. This shift is given as a fraction of the
chord. A positive value shifts the lifting-line back. This is defined the
same as “twist”, except that it may also be specified as “kuchemann” for
wings of constant sweep, including zero sweep, in which case the lifting-
line will be placed on the locus of aerodynamic centers as predicted by
Kuchemann’s equations. Specifying “kuchemann” for a wing segment
with variable sweep will result in an error. If Kuchemann’s equations
are selected, the user should ensure the number of control points for this
wing is large enough to capture the nonlinear locus of aerodynamic cen-
ters at the wing root and tips. MachUpX will cosine cluster these points
by default, but a very small number of control points may still fail to suf-
ficiently capture Kuchemann’s correction. Defaults to 0. The developers
consider placing the lifting-line using Kuchemann’s equations to be in-
appropriate; see Goates et al. “A Practical Implementation of General
Numerical Lifting-Line Theory” 2021 for further discussion of this.
Scene Class
The machupX module is imported through the Python interpreter. All functionality of MachUpX is available through
the Scene class. The Scene class takes a file or a Python dictionary containing the configuration information described
in ‘Input Files’. Various member functions of Scene can then be called to perform analyses on the aircraft in the scene.
Please note that all available functionality for MachUpX is accessed through the Scene class. Accessing lower-level
classes and members directly may cause unpredictable and undesired behavior.
class machupX.Scene(scene_input={})
A class defining a scene containing one or more aircraft.
Parameters scene_input (string or dict, optional) – Dictionary or path to the
JSON object specifying the scene parameters (see ‘Creating Input Files for MachUp’). If
not specified, all default values are chosen.
Raises IOError – If input filepath or filename is invalid
MAC(**kwargs)
Returns the mean aerodynamic chord (MAC) for the specified aircraft.
Parameters
• aircraft (str) – The name of the aircraft to get the reference params for. Does
not need to be specified if there is only one aircraft in the scene.
• filename (str) – JSON file to export the MAC data to. Defaults to None.
Returns
MAC –
MAC data for each aircraft. Structured as
{
“<AIRCRAFT_NAME>” [{] “length” : mean aerodynamic chord length,
“C_point” : location of the quarter chord of the MAC determined by Eq.
2.6.2 from Nickel and Wohlfahrt “Tailless Aircraft”
}
29
MachUpX, Release 2.5.1
}
Return type dict
add_aircraft(airplane_name, airplane_input, state={}, control_state={})
Inserts an aircraft into the scene. Note if an aircraft was specified in the input object, it has already been
added to the scene.
Parameters
• airplane_name (str) – Name of the airplane to be added.
• airplane_input (str or dict) – JSON object (path) or dictionary describ-
ing the airplane.
• state (dict) – Dictionary describing the state of the airplane.
• control_state (dict) – Dictionary describing the state of the controls.
aero_center(**kwargs)
Returns the location of the aerodynamic center of the aircraft at the current state.
Parameters
• aircraft (str or list) – The name(s) of the aircraft to determine the aerody-
namic center of. Defaults to all aircraft in the scene.
• filename (str) – Name of a .json file to output the aerodynamic center locations
to. Defaults to no file.
• verbose (bool) – If set to true, information will be output about the progress of
Newton’s method. Defaults to False.
Returns
AC_data – The location of the aerodynamic center in body-fixed coordinates for each
aircraft and the moment coefficient about the AC. Structured as:
{
“<AIRCRAFT_NAME>” [{] “aero_center” : [x_ac, y_ac, z_ac], “Cm_ac” :
Cm_ac
}
}
Return type dict
control_derivatives(**kwargs)
Determines the control derivatives at the current state. Uses a central difference scheme.
Parameters
• aircraft (str or list) – The name(s) of the aircraft to determine the control
derivatives of. Defaults to all aircraft in the scene.
• dtheta (float) – The finite difference used to perturb the controls in degrees and
determine the derivatives. Defaults to 0.5
• body_frame (boolean, optional) – Whether to output results in the body-
fixed frame. Defaults to True.
• stab_frame (boolean, optional) – Whether to output results in the stability
frame. Defaults to False.
31
MachUpX, Release 2.5.1
• aircraft (str or list) – The name(s) of the aircraft to plot the planform of.
Defaults to all aircraft in the scene.
• file_tag (str, optional) – File tag to be used in saving the plot(s). The
plot(s) will be saved to “<AIRCRAFT_NAME>_planform_file_tag.png”. If speci-
fied, the planform(s) will not be automatically displayed. If not specified, the plan-
form(s) will display to the user and not save.
display_wireframe(**kwargs)
Displays a 3D wireframe plot of the scene.
Parameters
• show_vortices (bool, optional) – If this is set to True, the distribution of
horseshoe vortices along each lifting surface will be shown. Defaults to True.
• show_legend (bool, optional) – If this is set to True, a legend will appear
detailing which color corresponds to which wing segment. Otherwise, the wing seg-
ments are all black. Defaults to False.
• filename (str, optional) – File to save an image of the wireframe to. If
specified, the wireframe will not be automatically displayed. If not specified, the
wireframe will display to the user and not save.
distributions(**kwargs)
Returns various parameters, as well as forces and moments, at each control point for all aircraft at the
current state. Note that if “correct_sections_for_sweep” (default True) is set to True, the section aerody-
namic properties given here will be the swept section properties. All angular values are given in radians
by default.
The following properties are stored as distributions:
“span_frac” : fraction along the span (distance along the LQC projected into the y-z plane)
“cpx” : control point x location “cpy” : control point y location “cpz” : control point z location
“chord” : section geometric chord “swept_chord” : section chord normal to the lifting-line
(corrected for sweep) “twist” : section geometric twist “dihedral” : section geometric dihedral
“sweep” : section geometric sweep “aero_sweep” : section aerodynamic sweep (based on the
lifting-line) “area” : section differential planform area “alpha” : angle of attack (corrected for
sweep) “delta_flap” : flap deflection “u” : body-x velocity “v” : body-y velocity “w” : body-z
velocity “Re” : Reynolds number “M” : Mach number “q” : dynamic pressure “section_CL”
: lift coefficient “section_Cm” : moment coefficient “section_parasitic_CD” : drag coefficient
“section_aL0” : zero-lift angle of attack “Fx” : body-x force acting on each section “Fy” :
body-y force acting on each section “Fz” : body-z force acting on each section “Mx” : body-x
moment acting on each section “My” : body-y moment acting on each section “Mz” : body-z
moment acting on each section “circ” : circulation
Parameters
• filename (str) – Output file to write the distributions to. Saves as a .txt file.
Defaults to no file.
• radians (bool) – Whether to output angular values in radians. Defaults to True.
If set to False, all angular values will be output in degrees. Note this also affects the
plots generated by make_plots.
• make_plots (list, optional) – List of keys from the dist dictionary to make
plots of. A plot of the parameter as a function of span fraction for each wing segment
will then be generated and saved. This can create a lot of plots!
• show_plots (bool, optional) – Whether to show the plots, rather than auto-
matically saving them. Defaults to False.
Returns dist – A dictionary containing lists of each parameter at each control point. The
distributions are organized by aircraft then by wing segment. The nested keys are then
each parameter.
Return type dict
export_dxf(**kwargs)
Creates a .dxf file representing each lifting surface of the specified aircraft.
Parameters
• aircraft (str) – The aircraft to export .dxf files of.
• file_tag (str, optional) – Optional tag to prepend to out-
put filename default. The output files will be named “<AIR-
CRAFT_NAME>_<WING_NAME>.dxf”.
• section_resolution (int, optional) – Number of points to use in dis-
cretizing the airfoil section outline. Defaults to 200.
• number_guide_curves (int) – Number of guidecurves to create. Defaults to 2
(one at the leading edge, one at the trailing edge).
• dxf_line_type (str) – Type of line to be used in the .dxf file creation. Options
include ‘line’, ‘spline’, and ‘polyline’. Defaults to ‘spline’.
export_pylot_model(**kwargs)
Creates a JSON object containing a linearized model of the aircraft to use as input for Pylot
(www.github.com/usuaero/Pylot). Any information not available to MachupX but required for Pylot will
be filled with “PLEASE SPECIFY” and must be changed by the user before the input can be used for
Pylot. Note, this can only be used if there is one aircraft in the scene.
We designed the input files for Pylot to be cross-compatible with MachUpX. With this in mind, if values
are already specified in the input but those values are not used in MachUpX, they will still be included in
the input file exported here.
Note, this will set the aircraft state to zero aerodynamic angles and zero control deflections.
Parameters
• filename (str, optional) – Name of the JSON file to write the model to.
Must be “.json”. Defaults to “<AIRCRAFT_NAME>_linearized.json”.
• inertia (dict, optional) – Moments of inertia for the aircraft, formatted as
{ “Ixx” : <VALUE>, “Iyy” : <VALUE>, “Izz” : <VALUE>, “Ixy” : <VALUE>,
“Ixz” : <VALUE>, “Iyz” : <VALUE>
}
If not specified, this will be left blank for the user to specify after the fact. Alterna-
tively, if “inertia” was already part of the aircraft input, it will remain the same as
inputted.
• angular_momentum (list, optional) – Angular momentum vector. De-
faults to [0.0, 0.0, 0.0]. Alternatively, if “angular_momentum” was already part of
the aircraft input, it will remain the same as inputted.
• stall_angle_of_attack (float, optional) – Angle of attack in degrees
at which the aircraft stalls.
33
MachUpX, Release 2.5.1
get_aircraft_reference_geometry(aircraft=None)
Returns the reference geometries for the specified aircraft.
Parameters aircraft (str) – The name of the aircraft to get the reference params for.
Does not need to be specified if there is only one aircraft in the scene. Only one may be
specified.
Returns
• S_w (float) – Reference area
• l_ref_lon (float) – Longitudinal reference length
• l_ref_lat (float) – Lateral reference length
out_gamma()
Plots the induced velocities and writes the circulation distribution to a file.
Author: Francois Fortin
pitch_trim(**kwargs)
Returns the required angle of attack and pitch control deflection for trim at the current state. Trim is
achieved when the lift cancels out the weight of the aircraft and the pitching moment is zero. This alters
the body-fixed aircraft velocity in order to achieve trim.
It is recommended this trim function be used when the aircraft is the only one in the scene, there is no wind,
and the bank angle is zero (a majority of cases). For more complex cases, pitch_trim_using_orientation()
is recommended.
Parameters
• aircraft (str, optional) – Aircraft to trim in pitch. If there is only one
aircraft in the scene, this does not need to be given.
• pitch_control (str) – The name of the control that should be used to trim in
pitch. Defaults to “elevator”.
• filename (str) – File to output the results to. Defaults to no file.
• set_trim_state (bool) – If set to True, once trim is determined, the state of
the aircraft will be set to this trim state. Note this will only affect the velocity of the
aircraft; its orientation will remain unchanged. If False, the state of the aircraft will
return to what it was before this method was called. Defaults to True.
• verbose (bool) – If set to true, information will be output about the progress of
Newton’s method. Defaults to False.
Returns The angle of attack and deflection of the specified control required to trim the aircraft
in pitch in the current state.
Return type dict
pitch_trim_using_orientation(**kwargs)
Trims the given aircraft in pitch by altering the elevation angle of the aircraft and the specified control
deflection. This will maintain the Earth-fixed velocity of the aircraft and the heading and bank angle.
Since bank angle is maintained, trim is achieved when the vertical component of lift cancels out the
weight of the aircraft.
This trim function is more general than pitch_trim() and can be used in all cases.
Parameters
• aircraft (str, optional) – Aircraft to trim in pitch. If there is only one
aircraft in the scene, this does not need to be given.
35
MachUpX, Release 2.5.1
solve_forces(**kwargs)
Solves the NLL equations to determine the forces and moments on each aircraft.
Parameters
• filename (str) – File to export the force and moment results to. Should be .json.
If not specified, results will not be exported to a file.
• non_dimensional (bool) – If this is set to True, nondimensional coefficients
will be included in the results. Defaults to True.
• dimensional (bool) – If this is set to True, dimensional forces and moments will
be included in the results. Defaults to True.
• report_by_segment (bool) – Whether to include results broken down by wing
segment. Defaults to False.
• body_frame (boolean, optional) – Whether to output results in the body-
fixed frame. Defaults to True.
• stab_frame (boolean, optional) – Whether to output results in the stability
frame. Defaults to False.
• wind_frame (boolean, optional) – Whether to output results in the wind
frame. Defaults to True.
• verbose (bool) – Whether to display timing and convergence information. De-
faults to False.
Returns FM – Dictionary of forces and moments acting on each wing segment.
Return type dict
stability_derivatives(**kwargs)
Determines the stability derivatives at the current state. Uses a central difference scheme.
Parameters
• aircraft (str or list) – The name(s) of the aircraft to determine the stability
derivatives of. Defaults to all aircraft in the scene.
• dtheta (float) – The finite difference in degrees used to perturb alpha and beta
and determine the derivatives. Defaults to 0.5
• body_frame (boolean, optional) – Whether to output results in the body-
fixed frame. Defaults to True.
• stab_frame (boolean, optional) – Whether to output results in the stability
frame. Defaults to False.
• wind_frame (boolean, optional) – Whether to output results in the wind
frame. Defaults to True.
Returns A dictionary of stability derivatives.
Return type dict
state_derivatives(**kwargs)
Determines the derivatives of forces and moments at the current state with respect to the 13 element state
vector. Uses a central difference scheme. These states are:
Position in Earth-fixed coordinates. Velocity in body-fixed coordinates. Orientation of the
body frame relative to the Earth-fixed frame. Angular rate in body-fixed coordinates.
These derivatives will always be determined using the body-fixed forces and moments.
37
MachUpX, Release 2.5.1
Parameters
• aircraft (str or list) – The name(s) of the aircraft to determine the stability
derivatives of. Defaults to all aircraft in the scene.
• dx (float) – The finite difference used to perturb position in either feet or meters.
Defaults to 0.5.
• dV (float) – The finite difference used to perturb velocity in either ft/s or m/s.
Defaults to 0.5.
• de (float) – The finite difference used to perturb the orientation quaternion. De-
faults to 0.001.
• dw (float) – The finite difference used to perturb the angular rates in rad/s. Defaults
to 0.01.
Returns A dictionary of state derivatives.
Return type dict
target_CL(**kwargs)
Determines the angle of attack necessary to produce the specified lift coefficient with the specified control
deflections. MAY ONLY BE USED IF THERE IS ONE AIRCRAFT IN THE SCENE AND THE WIND
IS CONSTANT.
Parameters
• CL (float) – Target lift coefficient.
• control_state (dict, optional) – Control deflections. Defaults to no de-
flections.
• set_state (bool, optional) – Whether to set the state of the aircraft to the
angle of attack determined.
• filename (str, optional) – File to output results to. Defaults to no file.
• verbose (bool, optional) – Whether to output the progress of the iterative
solver. Defaults to False.
Returns alpha – Angle of attack at the given CL.
Return type float
There are at three types of files for each wing segment created in MachUpX. How each file is used is described as
follows. Alternately, a video tutorial for the whole craft can be found here. The files used were generated for a
traditional aircraft with a main wing, horizontal, and vertical stabilizers.
This first file terminates in _planes for the wing segment being modeled. This .dxf file must be inserted on the right
plane. Note the plane must be selected prior to selecting Insert > DXF/DWG. . .
39
MachUpX, Release 2.5.1
If you’re using SI units in MachUpX, the base unit for all .dxf files created will be meters. If you’re using English
units, the base unit for all .dxf files is in inches. If you’re using English units, you don’t need to change the import
units. To modify the units import, move to the next window in the DXF/DWG Import wizard.
Select meters
Beginning near the origin point, select the body of each T, along with the right plane. Insert a plane using these
selections. The plane inserted will be coincident with the line, and perpendicular to the right plane.
Next the airfoil outlines must be imported to the planes previously created.
It can help to rename each plane created to _## beginning at 0 at the root / origin plane. The .dxf file to be imported
on this first plane (in the image plane_00) is traditional_airplane_main_wing_right_00.
Continue through each plane and related .dxf file. There will be at least 2. The number of these files depends on how
many changes in airfoil occur in the wing segement.
NOTE : If one of your airfoil outlines does not import, check whether you have a wing segment with a taper ratio of
0. Because Soliworks cannot loft between a point and 2D shape, MachUpX modifies the chord at the tip point from
0 to 1e-5. If your model is already extremely small, it may cause sever changes in the model compared to your input
design. Consider scaling the values you put into MachUpX to resolve this issue.
Often, with a complex shape, two guide curves are not enough to constrain the wing geometry through the loft. For
more complex lofts, we recommend several guide curves. The number of guide curves can be increased in the .dxf
export function. It should be noted that SolidWorks begins to fail after around forty guide curves. We recommend
between four and twenty if two is insufficient. If the loft does not complete, sometimes unselecting some guide curves
may help.
We also recommend an even number of guide curves. This ensures a guide curve is placed at the trailing edge and at
the leading edge. Otherwise, the nose of the wing may not loft as desired.
6.4 Loft
As selecting each 2D outline, ensure the loft points relate to the same point on each airfoil. Otherwise, the loft will
fail.
6.4. Loft 47
MachUpX, Release 2.5.1
Common Issues
This page is for explaining common issues users face and ways to avoid them
The nonlinear solver not converging quickly (or at all) can be caused by a number of things. Note, for me right now,
the nonlinear solver usually takes ~7-10 iterations to converge for a “traditional” airframe. Up to 70 iterations is not
uncommon though for more unusual airframes. If you’re using a nonlinear airfoil and are trying to model past stall,
good luck ever getting it to converge. The following have been found to help:
• If Reid corrections are being used, make sure you have properly specified “wing_ID” under “grid” for each
wing. Reid’s corrections involve blending the lifting line for a given lifting surface and so MachUpX needs to
know which wing segments actually belong to the same wing.
• If multiple lifting surfaces come together at a point which are not technically part of the same wing (i.e. vertical
and horizontal stabilizers), it can help to offset them slightly (on the order of 0.0001) from each other.
• The convergence can be adjusted by using the “relaxation” parameter under “solver” in the input dictio-
nary/JSON. This defaults to 1.0, which corresponds to accepting the full correction at each step. For highly
nonlinear geometries or for cases near stall, it may help to set this to some value less than unity.
• Try to make the wing geometry as smooth as possible. For example, if you are using winglets, adding a linear
distribution of dihedral at the wing tips to blend into the winglets will help the solution.
Getting all NaN results is not a convergence issue! If your solver does not converge, you will not get any results,
unless you have changed the default error state.
This error can occur if you are using a nonlinear airfoil database for determining section coefficients. It is caused by
the local angle of attack, Mach number, Reynolds number, flap deflection, or flap chord fraction falling outside the
49
MachUpX, Release 2.5.1
bounds of what is in the database. If you see this error, you need to expand your airfoil database to allow for greater
variation in the problem parameter.
For example, let’s say I generate a NACA 0012 airfoil database that ranges from 10 to -10 degrees angle of attack. I
then use this database for an aircraft I model in MachUpX. I then set the aircraft angle of attack (i.e. the freestream
angle of attack) to 10 degrees. I will likely get an error because, due to induced velocities, the angle of attack of a
given section may be increased above 10 degrees. My database doesn’t know how a NACA 0012 airfoil behaves at
above 10 degrees angle of attack, and so it will simply return a NaN. To fix this, I should regenerate my database over
a wider range, say from 15 to -15 degrees.
You can see exactly where the database interpolation is failing using a try...except statement, like the following.
try:
scene.solve_forces()
except airfoil_db.DatabaseBoundsError as e:
print(e.airfoil)
print(e.exception_indices)
print(e.inputs_dict)
MachUpX detected a trailing vortex impinging upon a control point. This can lead to
˓→greatly exaggerated induced velocities at the control point.
See "Common Issues" in the documentation for more information. This warning can be
˓→suppressed by reducing "impingement_threshold" in the solver parameters.
Error Handling
51
MachUpX, Release 2.5.1
This page lists changes made to the user interface between versions of MachUpX. Minor changes may be made which
do not affect the user interface, and these will likely not be listed here.
9.1 Version 2
After the development of MachUpX 1, we found that significant improvements could be made to the user interface
and code structure. As such, we have made some changes switching to Version 2. These changes mean that input files
written for Version 1 may no longer run properly for Version 2. However, minimal effort should be required to update.
The various changes are explained below.
MachUpX version 2.0 requires the AirfoilDatabase package, distributed by the USU AeroLab. It can be downloaded
here.
Version 1 of MachUpX supports two state input types, ‘aerodynamic’ and ‘rigid_body’. Essentially, the only difference
between these two was how the velocity was specified. To simplify things, we have removed the requirement to specify
whether the input state is ‘aerodynamic’ or ‘rigid_body’. Instead, the user must simply give the velocity in one of two
ways. The first method is to give the magnitude of the aircraft’s velocity and specify ‘alpha’ and ‘beta’ as well. If
‘alpha’ or ‘beta’ are not specified, they are assumed to be zero. The second method is to give the body-fixed velocity
components of the aircraft (i.e. u, v, and w). These should be given as a list to the ‘velocity’ key. Version 2 will no
longer support inputting the Earth-fixed velocity components. Please note that a velocity specified using a magnitude
and alpha and beta will take into account wind, if such is present in the scene. If there is wind, then ‘alpha’ and ‘beta’
will be true aerodynamic angles relative to the local wind vector at the aircraft’s origin.
As a whole, the USU AeroLab has decided to consistently use the sideslip angle defined as asin(Vy/V) in its analysis.
MachUpX has been updated to reflect this change.
53
MachUpX, Release 2.5.1
To simplify code structure, most of the scene member methods now use keyword arguments (kwargs as they are called
in Python). You can read more about kwargs here. This may cause some scene method calls to break. In most cases,
this can be fixed by formatting the method arguments as kwargs.
Due to research conducted by the developers, it was determined that placing the lifting-line on the locus of aerody-
namic centers was inappropriate. As such, the wing segment input “ac_offset” has been renamed to “ll_offset”. We
recommend this be left as 0, unless you have good reason to do otherwise and understand what’s going on.
Support
Unlike previous versions of MachUp, MachUpX is in active development, and we encourage users to submit bug
reports on the Github repo. We will continually push bug fixes to the ‘master’ branch. Suggested improvements are
also welcome but will be developed in separate branches. When a new version is ready to be released, we will merge
all developed improvements into the ‘master’ branch.
For questions, there is an active forum on Google Groups. Please submit bug reports on Github.
55
MachUpX, Release 2.5.1
Developer Notes
The purpose of this document is to explain the inner workings of MachUpX for those who are developing it. Please
update this as often as you can.
MachUpX solves the formulation of the numerical lifting-line equation presented in Reid A General Approach to
Lifting-Line Theory, Applied to Wings with Sweep and Goates, et al. “A Practical Implementation of General Nu-
merical Lifting-Line Theory”, AIAA SciTech Conference, 2020. This formulation differs somewhat from the original
formulation by Phillips and Snyder. Most significantly, the formulation is generalized to allow multiple aircraft to be
analyzed at once. MachUpX sets up and solves the lifting-line equation in Earth-fixed coordinates. Once the distribu-
tion of vortex strengths is obtained, the forces and moments are integrated then transformed to the body-fixed frame
for each aircraft.
For the most part, MachUpX is ignorant of how many aircraft are in the scene. When performing calculations, it will
simply execute a for loop on the stored dictionary of aircraft. I have made some exceptions to this to try to speed
things up. The exceptions have mostly been made in instances where there are calculations which could be performed
at both the scene or the aircraft leve. To speed things up, I’ve dropped the computations down to the aircraft level
where possible.
When using MachUpX as a Python module, the Airplane class is never exposed to the user. Rather, the user calls
getters and setters through the Scene class and supplies the name of the target aircraft to effect changes.
In the future, it could be beneficial to allow the user access to the Airplane class directly. The user could instantiate
an aircraft object and then pass this object as an argument to the Scene constructor. This would require some kind of
57
MachUpX, Release 2.5.1
listener/binding between the Airplane class and the Scene class so that certain functions in the Scene class, such as
_perform_geometry_calculations(), are called whenever a change is made to the Airplane object. This is
just an idea.
In implementing the WingSegment class, the set of wing segments constituting an airplane are stored as a tree. There
is an origin segment, which has no properties. Other segments are then attached to (or more accurately, defined relative
to) this segment. Each segment knows which segments are attached to it and segments are added recursively. This
structural choice was motivated by two factors. For one, recursion is elegant, simple, and fast. The second is that
this will more naturally allow for calculating the influence of forces and moments exerted by outboard wing segments
on inboard segments. The tree can be traversed recursively and forces, moments, and aeroelastic deflections can be
integrated as the function backs out of the recursion. Aeroelastic effects are not yet implemented in MachUpX and so
this may change in the future as needed functionality becomes clearer.
MAC seems to be a poor man’s estimate for the aerodynamic center, but not quite. It is based entirely off of geometry,
no aerodynamics involved. I took information from the following to code this up:
• Raymer “Simplified Aircraft Design for Homebuilders”
• McCormick “Aerodynamics, Aeronautics, and Flight Mechanics”
• Nickel & Wohlfahrt “Tailless Aircraft in Theory and Practice”
• Phillips “Mechanics of Flight”
There is agreement between all sources on only one thing, the definition of the MAC as a reference length. This is
given by Phillips Eq. 1.8.86 (excuse my ASCII math):
b/2
1 / 2
MAC = - | c dy
S /
-b/2
Phillips and Raymer are the only ones to tie the MAC to a specific location on the wing. Phillips simply states that
there is a spanwise position on the wing where the local chord is equal to the MAC. Raymer also does this and presents
a graphical method for determining the position of the MAC on a tapered wing. He briefly describes how to find the
MAC for a compound tapered wing, stating the MAC should be found for each section separately and the the 25%
point should be averaged using an area-weighted average. N&W and McCormick simply give the MAC as a reference
length and give it no positional significance.
Raymer ties the MAC to an introductory discussion of stability. He states, “The MAC is a sort of averaged chord, and
the entire wing tends to act as if all its area were concentrated at the MAC.” He thereby claims the point of neutral
stability (i.e. the aerodynamic center) on the wing is at the 25% MAC location. He then recommends, for a tailed
airplane, that the CG be placed at the 25% MAC location so the wing is neutrally stable and all longitudinal stability
comes from the horizontal stabilizer. This is reasonable, given his assumptions.
Phillips directly disputes the assumption that the wing aerodynamic center lies on the MAC. He shows this is not true
for most wing geometries (see Figure 1.8.28 in his book). However, he focuses on the fact that the aerodynamic center
does not lie on the same spanwise position as the MAC. For an unswept wing, Phillips states the aerodynamic center
of the wing lies on the locus of section aerodynamic centers (i.e. 25% root chord). This agrees with Raymer’s claim,
as the 25% MAC location also lies on the straight locus of section aerodynamic centers. For swept wings, determining
the location of the wing aerodynamic center becomes more hairy. Phillips gives the following approximation (Eq.
1.11.9):
/ b/2 \
_ 1 d | / ~ |
x = ---- -- | | CL c x dy |
ac CL,a da | / ac |
\-b/2 /
If we assume the section lift coefficient is constant over the span, as is often done, this reduces to:
b/2
_ 1 / ~
x = - | c x dy
ac S / ac
-b/2
This can be interpreted as an area-weighted average of the section aerodynamic centers. N&W provide this equation
and call this the “C-Point” or “Center of Lift for Constant Local Lift Coefficient”. This makes sense. They then
recommend the CG be placed at least 6-12% of the MAC in front of the C-Point for a flying wing. As the main wing
constitutes the entire airframe of a flying wing, this is simply the recommendation that the aircraft have a static margin
of at least 6-12%. Very reasonable.
I have coded up both methods of determining the main wing aerodynamic center (Raymer’s and Phillips’). For unswept
wings, the 25% MAC location and the average of the section aerodynamic centers are the same, i.e. 0. For swept
straight and tapered wings, they are also the same. For swept elliptic wings, however, the two results diverge. There-
fore, I have decided that in MachUpX, calling Scene.MAC() will give you the MAC (that is, the reference length) and
the location of the C-Point. This seems to me to be the most reliable.
Dr Hunsaker and Jaden Thurgood have done an excellent job of standardizing the directions of lift, drag, and side-
force for the AeroLab. However, their derivation relies on calculating trigonometric values, which is computationally
expensive. MachUpX, instead, uses vector definitions, which are much faster to compute. All that is required is the
freestream direction vector in body-fixed coordinates, u_inf. This defines the direction of drag. Taking the cross
product of this with the body-fixed y-axis vector and normalizing gives us the lift direction vector, u_lift. To complete
the system, the sideforce direction vector is given by the cross product of u_lift with u_inf. This should already be
normalized, but it can be normalized again to make sure. The force vector in body-fixed coordinates can then simply
be dotted with each of these direction vectors to obtain L, D, and S. Taking the dot product of a vector with a unit
vector gives the projection of the first vector in the direction of the unit vector.
Users will notice that differences exist between the results obtained from the two versions of MachUp. Here is a list
of things which vary in the implementations and which will affect results.
• MachUpX allows Kuchemann’s LAC correction.
• MachUpX implements thin-airfoil theory corrections to swept section properties.
• MachUpX implements Reid’s horseshoe vortex geometry corrections (i.e. jointed vortices and effective LAC).
• MachUpX redimensionalizes section properties using the total (freestream plus induced) velocity at each control
point. MachUp Pro uses only the freestream.
• MachUpX has a slightly different nonlinear Jacobian (a consequence of the above). This does not affect the
final solution, only convergence rates.
• MachUpX defaults to clustering control points about flap edges.
• MachUpX uses CL_max to truncate section lift coefficients within the lifting-line algorithm. MachUp Pro only
uses this to determine stall onset.
• MachUpX uses only the in-plane velocity for determining section behavior.
• MachUp Pro scales section coefficients by the magnitude of the freestream including rotation. MachUpX doesn’t
need to do this.
All of these can be toggled in MachUpX by the user. Under the “grid” parameter for each wing, “reid_corrections”
and “flap_edge_cluster” can be specified. Also, “ll_offset” can be set as “kuchemann” for each wing. In the input
file under “solver”, “use_swept_sections”, “use_total_velocity”, “use_in_plane”, and “match_machup_pro” can be
specified. “CL_max” is specified in the input for each airfoil.
A couple minor differences which cannot be toggled are:
• MachUpX uses the experimental sideslip angle whereas MachUp Pro uses the analytical sideslip angle.
• MachUpX uses a different definition for the directions of lift, drag, and sideforce. These are guaranteed to be
orthogonal, whereas those given by MachUp Pro are not.
• MachUp Pro is an inherently nondimensional derivation which ignores increases in local freestream velocity
due to aircraft rotation. At this point (June 2020), we have been unable to determine exactly how to alter the
dimensional derivation in MachUpX to correct for this.
Jackson’s original GNLL uses empirical fits of data he obtained from vortex panel method to correct airfoil sections
for sweep. However, he did it such that the corrections for the moment coefficient apply to the moment about the
leading edge. This is very inconvenient, especially when using “database” or “poly_fit” type airfoils. For this reason,
MachUpX corrects the section coefficients using thin-airfoil theory. These corrections are summarized here (see
Goates, et al. “A Practical Implementation of General Numerical Lifting-Line Theory”, AIAA SciTech Conference,
2020 for a more in-depth discussion).
• Zero-lift angle of attack is scaled by 1/cos(sweep).
• Section moment coefficient is scaled by 1/cos(sweep).
• Drag is weird. . .
Throughout MachUpX, two coordinate systems are used. These are the body-fixed and earth-fixed coordinate systems.
In the body-fixed coordinate system, the x-axis points forward out of the nose of the aircraft, the y-axis points to the
right along the wing, and the z-axis points down. The body-fixed coordinate system has its origin at the aircraft’s
center of gravity.
In the earth-fixed coordinate system, the x-axis points North, the y-axis points East, and the z-axis points down. The
origin of the earth-fixed coordinate system is somewhat arbitrary, but it is assumed to be at sea level. In this coordinate
system, the earth is assumed to be flat.
Calculations occurring within the Scene class are almost always done in the earth-fixed frame. Calculations occurring
within the Airplane and WingSegment classes are done in the body-fixed frame.
a
airfoil_db, 51
m
machupX, 29
63
MachUpX, Release 2.5.1
A M
add_aircraft() (machupX.Scene method), 30 MAC() (machupX.Scene method), 29
aero_center() (machupX.Scene method), 30 machupX (module), 29, 51
airfoil (airfoil_db.DatabaseBoundsError attribute), message (airfoil_db.DatabaseBoundsError attribute),
51 51
airfoil_db (module), 51
O
C out_gamma() (machupX.Scene method), 35
control_derivatives() (machupX.Scene
method), 30 P
pitch_trim() (machupX.Scene method), 35
D pitch_trim_using_orientation()
damping_derivatives() (machupX.Scene (machupX.Scene method), 35
method), 31
DatabaseBoundsError (class in airfoil_db), 51 R
derivatives() (machupX.Scene method), 31 remove_aircraft() (machupX.Scene method), 36
display_planform() (machupX.Scene method), 31
display_wireframe() (machupX.Scene method), S
32 Scene (class in machupX), 29
distributions() (machupX.Scene method), 32 set_aircraft_control_state()
(machupX.Scene method), 36
E set_aircraft_state() (machupX.Scene method),
exception_indices (air- 36
foil_db.DatabaseBoundsError attribute), set_err_state() (machupX.Scene method), 36
51 solve_forces() (machupX.Scene method), 36
export_dxf() (machupX.Scene method), 33 SolverNotConvergedError (class in machupX),
export_pylot_model() (machupX.Scene method), 51
33 stability_derivatives() (machupX.Scene
export_stl() (machupX.Scene method), 34 method), 37
export_stp() (machupX.Scene method), 34 state_derivatives() (machupX.Scene method),
37
G
get_aircraft_reference_geometry() T
(machupX.Scene method), 34 target_CL() (machupX.Scene method), 38
I
inputs_dict (airfoil_db.DatabaseBoundsError at-
tribute), 51
65