1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2 
3  Header:       FGStandardAtmosphere.h
4  Author:       Jon Berndt
5  Date started: 5/2011
6 
7  ------------- Copyright (C) 2011  Jon S. Berndt (jon@jsbsim.org) -------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free
11  Software Foundation; either version 2 of the License, or (at your option) any
12  later version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along
20  with this program; if not, write to the Free Software Foundation, Inc., 59
21  Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be
24  found on the world wide web at http://www.gnu.org.
25 
26 HISTORY
27 --------------------------------------------------------------------------------
28 5/2011   JSB   Created
29 
30 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
31 SENTRY
32 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
33 
34 #ifndef FGSTANDARDATMOSPHERE_H
35 #define FGSTANDARDATMOSPHERE_H
36 
37 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
38 INCLUDES
39 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
40 
41 #include <vector>
42 
43 #include "math/FGTable.h"
44 #include "models/FGAtmosphere.h"
45 
46 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
47 FORWARD DECLARATIONS
48 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
49 
50 namespace JSBSim {
51 
52 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 CLASS DOCUMENTATION
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55 
56 /** Models the 1976 U.S. Standard Atmosphere, with the ability to modify the
57     temperature and pressure. A base feature of the model is the temperature
58     profile that is stored as an FGTable object with this data:
59 
60 @code
61 GeoMet Alt    Temp      GeoPot Alt  GeoMet Alt
62    (ft)      (deg R)      (km)        (km)
63  ---------  --------    ----------  ----------
64        0.0    518.67 //    0.000       0.000
65    36151.6    390.0  //   11.000      11.019
66    65823.5    390.0  //   20.000      20.063
67   105518.4    411.6  //   32.000      32.162
68   155347.8    487.2  //   47.000      47.350
69   168677.8    487.2  //   51.000      51.413
70   235570.9    386.4  //   71.000      71.802
71   282152.2    336.5; //   84.852      86.000
72 @endcode
73 
74 The pressure is calculated at lower altitudes through the use of two equations
75 that are presented in the U.S. Standard Atmosphere document (see references).
76 Density, kinematic viscosity, speed of sound, etc., are all calculated based
77 on various constants and temperature and pressure. At higher altitudes (above
78 86 km (282152 ft) a different and more complicated method of calculating
79 pressure is used.
80 
81 The temperature may be modified through the use of several methods. Ultimately,
82 these access methods allow the user to modify the sea level standard
83 temperature, and/or the sea level standard pressure, so that the entire profile
84 will be consistently and accurately calculated.
85 
86   <h2> Properties </h2>
87   @property atmosphere/delta-T
88   @property atmosphere/T-sl-dev-F
89 
90   @author Jon Berndt
91   @see "U.S. Standard Atmosphere, 1976", NASA TM-X-74335
92 */
93 
94 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
95 CLASS DECLARATION
96 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
97 
98 class FGStandardAtmosphere : public FGAtmosphere {
99 public:
100   /// Constructor
101   FGStandardAtmosphere(FGFDMExec*);
102 
103   /// Destructor
104   virtual ~FGStandardAtmosphere();
105 
106   bool InitModel(void) override;
107 
108   //  *************************************************************************
109   /// @name Temperature access functions.
110   /// There are several ways to get the temperature, and several modeled
111   /// temperature values that can be retrieved. The U.S. Standard Atmosphere
112   /// temperature either at a specified altitude, or at sea level can be
113   /// retrieved. These two temperatures do NOT include the effects of any bias
114   /// or delta gradient that may have been supplied by the user. The modeled
115   /// temperature and the modeled temperature at sea level can also be
116   /// retrieved. These two temperatures DO include the effects of an optionally
117   /// user-supplied bias or delta gradient.
118   // @{
119   /// Returns the actual modeled temperature in degrees Rankine at a specified
120   /// altitude.
121   /// @param altitude The altitude above sea level (ASL) in feet.
122   /// @return Modeled temperature in degrees Rankine at the specified altitude.
123   double GetTemperature(double altitude) const override;
124 
125   /// Returns the standard temperature in degrees Rankine at a specified
126   /// altitude.
127   /// @param altitude The altitude in feet above sea level (ASL) to get the
128   ///                 temperature at.
129   /// @return The STANDARD temperature in degrees Rankine at the specified
130   ///         altitude.
131   virtual double GetStdTemperature(double altitude) const;
132 
133   /// Returns the standard sea level temperature in degrees Rankine.
134   /// @return The STANDARD temperature at sea level in degrees Rankine.
GetStdTemperatureSL()135   virtual double GetStdTemperatureSL() const { return StdSLtemperature; }
136 
137   /// Returns the ratio of the standard temperature at the supplied altitude
138   /// over the standard sea level temperature.
GetStdTemperatureRatio(double h)139   virtual double GetStdTemperatureRatio(double h) const { return GetStdTemperature(h)/StdSLtemperature; }
140 
141   /// Returns the temperature bias over the sea level value in degrees Rankine.
GetTemperatureBias(eTemperature to)142   virtual double GetTemperatureBias(eTemperature to) const
143   { if (to == eCelsius || to == eKelvin) return TemperatureBias/1.80; else return TemperatureBias; }
144 
145   /// Returns the temperature gradient to be applied on top of the standard
146   /// temperature gradient.
GetTemperatureDeltaGradient(eTemperature to)147   virtual double GetTemperatureDeltaGradient(eTemperature to)
148   { if (to == eCelsius || to == eKelvin) return TemperatureDeltaGradient/1.80; else return TemperatureDeltaGradient; }
149 
150   /// Sets the Sea Level temperature, if it is to be different than the
151   /// standard.
152   /// This function will calculate a bias - a difference - from the standard
153   /// atmosphere temperature and will apply that bias to the entire
154   /// temperature profile. This is one way to set the temperature bias. Using
155   /// the SetTemperatureBias function will replace the value calculated by
156   /// this function.
157   /// @param t the temperature value in the unit provided.
158   /// @param unit the unit of the temperature.
159   void SetTemperatureSL(double t, eTemperature unit=eFahrenheit) override;
160 
161   /// Sets the temperature at the supplied altitude, if it is to be different
162   /// than the standard temperature.
163   /// This function will calculate a bias - a difference - from the standard
164   /// atmosphere temperature at the supplied altitude and will apply that
165   /// calculated bias to the entire temperature profile. If a graded delta is
166   /// present, that will be included in the calculation - that is, regardless
167   /// of any graded delta present, a temperature bias will be determined so that
168   /// the temperature requested in this function call will be reached.
169   /// @param t The temperature value in the unit provided.
170   /// @param h The altitude in feet above sea level.
171   /// @param unit The unit of the temperature.
172   void SetTemperature(double t, double h, eTemperature unit=eFahrenheit) override;
173 
174   /// Sets the temperature bias to be added to the standard temperature at all
175   /// altitudes.
176   /// This function sets the bias - the difference - from the standard
177   /// atmosphere temperature. This bias applies to the entire
178   /// temperature profile. Another way to set the temperature bias is to use the
179   /// SetSLTemperature function, which replaces the value calculated by
180   /// this function with a calculated bias.
181   /// @param t the temperature value in the unit provided.
182   /// @param unit the unit of the temperature.
183   virtual void SetTemperatureBias(eTemperature unit, double t);
184 
185   /// Sets a Sea Level temperature delta that is ramped out by 86 km.
186   /// The value of the delta is used to calculate a delta gradient that is
187   /// applied to the temperature at all altitudes below 86 km (282152 ft).
188   /// For instance, if a temperature of 20 degrees F is supplied, the delta
189   /// gradient would be 20/282152 - or, about 7.09E-5 degrees/ft. At sea level,
190   /// the full 20 degrees would be added to the standard temperature,
191   /// but that 20 degree delta would be reduced by 7.09E-5 degrees for every
192   /// foot of altitude above sea level, so that by 86 km, there would be no
193   /// further delta added to the standard temperature.
194   /// The graded delta can be used along with the a bias to tailor the
195   /// temperature profile as desired.
196   /// @param t the sea level temperature delta value in the unit provided.
197   /// @param unit the unit of the temperature.
198   virtual void SetSLTemperatureGradedDelta(eTemperature unit, double t);
199 
200   /// Sets the temperature delta value at the supplied altitude/elevation above
201   /// sea level, to be added to the standard temperature and ramped out by
202   /// 86 km.
203   /// This function computes the sea level delta from the standard atmosphere
204   /// temperature at sea level.
205   /// @param t the temperature skew value in the unit provided.
206   /// @param unit the unit of the temperature.
207   virtual void SetTemperatureGradedDelta(double t, double h, eTemperature unit=eFahrenheit);
208 
209   /// This function resets the model to apply no bias or delta gradient to the
210   /// temperature.
211   /// The delta gradient and bias values are reset to 0.0, and the standard
212   /// temperature is used for the entire temperature profile at all altitudes.
213   virtual void ResetSLTemperature();
214   //@}
215 
216   //  *************************************************************************
217   /// @name Pressure access functions.
218   //@{
219   /// Returns the pressure at a specified altitude in psf.
220   double GetPressure(double altitude) const override;
221 
222   /// Returns the standard pressure at the specified altitude.
223   virtual double GetStdPressure(double altitude) const;
224 
225   /** Sets the sea level pressure for modeling an off-standard pressure
226       profile. This could be useful in the case where the pressure at an
227       airfield is known or set for a particular simulation run.
228       @param pressure The pressure in the units specified.
229       @param unit the unit of measure that the specified pressure is
230                        supplied in.*/
231   void SetPressureSL(ePressure unit, double pressure) override;
232 
233   /** Resets the sea level to the Standard sea level pressure, and recalculates
234       dependent parameters so that the pressure calculations are standard. */
235   virtual void ResetSLPressure();
236   //@}
237 
238   //  *************************************************************************
239   /// @name Density access functions.
240   //@{
241   /// Returns the standard density at a specified altitude
242   virtual double GetStdDensity(double altitude) const;
243   //@}
244 
245   //  *************************************************************************
246   ///@name Humidity access functions
247   //@{
248   /** Sets the dew point.
249       @param dewpoint The dew point in the units specified
250       @param unit The unit of measure that the specified dew point is supplied
251                   in. */
252   void SetDewPoint(eTemperature unit, double dewpoint);
253   /** Returns the dew point.
254       @param to The unit of measure that the dew point should be supplied in. */
255   double GetDewPoint(eTemperature to) const;
256   /** Sets the partial pressure of water vapor.
257       @param Pv The vapor pressure in the units specified
258       @param unit The unit of measure that the specified vapor pressure is
259                   supplied in. */
260   void SetVaporPressure(ePressure unit, double Pv);
261   /** Returns the partial pressure of water vapor.
262       @param to The unit of measure that the water vapor should be supplied in.
263   */
264   double GetVaporPressure(ePressure to) const;
265   /** Returns the saturated pressure of water vapor.
266       @param to The unit of measure that the water vapor should be supplied in.
267   */
268   double GetSaturatedVaporPressure(ePressure to) const;
269   /** Sets the relative humidity.
270       @param RH The relative humidity in percent. */
271   void SetRelativeHumidity(double RH);
272   /// Returns the relative humidity in percent.
273   double GetRelativeHumidity(void) const;
274   /** Sets the vapor mass per million of dry air mass units.
275       @param frac The fraction of water in ppm of dry air. */
276   void SetVaporMassFractionPPM(double frac);
277   /// Returns the vapor mass per million of dry air mass units (ppm).
278   double GetVaporMassFractionPPM(void) const;
279   //@}
280 
281   /// Prints the U.S. Standard Atmosphere table.
282   virtual void PrintStandardAtmosphereTable();
283 
284 protected:
285   /// Standard sea level conditions
286   double StdSLtemperature, StdSLdensity, StdSLpressure, StdSLsoundspeed;
287 
288   double TemperatureBias;
289   double TemperatureDeltaGradient;
290   double GradientFadeoutAltitude;
291   double VaporMassFraction;
292   double SaturatedVaporPressure;
293 
294   FGTable StdAtmosTemperatureTable;
295   FGTable MaxVaporMassFraction;
296   std::vector<double> LapseRates;
297   std::vector<double> PressureBreakpoints;
298   std::vector<double> StdPressureBreakpoints;
299   std::vector<double> StdDensityBreakpoints;
300   std::vector<double> StdLapseRates;
301 
302   void Calculate(double altitude) override;
303 
304   /// Recalculate the lapse rate vectors when the temperature profile is altered
305   /// in a way that would change the lapse rates, such as when a gradient is
306   /// applied.
307   /// This function is also called to initialize the lapse rate vector.
308   void CalculateLapseRates();
309 
310   /// Calculate (or recalculate) the atmospheric pressure breakpoints at the
311   /// altitudes in the standard temperature table.
312   void CalculatePressureBreakpoints(double SLpress);
313 
314   /// Calculate the atmospheric density breakpoints at the
315   /// altitudes in the standard temperature table.
316   void CalculateStdDensityBreakpoints();
317 
318   /// Convert a geometric altitude to a geopotential altitude
GeopotentialAltitude(double geometalt)319   double GeopotentialAltitude(double geometalt) const { return (geometalt * EarthRadius) / (EarthRadius + geometalt); }
320 
321   /// Convert a geopotential altitude to a geometric altitude
GeometricAltitude(double geopotalt)322   double GeometricAltitude(double geopotalt) const { return (geopotalt * EarthRadius) / (EarthRadius - geopotalt); }
323 
324   /** Calculates the density altitude given any temperature or pressure bias.
325   Calculated density for the specified geometric altitude given any temperature
326   or pressure biases is passed in.
327   @param density
328   @param geometricAlt
329   @see
330   https://en.wikipedia.org/wiki/Density_altitude
331   https://wahiduddin.net/calc/density_altitude.htm
332   */
333   double CalculateDensityAltitude(double density, double geometricAlt) override;
334 
335   /** Calculates the pressure altitude given any temperature or pressure bias.
336   Calculated density for the specified geometric altitude given any temperature
337   or pressure biases is passed in.
338   @param pressure
339   @param geometricAlt
340   @see
341   https://en.wikipedia.org/wiki/Pressure_altitude
342   */
343   double CalculatePressureAltitude(double pressure, double geometricAlt) override;
344 
345   /// Calculate the pressure of water vapor with the Magnus formula.
346   double CalculateVaporPressure(double temperature);
347 
348   /// Validate the value of the vapor mass fraction
349   void ValidateVaporMassFraction(double geometricAlt);
350 
351   /// Calculate the SL density
CalculateSLDensity(void)352   void CalculateSLDensity(void) { SLdensity = SLpressure / (Reng * SLtemperature); }
353 
354   /// Calculate the SL density and sound speed
355   void CalculateSLSoundSpeedAndDensity(void);
356 
357   void bind(void) override;
358   void Debug(int from) override;
359 
360   /// Earth radius in ft as defined for ISA 1976
361   static constexpr double EarthRadius = 6356766.0 / fttom;
362   /** Sonntag constants based on ref [2]. They are valid for temperatures
363       between -45 degC (-49 degF) and 60 degC (140 degF) with a precision of
364       +/-0.35 degC (+/-0.63 degF) */
365   static constexpr double a = 611.2/psftopa; // psf
366   static constexpr double b = 17.62; // 1/degC
367   static constexpr double c = 243.12; // degC
368   /// Mean molecular weight for water - slug/mol
369   static constexpr double Mwater = 18.016 * kgtoslug / 1000.0;
370   static constexpr double Rdry = Rstar / Mair;
371   static constexpr double Rwater = Rstar / Mwater;
372 };
373 
374 } // namespace JSBSim
375 
376 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
377 #endif
378