]> git.mxchange.org Git - flightgear.git/blob - src/Environment/environment.cxx
75adb24a3bc642e77a72b71fdc9f2bc7559c50a2
[flightgear.git] / src / Environment / environment.cxx
1 // environment.cxx -- routines to model the natural environment
2 //
3 // Written by David Megginson, started February 2002.
4 //
5 // Copyright (C) 2002  David Megginson - david@megginson.com
6 //
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.
11 //
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.
16 //
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.
20 //
21 // $Id$
22
23
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27
28 #ifdef HAVE_WINDOWS_H
29 #  include <windows.h>                     
30 #endif
31
32 #include <math.h>
33
34 #include <plib/sg.h>
35
36 #include <simgear/constants.h>
37 #include <simgear/debug/logstream.hxx>
38 #include <simgear/math/interpolater.hxx>
39
40 #include <Main/fg_props.hxx>
41 #include "environment.hxx"
42
43
44 FGEnvironment::FGEnvironment()
45   : _temperature_degc_table(new SGInterpTable),
46     _pressure_inhg_table(new SGInterpTable),
47     _density_slugft3_table(new SGInterpTable),
48     visibility_m(32000),
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),
53     wind_speed_kt(0),
54     wind_from_north_fps(0),
55     wind_from_east_fps(0),
56     wind_from_down_fps(0)
57 {
58   _setup_tables();
59 }
60
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)
75 {
76   _setup_tables();
77 }
78
79 FGEnvironment::~FGEnvironment()
80 {
81   delete _temperature_degc_table;
82   delete _pressure_inhg_table;
83   delete _density_slugft3_table;
84 }
85
86
87 double
88 FGEnvironment::get_visibility_m () const
89 {
90   return visibility_m;
91 }
92
93 double
94 FGEnvironment::get_temperature_sea_level_degc () const
95 {
96   return temperature_sea_level_degc;
97 }
98
99 double
100 FGEnvironment::get_temperature_degc () const
101 {
102   return temperature_degc;
103 }
104
105 double
106 FGEnvironment::get_pressure_sea_level_inhg () const
107 {
108   return pressure_sea_level_inhg;
109 }
110
111 double
112 FGEnvironment::get_pressure_inhg () const
113 {
114   return pressure_inhg;
115 }
116
117 double
118 FGEnvironment::get_density_sea_level_slugft3 () const
119 {
120   return density_sea_level_slugft3;
121 }
122
123 double
124 FGEnvironment::get_density_slugft3 () const
125 {
126   return density_slugft3;
127 }
128
129 double
130 FGEnvironment::get_wind_from_heading_deg () const
131 {
132   return wind_from_heading_deg;
133 }
134
135 double
136 FGEnvironment::get_wind_speed_kt () const
137 {
138   return wind_speed_kt;
139 }
140
141 double
142 FGEnvironment::get_wind_from_north_fps () const
143 {
144   return wind_from_north_fps;
145 }
146
147 double
148 FGEnvironment::get_wind_from_east_fps () const
149 {
150   return wind_from_east_fps;
151 }
152
153 double
154 FGEnvironment::get_wind_from_down_fps () const
155 {
156   return wind_from_down_fps;
157 }
158
159 double
160 FGEnvironment::get_elevation_ft () const
161 {
162   return elevation_ft;
163 }
164
165 void
166 FGEnvironment::set_visibility_m (double v)
167 {
168   visibility_m = v;
169 }
170
171 void
172 FGEnvironment::set_temperature_sea_level_degc (double t)
173 {
174   temperature_sea_level_degc = t;
175   _recalc_alt_temperature();
176 }
177
178 void
179 FGEnvironment::set_temperature_degc (double t)
180 {
181   temperature_degc = t;
182   _recalc_sl_temperature();
183 }
184
185 void
186 FGEnvironment::set_pressure_sea_level_inhg (double p)
187 {
188   pressure_sea_level_inhg = p;
189   _recalc_alt_pressure();
190 }
191
192 void
193 FGEnvironment::set_pressure_inhg (double p)
194 {
195   pressure_inhg = p;
196   _recalc_sl_pressure();
197 }
198
199 void
200 FGEnvironment::set_density_sea_level_slugft3 (double d)
201 {
202   density_sea_level_slugft3 = d;
203   _recalc_alt_density();
204 }
205
206 void
207 FGEnvironment::set_density_slugft3 (double d)
208 {
209   density_slugft3 = d;
210   _recalc_sl_density();
211 }
212
213 void
214 FGEnvironment::set_wind_from_heading_deg (double h)
215 {
216   wind_from_heading_deg = h;
217   _recalc_ne();
218 }
219
220 void
221 FGEnvironment::set_wind_speed_kt (double s)
222 {
223   wind_speed_kt = s;
224   _recalc_ne();
225 }
226
227 void
228 FGEnvironment::set_wind_from_north_fps (double n)
229 {
230   wind_from_north_fps = n;
231   _recalc_hdgspd();
232 }
233
234 void
235 FGEnvironment::set_wind_from_east_fps (double e)
236 {
237   wind_from_east_fps = e;
238   _recalc_hdgspd();
239 }
240
241 void
242 FGEnvironment::set_wind_from_down_fps (double d)
243 {
244   wind_from_down_fps = d;
245   _recalc_hdgspd();
246 }
247
248 void
249 FGEnvironment::set_elevation_ft (double e)
250 {
251   elevation_ft = e;
252   _recalc_alt_temperature();
253   _recalc_alt_pressure();
254   _recalc_alt_density();
255 }
256
257 // Atmosphere model.
258
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).
263
264 // Original comment from YASim:
265
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.
271
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,
297   -1, -1, -1, -1
298 };
299
300 void
301 FGEnvironment::_setup_tables ()
302 {
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]);
310   }
311 }
312
313 void
314 FGEnvironment::_recalc_hdgspd ()
315 {
316   double angle_rad;
317
318   if (wind_from_east_fps == 0) {
319     angle_rad = (wind_from_north_fps >= 0 ? SGD_PI/2 : -SGD_PI/2);
320   } else {
321     angle_rad = atan(wind_from_north_fps/wind_from_east_fps);
322   }
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;
326   else
327     wind_from_heading_deg = 270 - wind_from_heading_deg;
328   if (angle_rad == 0)
329     wind_speed_kt = fabs(wind_from_east_fps
330                          * SG_METER_TO_NM * SG_FEET_TO_METER * 3600);
331   else
332     wind_speed_kt = (wind_from_north_fps / sin(angle_rad))
333       * SG_METER_TO_NM * SG_FEET_TO_METER * 3600;
334 }
335
336 void
337 FGEnvironment::_recalc_ne ()
338 {
339   double speed_fps =
340     wind_speed_kt * SG_NM_TO_METER * SG_METER_TO_FEET * (1.0/3600);
341
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);
346 }
347
348 void
349 FGEnvironment::_recalc_sl_temperature ()
350 {
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)
356       - 273.15;
357   }
358 }
359
360 void
361 FGEnvironment::_recalc_alt_temperature ()
362 {
363   if (elevation_ft < 38000) {
364     temperature_degc =
365       (temperature_sea_level_degc + 273.15) *
366       _temperature_degc_table->interpolate(elevation_ft) - 273.15;
367   } else {
368     temperature_degc = -56.49;  // Stratosphere is constant
369   }
370 }
371
372 void
373 FGEnvironment::_recalc_sl_pressure ()
374 {
375   pressure_sea_level_inhg =
376     pressure_inhg / _pressure_inhg_table->interpolate(elevation_ft);
377 }
378
379 void
380 FGEnvironment::_recalc_alt_pressure ()
381 {
382   pressure_inhg =
383     pressure_sea_level_inhg * _pressure_inhg_table->interpolate(elevation_ft);
384 }
385
386 void
387 FGEnvironment::_recalc_sl_density ()
388 {
389   density_sea_level_slugft3 =
390     density_slugft3 / _density_slugft3_table->interpolate(elevation_ft);
391 }
392
393 void
394 FGEnvironment::_recalc_alt_density ()
395 {
396   density_slugft3 =
397     density_sea_level_slugft3 *
398     _density_slugft3_table->interpolate(elevation_ft);
399 }
400
401 // end of environment.cxx