FlightGear next
vertical_speed_indicator.cxx
Go to the documentation of this file.
1// vertical_speed_indicator.cxx - a regular VSI.
2// Written by David Megginson, started 2002.
3//
4// Last change by E. van den Berg, 17.02.1013
5//
6// This file is in the Public Domain and comes with no warranty.
7
8#ifdef HAVE_CONFIG_H
9# include "config.h"
10#endif
11
12#include <simgear/constants.h>
13#include <simgear/math/interpolater.hxx>
14
16#include <Main/fg_props.hxx>
17#include <Main/util.hxx>
18
19//** NOTE: do not change these values. If you change one of them the others need to be changed too */
20//** these values calibrate the VSI at SL. */
21#define Vol_casing 1.25e-4 //m3
22#define A_orifice 7.853982e-9 //m2
23#define Factor_cal 189.145628 //-
24
25using std::string;
26
28 : _casing_pressure_Pa(101325),
29 _name(node->getStringValue("name", "vertical-speed-indicator")),
30 _num(node->getIntValue("number", 0)),
31 _static_pressure(node->getStringValue("static-pressure", "/systems/static/pressure-inhg")),
32 _static_temperature(node->getStringValue("static-temperature", "/environment/temperature-degc"))
33{
34}
35
39
40void
42{
43 string branch;
44 branch = "/instrumentation/" + _name;
45
46 SGPropertyNode *node = fgGetNode(branch, _num, true );
47 _serviceable_node = node->getChild("serviceable", 0, true);
48 _pressure_node = fgGetNode(_static_pressure, true);
49 _temperature_node = fgGetNode(_static_temperature, true);
50 _speed_fpm_node = node->getChild("indicated-speed-fpm", 0, true);
51 _speed_mps_node = node->getChild("indicated-speed-mps", 0, true);
52 _speed_kts_node = node->getChild("indicated-speed-kts", 0, true);
53
54 reinit();
55}
56
57void
59{
60 // Initialize at ambient conditions
61 double casing_pressure_inHg = _pressure_node->getDoubleValue();
62 _casing_pressure_Pa = casing_pressure_inHg * SG_INHG_TO_PA;
63 double casing_temperature_C = _temperature_node->getDoubleValue();
64 double casing_temperature_K = casing_temperature_C + 273.15;
65 _casing_density_kgpm3 = _casing_pressure_Pa / (casing_temperature_K * SG_R_m2_p_s2_p_K);
66 _casing_airmass_kg = _casing_density_kgpm3 * Vol_casing;
67 _orifice_massflow_kgps = 0.0;
68}
69
70void
72{
73 if (_serviceable_node->getBoolValue()) {
74 const double pressure_inHg = _pressure_node->getDoubleValue() ;
75 const double pressure_Pa = pressure_inHg * SG_INHG_TO_PA;
76
77 // this occurs if the static pressure source didn't report valid data
78 // yet. Don't continue processing here since we will generate NaNs
79 // when dividing by zero
80 if (_casing_pressure_Pa < 1e-3) {
81 if (pressure_Pa > 1e3) {
82 // once the pressure becomes valid, reinit
83 reinit();
84 } else {
85 return; // no more processing
86 }
87 }
88
89 double Fsign = 0.;
90 double orifice_mach = 0.0;
91
92// This is a thermodynamically correct model of a mechanical vertical speed indicator:
93// It represents an aneroid in a closed (constant volume) casing with the aneroid internal pressure = static pressure
94// The casing has an orifice to static pressure
95// the mass flow through the orifice is calculated using compressible aerodynamics (but adiabatic and of course a perfect gas)
96// using the pressure in the casing and static pressure
97//
98// sadly at very low flows (small VS) in conjunction with the fact discrete timesteps (dt) are used, a numerical instability is formed.
99// this is counteracted by setting the massflow 0 at very small pressure differentials
100// this causes a small funny jump of your VSI when passing through 0...cannot be helped!
101//
102// also note the calibration is only valid for 0ft, so at higher altitudes, the vertical speed is not correct, but would indicate as a real mechanical VSI.
103// Only use for conventional mechanical VSI-s. Dont use in an Air Data Computer.
104//
105// (...and it is supposed to lag!)
106
107 _casing_airmass_kg = _casing_airmass_kg - _orifice_massflow_kgps * dt;
108 double new_density_kgpm3 = _casing_airmass_kg / Vol_casing;
109 _casing_pressure_Pa = _casing_pressure_Pa * pow(new_density_kgpm3 / _casing_density_kgpm3 , SG_gamma);
110 double casing_temperature_K = _casing_pressure_Pa / (new_density_kgpm3 * SG_R_m2_p_s2_p_K);
111
112 if( _casing_pressure_Pa - pressure_Pa > 0.0 ) {
113 Fsign = 1.0; //outflow, pos VS
114 } else {
115 Fsign = -1.0; //inflow, neg VS
116 }
117
118 if( fabs(_casing_pressure_Pa - pressure_Pa) < 0.01 ) {
119 orifice_mach = 0.0;
120 } else {
121 orifice_mach = sqrt(fabs (2.0*SG_cp_m2_p_s2_p_K / (SG_gamma * SG_R_m2_p_s2_p_K) * ( pow(pressure_Pa / _casing_pressure_Pa ,(SG_gamma-1)/SG_gamma ) -1 ) ) );
122 }
123
124 _orifice_massflow_kgps = Fsign * _casing_pressure_Pa / sqrt(casing_temperature_K) * sqrt(SG_gamma/SG_R_m2_p_s2_p_K) * orifice_mach * pow(1+(SG_gamma-1)/2*orifice_mach*orifice_mach,-(SG_gamma+1)/(2*(SG_gamma-1))) * A_orifice;
125
126 double vs_fpm = Fsign * sqrt( fabs( pressure_Pa - _casing_pressure_Pa ) ) * Factor_cal;
127 double vs_kts = vs_fpm / 60 * SG_FPS_TO_KT;
128 double vs_mps = vs_fpm / 60 * SG_FEET_TO_METER;
129
130 _speed_fpm_node
131 ->setDoubleValue(vs_fpm);
132 _speed_kts_node
133 ->setDoubleValue(vs_kts);
134 _speed_mps_node
135 ->setDoubleValue(vs_mps);
136
137 _casing_density_kgpm3 = new_density_kgpm3;
138
139 }
140}
141
142
143// Register the subsystem.
144#if 0
145SGSubsystemMgr::InstancedRegistrant<VerticalSpeedIndicator> registrantVerticalSpeedIndicator(
146 SGSubsystemMgr::FDM,
147 {{"instrumentation", SGSubsystemMgr::Dependency::HARD}});
148#endif
149
150// end of vertical_speed_indicator.cxx
VerticalSpeedIndicator(SGPropertyNode *node)
void update(double dt) override
SGPropertyNode * fgGetNode(const char *path, bool create)
Get a property node.
Definition proptest.cpp:27
#define Vol_casing
#define Factor_cal
#define A_orifice