Professional Documents
Culture Documents
Contents
Data for Boeing 747
Other Condition Data
Data for several aircraft are presented in :cite:`Heffley:1972wb` and, honestly, this is a good
exercise in showing you what a tremendous amount of being an engineer is - extracting data
from old reports and doing stuff with it.
Configuration Information
h = SL
V ∞ = 165KTAS
2
S = 5500f t
b = 195.68f t
c̄ = 27.31f t
θ0 = 0
note that the trim theta is not actually given, but assumed to be zero
Nondimensional Stability Derivatives
Longitudinal Lateral-Directional
−1
C L = 1.11 Cy = −0.96rad
β
−1
C D = 0.102 Cℓ = −0.221rad
β
−1 −1
C L α = 5.70rad C n β = 0.150rad
−1
CD = 0.66rad Cℓ = −0.45
α p
^
−1
C m α = −1.26rad Cn = −0.121
p
^
−1
CL = −6.7rad Cℓ = 0.101
α̇ r
^
−1
Cm = −3.2rad Cn = −0.30
α̇ r
^
−1
CL = 5.40 C ℓδ = 0.0461rad
q
^ a
−1
Cm = −20.8 C nδ = 0.0064rad
q
^ a
−1
CL = −0.81 Cy = 0.175rad
M δr
−1
Cm = 0.27 Cℓ = 0.007rad
M δr
−1 −1
C Lδ = 0.338rad C nδ = −0.109rad
e r
−1
Cm = −1.34rad
δe
Note that in :cite:`Heffley:1972wb`, the derivatives with respect to angular rates are erroneously
given units of /rad, when they clearly are non-dimensional rates. The derivatives with respect to
aerodynamic angles correctly are given units of /rad.
import numpy as np
from IPython.display import display, Math, Latex, Markdown
SIunits = False
if SIunits:
# Conversion factors
ft_to_metre = 0.3048
lb_to_kg = 0.453592
slug_to_kg = 14.5939
MOIconvert = slug_to_kg*ft_to_metre**2
# Constants
a = 340 # sonic velocity in m/s
g = 9.80665 # acceleration due to gravity
rho = 1.225 # density in kg/m^3
# Convert
U0 = U0 * ft_to_metre
S = S * ft_to_metre**2
b = b * ft_to_metre
c = c * ft_to_metre
m = m * lb_to_kg
Ixx = Ixx * MOIconvert
Iyy = Iyy * MOIconvert
Izz = Izz * MOIconvert
Ixz = Ixz * MOIconvert
else:
a = 1125.33 # sonic velocity in ft/s
g = 32.174
# Convert mass moments of inertia to consistent units --> INTO lb-ft^2 FROM slug-
ft^2
Ixx = Ixx * g
Iyy = Iyy * g
Izz = Izz * g
Ixz = Ixz * g
# Note that without doing the dictionary --> local namespace, the we'd have to write:
# Xu = q * S / m / U0 * (2 * B747_lon_ders["C_D"] + M * B747_lon_ders["C_D_M"])
# Convert to dimensional form
q = 0.5 * rho * U0**2
M = U0 / a
print(f"Xu = {Xu:1.4f}")
print(f"Xw = {Xw:1.4f}")
print(f"Zu = {Zu:1.4f}")
print(f"Zw = {Zw:1.4f}")
print(f"Zdw = {Zdw:1.4f}")
print(f"Zq = {Zq:1.4f}")
print(f"Mu = {Mu:1.4f}")
print(f"Mw = {Mw:1.4f}")
print(f"Mw = {Mw:1.4f}")
print(f"Mdw = {Mdw:1.4f}")
print(f"Mq = {Mq:1.4f}")
print(f"Zde = {Zde:1.4f}")
print(f"Mde = {Mde:1.4f}")
Xu = -0.0212
Xw = 0.0467
Zu = -0.2098
Zw = -0.6027
Zdw = -0.0341
Zq = -7.6596
Mu = 0.0001
Mw = -0.0019
Mw = -0.0019
Mdw = -0.0002
Mq = -0.4373
Zde = -9.7779
Mde = -0.5746
# Conversion factors
ft_to_metre = 0.3048
lb_to_kg = 0.453592
slug_to_kg = 14.5939
Using SI Units:
Dynamic pressure, q = 4414.9750 Pa
Wing area, S = 511 m^2
Mass, m = 255826 kg
Trim forward speed, U0 = 84.9 m/s
Gives a value for Xu = -0.2098, and a value for Zq of -2.3348
u̇ Xu Xw 0 −g ⋅ cos Θ e u 0
⎡ ⎤ ⎡ ⎤ ⎡ ⎤ ⎡ ⎤
ẇ Zu Zw U0 −g ⋅ sin Θ e w Zδ
e
= ∗ ∗ ∗ ∗
+ ∗
[δ e ]
q̇ Mu Mw Mq M q M
θ δe
⎣ ⎦ ⎣ ⎦ ⎣ ⎦ ⎣ ⎦
θ̇ 0 0 1 0 θ 0
1. The starred terms need to be made from the products of the stability derivatives.
2. We have a Z term from conversion of the stability derivatives, but no corresponding
q
import sympy as sp
Zu
Zw
Zq
[A lon ] =
⎢⎥
g * np.sin(theta_0)
* Zde
Now we’ve got all the terms, we don’t know where to put Z . The answer should be obvious - it
⎣
−0.021191
−0.20979
0.00015355
0
0.046745
−0.6027
−0.0017943
0
q
goes where the U term is - it doesn’t replace it, but is added to it. So:
# Get the eigenvalues - this is my own checking I got the matrix correct. It'll make
sense later.
eigs, _ = np.linalg.eig(Alon)
270.83
−0.43544
1.0
0
⎦
⎤
# Put the non-dimensional derivatives into the local namespace
locals().update(B747_lat_ders)
Yv = q * S / m / U0 * C_y_b
Yp = 0
Yr = 0
Lv = q * S * b / Ixx / U0 * C_l_b
Lp = q * S * b**2 / 2/ Ixx / U0 * C_l_hp
Lr = q * S * b**2 / 2/ Ixx / U0 * C_l_hr
Nv = q * S * b / Izz / U0 * C_n_b
Np = q * S * b**2 / 2 / Izz / U0 * C_n_hp
Nr = q * S * b**2 / 2 / Izz / U0 * C_n_hr
print(f"Yv = {Yv:1.4f}")
print(f"Yp = {Yp:1.4f}")
print(f"Yr = {Yr:1.4f}")
print(f"Lv = {Lv:1.4f}")
print(f"Lp = {Lp:1.4f}")
print(f"Lr = {Lr:1.4f}")
print(f"Nv = {Nv:1.4f}")
print(f"Np = {Np:1.4f}")
print(f"Nr = {Nr:1.4f}")
Yv = -0.0997
Yp = 0.0000
Yr = 0.0000
Lv = -0.0055
Lp = -1.0971
Lr = 0.2462
Nv = 0.0012
Np = -0.0931
Nr = -0.2309
Yv 0 −U 0 g ⋅ cos θ 0 0
⎡ ⎤
∗ ∗ ∗
Lv Lp Lr 0 0
∗ ∗ ∗
A = Nv Np Nr 0 0
0 1 tan θ 0 0 0
⎣ ⎦
0 0 sec θ 0 0 0
# Making the starred terms
I2 = Ixz / Ixx
# Lstarred terms
Lvstar = Imess * (Lv +
Lpstar = Imess * (Lp +
Lrstar = Imess * (Lr +
Ldrstar = Imess * (Ldr
Ldastar = Imess * (Lda
# Nstarred terms
I2 = Ixz / Izz
Nvstar = Imess * (Nv +
Npstar = Imess * (Np +
Nrstar = Imess * (Nr +
Ndrstar = Imess * (Ndr
Ndastar = Imess * (Nda
[A lat ] =
⎢⎥
Imess = Ixx * Izz / (Ixx * Izz - Ixz**2)
I2 *
I2 *
I2 *
+ I2
+ I2
Nv)
Np)
Nr)
* Ndr)
* Nda)
Lv)
Lp)
Lr)
* Ldr)
* Lda)
−0.099723
−0.0057348
0.0014622
+0.j
0
-0.08023692-0.74204291j -0.04646794+0.j
The coefficients of the CE are: [1.
0.03180283 0.
np.pi*2/.7420
8.467904726657125
]
0
−1.0909
−0.039417
1.0
0
−278.49
0.28442
−0.24488
1.0
-1.2285872 +0.j
]
32.174
0
0
0
⎤
Note that we’ve not made either of the control matrices yet - and there’s a good reason for that.
If we consider the linearised model of the aircraft created, the stability of the aircraft (i.e., its
response to a perturbation) will be governed by the system matrix.
In the first instance, it is desired to understand the stick fixed stability and understand what will
happen to the aircraft if no inputs are made.
Consider what the two matrices developed actually show us; if the aircraft is disturbed from a
given condition, then if the disturbance is a symmetric state variable (u, w, q, θ), then the output
is a time rate of change of all other symmetric variables.
The control matrices tell us how the aircraft responds due to control input. Therefore, if we’re
interested in aircraft response in the absense of pilot or control-system input, then we’re only
interested in the A matrices themselves. The A matrices give the open loop response of the
aircraft.
Since these are ODEs, we could write a means to time-march through the solution - but there
are some handy inbuilt tools in Python to look at the responses of state-space systems to
different inputs.
You will probably need to install these to work on your system - look here.
But if we create the B matrix, it can be used to excite the aircraft with unity impulse input. For
this reason, it makes sense to make the two control matrices with derivatives that have been
scaled by a factor of π
180
to allow a unity degree control input.
import control
import control.matlab
# We will make a B matrix to enable us to use the control system toolbox by _exciting
the aircraft_ through
# Elevator input. Turn from Zde in 1/radians to 1/degree to put a useful input in.
Blon = np.matrix([[0], [np.radians(Zde)], [np.radians(Mdestar)], [0]])
# Look at the first 100 seconds response to a unit impulse in the only
Time, [u, w, q, theta] = control.impulse_response(LonSS, T=np.linspace(0, 200,
10000))
fig.add_trace(
go.Scatter(x = Time, y = u, showlegend=False), row=1, col=1)
fig.add_trace(
go.Scatter(x = Time, y = w, showlegend=False), row=1, col=2)
fig.add_trace(
go.Scatter(x = Time, y = q, showlegend=False), row=2, col=1)
fig.add_trace(
go.Scatter(x = Time, y = theta, showlegend=False), row=2, col=2)
2 2
0 0
Time Time
q / (deg/s)
θ / deg
2 2
0 0
Time Time
As much as a pain as the non-dimensional to dimensional procedure is, it is useful in that you
can take fully non-dimensional data and then use whatever unit system you prefer, and you’ll
get results in those units.
Note that there is a flag to convert between US Customary (ugh) and SI units in the code above.
You can see that there’s some very annoying fiddly bits that have to be performed with the US
Customary units to ensure consistency - that is, the mass moments of inertia are given in slugs-
ft^2, but the masses etc. are presented in lbs. This can cause some dimensional moments of
inertia to be about thirty-two times too large, which has a large effect on the end result.
Other inputs?
If you wanted to look at the transient response of the aircraft to control inputs other
than one degree, what could we do with the output to explore this?
Response characteristics
We’ll spend the next module understanding the actual characteristics of the aircraft in terms of
dynamic response, but we can start to intuit some of this now:
There are two phases to the aircraft response - a short-term response that is heavily
damped, affecting mainly heave (i.e., angle of attack) and pitch rate, and a long-term
response that is lightly-damped, affecting mainly speed and pitch attitude, but also
showing in the other state variables.
Non-state variables can be explored - we could go back and change the state variable w for α,
for example, and then explore the change in AoA. This would require calculating a new set of
stability derivatives (many sources use α in place of u). Instead, perturbational angle of attack
can be determined from the linear relationship
alpha = np.degrees(w/(U0+u))
fig = go.Figure()
fig.add_trace(
go.Scatter(x = Time, y = alpha, showlegend=False))
fig.update_xaxes(title_text="Time")
fig.update_yaxes(title_text="$\\alpha/\\text{deg}$")
3
2
−1
0 50 100 150 200
Time
You will see that the angle of attack is affected much more by the short-term response than the
long-term response.
# We will make a B matrix to enable us to use the control system toolbox by _exciting
the aircraft_ through
# Elevator input. Turn from Zde in 1/radians to 1/degree to put a useful input in.
Blat = np.matrix([[Ydr, Yda], [Ldrstar, Ldastar], [Ndrstar, Ndastar], [0, 0], [0,
0]])
Blat = np.radians(Blat)
fig.add_trace(
go.Scatter(x = Time, y = v, showlegend=False), row=1, col=1)
fig.add_trace(
go.Scatter(x = Time, y = p, showlegend=False), row=1, col=2)
fig.add_trace(
go.Scatter(x = Time, y = r, showlegend=False), row=2, col=1)
fig.add_trace(
go.Scatter(x = Time, y = phi, showlegend=False), row=2, col=2)
p / (deg/s)
v / (m/s)
2 2
0 0
Time Time
φ / deg
2 2
0 0
Time Time
fig.add_trace(
go.Scatter(x = Time, y = v, showlegend=False), row=1, col=1)
fig.add_trace(
go.Scatter(x = Time, y = p, showlegend=False), row=1, col=2)
fig.add_trace(
go.Scatter(x = Time, y = r, showlegend=False), row=2, col=1)
fig.add_trace(
go.Scatter(x = Time, y = phi, showlegend=False), row=2, col=2)
0 0
Time Time
φ / deg
2 2
0 0
Time Time
fig.add_trace(
go.Scatter(x = Time, y = phi, showlegend=False))
dphi_est = 0.19
sp_est = dphi_est * np.exp(lam_sp_est*Time)
fig.add_trace(
go.Scatter(x = Time, y = sp_est, name="Estimated Spiral Mode", showlegend=True))
phi_dr = np.zeros(peaks_all.shape)
for i, p in enumerate(peaks_all[:4]):
fig.add_trace(go.Scatter(x = [Time[p]], y = [phi[p]], mode='markers+text',
text=f"{Time[p]:1.3f},{phi[p]:1.3f}", showlegend=False))
fig.show()
fig.update_traces(textposition='top right')
~/opt/anaconda3/lib/python3.8/site-packages/scipy/signal/_peak_finding.py in
find_peaks(x, height, threshold, distance, prominence, width, wlen, rel_height,
plateau_size)
930 """
931 # _argmaxima1d expects array of dtype 'float64'
--> 932 x = _arg_x_as_expected(x)
933 if distance is not None and distance < 1:
934 raise ValueError('`distance` must be greater or equal to 1')
~/opt/anaconda3/lib/python3.8/site-packages/scipy/signal/_peak_finding.py in
_arg_x_as_expected(value)
261 value = np.asarray(value, order='C', dtype=np.float64)
262 if value.ndim != 1:
--> 263 raise ValueError('`x` must be a 1-D array')
264 return value
265
The condition number confers to the Mach/SL diagram on Page 212 of the original report.
Condition Condition Condition Condition Condition
Derivative 2 5 7 9 10
α / ∘
5.70 6.80 0.0 4.60 2.40
I xx /(slug-ft 2
14.3 x 10 6
18.4 x 10 6
18.2 x 10 6
18.2 x 10 6
18.2 x 10 6
I yy /(slug-ft 2
32.3 x 10 6
33.1 x 10 6
33.1 x 10 6
33.1 x 10 6
33.1 x 10 6
I zz /(slug-ft )
2
45.3 x 10 6
49.5 x 10 6
49.7 x 10 6
49.7 x 10 6
49.7 x 10 6
I xz /(slug-ft 2
-2.23 x 10 6
-2.76 x 10 6
0.97 x 10 6
-1.56 x 10 6
-0.35 x 10 6
CD
α
0.66 0.366 0.084 0.425 0.527
CL
α̇
6.7 6.53 5.99 5.91 5.53
Cm
α̇
-3.2 -3.35 -5.4 -6.41 -8.82
Cm
q
-20.8 -20.7 -20.5 -24 -25.1
CD
M
0 0 0.008 0.0275 0.242
Cm
M
0 0.121 -0.116 0.166 -0.114
C Lδ
e
0.338 0.356 0.27 0.367 0.3
Cm
δe
-1.34 -1.43 -1.06 -1.45 -1.2
Cl
β
-0.221 -193 -0.164 -0.277 -0.095
Cn
β
0.15 0.147 0.179 0.195 0.207
Cn
p
-0.121 -0.069 0.0028 -0.042 0.023
Cn
r
-0.3 -0.278 -0.265 -0.327 -333
Cl
δa
0.0461 0.0129 0.012 0.0137 0.0139
Cn
δa
0.0064 0.0015 0.0008 0.0002 -0.003
Cy
δr
0.175 0.1448 0.0841 0.1157 0.062
C lδ
r
0.007 0.0039 0.009 0.007 0.0052
Cn
δr
-0.109 -0.1081 -0.099 -0.1256 -0.091
By Harry Smith
© Copyright 2022.
Aircraft Flight Mechanics by Harry Smith is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
Based on a work at www.aircraftflightmechanics.com.