JSBSim Flight Dynamics Model 1.2.4 (07 Feb 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGAtmosphere.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGAtmosphere.cpp
4 Author: Jon Berndt, Tony Peden
5 Date started: 6/2011
6 Purpose: Models an atmosphere interface class
7 Called by: FGFDMExec
8
9 ------------- Copyright (C) 2011 Jon S. Berndt (jon@jsbsim.org) -------------
10
11 This program is free software; you can redistribute it and/or modify it under
12 the terms of the GNU Lesser General Public License as published by the Free
13 Software Foundation; either version 2 of the License, or (at your option) any
14 later version.
15
16 This program is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19 details.
20
21 You should have received a copy of the GNU Lesser General Public License along
22 with this program; if not, write to the Free Software Foundation, Inc., 59
23 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24
25 Further information about the GNU Lesser General Public License can also be
26 found on the world wide web at http://www.gnu.org.
27
28FUNCTIONAL DESCRIPTION
29--------------------------------------------------------------------------------
30This models a base atmosphere class to serve as a common interface to any
31derived atmosphere models.
32
33HISTORY
34--------------------------------------------------------------------------------
356/18/2011 Started Jon S. Berndt
36
37%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38COMMENTS, REFERENCES, and NOTES
39%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
40
41%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
42INCLUDES
43%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
44
45#include "FGFDMExec.h"
46#include "FGAtmosphere.h"
47
48using namespace std;
49
50namespace JSBSim {
51
52/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53CLASS IMPLEMENTATION
54%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55
57 : FGModel(fdmex),
58 StdDaySLsoundspeed(sqrt(SHRatio*Reng0*StdDaySLtemperature))
59{
60 Name = "FGAtmosphere";
61
62 bind();
63 SGPropertyNode* root = PropertyManager->GetNode();
64 atmosphere_node = root->getNode("atmosphere");
65
66 assert(atmosphere_node);
67 Debug(0);
68}
69
70//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71
73{
74 Debug(1);
75}
76
77//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
79bool FGAtmosphere::InitModel(void)
80{
81 if (!FGModel::InitModel()) return false;
82
83 SLtemperature = Temperature = StdDaySLtemperature;
84 SLpressure = Pressure = StdDaySLpressure;
85 SLdensity = Density = Pressure/(Reng*Temperature);
86 SLsoundspeed = Soundspeed = StdDaySLsoundspeed;
87 Calculate(0.0);
88
89 return true;
90}
91
92//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93
94bool FGAtmosphere::Run(bool Holding)
95{
96 if (FGModel::Run(Holding)) return true;
97 if (Holding) return false;
98
99 Calculate(in.altitudeASL);
100
101 Debug(2);
102 return false;
103}
104
105//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106// Using pressure in Outer Space between stars in the Milky Way.
107
108double FGAtmosphere::ValidatePressure(double p, const string& msg, bool quiet) const
109{
110 const double MinPressure = ConvertToPSF(1E-15, ePascals);
111 if (p < MinPressure) {
112 if (!quiet) {
113 cerr << msg << " " << p << " is too low." << endl
114 << msg << " is capped to " << MinPressure << endl;
115 }
116 return MinPressure;
117 }
118 return p;
119}
120
121//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
122 // Make sure that the ambient temperature never drops to zero.
123 // According to Wikipedia, 1K is the temperature at the coolest natural place
124 // currently (2023) known in the Universe: the Boomerang Nebula
125
126double FGAtmosphere::ValidateTemperature(double t, const string& msg, bool quiet) const
127{
128 // Minimum known temperature in the universe currently
129 constexpr double minUniverseTemperature = KelvinToRankine(1.0);
130
131 if (t < minUniverseTemperature) {
132 if (!quiet) {
133 cerr << msg << " " << t << " is too low." << endl
134 << msg << " is capped to " << minUniverseTemperature << endl;
135 }
136 return minUniverseTemperature;
137 }
138 return t;
139}
140
141//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142
143void FGAtmosphere::Calculate(double altitude)
144{
145 double t =0.0;
146 double p = 0.0;
147
148 if (!override_node) override_node = atmosphere_node->getNode("override");
149
150 // Temperature and pressure
151 if (override_node) {
152 if (!override_temperature_node)
153 override_temperature_node = override_node->getNode("temperature");
154
155 if (override_temperature_node)
156 t = override_temperature_node->getDoubleValue();
157 else
158 t = GetTemperature(altitude);
159
160 if (!override_pressure_node)
161 override_pressure_node = override_node->getNode("pressure");
162
163 if (override_pressure_node)
164 p = override_pressure_node->getDoubleValue();
165 else
166 p = GetPressure(altitude);
167 } else {
168 t = GetTemperature(altitude);
169 p = GetPressure(altitude);
171
172 Temperature = ValidateTemperature(t, "", true);
173 Pressure = ValidatePressure(p, "", true);
174
175 // Density
176 if (override_node) {
177 if (!override_density_node)
178 override_density_node = override_node->getNode("density");
179
180 if (override_density_node)
181 Density = override_density_node->getDoubleValue();
182 else
183 Density = Pressure/(Reng*Temperature);
184 }
185 else
186 Density = Pressure/(Reng*Temperature);
187
188 Soundspeed = sqrt(SHRatio*Reng*Temperature);
189 PressureAltitude = CalculatePressureAltitude(Pressure, altitude);
190 DensityAltitude = CalculateDensityAltitude(Density, altitude);
191
192 Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
193 KinematicViscosity = Viscosity / Density;
194}
195
196//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197
198void FGAtmosphere::SetPressureSL(ePressure unit, double pressure)
199{
200 double press = ConvertToPSF(pressure, unit);
201
202 SLpressure = ValidatePressure(press, "Sea Level pressure");
203 SLdensity = GetDensity(0.0);
204}
205
206//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207// Get the modeled density at a specified altitude
208
209double FGAtmosphere::GetDensity(double altitude) const
210{
211 return GetPressure(altitude)/(Reng * GetTemperature(altitude));
212}
213//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
214// Get the sound speed at a specified altitude
215
216double FGAtmosphere::GetSoundSpeed(double altitude) const
217{
218 return sqrt(SHRatio * Reng * GetTemperature(altitude));
219}
220
221//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
222// This function sets the sea level temperature.
223// Internally, the Rankine scale is used for calculations, so any temperature
224// supplied must be converted to that unit.
225
227{
228 double temp = ConvertToRankine(t, unit);
229
230 SLtemperature = ValidateTemperature(temp, "Sea Level temperature");
231 SLdensity = GetDensity(0.0);
232 SLsoundspeed = GetSoundSpeed(0.0);
233}
234
235//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
236
238{
239 double targetTemp=0; // in degrees Rankine
240
241 switch(unit) {
242 case eFahrenheit:
243 targetTemp = t + 459.67;
244 break;
245 case eCelsius:
246 targetTemp = (t + 273.15) * 1.8;
247 break;
248 case eRankine:
249 targetTemp = t;
250 break;
251 case eKelvin:
252 targetTemp = t*1.8;
253 break;
254 default:
255 throw BaseException("Undefined temperature unit given");
256 }
257
258 return targetTemp;
259}
260
261//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
262
264{
265 double targetTemp=0;
266
267 switch(unit) {
268 case eFahrenheit:
269 targetTemp = t - 459.67;
270 break;
271 case eCelsius:
272 targetTemp = t/1.8 - 273.15;
273 break;
274 case eRankine:
275 targetTemp = t;
276 break;
277 case eKelvin:
278 targetTemp = t/1.8;
279 break;
280 default:
281 throw BaseException("Undefined temperature unit given");
282 }
283
284 return targetTemp;
285}
286
287//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288
289double FGAtmosphere::ConvertToPSF(double p, ePressure unit) const
290{
291 double targetPressure=0; // Pressure in PSF
292
293 switch(unit) {
294 case ePSF:
295 targetPressure = p;
296 break;
297 case eMillibars:
298 targetPressure = p*2.08854342;
299 break;
300 case ePascals:
301 targetPressure = p*0.0208854342;
302 break;
303 case eInchesHg:
304 targetPressure = p*70.7180803;
305 break;
306 default:
307 throw BaseException("Undefined pressure unit given");
308 }
309
310 return targetPressure;
311}
312
313//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
314
315double FGAtmosphere::ConvertFromPSF(double p, ePressure unit) const
316{
317 double targetPressure=0; // Pressure
318
319 switch(unit) {
320 case ePSF:
321 targetPressure = p;
322 break;
323 case eMillibars:
324 targetPressure = p/2.08854342;
325 break;
326 case ePascals:
327 targetPressure = p/0.0208854342;
328 break;
329 case eInchesHg:
330 targetPressure = p/70.7180803;
331 break;
332 default:
333 throw BaseException("Undefined pressure unit given");
334 }
335
336 return targetPressure;
337}
338
339//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340
341void FGAtmosphere::bind(void)
342{
343 PropertyManager->Tie("atmosphere/T-R", this, &FGAtmosphere::GetTemperature);
344 PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, &FGAtmosphere::GetDensity);
345 PropertyManager->Tie("atmosphere/P-psf", this, &FGAtmosphere::GetPressure);
346 PropertyManager->Tie("atmosphere/a-fps", this, &FGAtmosphere::GetSoundSpeed);
347 PropertyManager->Tie("atmosphere/T-sl-R", this, &FGAtmosphere::GetTemperatureSL);
348 PropertyManager->Tie("atmosphere/rho-sl-slugs_ft3", this, &FGAtmosphere::GetDensitySL);
349 PropertyManager->Tie("atmosphere/a-sl-fps", this, &FGAtmosphere::GetSoundSpeedSL);
350 PropertyManager->Tie("atmosphere/theta", this, &FGAtmosphere::GetTemperatureRatio);
351 PropertyManager->Tie("atmosphere/sigma", this, &FGAtmosphere::GetDensityRatio);
352 PropertyManager->Tie("atmosphere/delta", this, &FGAtmosphere::GetPressureRatio);
353 PropertyManager->Tie("atmosphere/a-ratio", this, &FGAtmosphere::GetSoundSpeedRatio);
354 PropertyManager->Tie("atmosphere/density-altitude", this, &FGAtmosphere::GetDensityAltitude);
355 PropertyManager->Tie("atmosphere/pressure-altitude", this, &FGAtmosphere::GetPressureAltitude);
356}
357
358//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
359// The bitmasked value choices are as follows:
360// unset: In this case (the default) JSBSim would only print
361// out the normally expected messages, essentially echoing
362// the config files as they are read. If the environment
363// variable is not set, debug_lvl is set to 1 internally
364// 0: This requests JSBSim not to output any messages
365// whatsoever.
366// 1: This value explicity requests the normal JSBSim
367// startup messages
368// 2: This value asks for a message to be printed out when
369// a class is instantiated
370// 4: When this value is set, a message is displayed when a
371// FGModel object executes its Run() method
372// 8: When this value is set, various runtime state variables
373// are printed out periodically
374// 16: When set various parameters are sanity checked and
375// a message is printed out when they go out of bounds
376
377void FGAtmosphere::Debug(int from)
378{
379 if (debug_lvl <= 0) return;
380
381 if (debug_lvl & 1) { // Standard console startup message output
382 if (from == 0) { // Constructor
383 }
384 }
385 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
386 if (from == 0) std::cout << "Instantiated: FGAtmosphere" << std::endl;
387 if (from == 1) std::cout << "Destroyed: FGAtmosphere" << std::endl;
388 }
389 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
390 }
391 if (debug_lvl & 8 ) { // Runtime state variables
392 }
393 if (debug_lvl & 16) { // Sanity checking
394 }
395 if (debug_lvl & 128) { //
396 }
397 if (debug_lvl & 64) {
398 if (from == 0) { // Constructor
399 }
400 }
401}
402
403} // namespace JSBSim
virtual double GetSoundSpeedRatio(void) const
Returns the ratio of at-altitude sound speed over the sea level value.
virtual double GetPressureRatio(void) const
Returns the ratio of at-altitude pressure over the sea level value.
double ConvertToRankine(double t, eTemperature unit) const
Converts to Rankine from one of several unit systems.
virtual double GetTemperatureRatio() const
Returns the ratio of the at-current-altitude temperature as modeled over the sea level value.
virtual double CalculatePressureAltitude(double pressure, double geometricAlt)
Calculates the pressure altitude given any temperature or pressure bias.
virtual void Calculate(double altitude)
Calculate the atmosphere for the given altitude.
double ConvertFromPSF(double t, ePressure unit=ePSF) const
Converts from PSF (pounds per square foot) to one of several unit systems.
virtual double GetPressure(void) const
Returns the pressure in psf.
virtual double GetSoundSpeedSL(void) const
Returns the sea level speed of sound in ft/sec.
eTemperature
Enums for specifying temperature units.
double ConvertFromRankine(double t, eTemperature unit) const
Converts from Rankine to one of several unit systems.
double ValidatePressure(double p, const std::string &msg, bool quiet=false) const
Check that the pressure is within plausible boundaries.
bool Run(bool Holding) override
Runs the atmosphere forces model; called by the Executive.
double ValidateTemperature(double t, const std::string &msg, bool quiet=false) const
Check that the temperature is within plausible boundaries.
double ConvertToPSF(double t, ePressure unit=ePSF) const
Converts to PSF (pounds per square foot) from one of several unit systems.
virtual double CalculateDensityAltitude(double density, double geometricAlt)
Calculates the density altitude given any temperature or pressure bias.
virtual double GetSoundSpeed(void) const
Returns the speed of sound in ft/sec.
virtual ~FGAtmosphere()
Destructor.
virtual double GetDensitySL(void) const
Returns the sea level density in slugs/ft^3.
ePressure
Enums for specifying pressure units.
virtual double GetTemperatureSL() const
Returns the actual, modeled sea level temperature in degrees Rankine.
virtual void SetPressureSL(ePressure unit, double pressure)
Sets the sea level pressure for modeling.
virtual void SetTemperatureSL(double t, eTemperature unit=eFahrenheit)
Sets the Sea Level temperature.
virtual double GetDensityRatio(void) const
Returns the ratio of at-altitude density over the sea level value.
FGAtmosphere(FGFDMExec *)
Constructor.
virtual double GetDensity(void) const
Returns the density in slugs/ft^3.
virtual double GetTemperature() const
Returns the actual, modeled temperature at the current altitude in degrees Rankine.
Encapsulates the JSBSim simulation executive.
Definition FGFDMExec.h:184
static constexpr double KelvinToRankine(double kelvin)
Converts from degrees Kelvin to degrees Rankine.
Definition FGJSBBase.h:206
Base class for all scheduled JSBSim models.
Definition FGModel.h:70
virtual bool Run(bool Holding)
Runs the model; called by the Executive.
Definition FGModel.cpp:89
A node in a property tree.
Definition props.hxx:754
SGPropertyNode * getNode(const char *relative_path, bool create=false)
Get a pointer to another node by relative path.