gps_to_flag_node(NULL),
gps_from_flag_node(NULL),
gps_has_gs_node(NULL),
+ gps_xtrack_error_nm_node(NULL),
play_count(0),
last_time(0),
target_radial(0.0),
last_x(0.0),
last_loc_dist(0.0),
last_xtrack_error(0.0),
+ xrate_ms(0.0),
_localizerWidth(5.0),
_name(node->getStringValue("name", "nav")),
_num(node->getIntValue("number", 0)),
- _time_before_search_sec(-1.0)
+ _time_before_search_sec(-1.0),
+ _falseCoursesEnabled(true),
+ _sgr(NULL)
{
SGPath path( globals->get_fg_root() );
SGPath term = path;
void
FGNavRadio::init ()
{
+ SGSoundMgr *smgr = globals->get_soundmgr();
+ _sgr = smgr->find("avionics", true);
+ _sgr->tie_to_listener();
+
morse.init();
string branch;
tofrom_serviceable_node = createServiceableProp(node, "to-from");
dme_serviceable_node = createServiceableProp(node, "dme");
+ globals->get_props()->tie("sim/realism/false-radio-courses-enabled",
+ SGRawValuePointer<bool>(&_falseCoursesEnabled));
+
// frequencies
SGPropertyNode *subnode = node->getChild("frequencies", 0, true);
freq_node = subnode->getChild("selected-mhz", 0, true);
gps_to_flag_node = fgGetNode("/instrumentation/gps/to-flag", true);
gps_from_flag_node = fgGetNode("/instrumentation/gps/from-flag", true);
gps_has_gs_node = fgGetNode("/instrumentation/gps/has-gs", true);
+ gps_course_node = fgGetNode("/instrumentation/gps/selected-course-deg", true);
+ gps_xtrack_error_nm_node = fgGetNode("/instrumentation/gps/wp/wp[1]/course-error-nm", true);
+ _magvarNode = fgGetNode("/environment/magnetic-variation-deg", true);
std::ostringstream temp;
temp << _name << "nav-ident" << _num;
SG_NORMALIZE_RANGE(r, -180.0, 180.0);
if ( is_loc ) {
- // The factor of 30.0 gives a period of 120 which gives us 3 cycles and six
- // zeros i.e. six courses: one front course, one back course, and four
- // false courses. Three of the six are reverse sensing.
- _cdiDeflection = 30.0 * sawtooth(r / 30.0);
+ if (_falseCoursesEnabled) {
+ // The factor of 30.0 gives a period of 120 which gives us 3 cycles and six
+ // zeros i.e. six courses: one front course, one back course, and four
+ // false courses. Three of the six are reverse sensing.
+ _cdiDeflection = 30.0 * sawtooth(r / 30.0);
+ } else {
+ // no false courses, but we do need to create a back course
+ if (fabs(r) > 90.0) { // front course
+ _cdiDeflection = r - copysign(180.0, r);
+ } else {
+ _cdiDeflection = r; // back course
+ }
+
+ _cdiDeflection = -_cdiDeflection; // reverse for outbound radial
+ } // of false courses disabled
+
const double VOR_FULL_ARC = 20.0; // VOR is -10 .. 10 degree swing
_cdiDeflection *= VOR_FULL_ARC / _localizerWidth; // increased localiser sensitivity
+
+ if (backcourse_node->getBoolValue()) {
+ _cdiDeflection = -_cdiDeflection;
+ }
} else {
// handle the TO side of the VOR
if (fabs(r) > 90.0) {
if (!_gs || !inrange_node->getBoolValue()) {
gs_dist_node->setDoubleValue( 0.0 );
gs_inrange_node->setBoolValue(false);
+ _gsNeedleDeflection = 0.0;
+ _gsNeedleDeflectionNorm = 0.0;
return;
}
gs_inrange_node->setBoolValue(gsInRange);
if (!gsInRange) {
+ _gsNeedleDeflection = 0.0;
+ _gsNeedleDeflectionNorm = 0.0;
return;
}
double dot_v = dot(pos, _gsVertical);
double angle = atan2(dot_v, dot_h) * SGD_RADIANS_TO_DEGREES;
double deflectionAngle = target_gs - angle;
-
- // Construct false glideslopes. The scale factor of 1.5
- // in the sawtooth gives a period of 6 degrees.
- // There will be zeros at 3, 6r, 9, 12r et cetera
- // where "r" indicates reverse sensing.
- // This is is consistent with conventional pilot lore
- // e.g. http://www.allstar.fiu.edu/aerojava/ILS.htm
- // but inconsistent with
- // http://www.freepatentsonline.com/3757338.html
- //
- // It may be that some of each exist.
- if (deflectionAngle < 0) {
- deflectionAngle = 1.5 * sawtooth(deflectionAngle / 1.5);
- } else {
- // no false GS below the true GS
+
+ if (_falseCoursesEnabled) {
+ // Construct false glideslopes. The scale factor of 1.5
+ // in the sawtooth gives a period of 6 degrees.
+ // There will be zeros at 3, 6r, 9, 12r et cetera
+ // where "r" indicates reverse sensing.
+ // This is is consistent with conventional pilot lore
+ // e.g. http://www.allstar.fiu.edu/aerojava/ILS.htm
+ // but inconsistent with
+ // http://www.freepatentsonline.com/3757338.html
+ //
+ // It may be that some of each exist.
+ if (deflectionAngle < 0) {
+ deflectionAngle = 1.5 * sawtooth(deflectionAngle / 1.5);
+ } else {
+ // no false GS below the true GS
+ }
}
_gsNeedleDeflection = deflectionAngle * 5.0;
_toFlag = gps_to_flag_node->getBoolValue();
_fromFlag = gps_from_flag_node->getBoolValue();
- inrange_node->setBoolValue(_toFlag | _fromFlag);
+ bool gpsValid = (_toFlag | _fromFlag);
+ inrange_node->setBoolValue(gpsValid);
+ if (!gpsValid) {
+ signal_quality_norm_node->setDoubleValue(0.0);
+ _cdiDeflection = 0.0;
+ _cdiCrossTrackErrorM = 0.0;
+ _gsNeedleDeflection = 0.0;
+ return;
+ }
+
+ // this is unfortunate, but panel instruments use this value to decide
+ // if the navradio output is valid.
+ signal_quality_norm_node->setDoubleValue(1.0);
_cdiDeflection = gps_cdi_deflection_node->getDoubleValue();
// clmap to some range (+/- 10 degrees) as the regular deflection
SG_CLAMP_RANGE(_cdiDeflection, -10.0, 10.0 );
- _cdiCrossTrackErrorM = 0.0; // FIXME, supply this
+ _cdiCrossTrackErrorM = gps_xtrack_error_nm_node->getDoubleValue() * SG_NM_TO_METER;
_gsNeedleDeflection = 0.0; // FIXME, supply this
+
+ double trtrue = gps_course_node->getDoubleValue() + _magvarNode->getDoubleValue();
+ SG_NORMALIZE_RANGE(trtrue, 0.0, 360.0);
+ target_radial_true_node->setDoubleValue( trtrue );
}
void FGNavRadio::updateCDI(double dt)
//////////////////////////////////////////////////////////
double t = 0.0;
if ( inrange && cdi_serviceable ) {
- double xrate_ms = (last_xtrack_error - _cdiCrossTrackErrorM) / dt;
+ double cur_rate = (last_xtrack_error - _cdiCrossTrackErrorM) / dt;
+ xrate_ms = 0.99 * xrate_ms + 0.01 * cur_rate;
if ( fabs(xrate_ms) > 0.00001 ) {
t = _cdiCrossTrackErrorM / xrate_ms;
} else {
// play station ident via audio system if on + ident,
// otherwise turn it off
- if (!power_btn_node->getBoolValue()
+ if (!power_btn_node->getBoolValue()
|| !(bus_power_node->getDoubleValue() > 1.0)
|| !ident_btn_node->getBoolValue()
|| !audio_btn_node->getBoolValue() ) {
- globals->get_soundmgr()->stop( nav_fx_name );
- globals->get_soundmgr()->stop( dme_fx_name );
+ _sgr->stop( nav_fx_name );
+ _sgr->stop( dme_fx_name );
return;
}
- SGSoundSample *sound = globals->get_soundmgr()->find( nav_fx_name );
- double vol = vol_btn_node->getDoubleValue();
+ SGSoundSample *sound = _sgr->find( nav_fx_name );
+ double vol = vol_btn_node->getFloatValue();
SG_CLAMP_RANGE(vol, 0.0, 1.0);
if ( sound != NULL ) {
SG_LOG( SG_COCKPIT, SG_ALERT, "Can't find nav-vor-ident sound" );
}
- sound = globals->get_soundmgr()->find( dme_fx_name );
+ sound = _sgr->find( dme_fx_name );
if ( sound != NULL ) {
sound->set_volume( vol );
} else {
play_count = ++play_count % NUM_IDENT_SLOTS;
// Previous ident is out of time; if still playing, cut it off:
- globals->get_soundmgr()->stop( nav_fx_name );
- globals->get_soundmgr()->stop( dme_fx_name );
+ _sgr->stop( nav_fx_name );
+ _sgr->stop( dme_fx_name );
if (play_count == 0) { // the DME slot
if (_dmeInRange && dme_serviceable_node->getBoolValue()) {
// play DME ident
- globals->get_soundmgr()->play_once( dme_fx_name );
+ if (vol > 0.05) _sgr->play_once( dme_fx_name );
}
} else { // NAV slot
if (inrange_node->getBoolValue() && nav_serviceable_node->getBoolValue()) {
- globals->get_soundmgr()->play_once(nav_fx_name);
+ if (vol > 0.05) _sgr->play_once(nav_fx_name);
}
}
}
_gs = NULL;
_dme = NULL;
nav_id_node->setStringValue("");
- globals->get_soundmgr()->remove( nav_fx_name );
- globals->get_soundmgr()->remove( dme_fx_name );
+
+ _sgr->remove( nav_fx_name );
+ _sgr->remove( dme_fx_name );
}
is_valid_node->setBoolValue(nav != NULL);
void FGNavRadio::audioNavidChanged()
{
- if ( globals->get_soundmgr()->exists(nav_fx_name)) {
- globals->get_soundmgr()->remove(nav_fx_name);
+ if (_sgr->exists(nav_fx_name)) {
+ _sgr->remove(nav_fx_name);
}
try {
string trans_ident(_navaid->get_trans_ident());
SGSoundSample* sound = morse.make_ident(trans_ident, LO_FREQUENCY);
sound->set_volume( 0.3 );
- if (!globals->get_soundmgr()->add( sound, nav_fx_name )) {
+ if (!_sgr->add( sound, nav_fx_name )) {
SG_LOG(SG_COCKPIT, SG_WARN, "Failed to add v1-vor-ident sound");
}
- if ( globals->get_soundmgr()->exists( dme_fx_name ) ) {
- globals->get_soundmgr()->remove( dme_fx_name );
+ if ( _sgr->exists( dme_fx_name ) ) {
+ _sgr->remove( dme_fx_name );
}
sound = morse.make_ident( trans_ident, HI_FREQUENCY );
sound->set_volume( 0.3 );
- globals->get_soundmgr()->add( sound, dme_fx_name );
+ _sgr->add( sound, dme_fx_name );
int offset = (int)(sg_random() * 30.0);
play_count = offset / 4;