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),
47 _density_slugft3_table(new SGInterpTable),
49 temperature_sea_level_degc(20),
50 pressure_sea_level_inhg(29.92),
51 density_sea_level_slugft3(0.00237),
52 wind_from_heading_deg(0),
54 wind_from_north_fps(0),
55 wind_from_east_fps(0),
61 FGEnvironment::FGEnvironment (const FGEnvironment &env)
62 : _temperature_degc_table(new SGInterpTable),
63 _pressure_inhg_table(new SGInterpTable),
64 _density_slugft3_table(new SGInterpTable),
65 elevation_ft(env.elevation_ft),
66 visibility_m(env.visibility_m),
67 temperature_sea_level_degc(env.temperature_sea_level_degc),
68 pressure_sea_level_inhg(env.pressure_sea_level_inhg),
69 density_sea_level_slugft3(env.density_sea_level_slugft3),
70 wind_from_heading_deg(env.wind_from_heading_deg),
71 wind_speed_kt(env.wind_speed_kt),
72 wind_from_north_fps(env.wind_from_north_fps),
73 wind_from_east_fps(env.wind_from_east_fps),
74 wind_from_down_fps(env.wind_from_down_fps)
79 FGEnvironment::~FGEnvironment()
81 delete _temperature_degc_table;
82 delete _pressure_inhg_table;
83 delete _density_slugft3_table;
88 FGEnvironment::get_visibility_m () const
94 FGEnvironment::get_temperature_sea_level_degc () const
96 return temperature_sea_level_degc;
100 FGEnvironment::get_temperature_degc () const
102 return temperature_degc;
106 FGEnvironment::get_pressure_sea_level_inhg () const
108 return pressure_sea_level_inhg;
112 FGEnvironment::get_pressure_inhg () const
114 return pressure_inhg;
118 FGEnvironment::get_density_sea_level_slugft3 () const
120 return density_sea_level_slugft3;
124 FGEnvironment::get_density_slugft3 () const
126 return density_slugft3;
130 FGEnvironment::get_wind_from_heading_deg () const
132 return wind_from_heading_deg;
136 FGEnvironment::get_wind_speed_kt () const
138 return wind_speed_kt;
142 FGEnvironment::get_wind_from_north_fps () const
144 return wind_from_north_fps;
148 FGEnvironment::get_wind_from_east_fps () const
150 return wind_from_east_fps;
154 FGEnvironment::get_wind_from_down_fps () const
156 return wind_from_down_fps;
160 FGEnvironment::get_elevation_ft () const
166 FGEnvironment::set_visibility_m (double v)
172 FGEnvironment::set_temperature_sea_level_degc (double t)
174 temperature_sea_level_degc = t;
175 _recalc_alt_temperature();
179 FGEnvironment::set_temperature_degc (double t)
181 temperature_degc = t;
182 _recalc_sl_temperature();
186 FGEnvironment::set_pressure_sea_level_inhg (double p)
188 pressure_sea_level_inhg = p;
189 _recalc_alt_pressure();
193 FGEnvironment::set_pressure_inhg (double p)
196 _recalc_sl_pressure();
200 FGEnvironment::set_density_sea_level_slugft3 (double d)
202 density_sea_level_slugft3 = d;
203 _recalc_alt_density();
207 FGEnvironment::set_density_slugft3 (double d)
210 _recalc_sl_density();
214 FGEnvironment::set_wind_from_heading_deg (double h)
216 wind_from_heading_deg = h;
221 FGEnvironment::set_wind_speed_kt (double s)
228 FGEnvironment::set_wind_from_north_fps (double n)
230 wind_from_north_fps = n;
235 FGEnvironment::set_wind_from_east_fps (double e)
237 wind_from_east_fps = e;
242 FGEnvironment::set_wind_from_down_fps (double d)
244 wind_from_down_fps = d;
249 FGEnvironment::set_elevation_ft (double e)
252 _recalc_alt_temperature();
253 _recalc_alt_pressure();
254 _recalc_alt_density();
259 // Copied from YASim Atmosphere.cxx, with m converted to ft, degK
260 // converted to degC, Pa converted to inHG, and kg/m^3 converted to
261 // slug/ft^3; they were then converted to deltas from the sea-level
262 // defaults (approx. 15degC, 29.92inHG, and 0.00237slugs/ft^3).
264 // Original comment from YASim:
266 // Copied from McCormick, who got it from "The ARDC Model Atmosphere"
267 // Note that there's an error in the text in the first entry,
268 // McCormick lists 299.16/101325/1.22500, but those don't agree with
269 // R=287. I chose to correct the temperature to 288.20, since 79F is
270 // pretty hot for a "standard" atmosphere.
272 // Elevation (ft), temperature factor (degK), pressure factor (inHG),
273 // density factor (slug/ft^3)
274 static double atmosphere_data[][4] = {
275 0.00, 1.00, 1.000, 1.000000,
276 2952.76, 0.98, 0.898, 0.916408,
277 5905.51, 0.96, 0.804, 0.838286,
278 8858.27, 0.94, 0.719, 0.765429,
279 11811.02, 0.92, 0.641, 0.697510,
280 14763.78, 0.90, 0.570, 0.634318,
281 17716.54, 0.88, 0.506, 0.575616,
282 20669.29, 0.86, 0.447, 0.521184,
283 23622.05, 0.84, 0.394, 0.470784,
284 26574.80, 0.82, 0.347, 0.424220,
285 29527.56, 0.80, 0.304, 0.381273,
286 32480.31, 0.78, 0.266, 0.341747,
287 35433.07, 0.76, 0.231, 0.305445,
288 38385.83, 0.75, 0.201, 0.266931,
289 41338.58, 0.75, 0.174, 0.231739,
290 44291.34, 0.75, 0.151, 0.201192,
291 47244.09, 0.75, 0.131, 0.174686,
292 50196.85, 0.75, 0.114, 0.151673,
293 53149.61, 0.75, 0.099, 0.131698,
294 56102.36, 0.75, 0.086, 0.114359,
295 59055.12, 0.75, 0.075, 0.099306,
296 62007.87, 0.75, 0.065, 0.086237,
301 FGEnvironment::_setup_tables ()
303 for (int i = 0; atmosphere_data[i][0] != -1; i++) {
304 _temperature_degc_table->addEntry(atmosphere_data[i][0],
305 atmosphere_data[i][1]);
306 _pressure_inhg_table->addEntry(atmosphere_data[i][0],
307 atmosphere_data[i][2]);
308 _density_slugft3_table->addEntry(atmosphere_data[i][0],
309 atmosphere_data[i][3]);
314 FGEnvironment::_recalc_hdgspd ()
318 if (wind_from_east_fps == 0) {
319 angle_rad = (wind_from_north_fps >= 0 ? SGD_PI/2 : -SGD_PI/2);
321 angle_rad = atan(wind_from_north_fps/wind_from_east_fps);
323 wind_from_heading_deg = angle_rad * SGD_RADIANS_TO_DEGREES;
324 if (wind_from_east_fps >= 0)
325 wind_from_heading_deg = 90 - wind_from_heading_deg;
327 wind_from_heading_deg = 270 - wind_from_heading_deg;
329 wind_speed_kt = fabs(wind_from_east_fps
330 * SG_METER_TO_NM * SG_FEET_TO_METER * 3600);
332 wind_speed_kt = (wind_from_north_fps / sin(angle_rad))
333 * SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
337 FGEnvironment::_recalc_ne ()
340 wind_speed_kt * SG_NM_TO_METER * SG_METER_TO_FEET * (1.0/3600);
342 wind_from_north_fps = speed_fps *
343 cos(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
344 wind_from_east_fps = speed_fps *
345 sin(wind_from_heading_deg * SGD_DEGREES_TO_RADIANS);
349 FGEnvironment::_recalc_sl_temperature ()
351 // If we're in the stratosphere, leave sea-level temp alone
352 if (elevation_ft < 38000) {
353 temperature_sea_level_degc =
354 (temperature_degc + 273.15)
355 /_temperature_degc_table->interpolate(elevation_ft)
361 FGEnvironment::_recalc_alt_temperature ()
363 if (elevation_ft < 38000) {
365 (temperature_sea_level_degc + 273.15) *
366 _temperature_degc_table->interpolate(elevation_ft) - 273.15;
368 temperature_degc = -56.49; // Stratosphere is constant
373 FGEnvironment::_recalc_sl_pressure ()
375 pressure_sea_level_inhg =
376 pressure_inhg / _pressure_inhg_table->interpolate(elevation_ft);
380 FGEnvironment::_recalc_alt_pressure ()
383 pressure_sea_level_inhg * _pressure_inhg_table->interpolate(elevation_ft);
387 FGEnvironment::_recalc_sl_density ()
389 density_sea_level_slugft3 =
390 density_slugft3 / _density_slugft3_table->interpolate(elevation_ft);
394 FGEnvironment::_recalc_alt_density ()
397 density_sea_level_slugft3 *
398 _density_slugft3_table->interpolate(elevation_ft);
401 // end of environment.cxx