From: ehofman Date: Sat, 25 Jun 2005 08:46:58 +0000 (+0000) Subject: TJ: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=486b59a431e76de1aff4b57b51a36d035e6b5cce;p=flightgear.git TJ: Annexed an IVSI (instantaneous ertical speed indicator), which bypasses a limitation with Concorde : - the cruise at Mach 2 must be with a slow climb rate of 50/60 ft/min (2h from 50000 ft). - with /velocities/vertical-speed-fpm, the real climb rate (altimeter) varies : One must constantly (every 5-10 minutes) change the vertical speed hold of the autopilot between 10 ft/min and 200 ft/min. This is very annoying because not a constant offset : that could be a lack of sensitivity of /velocities/vertical-speed-fpm (FDM ?). This new IVSI : - Is an emulation with works with environment pressure : a real IVSI works with static pressure (with lag) + accelerometers. It is not forbidden to later upgrade to the real model. - Doesn't require a tuning of the autopilot made with /velocities/vertical-speed-fpm (also tested with 737, 747) : Concorde's autoland works without update. --- diff --git a/src/Instrumentation/Makefile.am b/src/Instrumentation/Makefile.am index 949da0e20..44dd3c1f6 100644 --- a/src/Instrumentation/Makefile.am +++ b/src/Instrumentation/Makefile.am @@ -21,6 +21,7 @@ libInstrumentation_a_SOURCES = \ slip_skid_ball.cxx slip_skid_ball.hxx \ transponder.cxx transponder.hxx \ turn_indicator.cxx turn_indicator.hxx \ - vertical_speed_indicator.cxx vertical_speed_indicator.hxx + vertical_speed_indicator.cxx vertical_speed_indicator.hxx \ + inst_vertical_speed_indicator.cxx inst_vertical_speed_indicator.hxx INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src diff --git a/src/Instrumentation/inst_vertical_speed_indicator.cxx b/src/Instrumentation/inst_vertical_speed_indicator.cxx new file mode 100644 index 000000000..81c746306 --- /dev/null +++ b/src/Instrumentation/inst_vertical_speed_indicator.cxx @@ -0,0 +1,254 @@ +// inst_vertical_speed_indicator.cxx +// -- Instantaneous VSI (emulation calibrated to standard atmosphere). +// +// Started September 2004. +// +// Copyright (C) 2004 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#include + +#include "inst_vertical_speed_indicator.hxx" +#include
+#include
+ + +// Altitude based on pressure difference from sea level. +// +// See http://www.pdas.com/programs/atmos.f90, the tables match exactly +// environment.cxx (Standard 1976). +// Example : +// - at 27900 m the level is 20 km : +// geopotential altitude 27.9 x 6369 / ( 27.9 + 6369) = 27.778 km. +// - deltah = 27.778 - 20 = 7.778 km and tbase 216.65 degK. +// - delta = 5.403295E-2 x exp( -34.163195 x 7.778 / 216.65 ) = 0.016. +// - pressure = (1 - delta ) x 29.92 = 29.44 inhg. +// - to construct the tables, round delta to 3 digits. + +// altitude ft, pressure step inHG +static double pressure_data[][2] = { + { 0.00, 3.33 }, // guess ! + { 2952.76, 3.05 }, + { 5905.51, 2.81 }, + { 8858.27, 2.55 }, + { 11811.02, 2.33 }, + { 14763.78, 2.13 }, + { 17716.54, 1.91 }, + { 20669.29, 1.77 }, + { 23622.05, 1.58 }, + { 26574.80, 1.49 }, + { 29527.56, 1.20 }, + { 32480.31, 1.14 }, + { 35433.07, 1.05 }, + { 38385.83, 0.90 }, + { 41338.58, 0.80 }, + { 44291.34, 0.69 }, + { 47244.09, 0.60 }, + { 50196.85, 0.51 }, + { 53149.61, 0.45 }, + { 56102.36, 0.39 }, + { 59055.12, 0.33 }, + { 62007.87, 0.30 }, + { 64960.63, 0.26 }, + { 67913.39, 0.21 }, + { 70866.14, 0.18 }, + { 73818.90, 0.18 }, + { 76771.65, 0.15 }, + { 79724.41, 0.12 }, + { 82677.17, 0.12 }, + { 85629.92, 0.09 }, + { 88582.68, 0.09 }, + { 91535.43, 0.06 }, + { 94488.19, 0.06 }, + { 97440.94, 0.06 }, + { 100393.70, 0.06 }, + { -1, -1 } +}; + +// pressure difference inHG, altitude ft +static double altitude_data[][2] = { + { 0.00, 0.00 }, + { 3.05, 2952.76 }, + { 5.86, 5905.51 }, + { 8.41, 8858.27 }, + { 10.74, 11811.02 }, + { 12.87, 14763.78 }, + { 14.78, 17716.54 }, + { 16.55, 20669.29 }, + { 18.13, 23622.05 }, + { 19.62, 26574.80 }, + { 20.82, 29527.56 }, + { 21.96, 32480.31 }, + { 23.01, 35433.07 }, + { 23.91, 38385.83 }, + { 24.71, 41338.58 }, + { 25.40, 44291.34 }, + { 26.00, 47244.09 }, + { 26.51, 50196.85 }, + { 26.96, 53149.61 }, + { 27.35, 56102.36 }, + { 27.68, 59055.12 }, + { 27.98, 62007.87 }, + { 28.24, 64960.63 }, + { 28.45, 67913.39 }, + { 28.63, 70866.14 }, + { 28.81, 73818.90 }, + { 28.96, 76771.65 }, + { 29.08, 79724.41 }, + { 29.20, 82677.17 }, + { 29.29, 85629.92 }, + { 29.38, 88582.68 }, + { 29.44, 91535.43 }, + { 29.50, 94488.19 }, + { 29.56, 97440.94 }, + { 29.62, 100393.70 }, + { -1, -1 } +}; + + +// SI constants +#define SEA_LEVEL_INHG 29.92 + +// A higher number means more responsive. +#define RESPONSIVENESS 5.0 + +// External environment +#define MAX_INHG_PER_S 0.0002 + + +InstVerticalSpeedIndicator::InstVerticalSpeedIndicator ( SGPropertyNode *node ) : + _internal_pressure_inhg( SEA_LEVEL_INHG ), + _internal_sea_inhg( SEA_LEVEL_INHG ), + _pressure_table(new SGInterpTable), + _altitude_table(new SGInterpTable), + _speed_ft_per_s( 0 ) +{ + for (int i = 0; pressure_data[i][0] != -1; i++) + _pressure_table->addEntry( pressure_data[i][0], pressure_data[i][1] ); + + for (int i = 0; altitude_data[i][0] != -1; i++) + _altitude_table->addEntry( altitude_data[i][0], altitude_data[i][1] ); + + int i; + for ( i = 0; i < node->nChildren(); ++i ) { + SGPropertyNode *child = node->getChild(i); + string cname = child->getName(); + string cval = child->getStringValue(); + if ( cname == "name" ) { + name = cval; + } else if ( cname == "number" ) { + num = child->getIntValue(); + } else { + SG_LOG( SG_INSTR, SG_WARN, "Error in inst-vertical-speed-indicator config logic" ); + if ( name.length() ) { + SG_LOG( SG_INSTR, SG_WARN, "Section = " << name ); + } + } + } +} + + +InstVerticalSpeedIndicator::~InstVerticalSpeedIndicator () +{ + delete _pressure_table; + delete _altitude_table; +} + + +void InstVerticalSpeedIndicator::init () +{ + _serviceable_node = + fgGetNode("/instrumentation/inst-vertical-speed-indicator/serviceable", true); + _freeze_node = + fgGetNode("/sim/freeze/master", true); + + // A real IVSI is operated by static pressure changes. + // It operates like a conventional VSI, except that an internal sensor + // detects load factors, to momentarily alters the static pressure + // (with lag). + // It appears lag free at subsonic speed; at high altitude indication may + // be less than 1/3 of actual conditions. + _pressure_node = + fgGetNode("/environment/pressure-inhg", true); + _sea_node = + fgGetNode("/environment/pressure-sea-level-inhg", true); + _speed_up_node = + fgGetNode("/sim/speed-up", true); + _speed_node = + fgGetNode("/instrumentation/inst-vertical-speed-indicator/indicated-speed-fps", + true); + _speed_min_node = + fgGetNode("/instrumentation/inst-vertical-speed-indicator/indicated-speed-fpm", + true); + + // Initialize at ambient pressure + _internal_pressure_inhg = _pressure_node->getDoubleValue(); +} + + +void InstVerticalSpeedIndicator::update (double dt) +{ + if (_serviceable_node->getBoolValue()) + { + // avoids hang, when freeze + if( !_freeze_node->getBoolValue() ) + { + double pressure_inhg = _pressure_node->getDoubleValue(); + double sea_inhg = _sea_node->getDoubleValue(); + double speed_up = _speed_up_node->getDoubleValue(); + + // must work by speed up + if( speed_up > 1 ) + { + dt *= speed_up; + } + + // limit effect of external environment + double rate_sea_inhg_per_s = ( sea_inhg - _internal_sea_inhg ) / dt; + + if( rate_sea_inhg_per_s > - MAX_INHG_PER_S && rate_sea_inhg_per_s < MAX_INHG_PER_S ) + { + double rate_inhg_per_s = ( pressure_inhg - _internal_pressure_inhg ) / dt; + + // IVSI determines alone the current altitude, without altimeter setting. + // Altimeter setting is 29.92 above 10000 or 18000 ft. + // Below this level, the slope is slightly wrong. + double altitude_ft = _altitude_table->interpolate( SEA_LEVEL_INHG - pressure_inhg ); + double slope_inhg = _pressure_table->interpolate( altitude_ft ); + + + double last_speed_ft_per_s = _speed_ft_per_s; + + // slope at 900 m + _speed_ft_per_s = - rate_inhg_per_s * 2952.75591 / slope_inhg; + + // filter noise + _speed_ft_per_s = fgGetLowPass( last_speed_ft_per_s, _speed_ft_per_s, + dt * RESPONSIVENESS ); + } + + _speed_node->setDoubleValue( _speed_ft_per_s ); + _speed_min_node->setDoubleValue( _speed_ft_per_s * 60.0 ); + + // backup + _internal_pressure_inhg = pressure_inhg; + _internal_sea_inhg = sea_inhg; + } + } +} + +// end of inst_vertical_speed_indicator.cxx diff --git a/src/Instrumentation/inst_vertical_speed_indicator.hxx b/src/Instrumentation/inst_vertical_speed_indicator.hxx new file mode 100644 index 000000000..856aacda7 --- /dev/null +++ b/src/Instrumentation/inst_vertical_speed_indicator.hxx @@ -0,0 +1,85 @@ +// inst_vertical_speed_indicator.hxx -- Instantaneous VSI (emulation calibrated to standard atmosphere). +// +// Started September 2004. +// +// Copyright (C) 2004 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 2 of the +// License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// + +#ifndef __INST_VERTICAL_SPEED_INDICATOR_HXX +#define __INST_VERTICAL_SPEED_INDICATOR_HXX 1 + +#ifndef __cplusplus +# error This library requires C++ +#endif + +#include +#include + + +class SGInterpTable; + + +/** + * Model an instantaneous VSI tied to the external pressure. + * + * Input properties: + * + * /instrumentation/inst-vertical-speed-indicator/serviceable + * /environment/pressure-inhg + * /environment/pressure-sea-level-inhg + * /sim/speed-up + * /sim/freeze/master + * + * Output properties: + * + * /instrumentation/inst-vertical-speed-indicator/indicated-speed-fps + * /instrumentation/inst-vertical-speed-indicator/indicated-speed-fpm + */ +class InstVerticalSpeedIndicator : public SGSubsystem +{ + +public: + + InstVerticalSpeedIndicator ( SGPropertyNode *node ); + virtual ~InstVerticalSpeedIndicator (); + + virtual void init (); + virtual void update (double dt); + +private: + + double _internal_pressure_inhg; + double _internal_sea_inhg; + + double _speed_ft_per_s; + + string name; + int num; + + SGPropertyNode_ptr _serviceable_node; + SGPropertyNode_ptr _freeze_node; + SGPropertyNode_ptr _pressure_node; + SGPropertyNode_ptr _sea_node; + SGPropertyNode_ptr _speed_up_node; + SGPropertyNode_ptr _speed_node; + SGPropertyNode_ptr _speed_min_node; + + SGInterpTable * _pressure_table; + SGInterpTable * _altitude_table; +}; + +#endif // __INST_VERTICAL_SPEED_INDICATOR_HXX diff --git a/src/Instrumentation/instrument_mgr.cxx b/src/Instrumentation/instrument_mgr.cxx index 85e8b8779..603b24af1 100644 --- a/src/Instrumentation/instrument_mgr.cxx +++ b/src/Instrumentation/instrument_mgr.cxx @@ -35,6 +35,7 @@ #include "transponder.hxx" #include "turn_indicator.hxx" #include "vertical_speed_indicator.hxx" +#include "inst_vertical_speed_indicator.hxx" // (TJ) FGInstrumentMgr::FGInstrumentMgr () @@ -147,6 +148,9 @@ bool FGInstrumentMgr::build () } else if ( name == "vertical-speed-indicator" ) { set_subsystem( "instrument" + temp.str(), new VerticalSpeedIndicator( node ) ); + } else if ( name == "inst-vertical-speed-indicator" ) { // (TJ) + set_subsystem( "instrument" + temp.str(), + new InstVerticalSpeedIndicator( node ) ); } else { SG_LOG( SG_ALL, SG_ALERT, "Unknown top level section: " << name );