51#include "FGStandardAtmosphere.h"
52#include "input_output/FGLog.h"
63 :
FGAtmosphere(fdmex), StdSLpressure(StdDaySLpressure), TemperatureBias(0.0),
64 TemperatureDeltaGradient(0.0), VaporMassFraction(0.0),
65 SaturatedVaporPressure(StdDaySLpressure), StdAtmosTemperatureTable(9),
66 MaxVaporMassFraction(10)
68 Name =
"FGStandardAtmosphere";
90 StdAtmosTemperatureTable << 0.0000 << 518.67
91 << 36089.2388 << 389.97
92 << 65616.7979 << 389.97
93 << 104986.8766 << 411.57
94 << 154199.4751 << 487.17
95 << 167322.8346 << 487.17
96 << 232939.6325 << 386.37
97 << 278385.8268 << 336.5028
98 << 298556.4304 << 336.5028;
109 MaxVaporMassFraction << 0.0000 << 35000.
110 << 3280.8399 << 31000.
111 << 6561.6798 << 28000.
112 << 13123.3596 << 22000.
113 << 19685.0394 << 8900.
114 << 26246.7192 << 4700.
115 << 32808.3990 << 1300.
116 << 39370.0787 << 230.
118 << 52493.4383 << 38.;
120 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
124 StdLapseRates = LapseRates;
129 GradientFadeoutAltitude = StdAtmosTemperatureTable(numRows, 0);
132 PressureBreakpoints.resize(numRows);
134 StdPressureBreakpoints = PressureBreakpoints;
155bool FGStandardAtmosphere::InitModel(
void)
161 GradientFadeoutAltitude = StdAtmosTemperatureTable(StdAtmosTemperatureTable.GetNumRows(), 0);
163 TemperatureDeltaGradient = 0.0;
164 TemperatureBias = 0.0;
165 LapseRates = StdLapseRates;
167 PressureBreakpoints = StdPressureBreakpoints;
169 SLpressure = StdSLpressure;
171 SLdensity = StdSLdensity;
172 SLsoundspeed = StdSLsoundspeed;
203 double BaseAlt = StdAtmosTemperatureTable(1,0);
204 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
207 for (b=0; b < numRows-2; ++b) {
208 double testAlt = StdAtmosTemperatureTable(b+2,0);
209 if (GeoPotAlt < testAlt)
215 double deltaH = GeoPotAlt - BaseAlt;
216 double Lmb = LapseRates[b];
219 double Exp =
g0 / (Rdry*Lmb);
220 double factor = Tmb/(Tmb + Lmb*deltaH);
221 return PressureBreakpoints[b]*pow(factor, Exp);
223 return PressureBreakpoints[b]*exp(-
g0*deltaH/(Rdry*Tmb));
240 SLsoundspeed = sqrt(SHRatio*Reng*SLtemperature);
254 if (GeoPotAlt >= 0.0) {
255 T = StdAtmosTemperatureTable.
GetValue(GeoPotAlt);
257 if (GeoPotAlt <= GradientFadeoutAltitude)
258 T -= TemperatureDeltaGradient * GeoPotAlt;
263 T = StdAtmosTemperatureTable.
GetValue(0.0) + GeoPotAlt*LapseRates[0];
266 T += TemperatureBias;
268 if (GeoPotAlt <= GradientFadeoutAltitude)
269 T += TemperatureDeltaGradient * GradientFadeoutAltitude;
281 if (GeoPotAlt >= 0.0)
282 return StdAtmosTemperatureTable.
GetValue(GeoPotAlt);
284 return StdAtmosTemperatureTable.
GetValue(0.0) + GeoPotAlt*LapseRates[0];
298 double BaseAlt = StdAtmosTemperatureTable(1,0);
299 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
302 for (b=0; b < numRows-2; ++b) {
303 double testAlt = StdAtmosTemperatureTable(b+2,0);
304 if (GeoPotAlt < testAlt)
310 double deltaH = GeoPotAlt - BaseAlt;
311 double Lmb = LapseRates[b];
314 double Exp =
g0 / (Rdry*Lmb);
315 double factor = Tmb/(Tmb + Lmb*deltaH);
316 return StdPressureBreakpoints[b]*pow(factor, Exp);
318 return StdPressureBreakpoints[b]*exp(-
g0*deltaH/(Rdry*Tmb));
337 if (GeoPotAlt <= GradientFadeoutAltitude)
338 bias -= TemperatureDeltaGradient * (GradientFadeoutAltitude - GeoPotAlt);
354 const double minStdAtmosphereTemp = StdAtmosTemperatureTable.GetMinValue();
359 if (unit == eCelsius || unit == eKelvin)
365 if (minStdAtmosphereTemp + TemperatureBias < minUniverseTemperature) {
366 double minBias = minUniverseTemperature - minStdAtmosphereTemp;
368 log <<
"The temperature bias " << TemperatureBias <<
" R is too low. "
369 <<
"It could result in temperatures below the absolute zero." << endl
370 <<
"Temperature bias is therefore capped to " << minBias << endl;
371 TemperatureBias = minBias;
411 const double minStdAtmosphereTemp = StdAtmosTemperatureTable.GetMinValue();
414 if (unit == eCelsius || unit == eKelvin)
417 if (deltemp <= minDeltaTemperature) {
419 log <<
"The temperature delta " << deltemp <<
" R is too low. "
420 <<
"It could result in temperatures below the absolute zero." << endl
421 <<
"Temperature delta is therefore capped to " << minDeltaTemperature << endl;
422 deltemp = minDeltaTemperature;
438 out <<
"Altitude (ft) Temp (F) Pressure (psf) Density (sl/ft3)" << std::endl;
439 out <<
"------------- -------- -------------- ----------------" << std::endl;
440 for (
int i=0; i<280000; i+=1000) {
442 out << std::setw(12) << std::setprecision(2) << i
443 <<
" " << std::setw(9) << std::setprecision(2) << Temperature - 459.67
444 <<
" " << std::setw(13) << std::setprecision(4) << Pressure
445 <<
" " << std::setw(18) << std::setprecision(8) << Density
462 unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
465 for (
unsigned int bh=0; bh < numRows-1; bh++)
467 double t0 = StdAtmosTemperatureTable(bh+1,1);
468 double t1 = StdAtmosTemperatureTable(bh+2,1);
469 double h0 = StdAtmosTemperatureTable(bh+1,0);
470 double h1 = StdAtmosTemperatureTable(bh+2,0);
471 LapseRates.push_back((t1 - t0) / (h1 - h0) - TemperatureDeltaGradient);
479 PressureBreakpoints[0] = SLpress;
481 for (
unsigned int b=0; b<PressureBreakpoints.size()-1; b++) {
482 double BaseTemp = StdAtmosTemperatureTable(b+1,1);
483 double BaseAlt = StdAtmosTemperatureTable(b+1,0);
484 double UpperAlt = StdAtmosTemperatureTable(b+2,0);
485 double deltaH = UpperAlt - BaseAlt;
486 double Tmb = BaseTemp
488 + (GradientFadeoutAltitude - BaseAlt)*TemperatureDeltaGradient;
489 if (LapseRates[b] != 0.00) {
490 double Lmb = LapseRates[b];
491 double Exp =
g0 / (Rdry*Lmb);
492 double factor = Tmb/(Tmb + Lmb*deltaH);
493 PressureBreakpoints[b+1] = PressureBreakpoints[b]*pow(factor, Exp);
495 PressureBreakpoints[b+1] = PressureBreakpoints[b]*exp(-
g0*deltaH/(Rdry*Tmb));
504 TemperatureBias = TemperatureDeltaGradient = 0.0;
516 SLpressure = StdSLpressure;
525 StdDensityBreakpoints.clear();
526 for (
unsigned int i = 0; i < StdPressureBreakpoints.size(); i++)
527 StdDensityBreakpoints.push_back(StdPressureBreakpoints[i] / (Rdry * StdAtmosTemperatureTable(i + 1, 1)));
536 for (; b < StdDensityBreakpoints.size() - 2; b++) {
537 if (density >= StdDensityBreakpoints[b + 1])
542 double Tmb = StdAtmosTemperatureTable(b + 1, 1);
543 double Hb = StdAtmosTemperatureTable(b + 1, 0);
544 double Lmb = StdLapseRates[b];
545 double pb = StdDensityBreakpoints[b];
547 double density_altitude = 0.0;
551 double Exp = -1.0 / (1.0 +
g0/(Rdry*Lmb));
552 density_altitude = Hb + (Tmb / Lmb) * (pow(density / pb, Exp) - 1);
554 double Factor = -Rdry*Tmb /
g0;
555 density_altitude = Hb + Factor * log(density / pb);
567 for (; b < StdPressureBreakpoints.size() - 2; b++) {
568 if (pressure >= StdPressureBreakpoints[b + 1])
573 double Tmb = StdAtmosTemperatureTable(b + 1, 1);
574 double Hb = StdAtmosTemperatureTable(b + 1, 0);
575 double Lmb = StdLapseRates[b];
576 double Pb = StdPressureBreakpoints[b];
578 double pressure_altitude = 0.0;
582 double Exp = -Rdry*Lmb /
g0;
583 pressure_altitude = Hb + (Tmb / Lmb) * (pow(pressure / Pb, Exp) - 1);
586 double Factor = -Rdry*Tmb /
g0;
587 pressure_altitude = Hb + Factor * log(pressure / Pb);
598 return a*exp(b*temperature_degC/(c+temperature_degC));
605 if (SaturatedVaporPressure < Pressure) {
606 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
607 if (VaporPressure > SaturatedVaporPressure)
608 VaporMassFraction = Rdry * SaturatedVaporPressure / (Rwater * (Pressure - SaturatedVaporPressure));
612 double maxFraction = 1E-6*MaxVaporMassFraction.
GetValue(GeoPotAlt);
614 if ((VaporMassFraction > maxFraction) || (VaporMassFraction < 0.0))
615 VaporMassFraction = maxFraction;
618 Reng = (VaporMassFraction*Rwater + Rdry)/(1.0 + VaporMassFraction);
628 if (dewPoint_R <= minDewPoint) {
630 log <<
"The dew point temperature " << dewPoint_R <<
" is lower than "
631 << minDewPoint <<
" R." << endl
632 <<
"Dew point is therefore capped to " << minDewPoint << endl;
633 dewPoint_R = minDewPoint;
640 if (finalizedDewPoint < dewPoint_R) {
642 log <<
"Dew point temperature has been capped to " << finalizedDewPoint
651 double dewpoint_degC;
652 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
654 if (VaporPressure <= 0.0)
657 double x = log(VaporPressure/
a);
658 dewpoint_degC = c*x / (b - x);
670 if (VaporPressure < 0.0) {
672 log <<
"The vapor pressure cannot be negative." << endl
673 <<
"Vapor pressure is set to 0.0" << endl;
675 }
else if (VaporPressure >= Pressure) {
677 log <<
"The vapor pressure " << VaporPressure
678 <<
" PSF is higher than the ambient pressure." << endl
679 <<
"Vapor pressure is therefore capped to " << Pressure-1.0 << endl;
680 VaporPressure = Pressure - 1.0;
682 VaporMassFraction = Rdry * VaporPressure / (Rwater * (Pressure - VaporPressure));
690 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
705 double VaporPressure = Pressure*VaporMassFraction / (VaporMassFraction+Rdry/Rwater);
706 return 100.0*VaporPressure/SaturatedVaporPressure;
715 log <<
"The relative humidity cannot be negative." << endl
716 <<
"Relative humidity is set to 0%" << endl;
718 }
else if (RH > 100.0) {
720 log <<
"The relative humidity cannot be higher than 100%." << endl
721 <<
"Relative humidity is set to 100%" << endl;
725 double VaporPressure = 0.01*RH*SaturatedVaporPressure;
733 return VaporMassFraction*1E6;
741 VaporMassFraction = frac*1E-6;
744 if (fabs(VaporMassFraction*1E6-frac)>1E-2) {
746 log <<
"The vapor mass fraction " << frac <<
" has been capped to "
747 << VaporMassFraction*1E6 <<
"PPM." << endl;
753void FGStandardAtmosphere::bind(
void)
755 PropertyManager->Tie(
"atmosphere/delta-T",
this, eRankine,
758 PropertyManager->Tie(
"atmosphere/SL-graded-delta-T",
this, eRankine,
762 &FGStandardAtmosphere::GetPressureSL,
764 PropertyManager->Tie(
"atmosphere/dew-point-R",
this, eRankine,
767 PropertyManager->Tie(
"atmosphere/vapor-pressure-psf",
this, ePSF,
770 PropertyManager->Tie(
"atmosphere/saturated-vapor-pressure-psf",
this, ePSF,
772 PropertyManager->Tie(
"atmosphere/RH",
this,
775 PropertyManager->Tie(
"atmosphere/vapor-fraction-ppm",
this,
799void FGStandardAtmosphere::Debug(
int from)
801 if (debug_lvl <= 0)
return;
807 if (debug_lvl & 2 ) {
808 FGLogging log(LogLevel::DEBUG);
809 if (from == 0) log <<
"Instantiated: FGStandardAtmosphere" << std::endl;
810 if (from == 1) log <<
"Destroyed: FGStandardAtmosphere" << std::endl;
812 if (debug_lvl & 4 ) {
814 if (debug_lvl & 8 ) {
816 if (debug_lvl & 16) {
818 if (debug_lvl & 128) {
820 if (debug_lvl & 64) {
Models an empty, abstract base atmosphere class.
double ConvertToRankine(double t, eTemperature unit) const
Converts to Rankine from one of several unit systems.
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.
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 ConvertToPSF(double t, ePressure unit=ePSF) const
Converts to PSF (pounds per square foot) from one of several unit systems.
ePressure
Enums for specifying pressure units.
static constexpr double g0
Sea-level acceleration of gravity - ft/s^2.
virtual double GetTemperature() const
Returns the actual, modeled temperature at the current altitude in degrees Rankine.
Encapsulates the JSBSim simulation executive.
static constexpr double CelsiusToRankine(double celsius)
Converts from degrees Celsius to degrees Rankine.
static constexpr double RankineToCelsius(double rankine)
Converts from degrees Rankine to degrees Celsius.
static constexpr double KelvinToRankine(double kelvin)
Converts from degrees Kelvin to degrees Rankine.
void CalculateStdDensityBreakpoints()
Calculate the atmospheric density breakpoints at the altitudes in the standard temperature table.
double GeometricAltitude(double geopotalt) const
Convert a geopotential altitude to a geometric altitude.
void SetVaporPressure(ePressure unit, double Pv)
Sets the partial pressure of water vapor.
virtual double GetStdPressure(double altitude) const
Returns the standard pressure at the specified altitude.
static constexpr double a
Sonntag constants based on ref [2].
double CalculateDensityAltitude(double density, double geometricAlt) override
Calculates the density altitude given any temperature or pressure bias.
double GetRelativeHumidity(void) const
Returns the relative humidity in percent.
void CalculateLapseRates()
Recalculate the lapse rate vectors when the temperature profile is altered in a way that would change...
void SetRelativeHumidity(double RH)
Sets the relative humidity.
virtual double GetTemperatureBias(eTemperature to) const
Returns the temperature bias over the sea level value in degrees Rankine.
virtual double GetStdTemperature(double altitude) const
Returns the standard temperature in degrees Rankine at a specified altitude.
void Calculate(double altitude) override
Calculate the atmosphere for the given altitude.
virtual double GetTemperatureDeltaGradient(eTemperature to) const
Returns the temperature gradient to be applied on top of the standard temperature gradient.
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...
void CalculatePressureBreakpoints(double SLpress)
Calculate (or recalculate) the atmospheric pressure breakpoints at the altitudes in the standard temp...
virtual void SetTemperatureGradedDelta(double t, double h, eTemperature unit=eFahrenheit)
Sets the temperature delta value at the supplied altitude/elevation above sea level,...
void CalculateSLDensity(void)
Calculate the SL density.
virtual void ResetSLPressure()
Resets the sea level to the Standard sea level pressure, and recalculates dependent parameters so tha...
double GetVaporPressure(ePressure to) const
Returns the partial pressure of water vapor.
double GeopotentialAltitude(double geometalt) const
Convert a geometric altitude to a geopotential altitude.
virtual void PrintStandardAtmosphereTable()
Prints the U.S. Standard Atmosphere table.
virtual double GetStdDensity(double altitude) const
Returns the standard density at a specified altitude.
FGStandardAtmosphere(FGFDMExec *)
Constructor.
virtual void SetTemperatureBias(eTemperature unit, double t)
Sets the temperature bias to be added to the standard temperature at all altitudes.
double GetSaturatedVaporPressure(ePressure to) const
Returns the saturated pressure of water vapor.
double StdSLtemperature
Standard sea level conditions.
virtual ~FGStandardAtmosphere()
Destructor.
void SetPressureSL(ePressure unit, double pressure) override
Sets the sea level pressure for modeling an off-standard pressure profile.
void SetTemperatureSL(double t, eTemperature unit=eFahrenheit) override
Sets the Sea Level temperature, if it is to be different than the standard.
double CalculateVaporPressure(double temperature)
Calculate the pressure of water vapor with the Magnus formula.
void CalculateSLSoundSpeedAndDensity(void)
Calculate the SL density and sound speed.
virtual void SetSLTemperatureGradedDelta(eTemperature unit, double t)
Sets a Sea Level temperature delta that is ramped out by 86 km.
void SetVaporMassFractionPPM(double frac)
Sets the vapor mass per million of dry air mass units.
void SetDewPoint(eTemperature unit, double dewpoint)
Sets the dew point.
void ValidateVaporMassFraction(double geometricAlt)
Validate the value of the vapor mass fraction.
virtual void ResetSLTemperature()
This function resets the model to apply no bias or delta gradient to the temperature.
double GetVaporMassFractionPPM(void) const
Returns the vapor mass per million of dry air mass units (ppm).
double CalculatePressureAltitude(double pressure, double geometricAlt) override
Calculates the pressure altitude given any temperature or pressure bias.
double GetDewPoint(eTemperature to) const
Returns the dew point.
double GetValue(void) const
Get the current table value.
Main namespace for the JSBSim Flight Dynamics Model.