Standard Atmosphere#

Aerodynamic analyses need various air properties to do the calculations. The standard way to come up with thoseproperties is to use the Standard Atmosphere model, published in 1976. There is a Python package that provides access to this model, but for our purposes, I will use methods defined in Mark Drela’s Flight Vehicle Aerodynamics[Dre14].

To get started with this model, we need to define the properties at sea-level. Each of these properties has engineering units attached to the number. It is critical that these units be consistent in calculations, so we will use the Python pint package to add these units to the data.

import pint
u = pint.UnitRegistry()
rho_SL = 1.225*u.kg/u.m**3
rho_SL
1.225 kilogram/meter3
p_SL = 1.0132e5*u.pascal
p_SL
101320.0 pascal
T_SL = 288.15*u.kelvin
T_SL
288.15 kelvin
a_SL = 340.3*u.m/u.sec
a_SL
340.3 meter/second
mu_SL = 1.79e-5*u.kg/(u.m*u.sec)
mu_SL
1.79×10-5 kilogram/(meter second)

The equations that define these properties for altitudes other than sea-level are given in Drela’s book, but they originally come from the COESA Working Group[Gro76]

\begin{equation} p(z) = e^{-0.118z -\frac{0.0015z^2}{1-0.018z+0.0011z^2}} \end{equation}

import matplotlib.pyplot as plt
import numpy as np
alt = np.linspace(0,26,27)*u.km
alt
Magnitude
[0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0 11.0 12.0 13.0 14.0 15.0
16.0 17.0 18.0 19.0 20.0 21.0 22.0 23.0 24.0 25.0 26.0]
Unitskilometer

Pressure vs Altitude#

def p(z):
    zm = z.magnitude
    return p_SL*np.exp(-0.118*zm-(0.0015*zm**2)/(1-0.018*zm+0.0011*zm**2))
poa = p(alt)
poa
Magnitude
[101320.0 89905.40296142412 79526.3201763238 70116.7008535207
61614.862419002806 53962.20127801882 47102.168173822436 40979.53120929073
35539.93103120646 30729.71191496322 26495.992696378078 22786.925696046874
19552.082212282578 16742.900854417207 14313.13965090953
12219.283063740182 10420.868635489112 8880.712667420943 7565.028033761941
6443.43852153456 5488.902186947324 4677.561021642893 3988.536089189105
3403.6868673416725 2907.3515509893737 2486.0822244901847
2128.3856626436877]
Unitspascal
popsl = poa/p_SL

Temperature vs Altitude#

def T(z):
    zm = z.magnitude
    res = 216.65 + 2.0*np.log(1 + np.exp(35.75 - 3.25*zm) + np.exp(-3.0+0.0003*zm**3))
    return res*u.kelvin
T(0*u.km)
288.15 kelvin
totsl = T(alt)
totsl = totsl/T_SL
totsl
Magnitude
[1.0 0.9774423043553707 0.9548846087107425 0.9323269130661487
0.909769217422443 0.8872115218016585 0.864653826772848 0.8420961470418766
0.8195388629320705 0.7969918120142241 0.7747044719977422
0.7569292795636732 0.7526666985587329 0.7525126326478171
0.7526113080276051 0.7527567465845564 0.7529558481885794
0.7532306263698091 0.7536133264982797 0.7541496428151572
0.7549018771506926 0.755949529762568 0.7573837493026108 0.75929287550148
0.7617418335517596 0.7647560442698814 0.7683210471896667]
Unitsdimensionless

Viscosity vs Altitude#

The viscosity function is given next:

\begin{equation} \mu(z) = \mu(T(z)) = \mu_{SL}\left(\frac{T}{T_{SL}} \right)^\frac{3}{2}\frac{T_{SL} + T_S}{T + T_S} \end{equation}

From Sutherland’s Law, the value for \(T_S\) is \(110K\) for air.

T_S = 110 * u.kelvin
temp = T(alt)
temp
Magnitude
[288.15 281.65000000000003 275.15000000000043 268.6500000000107
262.1500000002769 255.65000000714787 249.1500001845961 242.65000477011674
236.15012335387607 229.65319063189864 223.2310936061494
218.10917190627242 216.88090918969888 216.83651509746846
216.8649484081544 216.90685652833992 216.96422765553913
217.04340498846048 217.15368003047928 217.30821957718751
217.52497590097204 217.82685700108397 218.24012736154728
218.79024207575142 219.4959093379395 220.36445415636632
221.39170974770244]
Unitskelvin
def mu(z):
    temp = T(z)
    return mu_SL*(temp/T_SL)**1.5*(T_SL + T_S)/(temp+T_S)
muoa = mu(alt)
muoa
Magnitude
[1.79e-05 1.7584835809587085e-05 1.7266177001104793e-05
1.694392893819139e-05 1.6617993505788143e-05 1.628826899776725e-05
1.5954650017569277e-05 1.561702758439764e-05 1.5275294416681778e-05
1.4929485519502643e-05 1.4583384522673428e-05 1.4304225162586247e-05
1.4236861027383915e-05 1.4234423157951812e-05 1.423598457735019e-05
1.4238285807250525e-05 1.4241435820872942e-05 1.4245782535101866e-05
1.425183532845563e-05 1.4260315491725273e-05 1.427220534594282e-05
1.428875609091321e-05 1.4311397759875444e-05 1.4341507963811481e-05
1.4380084373826825e-05 1.4427491109355978e-05 1.4483456082874562e-05]
Unitskilogram/(meter second)

Density vs Altitude#

To get density we need to use the ideal gas state equation

\begin{equation} p = \rho R T \end{equation}

Where the gas constant is \(R = 287.04\frac{J}{kgK}\)

Rgas = 287.04*u.joule/(u.kg*u.kelvin)
def rho(z):
    temp = T(z)
    press = p(z)
    rho = press/(Rgas*temp)
    return rho
rho(alt).to_base_units()
Magnitude
[1.2249944916355073 1.1120738151154193 1.006929231672808
0.9092686279875508 0.818828970279342 0.7353624321726699
0.6586240505752484 0.5883615187817502 0.5243073942276445
0.4661692083875943 0.4135072107201098 0.3639731823997718
0.3140720347286737 0.2690022207064919 0.229933962687512
0.19625919974048978 0.16732982820764872 0.1425472368849524
0.12136708656500936 0.10329971282845796 0.08790912170823537
0.07481102675886994 0.06367024165768087 0.054197496853412463
0.046145429941715554 0.0393035270301297 0.033492421578613936]
Unitskilogram/meter3
rhooa = rho(alt)
rhooa = rhooa/rho_SL

Speed of Sound vs Altitude#

The speed of sound is calculated using this formula:

\begin{equation} a= \sqrt{\gamma RT} \end{equation}

gamma = 1.4
def sos(z):
    temp = T(z)
    res = np.sqrt(gamma*Rgas*temp)
    return res
sosoa = sos(alt).to_base_units()
aoasl = sosoa/a_SL
plt.plot(popsl,alt)
plt.ylabel("z(km)")
plt.plot(totsl, alt, label=r"$p/p_{sl}$")
plt.plot(muoa/mu_SL,alt, label=r"$\mu/\mu_{sl}$")
plt.plot(rhooa,alt, label = r"$\rho/\rho_{sl}$")
plt.plot(aoasl,alt, label = r"$a/a_{sl}$")
plt.legend()
/Users/rblack/_dev/mmqprop/.venv/lib/python3.10/site-packages/matplotlib/cbook/__init__.py:1369: UnitStrippedWarning: The unit of the quantity is stripped when downcasting to ndarray.
  return np.asarray(x, float)
<matplotlib.legend.Legend at 0x10dacafe0>
../../_images/standard-atmosphere_39_2.png

That plot looks like the figure presented in Drela’s book.

All of this code has been placed in a single class names StdATm which takes an altitude in meters, and returns the properties as a dictionary. We can nhand this function a ((numpy** array of altitudes is needed.))

import sys
import os
sys.path.insert(0, '../../..')
from mmqprop.StdAtm import StdAtm
s = StdAtm(u,alt)
s.properties().to_base_units()
Magnitude
[340.28635940924806 336.4264294017341 332.52169613425247 328.5705622845788
324.57133329995617 320.5222089073897 316.4212737383203 312.26648926341744
308.055748153634 303.78859849338033 299.51085848795657 296.05485874338723
295.2200783201163 295.189861971932 295.2092151466604 295.2377376573878
295.2767797656028 295.3306529215055 295.4056689407437 295.5107644171532
295.6581078131648 295.8631938025201 296.1437229133886 296.51673058968044
296.9945254426535 297.58154863744613 298.27434839820313]
Unitsmeter/second

..literalinclude:: ../../mmqprop/StdAtm.py