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