FlightGear next
YASimAtmosphere.cpp
Go to the documentation of this file.
1#include <string>
2#include "Math.hpp"
3#include "Atmosphere.hpp"
4
5namespace yasim {
6// Copied from McCormick, who got it from "The ARDC Model Atmosphere"
7// Note that there's an error in the text in the first entry,
8// McCormick lists 299.16/101325/1.22500, but those don't agree with
9// R=287. I chose to correct the temperature to 288.20, since 79F is
10// pretty hot for a "standard" atmosphere.
11// Numbers above 19000 meters calculated from src/Environment/environment.cxx
12// meters kelvin Pa kg/m^3
13float Atmosphere::data[][Atmosphere::numColumns] = {
14 { -900.0f, 293.91f, 111679.0f, 1.32353f },
15 { 0.0f, 288.11f, 101325.0f, 1.22500f },
16 { 900.0f, 282.31f, 90971.0f, 1.12260f },
17 { 1800.0f, 276.46f, 81494.0f, 1.02690f },
18 { 2700.0f, 270.62f, 72835.0f, 0.93765f },
19 { 3600.0f, 264.77f, 64939.0f, 0.85445f },
20 { 4500.0f, 258.93f, 57752.0f, 0.77704f },
21 { 5400.0f, 253.09f, 51226.0f, 0.70513f },
22 { 6300.0f, 247.25f, 45311.0f, 0.63845f },
23 { 7200.0f, 241.41f, 39963.0f, 0.57671f },
24 { 8100.0f, 235.58f, 35140.0f, 0.51967f },
25 { 9000.0f, 229.74f, 30800.0f, 0.46706f },
26 { 9900.0f, 223.91f, 26906.0f, 0.41864f },
27 { 10800.0f, 218.08f, 23422.0f, 0.37417f },
28 { 11700.0f, 216.66f, 20335.0f, 0.32699f },
29 { 12600.0f, 216.66f, 17654.0f, 0.28388f },
30 { 13500.0f, 216.66f, 15327.0f, 0.24646f },
31 { 14400.0f, 216.66f, 13308.0f, 0.21399f },
32 { 15300.0f, 216.66f, 11555.0f, 0.18580f },
33 { 16200.0f, 216.66f, 10033.0f, 0.16133f },
34 { 17100.0f, 216.66f, 8712.0f, 0.14009f },
35 { 18000.0f, 216.66f, 7565.0f, 0.12165f },
36 {18900.0f, 216.66f, 6570.0f, 0.10564f },
37 {19812.0f, 216.66f, 5644.0f, 0.09073f },
38 {20726.0f, 217.23f, 4884.0f, 0.07831f },
39 {21641.0f, 218.39f, 4235.0f, 0.06755f },
40 {22555.0f, 219.25f, 3668.0f, 0.05827f },
41 {23470.0f, 220.12f, 3182.0f, 0.05035f },
42 {24384.0f, 220.98f, 2766.0f, 0.04360f },
43 {25298.0f, 221.84f, 2401.0f, 0.03770f },
44 {26213.0f, 222.71f, 2087.0f, 0.03265f },
45 {27127.0f, 223.86f, 1814.0f, 0.02822f },
46 {28042.0f, 224.73f, 1581.0f, 0.02450f },
47 {28956.0f, 225.59f, 1368.0f, 0.02112f },
48 {29870.0f, 226.45f, 1196.0f, 0.01839f },
49 {30785.0f, 227.32f, 1044.0f, 0.01599f }
50};
51
52// Universal gas constant for air, in SI units. P = R * rho * T.
53// P in pascals (N/m^2), rho is kg/m^3, T in kelvin.
54const float R = 287.058f;
55
56// Specific heat ratio for air, at "low" temperatures.
57const float GAMMA = 1.4f;
58
59void Atmosphere::setStandard(float altitude)
60{
61 _density = getStdDensity(altitude);
62 _pressure = getStdPressure(altitude);
63 _temperature = getStdTemperature(altitude);
64}
65
66float Atmosphere::getStdTemperature(float alt)
67{
68 return getRecord(alt, TEMPERATURE);
69}
70
71float Atmosphere::getStdPressure(float alt)
72{
73 return getRecord(alt, PRESSURE);
74}
75
76float Atmosphere::getStdDensity(float alt)
77{
78 return getRecord(alt, DENSITY);
79}
80
81float Atmosphere::calcVEAS(float spd, float pressure, float temp, float density)
82{
83 static float rho0 = getStdDensity(0);
84 float densityRatio = density / rho0;
85 return spd * Math::sqrt(densityRatio);
86}
87
88float Atmosphere::calcVCAS(float spd, float pressure, float temp)
89{
90 // Stolen shamelessly from JSBSim. Constants that appear:
91 // 2/5 == gamma-1
92 // 5/12 == 1/(gamma+1)
93 // 4/5 == 2*(gamma-1)
94 // 14/5 == 2*gamma
95 // 28/5 == 4*gamma
96 // 144/25 == (gamma+1)^2
97
98 float m2 = calcMach(spd, temp);
99 m2 = m2*m2; // mach^2
100
101 float cp; // pressure coefficient
102 if(m2 < 1) {
103 // (1+(mach^2)/5)^(gamma/(gamma-1))
104 cp = Math::pow(1+0.2*m2, 3.5);
105 } else {
106 float tmp0 = ((144.0f/25.0f) * m2) / (28.0f/5.0f*m2 - 4.0f/5.0f);
107 float tmp1 = ((14.0f/5.0f) * m2 - (2.0f/5.0f)) * (5.0f/12.0f);
108 cp = Math::pow(tmp0, 3.5) * tmp1;
109 }
110
111 // Conditions at sea level
112 float p0 = getStdPressure(0);
113 float rho0 = getStdDensity(0);
114
115 float tmp = Math::pow((pressure/p0)*(cp-1) + 1, (2/7.));
116 return Math::sqrt((7*p0/rho0)*(tmp-1));
117}
118
119float Atmosphere::calcStdDensity(float pressure, float temp)
120{
121 return pressure / (R * temp);
122}
123
124float Atmosphere::calcMach(float spd, float temp)
125{
126 return spd / Math::sqrt(GAMMA * R * temp);
127}
128
129float Atmosphere::machFromSpeed(float spd)
130{
131 return spd / Math::sqrt(GAMMA * R * _temperature);
132}
133
134float Atmosphere::speedFromMach(float mach, float temp)
135{
136 return mach * Math::sqrt(GAMMA * R * temp);
137}
138
139float Atmosphere::speedFromMach(float mach)
140{
141 return speedFromMach(mach, _temperature);
142}
143
144float Atmosphere::speedFromVCAS(float vcas, float pressure, float temp)
145{
146 // FIXME: does not account for supersonic
147 float p0 = getStdPressure(0);
148 float rho0 = getStdDensity(0);
149
150 float tmp = (vcas*vcas)/(7*p0/rho0) + 1;
151 float cp = ((Math::pow(tmp,(7/2.))-1)/(pressure/p0)) + 1;
152
153 float m2 = (Math::pow(cp,(1/3.5))-1)/0.2;
154 float vtas= speedFromMach(Math::sqrt(m2), temp);
155 return vtas;
156}
157
158float Atmosphere::speedFromVCAS(float vcas)
159{
160 return speedFromVCAS(vcas, _pressure, _temperature);
161}
162
163void Atmosphere::calcStaticAir(float p0, float t0, float d0, float v,
164 float* pOut, float* tOut, float* dOut)
165{
166 const static float C0 = ((GAMMA-1)/(2*R*GAMMA));
167 const static float C1 = 1/(GAMMA-1);
168
169 *tOut = t0 + (v*v) * C0;
170 *dOut = d0 * Math::pow(*tOut / t0, C1);
171 *pOut = (*dOut) * R * (*tOut);
172}
173
174void Atmosphere::calcStaticAir(float v, float* pOut, float* tOut, float* dOut)
175{
176 return calcStaticAir(_pressure, _temperature, _density, v, pOut, tOut, dOut);
177}
178
179
180float Atmosphere::getRecord(float alt, Column recNum)
181{
182 int hi = maxTableIndex();
183 int lo = 0;
184
185 // safety valve, clamp to the edges of the table
186 if(alt < data[0][ALTITUDE]) {
187 hi = 1;
188 }
189 else if(alt > data[hi][ALTITUDE]) {
190 lo = hi-1;
191 }
192
193 // binary search
194 while(1) {
195 if(hi-lo == 1) break;
196 int mid = (hi+lo)>>1;
197 if(alt < data[mid][0]) hi = mid;
198 else lo = mid;
199 }
200
201 // interpolate
202 float frac = (alt - data[lo][ALTITUDE])/(data[hi][ALTITUDE] - data[lo][ALTITUDE]);
203 float a = data[lo][recNum];
204 float b = data[hi][recNum];
205 return a + frac * (b-a);
206}
207
208int Atmosphere::maxTableIndex() {
209 return (sizeof(data) / (numColumns * sizeof(float))) - 1;
210}
211
212}; // namespace yasim
double altitude
Definition ADA.cxx:46
const float GAMMA
const float R