FlightGear next
FGStandardAtmosphere.cpp
Go to the documentation of this file.
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGStandardAtmosphere.cpp
4 Author: Jon Berndt, Tony Peden
5 Date started: 5/2011
6 Purpose: Models the 1976 U.S. Standard Atmosphere
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--------------------------------------------------------------------------------
30
31
32HISTORY
33--------------------------------------------------------------------------------
34
35%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
36COMMENTS, REFERENCES, and NOTES
37%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38[1] Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
39 1989, ISBN 0-07-001641-0
40[2] Sonntag, D. "Important New Values of the Physical Constants of 1986,
41 Vapour Pressure Formulations based on the IST-90 and Psychrometer
42 Formulae", Z. Meteorol., 70 (5), pp. 340-344, 1990
43
44%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
45INCLUDES
46%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
47
48#include <iomanip>
49
50#include "FGFDMExec.h"
52
53namespace JSBSim {
54
55/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56CLASS IMPLEMENTATION
57%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
58
64{
65 Name = "FGStandardAtmosphere";
66
67 // This is the U.S. Standard Atmosphere table for temperature in degrees
68 // Rankine, based on geometric altitude. The table values are often given
69 // in literature relative to geopotential altitude.
70 //
71 // GeoMet Alt Temp GeoPot Alt GeoMet Alt
72 // (ft) (deg R) (km) (km)
73 // -------- -------- ---------- ----------
74 //StdAtmosTemperatureTable << 0.00 << 518.67 // 0.000 0.000
75 // << 36151.80 << 389.97 // 11.000 11.019
76 // << 65823.90 << 389.97 // 20.000 20.063
77 // << 105518.06 << 411.60 // 32.000 32.162
78 // << 155348.07 << 487.20 // 47.000 47.350
79 // << 168676.12 << 487.20 // 51.000 51.413
80 // << 235570.77 << 386.40 // 71.000 71.802
81 // << 282152.08 << 336.50 // 84.852 86.000
82 // << 298556.40 << 336.50; // 91.000 - First layer in high altitude regime
83
84 // GeoPot Alt Temp GeoPot Alt GeoMet Alt
85 // (ft) (deg R) (km) (km)
86 // ----------- -------- ---------- ----------
87 StdAtmosTemperatureTable << 0.0000 << 518.67 // 0.000 0.000
88 << 36089.2388 << 389.97 // 11.000 11.019
89 << 65616.7979 << 389.97 // 20.000 20.063
90 << 104986.8766 << 411.57 // 32.000 32.162
91 << 154199.4751 << 487.17 // 47.000 47.350
92 << 167322.8346 << 487.17 // 51.000 51.413
93 << 232939.6325 << 386.37 // 71.000 71.802
94 << 278385.8268 << 336.5028 // 84.852 86.000
95 << 298556.4304 << 336.5028; // 91.000 - First layer in high altitude regime
96
97
98 // This is the maximum water vapor mass fraction in ppm (parts per million) of
99 // dry air measured in the atmosphere according to the ISA 1976 document.
100 // Values at altitude below 8 km are record high. All other values are 1%
101 // high.
102
103 // Geopot Alt Water Geopot Alt
104 // (ft) (ppm) (km)
105 // ---------- ----- ----------
106 MaxVaporMassFraction << 0.0000 << 35000. // 0.0000 - Record high
107 << 3280.8399 << 31000. // 1.0000
108 << 6561.6798 << 28000. // 2.0000
109 << 13123.3596 << 22000. // 4.0000
110 << 19685.0394 << 8900. // 6.0000
111 << 26246.7192 << 4700. // 8.0000 - Record high
112 << 32808.3990 << 1300. // 10.0000 - 1% high
113 << 39370.0787 << 230. // 12.0000
114 << 45931.7585 << 48. // 14.0000
115 << 52493.4383 << 38.; // 16.0000 - 1% high
116
117 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
118
119 // Initialize the standard atmosphere lapse rates.
122
123 // Assume the altitude to fade out the gradient at is at the highest
124 // altitude in the table. Above that, other functions are used to
125 // calculate temperature.
127
128 // Initialize the standard atmosphere pressure break points.
129 PressureBreakpoints.resize(numRows);
132
135
138
139 bind();
140 Debug(0);
141}
142
143//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
144
149
150//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
151
153{
154
155 // Assume the altitude to fade out the gradient at is at the highest
156 // altitude in the table. Above that, other functions are used to
157 // calculate temperature.
159
161 TemperatureBias = 0.0;
163
165
170
171 Calculate(0.0);
172
173// PrintStandardAtmosphereTable();
174
175 return true;
176}
177//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
178
185
186//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187// Get the actual pressure as modeled at a specified altitude
188// These calculations are from equations 33a and 33b in the U.S. Standard
189// Atmosphere document referenced in the documentation for this code.
190
192{
193 double GeoPotAlt = GeopotentialAltitude(altitude);
194
195 // Iterate through the altitudes to find the current Base Altitude
196 // in the table. That is, if the current altitude (the argument passed in)
197 // is 20000 ft, then the base altitude from the table is 0.0. If the
198 // passed-in altitude is 40000 ft, the base altitude is 36089.2388 ft (and
199 // the index "b" is 2 - the second entry in the table).
200 double BaseAlt = StdAtmosTemperatureTable(1,0);
201 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
202 unsigned int b;
203
204 for (b=0; b < numRows-2; ++b) {
205 double testAlt = StdAtmosTemperatureTable(b+2,0);
206 if (GeoPotAlt < testAlt)
207 break;
208 BaseAlt = testAlt;
209 }
210
211 double Tmb = GetTemperature(GeometricAltitude(BaseAlt));
212 double deltaH = GeoPotAlt - BaseAlt;
213 double Lmb = LapseRates[b];
214
215 if (Lmb != 0.0) {
216 double Exp = g0 / (Rdry*Lmb);
217 double factor = Tmb/(Tmb + Lmb*deltaH);
218 return PressureBreakpoints[b]*pow(factor, Exp);
219 } else
220 return PressureBreakpoints[b]*exp(-g0*deltaH/(Rdry*Tmb));
221}
222
223//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
224
231
232//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233
239
240//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
241// Get the modeled temperature at a specified altitude, including any bias or gradient
242// effects.
243
245{
246 double GeoPotAlt = GeopotentialAltitude(altitude);
247
248 double T;
249
250 if (GeoPotAlt >= 0.0) {
251 T = StdAtmosTemperatureTable.GetValue(GeoPotAlt);
252
253 if (GeoPotAlt <= GradientFadeoutAltitude)
254 T -= TemperatureDeltaGradient * GeoPotAlt;
255 }
256 else {
257 // We don't need to add TemperatureDeltaGradient*GeoPotAlt here because
258 // the lapse rate vector already accounts for the temperature gradient.
259 T = StdAtmosTemperatureTable.GetValue(0.0) + GeoPotAlt*LapseRates[0];
260 }
261
262 T += TemperatureBias;
263
264 if (GeoPotAlt <= GradientFadeoutAltitude)
266
267 return T;
268}
269
270//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271// Retrieves the standard temperature at a particular altitude.
272
274{
275 double GeoPotAlt = GeopotentialAltitude(altitude);
276
277 if (GeoPotAlt >= 0.0)
278 return StdAtmosTemperatureTable.GetValue(GeoPotAlt);
279 else
280 return StdAtmosTemperatureTable.GetValue(0.0) + GeoPotAlt*LapseRates[0];
281}
282
283//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
284
286{
287 double GeoPotAlt = GeopotentialAltitude(altitude);
288
289 // Iterate through the altitudes to find the current Base Altitude
290 // in the table. That is, if the current altitude (the argument passed in)
291 // is 20000 ft, then the base altitude from the table is 0.0. If the
292 // passed-in altitude is 40000 ft, the base altitude is 36089.2388 ft (and
293 // the index "b" is 2 - the second entry in the table).
294 double BaseAlt = StdAtmosTemperatureTable(1,0);
295 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
296 unsigned int b;
297
298 for (b=0; b < numRows-2; ++b) {
299 double testAlt = StdAtmosTemperatureTable(b+2,0);
300 if (GeoPotAlt < testAlt)
301 break;
302 BaseAlt = testAlt;
303 }
304
305 double Tmb = GetStdTemperature(GeometricAltitude(BaseAlt));
306 double deltaH = GeoPotAlt - BaseAlt;
307 double Lmb = LapseRates[b];
308
309 if (Lmb != 0.0) {
310 double Exp = g0 / (Rdry*Lmb);
311 double factor = Tmb/(Tmb + Lmb*deltaH);
312 return StdPressureBreakpoints[b]*pow(factor, Exp);
313 } else
314 return StdPressureBreakpoints[b]*exp(-g0*deltaH/(Rdry*Tmb));
315}
316
317//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
318// Get the standard density at a specified altitude
319
324
325//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326
328{
329 double targetTemp = ConvertToRankine(t, unit);
330 double GeoPotAlt = GeopotentialAltitude(h);
331
332 TemperatureBias = targetTemp - GetStdTemperature(h);
333
334 if (GeoPotAlt <= GradientFadeoutAltitude)
336
338
341}
342
343//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
344
346{
347 if (unit == eCelsius || unit == eKelvin)
348 t *= 1.80; // If temp delta "t" is given in metric, scale up to English
349
350 TemperatureBias = t;
352
355}
356
357//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
358// This function calculates a bias based on the supplied temperature for sea
359// level. The bias is applied to the entire temperature profile at all altitudes.
360// Internally, the Rankine scale is used for calculations, so any temperature
361// supplied must be converted to that unit.
362
364{
365 SetTemperature(t, 0.0, unit);
366}
367
368//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
369// Sets a Sea Level temperature delta that is ramped out by 86 km (282,152 ft).
370
372{
373 SetTemperatureGradedDelta(deltemp, 0.0, unit);
374}
375
376//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377// Sets a temperature delta at the supplied altitude that is ramped out by 86 km.
378// After this calculation is performed, the lapse rates and pressure breakpoints
379// must be recalculated. Since we are calculating a delta here and not an actual
380// temperature, we only need to be concerned about a scale factor and not
381// the actual temperature itself.
382
384{
385 if (unit == eCelsius || unit == eKelvin)
386 deltemp *= 1.80; // If temp delta "t" is given in metric, scale up to English
387
391
394}
395
396//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
397
399{
400 std::cout << "Altitude (ft) Temp (F) Pressure (psf) Density (sl/ft3)" << std::endl;
401 std::cout << "------------- -------- -------------- ----------------" << std::endl;
402 for (int i=0; i<280000; i+=1000) {
403 Calculate(i);
404 std::cout << std::setw(12) << std::setprecision(2) << i
405 << " " << std::setw(9) << std::setprecision(2) << Temperature - 459.67
406 << " " << std::setw(13) << std::setprecision(4) << Pressure
407 << " " << std::setw(18) << std::setprecision(8) << Density
408 << std::endl;
409 }
410
411 // Re-execute the Run() method to reset the calculated values
412 Run(false);
413}
414
415//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416// This function calculates (or recalculates) the lapse rate over an altitude range
417// where the "bh" in this case refers to the index of the base height in the
418// StdAtmosTemperatureTable table. This function should be called anytime the
419// temperature table is altered, such as when a gradient is applied across the
420// temperature table for a range of altitudes.
421
423{
424 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
425 LapseRates.clear();
426
427 for (unsigned int bh=0; bh < numRows-1; bh++)
428 {
429 double t0 = StdAtmosTemperatureTable(bh+1,1);
430 double t1 = StdAtmosTemperatureTable(bh+2,1);
431 double h0 = StdAtmosTemperatureTable(bh+1,0);
432 double h1 = StdAtmosTemperatureTable(bh+2,0);
433 LapseRates.push_back((t1 - t0) / (h1 - h0) - TemperatureDeltaGradient);
434 }
435}
436
437//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438
440{
441 PressureBreakpoints[0] = SLpress;
442
443 for (unsigned int b=0; b<PressureBreakpoints.size()-1; b++) {
444 double BaseTemp = StdAtmosTemperatureTable(b+1,1);
445 double BaseAlt = StdAtmosTemperatureTable(b+1,0);
446 double UpperAlt = StdAtmosTemperatureTable(b+2,0);
447 double deltaH = UpperAlt - BaseAlt;
448 double Tmb = BaseTemp
451 if (LapseRates[b] != 0.00) {
452 double Lmb = LapseRates[b];
453 double Exp = g0 / (Rdry*Lmb);
454 double factor = Tmb/(Tmb + Lmb*deltaH);
455 PressureBreakpoints[b+1] = PressureBreakpoints[b]*pow(factor, Exp);
456 } else {
457 PressureBreakpoints[b+1] = PressureBreakpoints[b]*exp(-g0*deltaH/(Rdry*Tmb));
458 }
459 }
460}
461
462//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
463
473
474//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475
482
483//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484
491
492//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493
494double FGStandardAtmosphere::CalculateDensityAltitude(double density, double geometricAlt)
495{
496 // Work out which layer we're dealing with
497 unsigned int b = 0;
498 for (; b < StdDensityBreakpoints.size() - 2; b++) {
499 if (density >= StdDensityBreakpoints[b + 1])
500 break;
501 }
502
503 // Get layer properties
504 double Tmb = StdAtmosTemperatureTable(b + 1, 1);
505 double Hb = StdAtmosTemperatureTable(b + 1, 0);
506 double Lmb = StdLapseRates[b];
507 double pb = StdDensityBreakpoints[b];
508
509 double density_altitude = 0.0;
510
511 // https://en.wikipedia.org/wiki/Barometric_formula for density solved for H
512 if (Lmb != 0.0) {
513 double Exp = -1.0 / (1.0 + g0/(Rdry*Lmb));
514 density_altitude = Hb + (Tmb / Lmb) * (pow(density / pb, Exp) - 1);
515 } else {
516 double Factor = -Rdry*Tmb / g0;
517 density_altitude = Hb + Factor * log(density / pb);
518 }
519
520 return GeometricAltitude(density_altitude);
521}
522
523//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
524
525double FGStandardAtmosphere::CalculatePressureAltitude(double pressure, double geometricAlt)
526{
527 // Work out which layer we're dealing with
528 unsigned int b = 0;
529 for (; b < StdPressureBreakpoints.size() - 2; b++) {
530 if (pressure >= StdPressureBreakpoints[b + 1])
531 break;
532 }
533
534 // Get layer properties
535 double Tmb = StdAtmosTemperatureTable(b + 1, 1);
536 double Hb = StdAtmosTemperatureTable(b + 1, 0);
537 double Lmb = StdLapseRates[b];
538 double Pb = StdPressureBreakpoints[b];
539
540 double pressure_altitude = 0.0;
541
542 if (Lmb != 0.00) {
543 // Equation 33(a) from ISA document solved for H
544 double Exp = -Rdry*Lmb / g0;
545 pressure_altitude = Hb + (Tmb / Lmb) * (pow(pressure / Pb, Exp) - 1);
546 } else {
547 // Equation 33(b) from ISA document solved for H
548 double Factor = -Rdry*Tmb / g0;
549 pressure_altitude = Hb + Factor * log(pressure / Pb);
550 }
551
552 return GeometricAltitude(pressure_altitude);
553}
554
555//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
556
558{
559 double temperature_degC = RankineToCelsius(temperature);
560 return a*exp(b*temperature_degC/(c+temperature_degC));
561}
562
563//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
564
566{
568 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
569 if (VaporPressure > SaturatedVaporPressure)
571 }
572
573 double GeoPotAlt = GeopotentialAltitude(h);
574 double maxFraction = 1E-6*MaxVaporMassFraction.GetValue(GeoPotAlt);
575
576 if ((VaporMassFraction > maxFraction) || (VaporMassFraction < 0.0))
577 VaporMassFraction = maxFraction;
578
579 // Update the gas constant factor
581}
582
583//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
584
586{
588 double VaporPressure = CalculateVaporPressure(ConvertToRankine(dewpoint, unit));
589 VaporMassFraction = Rdry * VaporPressure / (Rwater * (Pressure - VaporPressure));
591}
592
593//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594
596{
597 double dewpoint_degC;
598 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
599
600 if (VaporPressure <= 0.0)
601 dewpoint_degC = -c;
602 else {
603 double x = log(VaporPressure/a);
604 dewpoint_degC = c*x / (b - x);
605 }
606
607 return ConvertFromRankine(1.8*(dewpoint_degC + 273.15), to);
608}
609
610//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611
613{
615 double VaporPressure = ConvertToPSF(Pa, unit);
616 VaporMassFraction = Rdry * VaporPressure / (Rwater * (Pressure - VaporPressure));
618}
619
620//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
621
623{
624 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
625 return ConvertFromPSF(VaporPressure, to);
626}
627
628//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629
634
635//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
636
638{
639 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
640 return 100.0*VaporPressure/SaturatedVaporPressure;
641}
642
643//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
644
646{
648 double VaporPressure = 0.01*RH*SaturatedVaporPressure;
649 VaporMassFraction = Rdry * VaporPressure / (Rwater * (Pressure - VaporPressure));
651}
652
653//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
654
656{
657 return VaporMassFraction*1E6;
658}
659
660//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
661
668
669//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670
672{
673 typedef double (FGStandardAtmosphere::*PMFi)(int) const;
674 typedef void (FGStandardAtmosphere::*PMF)(int, double);
675 PropertyManager->Tie("atmosphere/delta-T", this, eRankine,
678 PropertyManager->Tie("atmosphere/SL-graded-delta-T", this, eRankine,
681 PropertyManager->Tie("atmosphere/P-sl-psf", this, ePSF,
684 PropertyManager->Tie("atmosphere/dew-point-R", this, eRankine,
687 PropertyManager->Tie("atmosphere/vapor-pressure-psf", this, ePSF,
690 PropertyManager->Tie("atmosphere/saturated-vapor-pressure-psf", this, ePSF,
692 PropertyManager->Tie("atmosphere/RH", this,
695 PropertyManager->Tie("atmosphere/vapor-fraction-ppm", this,
698}
699
700//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
701// The bitmasked value choices are as follows:
702// unset: In this case (the default) JSBSim would only print
703// out the normally expected messages, essentially echoing
704// the config files as they are read. If the environment
705// variable is not set, debug_lvl is set to 1 internally
706// 0: This requests JSBSim not to output any messages
707// whatsoever.
708// 1: This value explicity requests the normal JSBSim
709// startup messages
710// 2: This value asks for a message to be printed out when
711// a class is instantiated
712// 4: When this value is set, a message is displayed when a
713// FGModel object executes its Run() method
714// 8: When this value is set, various runtime state variables
715// are printed out periodically
716// 16: When set various parameters are sanity checked and
717// a message is printed out when they go out of bounds
718
720{
721 if (debug_lvl <= 0) return;
722
723 if (debug_lvl & 1) { // Standard console startup message output
724 if (from == 0) { // Constructor
725 }
726 }
727 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
728 if (from == 0) std::cout << "Instantiated: FGStandardAtmosphere" << std::endl;
729 if (from == 1) std::cout << "Destroyed: FGStandardAtmosphere" << std::endl;
730 }
731 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
732 }
733 if (debug_lvl & 8 ) { // Runtime state variables
734 }
735 if (debug_lvl & 16) { // Sanity checking
736 }
737 if (debug_lvl & 128) { //
738 }
739 if (debug_lvl & 64) {
740 if (from == 0) { // Constructor
741 }
742 }
743}
744
745} // namespace JSBSim
double altitude
Definition ADA.cxx:46
#define i(x)
bool Run(bool Holding) override
Runs the atmosphere forces model; called by the Executive.
eTemperature
Enums for specifying temperature units.
double ConvertToPSF(double t, ePressure unit=ePSF) const
Converts to PSF (pounds per square foot) from one of several unit systems.
virtual double GetPressureSL(ePressure to=ePSF) const
FGAtmosphere(FGFDMExec *)
Constructor.
double ConvertFromRankine(double t, eTemperature unit) const
Converts from Rankine to one of several unit systems.
static double Reng
Specific gas constant for air - ft*lbf/slug/R.
virtual double GetTemperature() const
Returns the actual, modeled temperature at the current altitude in degrees Rankine.
double ConvertToRankine(double t, eTemperature unit) const
Converts to Rankine from one of several unit systems.
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.
static constexpr double StdDaySLpressure
virtual void Calculate(double altitude)
Calculate the atmosphere for the given altitude.
ePressure
Enums for specifying pressure units.
static constexpr double SHRatio
static constexpr double g0
Sea-level acceleration of gravity - ft/s^2.
static constexpr double RankineToCelsius(double rankine)
Converts from degrees Rankine to degrees Celsius.
Definition FGJSBBase.h:209
FGPropertyManager * PropertyManager
Definition FGModel.h:117
std::string Name
Definition FGModel.h:103
virtual void SetSLTemperatureGradedDelta(eTemperature unit, double t)
Sets a Sea Level temperature delta that is ramped out by 86 km.
double CalculateDensityAltitude(double density, double geometricAlt) override
Calculates the density altitude given any temperature or pressure bias.
virtual double GetStdTemperature(double altitude) const
Returns the standard temperature in degrees Rankine at a specified altitude.
void SetDewPoint(eTemperature unit, double dewpoint)
Sets the dew point.
double GetVaporPressure(ePressure to) const
Returns the partial pressure of water vapor.
virtual double GetTemperatureDeltaGradient(eTemperature to)
Returns the temperature gradient to be applied on top of the standard temperature gradient.
std::vector< double > StdDensityBreakpoints
virtual void PrintStandardAtmosphereTable()
Prints the U.S. Standard Atmosphere table.
void SetVaporPressure(ePressure unit, double Pv)
Sets the partial pressure of water vapor.
double CalculatePressureAltitude(double pressure, double geometricAlt) override
Calculates the pressure altitude given any temperature or pressure bias.
std::vector< double > PressureBreakpoints
void CalculateLapseRates()
Recalculate the lapse rate vectors when the temperature profile is altered in a way that would change...
void CalculatePressureBreakpoints(double SLpress)
Calculate (or recalculate) the atmospheric pressure breakpoints at the altitudes in the standard temp...
void SetTemperatureSL(double t, eTemperature unit=eFahrenheit) override
Sets the Sea Level temperature, if it is to be different than the standard.
virtual void ResetSLTemperature()
This function resets the model to apply no bias or delta gradient to the temperature.
static constexpr double a
Sonntag constants based on ref [2].
virtual void SetTemperatureBias(eTemperature unit, double t)
Sets the temperature bias to be added to the standard temperature at all altitudes.
void ValidateVaporMassFraction(double geometricAlt)
Validate the value of the vapor mass fraction.
FGStandardAtmosphere(FGFDMExec *)
Constructor.
void CalculateStdDensityBreakpoints()
Calculate the atmospheric density breakpoints at the altitudes in the standard temperature table.
std::vector< double > StdLapseRates
virtual double GetTemperatureBias(eTemperature to) const
Returns the temperature bias over the sea level value in degrees Rankine.
std::vector< double > StdPressureBreakpoints
void Calculate(double altitude) override
Calculate the atmosphere for the given altitude.
virtual void SetTemperatureGradedDelta(double t, double h, eTemperature unit=eFahrenheit)
Sets the temperature delta value at the supplied altitude/elevation above sea level,...
virtual double GetStdPressure(double altitude) const
Returns the standard pressure at the specified altitude.
double GetSaturatedVaporPressure(ePressure to) const
Returns the saturated pressure of water vapor.
double GeometricAltitude(double geopotalt) const
Convert a geopotential altitude to a geometric altitude.
double GetRelativeHumidity(void) const
Returns the relative humidity in percent.
double GeopotentialAltitude(double geometalt) const
Convert a geometric altitude to a geopotential altitude.
virtual void ResetSLPressure()
Resets the sea level to the Standard sea level pressure, and recalculates dependent parameters so tha...
void SetPressureSL(ePressure unit, double pressure) override
Sets the sea level pressure for modeling an off-standard pressure profile.
void CalculateSLDensity(void)
Calculate the SL density.
void CalculateSLSoundSpeedAndDensity(void)
Calculate the SL density and sound speed.
void SetRelativeHumidity(double RH)
Sets the relative humidity.
double GetVaporMassFractionPPM(void) const
Returns the vapor mass per million of dry air mass units (ppm).
double StdSLtemperature
Standard sea level conditions.
void SetTemperature(double t, double h, eTemperature unit=eFahrenheit) override
Sets the temperature at the supplied altitude, if it is to be different than the standard temperature...
virtual double GetStdDensity(double altitude) const
Returns the standard density at a specified altitude.
double GetDewPoint(eTemperature to) const
Returns the dew point.
virtual ~FGStandardAtmosphere()
Destructor.
double CalculateVaporPressure(double temperature)
Calculate the pressure of water vapor with the Magnus formula.
void SetVaporMassFractionPPM(double frac)
Sets the vapor mass per million of dry air mass units.
short debug_lvl