JSBSim Flight Dynamics Model 1.3.0 (09 Apr 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#include "input_output/FGLog.h"
48
49using namespace std;
50
51namespace JSBSim {
52
53/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54CLASS IMPLEMENTATION
55%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
56
58 : FGModel(fdmex),
59 StdDaySLsoundspeed(sqrt(SHRatio*Reng0*StdDaySLtemperature))
60{
61 Name = "FGAtmosphere";
62
63 bind();
64 SGPropertyNode* root = PropertyManager->GetNode();
65 atmosphere_node = root->getNode("atmosphere");
66
67 assert(atmosphere_node);
68 Debug(0);
69}
70
71//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
72
74{
75 Debug(1);
76}
77
78//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
79
80bool FGAtmosphere::InitModel(void)
81{
82 if (!FGModel::InitModel()) return false;
83
84 SLtemperature = Temperature = StdDaySLtemperature;
85 SLpressure = Pressure = StdDaySLpressure;
86 SLdensity = Density = Pressure/(Reng*Temperature);
87 SLsoundspeed = Soundspeed = StdDaySLsoundspeed;
88 Calculate(0.0);
89
90 return true;
91}
92
93//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94
95bool FGAtmosphere::Run(bool Holding)
96{
97 if (FGModel::Run(Holding)) return true;
98 if (Holding) return false;
99
100 Calculate(in.altitudeASL);
101
102 Debug(2);
103 return false;
104}
105
106//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
107// Using pressure in Outer Space between stars in the Milky Way.
108
109double FGAtmosphere::ValidatePressure(double p, const string& msg, bool quiet) const
110{
111 const double MinPressure = ConvertToPSF(1E-15, ePascals);
112 if (p < MinPressure) {
113 if (!quiet) {
114 FGLogging log(LogLevel::WARN);
115 log << msg << " " << p << " is too low." << endl
116 << msg << " will be capped to " << MinPressure << endl;
117 }
118 return MinPressure;
119 }
120 return p;
121}
122
123//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
124 // Make sure that the ambient temperature never drops to zero.
125 // According to Wikipedia, 1K is the temperature at the coolest natural place
126 // currently (2023) known in the Universe: the Boomerang Nebula
127
128double FGAtmosphere::ValidateTemperature(double t, const string& msg, bool quiet) const
129{
130 // Minimum known temperature in the universe currently
131 constexpr double minUniverseTemperature = KelvinToRankine(1.0);
132
133 if (t < minUniverseTemperature) {
134 if (!quiet) {
135 FGLogging log(LogLevel::WARN);
136 log << msg << " " << t << " is too low." << endl
137 << msg << " will be capped to " << minUniverseTemperature << endl;
138 }
139 return minUniverseTemperature;
140 }
141 return t;
142}
143
144//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145
146void FGAtmosphere::Calculate(double altitude)
147{
148 double t =0.0;
149 double p = 0.0;
150
151 if (!override_node) override_node = atmosphere_node->getNode("override");
152
153 // Temperature and pressure
154 if (override_node) {
155 if (!override_temperature_node)
156 override_temperature_node = override_node->getNode("temperature");
157
158 if (override_temperature_node)
159 t = override_temperature_node->getDoubleValue();
160 else
161 t = GetTemperature(altitude);
162
163 if (!override_pressure_node)
164 override_pressure_node = override_node->getNode("pressure");
165
166 if (override_pressure_node)
167 p = override_pressure_node->getDoubleValue();
168 else
169 p = GetPressure(altitude);
170 } else {
171 t = GetTemperature(altitude);
172 p = GetPressure(altitude);
173 }
174
175 Temperature = ValidateTemperature(t, "", true);
176 Pressure = ValidatePressure(p, "", true);
177
178 // Density
179 if (override_node) {
180 if (!override_density_node)
181 override_density_node = override_node->getNode("density");
182
183 if (override_density_node)
184 Density = override_density_node->getDoubleValue();
185 else
186 Density = Pressure/(Reng*Temperature);
187 }
188 else
189 Density = Pressure/(Reng*Temperature);
190
191 Soundspeed = sqrt(SHRatio*Reng*Temperature);
192 PressureAltitude = CalculatePressureAltitude(Pressure, altitude);
193 DensityAltitude = CalculateDensityAltitude(Density, altitude);
194
195 Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
196 KinematicViscosity = Viscosity / Density;
197}
198
199//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
200
201void FGAtmosphere::SetPressureSL(ePressure unit, double pressure)
202{
203 double press = ConvertToPSF(pressure, unit);
204
205 SLpressure = ValidatePressure(press, "Sea Level pressure");
206 SLdensity = GetDensity(0.0);
207}
208
209//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210// Get the modeled density at a specified altitude
211
212double FGAtmosphere::GetDensity(double altitude) const
213{
214 return GetPressure(altitude)/(Reng * GetTemperature(altitude));
215}
216//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
217// Get the sound speed at a specified altitude
218
219double FGAtmosphere::GetSoundSpeed(double altitude) const
220{
221 return sqrt(SHRatio * Reng * GetTemperature(altitude));
222}
223
224//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
225// This function sets the sea level temperature.
226// Internally, the Rankine scale is used for calculations, so any temperature
227// supplied must be converted to that unit.
228
230{
231 double temp = ConvertToRankine(t, unit);
232
233 SLtemperature = ValidateTemperature(temp, "Sea Level temperature");
234 SLdensity = GetDensity(0.0);
235 SLsoundspeed = GetSoundSpeed(0.0);
236}
237
238//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
239
241{
242 double targetTemp=0; // in degrees Rankine
243
244 switch(unit) {
245 case eFahrenheit:
246 targetTemp = t + 459.67;
247 break;
248 case eCelsius:
249 targetTemp = (t + 273.15) * 1.8;
250 break;
251 case eRankine:
252 targetTemp = t;
253 break;
254 case eKelvin:
255 targetTemp = t*1.8;
256 break;
257 default:
258 throw BaseException("Undefined temperature unit given");
259 }
260
261 return targetTemp;
262}
263
264//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
265
267{
268 double targetTemp=0;
269
270 switch(unit) {
271 case eFahrenheit:
272 targetTemp = t - 459.67;
273 break;
274 case eCelsius:
275 targetTemp = t/1.8 - 273.15;
276 break;
277 case eRankine:
278 targetTemp = t;
279 break;
280 case eKelvin:
281 targetTemp = t/1.8;
282 break;
283 default:
284 throw BaseException("Undefined temperature unit given");
285 }
286
287 return targetTemp;
288}
289
290//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291
292double FGAtmosphere::ConvertToPSF(double p, ePressure unit) const
293{
294 double targetPressure=0; // Pressure in PSF
295
296 switch(unit) {
297 case ePSF:
298 targetPressure = p;
299 break;
300 case eMillibars:
301 targetPressure = p*2.08854342;
302 break;
303 case ePascals:
304 targetPressure = p*0.0208854342;
305 break;
306 case eInchesHg:
307 targetPressure = p*70.7180803;
308 break;
309 default:
310 throw BaseException("Undefined pressure unit given");
311 }
312
313 return targetPressure;
314}
315
316//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317
318double FGAtmosphere::ConvertFromPSF(double p, ePressure unit) const
319{
320 double targetPressure=0; // Pressure
321
322 switch(unit) {
323 case ePSF:
324 targetPressure = p;
325 break;
326 case eMillibars:
327 targetPressure = p/2.08854342;
328 break;
329 case ePascals:
330 targetPressure = p/0.0208854342;
331 break;
332 case eInchesHg:
333 targetPressure = p/70.7180803;
334 break;
335 default:
336 throw BaseException("Undefined pressure unit given");
337 }
338
339 return targetPressure;
340}
341
342//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
343
344void FGAtmosphere::bind(void)
345{
346 PropertyManager->Tie("atmosphere/T-R", this, &FGAtmosphere::GetTemperature);
347 PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, &FGAtmosphere::GetDensity);
348 PropertyManager->Tie("atmosphere/P-psf", this, &FGAtmosphere::GetPressure);
349 PropertyManager->Tie("atmosphere/a-fps", this, &FGAtmosphere::GetSoundSpeed);
350 PropertyManager->Tie("atmosphere/T-sl-R", this, &FGAtmosphere::GetTemperatureSL);
351 PropertyManager->Tie("atmosphere/rho-sl-slugs_ft3", this, &FGAtmosphere::GetDensitySL);
352 PropertyManager->Tie("atmosphere/a-sl-fps", this, &FGAtmosphere::GetSoundSpeedSL);
353 PropertyManager->Tie("atmosphere/theta", this, &FGAtmosphere::GetTemperatureRatio);
354 PropertyManager->Tie("atmosphere/sigma", this, &FGAtmosphere::GetDensityRatio);
355 PropertyManager->Tie("atmosphere/delta", this, &FGAtmosphere::GetPressureRatio);
356 PropertyManager->Tie("atmosphere/a-ratio", this, &FGAtmosphere::GetSoundSpeedRatio);
357 PropertyManager->Tie("atmosphere/density-altitude", this, &FGAtmosphere::GetDensityAltitude);
358 PropertyManager->Tie("atmosphere/pressure-altitude", this, &FGAtmosphere::GetPressureAltitude);
359}
360
361//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362// The bitmasked value choices are as follows:
363// unset: In this case (the default) JSBSim would only print
364// out the normally expected messages, essentially echoing
365// the config files as they are read. If the environment
366// variable is not set, debug_lvl is set to 1 internally
367// 0: This requests JSBSim not to output any messages
368// whatsoever.
369// 1: This value explicity requests the normal JSBSim
370// startup messages
371// 2: This value asks for a message to be printed out when
372// a class is instantiated
373// 4: When this value is set, a message is displayed when a
374// FGModel object executes its Run() method
375// 8: When this value is set, various runtime state variables
376// are printed out periodically
377// 16: When set various parameters are sanity checked and
378// a message is printed out when they go out of bounds
379
380void FGAtmosphere::Debug(int from)
381{
382 if (debug_lvl <= 0) return;
383
384 if (debug_lvl & 1) { // Standard console startup message output
385 if (from == 0) { // Constructor
386 }
387 }
388 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
389 FGLogging log(LogLevel::DEBUG);
390 if (from == 0) log << "Instantiated: FGAtmosphere" << std::endl;
391 if (from == 1) log << "Destroyed: FGAtmosphere" << std::endl;
392 }
393 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
394 }
395 if (debug_lvl & 8 ) { // Runtime state variables
396 }
397 if (debug_lvl & 16) { // Sanity checking
398 }
399 if (debug_lvl & 128) { //
400 }
401 if (debug_lvl & 64) {
402 if (from == 0) { // Constructor
403 }
404 }
405}
406
407} // 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:185
static constexpr double KelvinToRankine(double kelvin)
Converts from degrees Kelvin to degrees Rankine.
Definition FGJSBBase.h:207
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:90
A node in a property tree.
Definition props.hxx:747
SGPropertyNode * getNode(const char *relative_path, bool create=false)
Get a pointer to another node by relative path.
Main namespace for the JSBSim Flight Dynamics Model.
Definition FGFDMExec.cpp:71