1 // environment.cxx -- routines to model the natural environment
3 // Written by David Megginson, started February 2002.
5 // Copyright (C) 2002 David Megginson - david@megginson.com
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 // General Public License for more details.
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
36 #include <simgear/constants.h>
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/math/interpolater.hxx>
40 #include <Main/fg_props.hxx>
41 #include "environment.hxx"
44 FGEnvironment::FGEnvironment()
45 : _temperature_degc_table(new SGInterpTable),
46 _pressure_inhg_table(new SGInterpTable),
48 temperature_sea_level_degc(15),
49 dewpoint_sea_level_degc(5), // guess
50 pressure_sea_level_inhg(29.92),
51 wind_from_heading_deg(0),
53 wind_from_north_fps(0),
54 wind_from_east_fps(0),
60 FGEnvironment::FGEnvironment (const FGEnvironment &env)
61 : _temperature_degc_table(new SGInterpTable),
62 _pressure_inhg_table(new SGInterpTable),
63 elevation_ft(env.elevation_ft),
64 visibility_m(env.visibility_m),
65 temperature_sea_level_degc(env.temperature_sea_level_degc),
66 dewpoint_sea_level_degc(env.dewpoint_sea_level_degc),
67 pressure_sea_level_inhg(env.pressure_sea_level_inhg),
68 wind_from_heading_deg(env.wind_from_heading_deg),
69 wind_speed_kt(env.wind_speed_kt),
70 wind_from_north_fps(env.wind_from_north_fps),
71 wind_from_east_fps(env.wind_from_east_fps),
72 wind_from_down_fps(env.wind_from_down_fps)
77 FGEnvironment::~FGEnvironment()
79 delete _temperature_degc_table;
80 delete _pressure_inhg_table;
85 FGEnvironment::get_visibility_m () const
91 FGEnvironment::get_temperature_sea_level_degc () const
93 return temperature_sea_level_degc;
97 FGEnvironment::get_temperature_degc () const
99 return temperature_degc;
103 FGEnvironment::get_dewpoint_sea_level_degc () const
105 return dewpoint_sea_level_degc;
109 FGEnvironment::get_dewpoint_degc () const
111 return dewpoint_degc;
115 FGEnvironment::get_pressure_sea_level_inhg () const
117 return pressure_sea_level_inhg;
121 FGEnvironment::get_pressure_inhg () const
123 return pressure_inhg;
127 FGEnvironment::get_density_slugft3 () const
129 return density_slugft3;
133 FGEnvironment::get_wind_from_heading_deg () const
135 return wind_from_heading_deg;
139 FGEnvironment::get_wind_speed_kt () const
141 return wind_speed_kt;
145 FGEnvironment::get_wind_from_north_fps () const
147 return wind_from_north_fps;
151 FGEnvironment::get_wind_from_east_fps () const
153 return wind_from_east_fps;
157 FGEnvironment::get_wind_from_down_fps () const
159 return wind_from_down_fps;
163 FGEnvironment::get_elevation_ft () const
169 FGEnvironment::set_visibility_m (double v)
175 FGEnvironment::set_temperature_sea_level_degc (double t)
177 temperature_sea_level_degc = t;
178 _recalc_alt_temperature();
183 FGEnvironment::set_temperature_degc (double t)
185 temperature_degc = t;
186 _recalc_sl_temperature();
191 FGEnvironment::set_dewpoint_sea_level_degc (double t)
193 dewpoint_sea_level_degc = t;
194 _recalc_alt_dewpoint();
199 FGEnvironment::set_dewpoint_degc (double t)
202 _recalc_sl_dewpoint();
207 FGEnvironment::set_pressure_sea_level_inhg (double p)
209 pressure_sea_level_inhg = p;
210 _recalc_alt_pressure();
215 FGEnvironment::set_pressure_inhg (double p)
218 _recalc_sl_pressure();
223 FGEnvironment::set_wind_from_heading_deg (double h)
225 wind_from_heading_deg = h;
230 FGEnvironment::set_wind_speed_kt (double s)
237 FGEnvironment::set_wind_from_north_fps (double n)
239 wind_from_north_fps = n;
244 FGEnvironment::set_wind_from_east_fps (double e)
246 wind_from_east_fps = e;
251 FGEnvironment::set_wind_from_down_fps (double d)
253 wind_from_down_fps = d;
258 FGEnvironment::set_elevation_ft (double e)
261 _recalc_alt_temperature();
262 _recalc_alt_dewpoint();
263 _recalc_alt_pressure();
269 // Copied from YASim Atmosphere.cxx, with m converted to ft, degK
270 // converted to degC, Pa converted to inHG, and kg/m^3 converted to
271 // slug/ft^3; they were then converted to deltas from the sea-level
272 // defaults (approx. 15degC, 29.92inHG, and 0.00237slugs/ft^3).
274 // Original comment from YASim:
276 // Copied from McCormick, who got it from "The ARDC Model Atmosphere"
277 // Note that there's an error in the text in the first entry,
278 // McCormick lists 299.16/101325/1.22500, but those don't agree with
279 // R=287. I chose to correct the temperature to 288.20, since 79F is
280 // pretty hot for a "standard" atmosphere.
282 // Elevation (ft), temperature factor (degK), pressure factor (inHG)
283 static double atmosphere_data[][3] = {
285 2952.76, 0.98, 0.898,
286 5905.51, 0.96, 0.804,
287 8858.27, 0.94, 0.719,
288 11811.02, 0.92, 0.641,
289 14763.78, 0.90, 0.570,
290 17716.54, 0.88, 0.506,
291 20669.29, 0.86, 0.447,
292 23622.05, 0.84, 0.394,
293 26574.80, 0.82, 0.347,
294 29527.56, 0.80, 0.304,
295 32480.31, 0.78, 0.266,
296 35433.07, 0.76, 0.231,
297 38385.83, 0.75, 0.201,
298 41338.58, 0.75, 0.174,
299 44291.34, 0.75, 0.151,
300 47244.09, 0.75, 0.131,
301 50196.85, 0.75, 0.114,
302 53149.61, 0.75, 0.099,
303 56102.36, 0.75, 0.086,
304 59055.12, 0.75, 0.075,
305 62007.87, 0.75, 0.065,
310 FGEnvironment::_setup_tables ()
312 for (int i = 0; atmosphere_data[i][0] != -1; i++) {
313 _temperature_degc_table->addEntry(atmosphere_data[i][0],
314 atmosphere_data[i][1]);
315 _pressure_inhg_table->addEntry(atmosphere_data[i][0],
316 atmosphere_data[i][2]);
321 FGEnvironment::_recalc_hdgspd ()
325 if (wind_from_east_fps == 0) {
326 angle_rad = (wind_from_north_fps >= 0 ? SGD_PI/2 : -SGD_PI/2);
328 angle_rad = atan(wind_from_north_fps/wind_from_east_fps);
330 wind_from_heading_deg = angle_rad * SGD_RADIANS_TO_DEGREES;
331 if (wind_from_east_fps >= 0)
332 wind_from_heading_deg = 90 - wind_from_heading_deg;
334 wind_from_heading_deg = 270 - wind_from_heading_deg;
336 wind_speed_kt = fabs(wind_from_east_fps
337 * SG_METER_TO_NM * SG_FEET_TO_METER * 3600);
339 wind_speed_kt = (wind_from_north_fps / sin(angle_rad))
340 * SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
344 FGEnvironment::_recalc_ne ()
347 wind_speed_kt * SG_NM_TO_METER * SG_METER_TO_FEET * (1.0/3600);
349 wind_from_north_fps = speed_fps *
350 cos(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
351 wind_from_east_fps = speed_fps *
352 sin(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
356 FGEnvironment::_recalc_sl_temperature ()
358 // If we're in the stratosphere, leave sea-level temp alone
359 if (elevation_ft < 38000) {
360 temperature_sea_level_degc =
361 (temperature_degc + 273.15)
362 /_temperature_degc_table->interpolate(elevation_ft)
368 FGEnvironment::_recalc_alt_temperature ()
370 if (elevation_ft < 38000) {
372 (temperature_sea_level_degc + 273.15) *
373 _temperature_degc_table->interpolate(elevation_ft) - 273.15;
375 temperature_degc = -56.49; // Stratosphere is constant
380 FGEnvironment::_recalc_sl_dewpoint ()
383 // FIXME: this will work only for low
385 dewpoint_sea_level_degc = dewpoint_degc + (elevation_ft * .0002);
386 if (dewpoint_sea_level_degc > temperature_sea_level_degc)
387 dewpoint_sea_level_degc = temperature_sea_level_degc;
391 FGEnvironment::_recalc_alt_dewpoint ()
394 // FIXME: this will work only for low
396 dewpoint_degc = dewpoint_sea_level_degc + (elevation_ft * .0002);
397 if (dewpoint_degc > temperature_degc)
398 dewpoint_degc = temperature_degc;
402 FGEnvironment::_recalc_sl_pressure ()
404 pressure_sea_level_inhg =
405 pressure_inhg / _pressure_inhg_table->interpolate(elevation_ft);
409 FGEnvironment::_recalc_alt_pressure ()
412 pressure_sea_level_inhg * _pressure_inhg_table->interpolate(elevation_ft);
416 FGEnvironment::_recalc_density ()
418 double pressure_psf = pressure_inhg * 70.7487;
420 // adjust for humidity
421 // calculations taken from USA Today (oops!) at
422 // http://www.usatoday.com/weather/basics/density-calculations.htm
423 double temperature_degk = temperature_degc + 273.15;
424 double pressure_mb = pressure_inhg * 33.86;
425 double vapor_pressure_mb =
426 6.11 * pow(10.0, 7.5 * dewpoint_degc / (237.7 + dewpoint_degc));
427 double virtual_temperature_degk = temperature_degk / (1 - (vapor_pressure_mb / pressure_mb) * (1.0 - 0.622));
428 double virtual_temperature_degr = virtual_temperature_degk * 1.8;
430 density_slugft3 = pressure_psf / (virtual_temperature_degr * 1718);
433 // end of environment.cxx