1 // inst_vertical_speed_indicator.cxx
2 // -- Instantaneous VSI (emulation calibrated to standard atmosphere).
4 // Started September 2004.
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // General Public License for more details.
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include <simgear/math/interpolater.hxx>
25 #include "inst_vertical_speed_indicator.hxx"
26 #include <Main/fg_props.hxx>
27 #include <Main/util.hxx>
30 // Altitude based on pressure difference from sea level.
32 // See http://www.pdas.com/programs/atmos.f90, the tables match exactly
33 // environment.cxx (Standard 1976).
35 // - at 27900 m the level is 20 km :
36 // geopotential altitude 27.9 x 6369 / ( 27.9 + 6369) = 27.778 km.
37 // - deltah = 27.778 - 20 = 7.778 km and tbase 216.65 degK.
38 // - delta = 5.403295E-2 x exp( -34.163195 x 7.778 / 216.65 ) = 0.016.
39 // - pressure = (1 - delta ) x 29.92 = 29.44 inhg.
40 // - to construct the tables, round delta to 3 digits.
42 // altitude ft, pressure step inHG
43 static double pressure_data[][2] = {
44 { 0.00, 3.33 }, // guess !
82 // pressure difference inHG, altitude ft
83 static double altitude_data[][2] = {
118 { 29.62, 100393.70 },
124 #define SEA_LEVEL_INHG 29.92
126 // A higher number means more responsive.
127 #define RESPONSIVENESS 5.0
129 // External environment
130 #define MAX_INHG_PER_S 0.0002
133 InstVerticalSpeedIndicator::InstVerticalSpeedIndicator ( SGPropertyNode *node ) :
134 _internal_pressure_inhg( SEA_LEVEL_INHG ),
135 _internal_sea_inhg( SEA_LEVEL_INHG ),
136 _speed_ft_per_s( 0 ),
137 _pressure_table(new SGInterpTable),
138 _altitude_table(new SGInterpTable)
141 for ( i = 0; pressure_data[i][0] != -1; i++)
142 _pressure_table->addEntry( pressure_data[i][0], pressure_data[i][1] );
144 for ( i = 0; altitude_data[i][0] != -1; i++)
145 _altitude_table->addEntry( altitude_data[i][0], altitude_data[i][1] );
147 for ( i = 0; i < node->nChildren(); ++i ) {
148 SGPropertyNode *child = node->getChild(i);
149 string cname = child->getName();
150 string cval = child->getStringValue();
151 if ( cname == "name" ) {
153 } else if ( cname == "number" ) {
154 num = child->getIntValue();
156 SG_LOG( SG_INSTR, SG_WARN, "Error in inst-vertical-speed-indicator config logic" );
157 if ( name.length() ) {
158 SG_LOG( SG_INSTR, SG_WARN, "Section = " << name );
165 InstVerticalSpeedIndicator::~InstVerticalSpeedIndicator ()
167 delete _pressure_table;
168 delete _altitude_table;
172 void InstVerticalSpeedIndicator::init ()
175 fgGetNode("/instrumentation/inst-vertical-speed-indicator/serviceable", true);
177 fgGetNode("/sim/freeze/master", true);
179 // A real IVSI is operated by static pressure changes.
180 // It operates like a conventional VSI, except that an internal sensor
181 // detects load factors, to momentarily alters the static pressure
183 // It appears lag free at subsonic speed; at high altitude indication may
184 // be less than 1/3 of actual conditions.
186 fgGetNode("/environment/pressure-inhg", true);
188 fgGetNode("/environment/pressure-sea-level-inhg", true);
190 fgGetNode("/sim/speed-up", true);
192 fgGetNode("/instrumentation/inst-vertical-speed-indicator/indicated-speed-fps",
195 fgGetNode("/instrumentation/inst-vertical-speed-indicator/indicated-speed-fpm",
198 // Initialize at ambient pressure
199 _internal_pressure_inhg = _pressure_node->getDoubleValue();
203 void InstVerticalSpeedIndicator::update (double dt)
205 if (_serviceable_node->getBoolValue())
207 // avoids hang, when freeze
208 if( !_freeze_node->getBoolValue() )
210 double pressure_inhg = _pressure_node->getDoubleValue();
211 double sea_inhg = _sea_node->getDoubleValue();
212 double speed_up = _speed_up_node->getDoubleValue();
214 // must work by speed up
220 // limit effect of external environment
221 double rate_sea_inhg_per_s = ( sea_inhg - _internal_sea_inhg ) / dt;
223 if( rate_sea_inhg_per_s > - MAX_INHG_PER_S && rate_sea_inhg_per_s < MAX_INHG_PER_S )
225 double rate_inhg_per_s = ( pressure_inhg - _internal_pressure_inhg ) / dt;
227 // IVSI determines alone the current altitude, without altimeter setting.
228 // Altimeter setting is 29.92 above 10000 or 18000 ft.
229 // Below this level, the slope is slightly wrong.
230 double altitude_ft = _altitude_table->interpolate( SEA_LEVEL_INHG - pressure_inhg );
231 double slope_inhg = _pressure_table->interpolate( altitude_ft );
234 double last_speed_ft_per_s = _speed_ft_per_s;
237 _speed_ft_per_s = - rate_inhg_per_s * 2952.75591 / slope_inhg;
240 _speed_ft_per_s = fgGetLowPass( last_speed_ft_per_s, _speed_ft_per_s,
241 dt * RESPONSIVENESS );
244 _speed_node->setDoubleValue( _speed_ft_per_s );
245 _speed_min_node->setDoubleValue( _speed_ft_per_s * 60.0 );
248 _internal_pressure_inhg = pressure_inhg;
249 _internal_sea_inhg = sea_inhg;
254 // end of inst_vertical_speed_indicator.cxx