#include <simgear/constants.h>
#include <simgear/math/fg_types.hxx>
+#include <Aircraft/aircraft.hxx>
#include <Main/options.hxx>
#include <Main/bfi.hxx>
+#include <NetworkOLK/features.hxx>
FG_USING_NAMESPACE(std);
+#include "radiostack.hxx"
#include "steam.hxx"
double FGSteam::the_VSI_fps = 0.0;
double FGSteam::get_VSI_fps() { _CatchUp(); return the_VSI_fps; }
-double FGSteam::get_MH_deg () { return FGBFI::getHeading (); }
-double FGSteam::get_DG_deg () { return FGBFI::getHeading (); }
+double FGSteam::the_VACUUM_inhg = 0.0;
+double FGSteam::get_VACUUM_inhg() { _CatchUp(); return the_VACUUM_inhg; }
-double FGSteam::get_TC_rad () { return FGBFI::getSideSlip (); }
-double FGSteam::get_TC_radps () { return FGBFI::getRoll (); }
+double FGSteam::the_MH_err = 0.0;
+double FGSteam::the_MH_deg = 0.0;
+double FGSteam::the_MH_degps = 0.0;
+double FGSteam::get_MH_deg () { _CatchUp(); return the_MH_deg; }
+double FGSteam::the_DG_deg = 0.0;
+double FGSteam::the_DG_degps = 0.0;
+double FGSteam::the_DG_inhg = 0.0;
+double FGSteam::get_DG_deg () { _CatchUp(); return the_DG_deg; }
+
+double FGSteam::the_TC_rad = 0.0;
+double FGSteam::the_TC_std = 0.0;
+double FGSteam::get_TC_rad () { _CatchUp(); return the_TC_rad; }
+double FGSteam::get_TC_std () { _CatchUp(); return the_TC_std; }
\f
////////////////////////////////////////////////////////////////////////
(*outthe) = (*outthe) * ( 1.0 - tc )
+ inthe * tc;
} else
- if ( tc > 5 )
+ if ( tc > 5.0 )
{ /* Huge time step; assume filter has settled */
(*outthe) = inthe;
} else
{ /* Moderate time step; non linear response */
- tc = exp ( -tc );
- (*outthe) = (*outthe) * ( 1.0 - tc )
- + inthe * tc;
+ double keep = exp ( -tc );
+ // printf ( "ARP: Keep is %f\n", keep );
+ (*outthe) = (*outthe) * keep
+ + inthe * ( 1.0 - keep );
}
}
void FGSteam::_CatchUp()
{ if ( _UpdatesPending != 0 )
{ double dt = _UpdatesPending * 1.0 / current_options.get_model_hz();
+ double AccN, AccE, AccU;
int i,j;
- double d;
- /*
- Someone has called our update function and we haven't
- incorporated this into our instrument modelling yet
+ double d, the_ENGINE_rpm;
+
+#if 0
+ /**************************
+ There is the possibility that this is the first call.
+ If this is the case, we will emit the feature registrations
+ just to be on the safe side. Doing it more than once will
+ waste CPU time but doesn't hurt anything really.
+ */
+ if ( _UpdatesPending == 999 )
+ { FGFeature::register_int ( "Avionics/NAV1/Localizer", &NAV1_LOC );
+ FGFeature::register_double ( "Avionics/NAV1/Latitude", &NAV1_Lat );
+ FGFeature::register_double ( "Avionics/NAV1/Longitude", &NAV1_Lon );
+ FGFeature::register_double ( "Avionics/NAV1/Radial", &NAV1_Rad );
+ FGFeature::register_double ( "Avionics/NAV1/Altitude", &NAV1_Alt );
+ FGFeature::register_int ( "Avionics/NAV2/Localizer", &NAV2_LOC );
+ FGFeature::register_double ( "Avionics/NAV2/Latitude", &NAV2_Lat );
+ FGFeature::register_double ( "Avionics/NAV2/Longitude", &NAV2_Lon );
+ FGFeature::register_double ( "Avionics/NAV2/Radial", &NAV2_Rad );
+ FGFeature::register_double ( "Avionics/NAV2/Altitude", &NAV2_Alt );
+ FGFeature::register_double ( "Avionics/ADF/Latitude", &ADF_Lat );
+ FGFeature::register_double ( "Avionics/ADF/Longitude", &ADF_Lon );
+ }
+#endif
+
+ /**************************
+ Someone has called our update function and
+ it turns out that we are running somewhat behind.
+ Here, we recalculate everything for a 'dt' second step.
+ */
+
+ /**************************
+ The ball responds to the acceleration vector in the body
+ frame, only the components perpendicular to the longitudinal
+ axis of the aircraft. This is only related to actual
+ side slip for a symmetrical aircraft which is not touching
+ the ground and not changing its attitude. Math simplifies
+ by assuming (for small angles) arctan(x)=x in radians.
+ Obvious failure mode is the absence of liquid in the
+ tube, which is there to damp the motion, so that instead
+ the ball will bounce around, hitting the tube ends.
+ More subtle flaw is having it not move or a travel limit
+ occasionally due to some dirt in the tube or on the ball.
+ */
+ // the_TC_rad = - ( FGBFI::getSideSlip () ); /* incorrect */
+ d = - current_aircraft.fdm_state->get_A_Z_pilot();
+ if ( d < 1 ) d = 1;
+ set_lowpass ( & the_TC_rad,
+ current_aircraft.fdm_state->get_A_Y_pilot () / d,
+ dt );
+
+ /**************************
+ The rate of turn indication is from an electric gyro.
+ We should have it spin up with the master switch.
+ It is mounted at a funny angle so that it detects
+ both rate of bank (i.e. rolling into and out of turns)
+ and the rate of turn (i.e. how fast heading is changing).
*/
+ set_lowpass ( & the_TC_std,
+ current_aircraft.fdm_state->get_Phi_dot ()
+ * RAD_TO_DEG / 20.0 +
+ current_aircraft.fdm_state->get_Psi_dot ()
+ * RAD_TO_DEG / 3.0 , dt );
+
+ /**************************
+ We want to know the pilot accelerations,
+ to compute the magnetic compass errors.
+ */
+ AccN = current_aircraft.fdm_state->get_V_dot_north();
+ AccE = current_aircraft.fdm_state->get_V_dot_east();
+ AccU = current_aircraft.fdm_state->get_V_dot_down()
+ - 9.81 / 0.3;
+ if ( fabs(the_TC_rad) > 0.2 )
+ { /* Massive sideslip jams it; it stops turning */
+ the_MH_degps = 0.0;
+ the_MH_err = FGBFI::getHeading () - the_MH_deg;
+ } else
+ { double MagDip, MagVar, CosDip;
+ double FrcN, FrcE, FrcU, AccTot;
+ double EdgN, EdgE, EdgU;
+ double TrqN, TrqE, TrqU, Torque;
+ /* Find a force vector towards exact magnetic north */
+ MagVar = FGBFI::getMagVar() / RAD_TO_DEG;
+ MagDip = FGBFI::getMagDip() / RAD_TO_DEG;
+ CosDip = cos ( MagDip );
+ FrcN = CosDip * cos ( MagVar );
+ FrcE = CosDip * sin ( MagVar );
+ FrcU = sin ( MagDip );
+ /* Rotation occurs around acceleration axis,
+ but axis magnitude is irrelevant. So compute it. */
+ AccTot = AccN*AccN + AccE*AccE + AccU*AccU;
+ if ( AccTot > 1.0 ) AccTot = sqrt ( AccTot );
+ else AccTot = 1.0;
+ /* Force applies to north marking on compass card */
+ EdgN = cos ( the_MH_err / RAD_TO_DEG );
+ EdgE = sin ( the_MH_err / RAD_TO_DEG );
+ EdgU = 0.0;
+ /* Apply the force to the edge to get torques */
+ TrqN = EdgE * FrcU - EdgU * FrcE;
+ TrqE = EdgU * FrcN - EdgN * FrcU;
+ TrqU = EdgN * FrcE - EdgE * FrcN;
+ /* Select the component parallel to the axis */
+ Torque = ( TrqN * AccN +
+ TrqE * AccE +
+ TrqU * AccU ) * 5.0 / AccTot;
+ /* The magnetic compass has angular momentum,
+ so we apply a torque to it and wait */
+ if ( dt < 1.0 )
+ { the_MH_degps= the_MH_degps * (1.0 - dt) - Torque;
+ the_MH_err += dt * the_MH_degps;
+ }
+ if ( the_MH_err > 180.0 ) the_MH_err -= 360.0; else
+ if ( the_MH_err < -180.0 ) the_MH_err += 360.0;
+ the_MH_deg = FGBFI::getHeading () - the_MH_err;
+ }
/**************************
- This is just temporary
+ This is not actually correct, but provides a
+ scaling capability for the vacuum pump later on.
+ When we have a real engine model, we can ask it.
*/
- the_ALT_ft = FGBFI::getAltitude();
+ 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 );
/**************************
First, we need to know what the static line is reporting,
*/
the_STATIC_inhg = 29.92;
i = (int) the_ALT_ft;
- while ( i > 18000 )
- { the_STATIC_inhg /= 2;
- i -= 18000;
+ while ( i > 9000 )
+ { the_STATIC_inhg *= 0.707;
+ i -= 9000;
}
- the_STATIC_inhg /= ( 1.0 + i / 18000.0 );
+ the_STATIC_inhg *= ( 1.0 - 0.293 * i / 9000.0 );
/*
NO alternate static source error (student feature),
NO capability for a fixed non-zero reading when level.
NO capability to have a scaling error of maybe a factor of two.
*/
- set_lowpass ( & the_VSI_case, the_STATIC_inhg, dt/9.0 );
the_VSI_fps = ( the_VSI_case - the_STATIC_inhg )
- * 7000.0; /* manual scaling factor */
+ * 10000.0; /* manual scaling factor */
+ set_lowpass ( & the_VSI_case, the_STATIC_inhg, dt/6.0 );
+
+ /**************************
+ The engine driven vacuum pump is directly attached
+ to the engine shaft, so each engine rotation pumps
+ a fixed volume. The amount of air in that volume
+ is determined by the vacuum line's internal pressure.
+ The instruments are essentially leaking air like
+ a fixed source impedance from atmospheric pressure.
+ The regulator provides a digital limit setting,
+ which is open circuit unless the pressure drop is big.
+ Thus, we can compute the vacuum line pressure directly.
+ We assume that there is negligible reservoir space.
+ NO failure of the pump supported (yet)
+ */
+ the_VACUUM_inhg = the_STATIC_inhg *
+ the_ENGINE_rpm / ( the_ENGINE_rpm + 10000.0 );
+ if ( the_VACUUM_inhg > 5.0 )
+ the_VACUUM_inhg = 5.0;
+
+/*
+> I was merely going to do the engine rpm driven vacuum pump for both
+> the AI and DG, have the gyros spin down down in power off descents,
+> have it tumble when you exceed the usual pitch or bank limits,
+> put in those insidious turning errors ... for now anyway.
+*/
+ the_DG_deg = FGBFI::getHeading () - FGBFI::getMagVar ();
/**************************
Finished updates, now clear the timer
}
}
+\f
+////////////////////////////////////////////////////////////////////////
+// Everything below is a transient hack; expect it to disappear
+////////////////////////////////////////////////////////////////////////
+
+
+double FGSteam::get_HackGS_deg () {
+ if ( current_radiostack->get_nav1_inrange() &&
+ current_radiostack->get_nav1_loc() )
+ {
+ double x = current_radiostack->get_nav1_dist();
+ double y = (FGBFI::getAltitude() - current_radiostack->get_nav1_elev())
+ * FEET_TO_METER;
+ double angle = atan2( y, x ) * RAD_TO_DEG;
+ return current_radiostack->get_nav1_target_gs() - angle;
+ } else {
+ return 0.0;
+ }
+}
+
+
+double FGSteam::get_HackVOR1_deg () {
+ double r;
+
+ if ( current_radiostack->get_nav1_inrange() ) {
+ 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;
+
+ if (r> 180.0) r-=360.0; else
+ if (r<-180.0) r+=360.0;
+ if ( fabs(r) > 90.0 )
+ r = ( r<0.0 ? -r-180.0 : -r+180.0 );
+ if ( current_radiostack->get_nav1_loc() ) r *= -5.0;
+ } else {
+ r = 0.0;
+ }
+
+ return r;
+}
+
+
+double FGSteam::get_HackVOR2_deg () {
+ double r;
+
+ if ( current_radiostack->get_nav2_inrange() ) {
+ r = current_radiostack->get_nav2_radial() -
+ current_radiostack->get_nav2_heading() + 180.0;
+ // cout << "Radial = " << current_radiostack->get_nav1_radial()
+ // << " Bearing = " << current_radiostack->get_nav1_heading() << endl;
+
+ if (r> 180.0) r-=360.0; else
+ if (r<-180.0) r+=360.0;
+ if ( fabs(r) > 90.0 )
+ r = ( r<0.0 ? -r-180.0 : -r+180.0 );
+ } else {
+ r = 0.0;
+ }
+
+ return r;
+}
+
+
+double FGSteam::get_HackOBS1_deg () {
+ return current_radiostack->get_nav1_radial();
+}
+
+
+double FGSteam::get_HackOBS2_deg () {
+ return current_radiostack->get_nav2_radial();
+}
+
+
+double FGSteam::get_HackADF_deg () {
+ double r;
+
+ if ( current_radiostack->get_adf_inrange() ) {
+ r = current_radiostack->get_adf_heading() - FGBFI::getHeading() + 180.0;
+
+ // cout << "Radial = " << current_radiostack->get_adf_heading()
+ // << " Heading = " << FGBFI::getHeading() << endl;
+ } else {
+ r = 0.0;
+ }
+
+ return r;
+}
+
// end of steam.cxx