#include <simgear/misc/props.hxx>
#include <Aircraft/aircraft.hxx>
#include <Main/bfi.hxx>
-#include <Main/globals.hxx>
#include <NetworkOLK/features.hxx>
FG_USING_NAMESPACE(std);
double FGSteam::the_STATIC_inhg = 29.92;
-double FGSteam::the_ALT_ft = 0.0;
+double FGSteam::the_ALT_ft = 0.0; // Indicated altitude
double FGSteam::get_ALT_ft() { _CatchUp(); return the_ALT_ft; }
+double FGSteam::the_ALT_datum_mb = 1013.0;
+double FGSteam::get_ALT_datum_mb() { return the_ALT_datum_mb; }
+
+void FGSteam::set_ALT_datum_mb ( double datum_mb ) {
+ the_ALT_datum_mb = datum_mb;
+}
+
double FGSteam::get_ASI_kias() { return FGBFI::getAirspeed(); }
double FGSteam::the_VSI_case = 29.92;
int FGSteam::_UpdatesPending = 1000000; /* Forces filter to reset */
+ // FIXME: no need to use static
+ // functions any longer.
+
void FGSteam::update ( int timesteps )
{
if (!isTied) {
isTied = true;
- current_properties.tieDouble("/steam/airspeed",
- FGSteam::get_ASI_kias);
- current_properties.tieDouble("/steam/altitude",
- FGSteam::get_ALT_ft);
- current_properties.tieDouble("/steam/turn-rate",
- FGSteam::get_TC_std);
- current_properties.tieDouble("/steam/slip-skid",
- FGSteam::get_TC_rad);
- current_properties.tieDouble("/steam/vertical-speed",
- FGSteam::get_VSI_fps);
- current_properties.tieDouble("/steam/gyro-compass",
- FGSteam::get_DG_deg);
- current_properties.tieDouble("/steam/vor1",
- FGSteam::get_HackVOR1_deg);
- current_properties.tieDouble("/steam/vor2",
- FGSteam::get_HackVOR2_deg);
- current_properties.tieDouble("/steam/glidescope1",
- FGSteam::get_HackGS_deg);
- current_properties.tieDouble("/steam/adf",
- FGSteam::get_HackADF_deg);
- current_properties.tieDouble("/steam/gyro-compass-error",
- FGSteam::get_DG_err,
- FGSteam::set_DG_err);
- current_properties.tieDouble("/steam/mag-compass",
- FGSteam::get_MH_deg);
+ fgTie("/steam/airspeed", FGSteam::get_ASI_kias);
+ fgTie("/steam/altitude", FGSteam::get_ALT_ft);
+ fgTie("/steam/altimeter-datum-mb",
+ FGSteam::get_ALT_datum_mb, FGSteam::set_ALT_datum_mb,
+ false); /* don't modify the value */
+ fgTie("/steam/turn-rate", FGSteam::get_TC_std);
+ fgTie("/steam/slip-skid", FGSteam::get_TC_rad);
+ fgTie("/steam/vertical-speed", FGSteam::get_VSI_fps);
+ fgTie("/steam/gyro-compass", FGSteam::get_DG_deg);
+ fgTie("/steam/adf", FGSteam::get_HackADF_deg);
+ fgTie("/steam/gyro-compass-error",
+ FGSteam::get_DG_err, FGSteam::set_DG_err,
+ false); /* don't modify the value */
+ fgTie("/steam/mag-compass", FGSteam::get_MH_deg);
}
_UpdatesPending += timesteps;
}
+/* tc should be (elapsed_time_between_updates / desired_smoothing_time) */
void FGSteam::set_lowpass ( double *outthe, double inthe, double tc )
{
if ( tc < 0.0 )
}
} else
if ( tc < 0.2 )
- { /* Normal mode of operation */
+ { /* Normal mode of operation; fast approximation to exp(-tc) */
(*outthe) = (*outthe) * ( 1.0 - tc )
+ inthe * tc;
} else
}
+#define INHG_TO_MB 33.86388 /* Inches_of_mercury * INHG_TO_MB == millibars. */
+
+// Convert air pressure to altitude by ICAO Standard Atmosphere
+double pressInHgToAltFt(double p_inhg)
+{
+ // Ref. Aviation Formulary, Ed Williams, www.best.com/~williams/avform.htm
+ const double P_0 = 29.92126; // Std. MSL pressure, inHg. (=1013.25 mb)
+ const double p_Tr = 0.2233609 * P_0; // Pressure at tropopause, same units.
+ const double h_Tr = 36089.24; // Alt of tropopause, ft. (=11.0 km)
+
+ if (p_inhg > p_Tr) // 0.0 to 11.0 km
+ return (1.0 - pow((p_inhg / P_0), 1.0 / 5.2558797)) / 6.8755856e-6;
+ return h_Tr + log10(p_inhg / p_Tr) / -4.806346e-5; // 11.0 to 20.0 km
+ // We could put more code for higher altitudes here.
+}
+
+
+// Convert altitude to air pressure by ICAO Standard Atmosphere
+double altFtToPressInHg(double alt_ft)
+{
+ // Ref. Aviation Formulary, Ed Williams, www.best.com/~williams/avform.htm
+ const double P_0 = 29.92126; // Std. MSL pressure, inHg. (=1013.25 mb)
+ const double p_Tr = 0.2233609 * P_0; // Pressure at tropopause, same units.
+ const double h_Tr = 36089.24; // Alt of tropopause, ft. (=11.0 km)
+
+ if (alt_ft < h_Tr) // 0.0 to 11.0 km
+ return P_0 * pow(1.0 - 6.8755856e-6 * alt_ft, 5.2558797);
+ return p_Tr * exp(-4.806346e-5 * (alt_ft - h_Tr)); // 11.0 to 20.0 km
+ // We could put more code for higher altitudes here.
+}
+
+
\f
////////////////////////////////////////////////////////////////////////
// Here the fun really begins
void FGSteam::_CatchUp()
{ if ( _UpdatesPending != 0 )
{ double dt = _UpdatesPending * 1.0 /
- globals->get_options()->get_model_hz();
+ fgGetInt("/sim/model-hz"); // FIXME: inefficient
double AccN, AccE, AccU;
int i /*,j*/;
double d, the_ENGINE_rpm;
scaling capability for the vacuum pump later on.
When we have a real engine model, we can ask it.
*/
- the_ENGINE_rpm = FGBFI::getThrottle() * 26.0;
-
- /**************************
- This is just temporary, until the static source works,
- so we just filter the actual value by one second to
- account for the line impedance of the plumbing.
- */
- set_lowpass ( & the_ALT_ft, FGBFI::getAltitude(), dt );
+ the_ENGINE_rpm = controls.get_throttle(0) * 26.0;
/**************************
First, we need to know what the static line is reporting,
which is a whole simulation area in itself. For now, we cheat.
+ We filter the actual value by one second to
+ account for the line impedance of the plumbing.
*/
- the_STATIC_inhg = 29.92;
- i = (int) the_ALT_ft;
- while ( i > 9000 )
- { the_STATIC_inhg *= 0.707;
- i -= 9000;
- }
- the_STATIC_inhg *= ( 1.0 - 0.293 * i / 9000.0 );
+ double static_inhg = altFtToPressInHg(FGBFI::getAltitude());
+ set_lowpass ( & the_STATIC_inhg, static_inhg, dt );
/*
NO alternate static source error (student feature),
NO slip-induced error, important for C172 for example.
*/
+ /**************************
+ Altimeter.
+ ICAO standard atmosphere MSL pressure is 1013.25 mb, and pressure
+ gradient is about 28 ft per mb at MSL increasing to about 32 at
+ 5000 and 38 at 10000 ft.
+ Standard altimeters apply the subscale offset to the output altitude,
+ not to the input pressure; I don't know exactly what pressure gradient
+ they assume for this. I choose to make it accurate at low altitudes.
+ Remember, we are trying to simulate a real altimeter, not an ideal one.
+ */
+ set_lowpass ( & the_ALT_ft,
+ pressInHgToAltFt(the_STATIC_inhg) +
+ (the_ALT_datum_mb - 1013.25) * 28.0, /* accurate at low alt. */
+ dt * 10 ); /* smoothing time 0.1 s */
+
/**************************
The VSI case is a low-pass filter of the static line pressure.
The instrument reports the difference, scaled to approx ft.
////////////////////////////////////////////////////////////////////////
+#if 0
+
double FGSteam::get_HackGS_deg () {
if ( current_radiostack->get_nav1_inrange() &&
current_radiostack->get_nav1_has_gs() )
double r;
if ( current_radiostack->get_nav1_inrange() ) {
- if ( current_radiostack->get_nav1_loc() ) {
- // localizer doesn't need magvar offset
- r = current_radiostack->get_nav1_heading()
- - current_radiostack->get_nav1_radial();
- } else {
- r = current_radiostack->get_nav1_heading() - FGBFI::getMagVar()
- - current_radiostack->get_nav1_radial();
- }
+ r = current_radiostack->get_nav1_heading()
+ - current_radiostack->get_nav1_radial();
// cout << "Radial = " << current_radiostack->get_nav1_radial()
// << " Bearing = " << current_radiostack->get_nav1_heading()
// << endl;
double r;
if ( current_radiostack->get_nav2_inrange() ) {
- if ( current_radiostack->get_nav2_loc() ) {
- // localizer doesn't need magvar offset
- r = current_radiostack->get_nav2_heading()
- - current_radiostack->get_nav2_radial();
- } else {
- r = current_radiostack->get_nav2_heading() - FGBFI::getMagVar()
- - current_radiostack->get_nav2_radial();
- }
+ r = current_radiostack->get_nav2_heading()
+ - current_radiostack->get_nav2_radial();
// cout << "Radial = " << current_radiostack->get_nav1_radial()
// << " Bearing = " << current_radiostack->get_nav1_heading() << endl;
return r;
}
+#endif
double FGSteam::get_HackOBS1_deg () {