Source code for aerosandbox.dynamics.flight_dynamics.airplane

from aerosandbox.geometry.airplane import Airplane
from aerosandbox.performance import OperatingPoint
from aerosandbox.weights import MassProperties
import aerosandbox.numpy as np


[docs]def get_modes( airplane: Airplane, op_point: OperatingPoint, mass_props: MassProperties, aero, g=9.81, ): Q = op_point.dynamic_pressure() S = airplane.s_ref c = airplane.c_ref b = airplane.b_ref QS = Q * S m = mass_props.mass Ixx = mass_props.Ixx Iyy = mass_props.Iyy Izz = mass_props.Izz u0 = op_point.velocity Cxu = -2 * aero["CD"] Czu = -2 * aero["CL"] Cmq = aero["Cmq"] Cma = aero["Cma"] X_u = QS / m / u0 * Cxu # Units: 1/sec # X_w = QS / m / u0 * Cxa # X_q = QS / m * c / (2 * u0) * Cxq Z_u = QS / m / u0 * Czu # Units: 1/sec # Z_w = QS / m / u0 * Cza # Z_q = QS / m * c / (2 * u0) * Czq # M_u = QS * c / Iyy / u0 * Cmu M_w = QS * c / Iyy / u0 * Cma # Units: 1/(meter * sec) M_q = QS * c / Iyy * c / (2 * u0) * Cmq # Units: 1/sec modes = {} def get_mode_info( sigma, omega_squared, ): is_oscillatory = omega_squared > 0 return { "eigenvalue_real": sigma + np.where( is_oscillatory, 0, np.abs(omega_squared + 1e-100) ** 0.5, ), "eigenvalue_imag": np.where( is_oscillatory, np.abs(omega_squared + 1e-100) ** 0.5, 0, ), } ##### Longitudinal modes ### Phugoid modes["phugoid"] = { # FVA, Eq. 9.55-9.57 **get_mode_info(sigma=X_u / 2, omega_squared=-(X_u**2) / 4 - g * Z_u / u0), "eigenvalue_imag_approx": 2**0.5 * g / u0, "damping_ratio_approx": 2**-0.5 * aero["CD"] / aero["CL"], } # # ### Short-period modes["short_period"] = get_mode_info( sigma=0.5 * M_q, omega_squared=-(M_q**2) / 4 - u0 * M_w ) ##### Lateral modes ### Roll subsidence modes["roll_subsidence"] = { # FVA, Eq. 9.63 "eigenvalue_real": (QS * b**2 / (2 * Ixx * u0) * aero["Clp"]), "eigenvalue_imag": 0, "damping_ratio": 1, } ### Dutch roll modes["dutch_roll"] = get_mode_info( # FVA, Eq. 9.68 sigma=( QS * b**2 / (2 * Izz * u0) * (aero["Cnr"] + Izz / (m * b**2) * aero["CYb"]) ), omega_squared=( QS * b / Izz * ( aero["Cnb"] + ( op_point.atmosphere.density() * S * b / (4 * m) * (aero["CYb"] * aero["Cnr"] - aero["Cnb"] * aero["CYr"]) ) ) ), ) ### Spiral spiral_parameter = ( aero["Cnr"] - aero["Cnb"] * aero["Clr"] / aero["Clb"] ) # FVA, Eq. 9.66 modes["spiral"] = { # FVA, Eq. 9.66 "eigenvalue_real": (QS * b**2 / (2 * Izz * u0) * spiral_parameter), "eigenvalue_imag": 0, } ### Compute damping ratios of all modes for mode_name, mode_data in modes.items(): modes[mode_name]["damping_ratio"] = ( -mode_data["eigenvalue_real"] / (mode_data["eigenvalue_real"] ** 2 + mode_data["eigenvalue_imag"] ** 2) ** 0.5 ) return modes
if __name__ == "__main__": import aerosandbox as asb import aerosandbox.numpy as np from aerosandbox.tools import units as u from pprint import pprint # Numbers below are from: # Caughey, David A., "Introduction to Aircraft Stability and Control, Course Notes for M&AE 5070", 2011 # https://courses.cit.cornell.edu/mae5070/Caughey_2011_04.pdf
[docs] airplane = asb.Airplane( name="Boeing 737-800", s_ref=1260 * u.foot**2, c_ref=11 * u.foot, b_ref=113 * u.foot, )
aero = dict( CL=1.83443, CD=0.13037, Cm=0, CLa=5.542930, Cma=-2.044696, CYb=-1.103873, Clb=-0.374933, Cnb=0.239877, CYp=0.800161, Clp=-0.449404, Cnp=-0.255028, CLq=18.973344, Cmq=-74.997742, CYr=0.796001, Clr=0.364638, Cnr=-0.434410, ) mass_props_TOGW = asb.MassProperties( mass=77146, x_cg=65.2686 * u.foot, y_cg=0.0, z_cg=1.16559 * u.foot, Ixx=706684, Iyy=0.270824e7, Izz=0.330763e7, Ixy=0.0, Iyz=0.0, Ixz=26994.4, ) op_point = asb.OperatingPoint( atmosphere=asb.Atmosphere( altitude=2438.399975619396, method="differentiable", ), velocity=85.64176936131635, ) assert np.allclose( aero["CL"], mass_props_TOGW.mass * 9.81 / op_point.dynamic_pressure() / airplane.s_ref, rtol=0.001, ) eigenvalues_from_AVL = { "phugoid": -0.0171382 + 0.145072j, # Real is wrong (2x) "short_period": -0.439841 + 0.842195j, # Pretty close "roll_subsidence": -1.35132, # get_modes says -1.81 "dutch_roll": -0.385418 + 1.52695j, # Imag is wrong (1.5x) "spiral": -0.0573017, # Too small, get_modes says -0.17 } pprint( get_modes( airplane=airplane, op_point=op_point, mass_props=mass_props_TOGW, aero=aero ) )