]> git.mxchange.org Git - flightgear.git/blob - src/Cockpit/steam.cxx
First stab at NAV1 and GS hold modes for the autopilot.
[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
218 double FGSteam::get_HackGS_deg () {
219
220 #if 0
221     double x,y,dme;
222     if (0==NAV1_LOC) return 0.0;
223     y = 60.0 * ( NAV1_Lat - FGBFI::getLatitude () );
224     x = 60.0 * ( NAV1_Lon - FGBFI::getLongitude() )
225                         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
226     dme = x*x + y*y;
227     if ( dme > 0.1 ) x = sqrt ( dme ); else x = 0.3;
228     y = FGBFI::getAltitude() - NAV1_Alt;
229     return 3.0 - (y/x) * 60.0 / 6000.0;
230 #endif
231
232     if ( current_radiostack->get_nav1_inrange() ) {
233         double x = current_radiostack->get_nav1_dist();
234         double y = (FGBFI::getAltitude() - current_radiostack->get_nav1_elev())
235             * FEET_TO_METER;
236         double angle = atan2( y, x ) * RAD_TO_DEG;
237         return current_radiostack->get_nav1_target_gs() - angle;
238     } else {
239         return 0.0;
240     }
241 }
242
243
244 double FGSteam::get_HackVOR1_deg () {
245     double r;
246
247 #if 0
248     double x,y;
249     y = 60.0 * ( NAV1_Lat - FGBFI::getLatitude () );
250     x = 60.0 * ( NAV1_Lon - FGBFI::getLongitude() )
251         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
252     r = atan2 ( x, y ) * RAD_TO_DEG - NAV1_Rad - FGBFI::getMagVar();
253 #endif
254
255     if ( current_radiostack->get_nav1_inrange() ) {
256         r = current_radiostack->get_nav1_radial() - 
257             current_radiostack->get_nav1_heading();
258         // cout << "Radial = " << current_radiostack->get_nav1_radial() 
259         //      << "  Bearing = " << current_radiostack->get_nav1_heading()
260         //      << endl;
261     
262         if (r> 180.0) r-=360.0; else
263             if (r<-180.0) r+=360.0;
264         if ( fabs(r) > 90.0 )
265             r = ( r<0.0 ? -r-180.0 : -r+180.0 );
266         if ( current_radiostack->get_nav1_loc() ) r*=5.0;
267     } else {
268         r = 0.0;
269     }
270
271     return r;
272 }
273
274
275 double FGSteam::get_HackVOR2_deg () {
276     double r;
277
278 #if 0
279     double x,y;
280     y = 60.0 * ( NAV2_Lat - FGBFI::getLatitude () );
281     x = 60.0 * ( NAV2_Lon - FGBFI::getLongitude() )
282         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
283     r = atan2 ( x, y ) * RAD_TO_DEG - NAV2_Rad - FGBFI::getMagVar();
284 #endif
285
286     if ( current_radiostack->get_nav2_inrange() ) {
287         r = current_radiostack->get_nav2_radial() -
288             current_radiostack->get_nav2_heading() + 180.0;
289         // cout << "Radial = " << current_radiostack->get_nav1_radial() 
290         // << "  Bearing = " << current_radiostack->get_nav1_heading() << endl;
291     
292         if (r> 180.0) r-=360.0; else
293             if (r<-180.0) r+=360.0;
294         if ( fabs(r) > 90.0 )
295             r = ( r<0.0 ? -r-180.0 : -r+180.0 );
296     } else {
297         r = 0.0;
298     }
299
300     return r;
301 }
302
303
304 double FGSteam::get_HackOBS1_deg () {
305     return current_radiostack->get_nav1_radial(); 
306 }
307
308
309 double FGSteam::get_HackOBS2_deg () {
310     return current_radiostack->get_nav2_radial(); 
311 }
312
313
314 double FGSteam::get_HackADF_deg () {
315     double r;
316
317 #if 0
318     double x,y;
319     y = 60.0 * ( ADF_Lat - FGBFI::getLatitude () );
320     x = 60.0 * ( ADF_Lon - FGBFI::getLongitude() )
321         * cos ( FGBFI::getLatitude () / RAD_TO_DEG );
322     r = atan2 ( x, y ) * RAD_TO_DEG - FGBFI::getHeading ();
323 #endif
324
325     if ( current_radiostack->get_adf_inrange() ) {
326         r = current_radiostack->get_adf_heading() - FGBFI::getHeading() + 180.0;
327
328         // cout << "Radial = " << current_radiostack->get_adf_heading() 
329         //      << "  Heading = " << FGBFI::getHeading() << endl;
330     } else {
331         r = 0.0;
332     }
333
334     return r;
335 }
336
337
338 // end of steam.cxx