]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/steam.cxx
0c82bd72f38234702b4250b20d12cd70b8e63f66
[flightgear.git] / src / Cockpit / steam.cxx
1 // steam.cxx - Steam Gauge Calculations
2 //
3 // Copyright (C) 2000  Alexander Perry - alex.perry@ieee.org
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful, but
11 // WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 //
19 // $Id$
20
21
22 #ifdef HAVE_CONFIG_H
23 #  include <config.h>
24 #endif
25
26 #if defined( FG_HAVE_NATIVE_SGI_COMPILERS )
27 #  include <iostream.h>
28 #else
29 #  include <iostream>
30 #endif
31
32 #include <simgear/constants.h>
33 #include <simgear/math/fg_types.hxx>
34 #include <Main/options.hxx>
35 #include <Main/bfi.hxx>
36
37 FG_USING_NAMESPACE(std);
38
39 #include "radiostack.hxx"
40 #include "steam.hxx"
41
42
43 \f
44 ////////////////////////////////////////////////////////////////////////
45 // Declare the functions that read the variables
46 ////////////////////////////////////////////////////////////////////////
47
48 // Anything that reads the BFI directly is not implemented at all!
49
50
51 #define VARY_E          (14)
52
53
54 double FGSteam::the_STATIC_inhg = 29.92;
55 double FGSteam::the_ALT_ft = 0.0;
56 double FGSteam::get_ALT_ft() { _CatchUp(); return the_ALT_ft; }
57
58 double FGSteam::get_ASI_kias() { return FGBFI::getAirspeed(); }
59
60 double FGSteam::the_VSI_case = 29.92;
61 double FGSteam::the_VSI_fps = 0.0;
62 double FGSteam::get_VSI_fps() { _CatchUp(); return the_VSI_fps; }
63
64 double FGSteam::the_VACUUM_inhg = 0.0;
65 double FGSteam::get_VACUUM_inhg() { _CatchUp(); return the_VACUUM_inhg; }
66
67 double FGSteam::get_MH_deg () {
68     return FGBFI::getHeading () - FGBFI::getMagVar ();
69 }
70 double FGSteam::get_DG_deg () {
71     return FGBFI::getHeading () - FGBFI::getMagVar ();
72 }
73
74 double FGSteam::get_TC_rad   () { return FGBFI::getSideSlip (); }
75 double FGSteam::get_TC_radps () { return FGBFI::getRoll (); }
76
77 \f
78 ////////////////////////////////////////////////////////////////////////
79 // Recording the current time
80 ////////////////////////////////////////////////////////////////////////
81
82
83 int FGSteam::_UpdatesPending = 9999;  /* Forces filter to reset */
84
85
86 void FGSteam::update ( int timesteps )
87 {
88         _UpdatesPending += timesteps;
89 }
90
91
92 void FGSteam::set_lowpass ( double *outthe, double inthe, double tc )
93 {
94         if ( tc < 0.0 )
95         {       if ( tc < -1.0 )
96                 {       /* time went backwards; kill the filter */
97                         (*outthe) = inthe;
98                 } else
99                 {       /* ignore mildly negative time */
100                 }
101         } else
102         if ( tc < 0.2 )
103         {       /* Normal mode of operation */
104                 (*outthe) = (*outthe) * ( 1.0 - tc )
105                           +    inthe  * tc;
106         } else
107         if ( tc > 5.0 )
108         {       /* Huge time step; assume filter has settled */
109                 (*outthe) = inthe;
110         } else
111         {       /* Moderate time step; non linear response */
112                 double keep = exp ( -tc );
113                 // printf ( "ARP: Keep is %f\n", keep );
114                 (*outthe) = (*outthe) * keep
115                           +    inthe  * ( 1.0 - keep );
116         }
117 }
118
119
120 \f
121 ////////////////////////////////////////////////////////////////////////
122 // Here the fun really begins
123 ////////////////////////////////////////////////////////////////////////
124
125
126 void FGSteam::_CatchUp()
127 { if ( _UpdatesPending != 0 )
128   {     double dt = _UpdatesPending * 1.0 / current_options.get_model_hz();
129         int i,j;
130         double d, the_ENGINE_rpm;
131         /*
132         Someone has called our update function and
133         it turns out that we are running somewhat behind.
134         Here, we recalculate everything for a 'dt' second step.
135         */
136
137         /**************************
138         This is not actually correct, but provides a
139         scaling capability for the vacuum pump later on.
140         When we have a real engine model, we can ask it.
141         */
142         the_ENGINE_rpm = FGBFI::getThrottle() * 26.0;
143
144         /**************************
145         This is just temporary, until the static source works,
146         so we just filter the actual value by one second to
147         account for the line impedance of the plumbing.
148         */
149         set_lowpass ( & the_ALT_ft, FGBFI::getAltitude(), dt );
150
151         /**************************
152         First, we need to know what the static line is reporting,
153         which is a whole simulation area in itself.  For now, we cheat.
154         */
155         the_STATIC_inhg = 29.92; 
156         i = (int) the_ALT_ft;
157         while ( i > 9000 )
158         {       the_STATIC_inhg *= 0.707;
159                 i -= 9000;
160         }
161         the_STATIC_inhg *= ( 1.0 - 0.293 * i / 9000.0 );
162
163         /*
164         NO alternate static source error (student feature), 
165         NO possibility of blockage (instructor feature),
166         NO slip-induced error, important for C172 for example.
167         */
168
169         /**************************
170         The VSI case is a low-pass filter of the static line pressure.
171         The instrument reports the difference, scaled to approx ft.
172         NO option for student to break glass when static source fails.
173         NO capability for a fixed non-zero reading when level.
174         NO capability to have a scaling error of maybe a factor of two.
175         */
176         the_VSI_fps = ( the_VSI_case - the_STATIC_inhg )
177                     * 10000.0; /* manual scaling factor */      
178         set_lowpass ( & the_VSI_case, the_STATIC_inhg, dt/6.0 );
179
180         /**************************
181         The engine driven vacuum pump is directly attached
182         to the engine shaft, so each engine rotation pumps
183         a fixed volume.  The amount of air in that volume
184         is determined by the vacuum line's internal pressure.
185         The instruments are essentially leaking air like
186         a fixed source impedance from atmospheric pressure.
187         The regulator provides a digital limit setting,
188         which is open circuit unless the pressure drop is big.
189         Thus, we can compute the vacuum line pressure directly.
190         We assume that there is negligible reservoir space.
191         NO failure of the pump supported (yet)
192         */
193         the_VACUUM_inhg = the_STATIC_inhg *
194                 the_ENGINE_rpm / ( the_ENGINE_rpm + 10000.0 );
195         if ( the_VACUUM_inhg > 5.0 )
196              the_VACUUM_inhg = 5.0;
197
198 /*
199 > I was merely going to do the engine rpm driven vacuum pump for both
200 > the AI and DG, have the gyros spin down down in power off descents, 
201 > have it tumble when you exceed the usual pitch or bank limits,
202 > put in those insidious turning errors ... for now anyway.
203 */
204
205         /**************************
206         Finished updates, now clear the timer 
207         */
208         _UpdatesPending = 0;
209   }
210 }
211
212 \f
213 ////////////////////////////////////////////////////////////////////////
214 // Everything below is a transient hack; expect it to disappear
215 ////////////////////////////////////////////////////////////////////////
216
217 #if 0
218 /* KMYF ILS */
219 #define NAV1_LOC        (1)
220 #define NAV1_Lat        (  32.0 + 48.94/60.0)
221 #define NAV1_Lon        (-117.0 - 08.37/60.0)
222 #define NAV1_Rad        280.0
223 #define NAV1_Alt        423
224
225 /* MZB stepdown radial */
226 #define NAV2_Lat        (  32.0 + 46.93/60.0)
227 #define NAV2_Lon        (-117.0 - 13.53/60.0)
228 #define NAV2_Rad        068.0
229
230 /* HAILE intersection */
231 #define ADF_Lat         (  32.0 + 46.79/60.0)
232 #define ADF_Lon         (-117.0 - 02.70/60.0)
233 #endif
234
235
236 double FGSteam::get_HackGS_deg () {
237
238 #if 0
239     double x,y,dme;
240     if (0==NAV1_LOC) return 0.0;
241     y = 60.0 * ( NAV1_Lat - FGBFI::getLatitude () );
242     x = 60.0 * ( NAV1_Lon - FGBFI::getLongitude() )
243                         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
244     dme = x*x + y*y;
245     if ( dme > 0.1 ) x = sqrt ( dme ); else x = 0.3;
246     y = FGBFI::getAltitude() - NAV1_Alt;
247     return 3.0 - (y/x) * 60.0 / 6000.0;
248 #endif
249
250     if ( current_radiostack->get_nav1_inrange() ) {
251         double x = current_radiostack->get_nav1_dist();
252         double y = (FGBFI::getAltitude() - current_radiostack->get_nav1_elev())
253             * FEET_TO_METER;
254         double angle = atan2( y, x ) * RAD_TO_DEG;
255         return current_radiostack->get_nav1_target_gs() - angle;
256     } else {
257         return 0.0;
258     }
259 }
260
261
262 double FGSteam::get_HackVOR1_deg () {
263     double r;
264
265 #if 0
266     double x,y;
267     y = 60.0 * ( NAV1_Lat - FGBFI::getLatitude () );
268     x = 60.0 * ( NAV1_Lon - FGBFI::getLongitude() )
269         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
270     r = atan2 ( x, y ) * RAD_TO_DEG - NAV1_Rad - FGBFI::getMagVar();
271 #endif
272
273     if ( current_radiostack->get_nav1_inrange() ) {
274         r = current_radiostack->get_nav1_radial() - 
275             current_radiostack->get_nav1_heading() + 180.0;
276         // cout << "Radial = " << current_radiostack->get_nav1_radial() 
277         //      << "  Bearing = " << current_radiostack->get_nav1_heading()
278         //      << endl;
279     
280         if (r> 180.0) r-=360.0; else
281             if (r<-180.0) r+=360.0;
282         if ( fabs(r) > 90.0 )
283             r = ( r<0.0 ? -r-180.0 : -r+180.0 );
284         if ( current_radiostack->get_nav1_loc() ) r*=5.0;
285     } else {
286         r = 0.0;
287     }
288
289     return r;
290 }
291
292
293 double FGSteam::get_HackVOR2_deg () {
294     double r;
295
296 #if 0
297     double x,y;
298     y = 60.0 * ( NAV2_Lat - FGBFI::getLatitude () );
299     x = 60.0 * ( NAV2_Lon - FGBFI::getLongitude() )
300         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
301     r = atan2 ( x, y ) * RAD_TO_DEG - NAV2_Rad - FGBFI::getMagVar();
302 #endif
303
304     if ( current_radiostack->get_nav2_inrange() ) {
305         r = current_radiostack->get_nav2_radial() -
306             current_radiostack->get_nav2_heading() + 180.0;
307         // cout << "Radial = " << current_radiostack->get_nav1_radial() 
308         // << "  Bearing = " << current_radiostack->get_nav1_heading() << endl;
309     
310         if (r> 180.0) r-=360.0; else
311             if (r<-180.0) r+=360.0;
312         if ( fabs(r) > 90.0 )
313             r = ( r<0.0 ? -r-180.0 : -r+180.0 );
314     } else {
315         r = 0.0;
316     }
317
318     return r;
319 }
320
321
322 double FGSteam::get_HackOBS1_deg () {
323     return current_radiostack->get_nav1_radial(); 
324 }
325
326
327 double FGSteam::get_HackOBS2_deg () {
328     return current_radiostack->get_nav2_radial(); 
329 }
330
331
332 double FGSteam::get_HackADF_deg () {
333     double r;
334
335 #if 0
336     double x,y;
337     y = 60.0 * ( ADF_Lat - FGBFI::getLatitude () );
338     x = 60.0 * ( ADF_Lon - FGBFI::getLongitude() )
339         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
340     r = atan2 ( x, y ) * RAD_TO_DEG - FGBFI::getHeading ();
341 #endif
342
343     if ( current_radiostack->get_adf_inrange() ) {
344         r = current_radiostack->get_adf_heading() - FGBFI::getHeading() + 180.0;
345
346         // cout << "Radial = " << current_radiostack->get_adf_heading() 
347         //      << "  Heading = " << FGBFI::getHeading() << endl;
348     } else {
349         r = 0.0;
350     }
351
352     return r;
353 }
354
355
356 // end of steam.cxx