# include <config.h>
#endif
-#include <iostream>
-#include <string>
#include <sstream>
-#include <simgear/compiler.h>
#include <simgear/sg_inlines.h>
-#include <simgear/math/sg_random.h>
+#include <simgear/timing/sg_time.hxx>
#include <simgear/math/vector.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/structure/exception.hxx>
-#include <Aircraft/aircraft.hxx>
#include <Navaids/navlist.hxx>
-
+#include <Main/util.hxx>
#include "navradio.hxx"
-#include <string>
-SG_USING_STD(string);
-
+using std::string;
// Constructor
FGNavRadio::FGNavRadio(SGPropertyNode *node) :
vol_btn_node(NULL),
ident_btn_node(NULL),
audio_btn_node(NULL),
+ backcourse_node(NULL),
nav_serviceable_node(NULL),
cdi_serviceable_node(NULL),
gs_serviceable_node(NULL),
to_flag_node(NULL),
from_flag_node(NULL),
inrange_node(NULL),
+ signal_quality_norm_node(NULL),
cdi_deflection_node(NULL),
cdi_xtrack_error_node(NULL),
cdi_xtrack_hdg_err_node(NULL),
gps_cdi_deflection_node(NULL),
gps_to_flag_node(NULL),
gps_from_flag_node(NULL),
+ gps_has_gs_node(NULL),
last_nav_id(""),
last_nav_vor(false),
play_count(0),
last_x(0.0),
last_loc_dist(0.0),
last_xtrack_error(0.0),
- name("nav"),
- num(0),
+ _name(node->getStringValue("name", "nav")),
+ _num(node->getIntValue("number", 0)),
_time_before_search_sec(-1.0)
{
SGPath path( globals->get_fg_root() );
term_tbl = new SGInterpTable( term.str() );
low_tbl = new SGInterpTable( low.str() );
high_tbl = new SGInterpTable( high.str() );
-
- 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 nav radio config logic" );
- if ( name.length() ) {
- SG_LOG( SG_INSTR, SG_WARN, "Section = " << name );
- }
- }
- }
-
}
morse.init();
string branch;
- branch = "/instrumentation/" + name;
+ branch = "/instrumentation/" + _name;
- SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
+ SGPropertyNode *node = fgGetNode(branch.c_str(), _num, true );
bus_power_node =
- fgGetNode(("/systems/electrical/outputs/" + name).c_str(), true);
+ fgGetNode(("/systems/electrical/outputs/" + _name).c_str(), true);
// inputs
is_valid_node = node->getChild("data-is-valid", 0, true);
ident_btn_node->setBoolValue( true );
audio_btn_node = node->getChild("audio-btn", 0, true);
audio_btn_node->setBoolValue( true );
+ backcourse_node = node->getChild("back-course-btn", 0, true);
+ backcourse_node->setBoolValue( false );
nav_serviceable_node = node->getChild("serviceable", 0, true);
cdi_serviceable_node = (node->getChild("cdi", 0, true))
->getChild("serviceable", 0, true);
to_flag_node = node->getChild("to-flag", 0, true);
from_flag_node = node->getChild("from-flag", 0, true);
inrange_node = node->getChild("in-range", 0, true);
+ signal_quality_norm_node = node->getChild("signal-quality-norm", 0, true);
cdi_deflection_node = node->getChild("heading-needle-deflection", 0, true);
cdi_xtrack_error_node = node->getChild("crosstrack-error-m", 0, true);
cdi_xtrack_hdg_err_node
gps_cdi_deflection_node = fgGetNode("/instrumentation/gps/cdi-deflection", 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);
std::ostringstream temp;
- temp << name << "nav-ident" << num;
+ temp << _name << "nav-ident" << _num;
nav_fx_name = temp.str();
- temp << name << "dme-ident" << num;
+ temp << _name << "dme-ident" << _num;
dme_fx_name = temp.str();
}
{
std::ostringstream temp;
string branch;
- temp << num;
- branch = "/instrumentation/" + name + "[" + temp.str() + "]";
+ temp << _num;
+ branch = "/instrumentation/" + _name + "[" + temp.str() + "]";
}
{
std::ostringstream temp;
string branch;
- temp << num;
- branch = "/instrumentation/" + name + "[" + temp.str() + "]";
+ temp << _num;
+ branch = "/instrumentation/" + _name + "[" + temp.str() + "]";
}
bool nav_serviceable = nav_serviceable_node->getBoolValue();
bool cdi_serviceable = cdi_serviceable_node->getBoolValue();
bool tofrom_serviceable = tofrom_serviceable_node->getBoolValue();
- bool inrange = inrange_node->getBoolValue();
- bool has_gs = has_gs_node->getBoolValue();
+ bool inrange = false;
+ bool has_gs = false;
+ if ( nav_slaved_to_gps_node->getBoolValue() ) {
+ has_gs = gps_has_gs_node->getBoolValue();
+ has_gs_node->setBoolValue( has_gs );
+ inrange = gps_to_flag_node->getBoolValue()
+ || gps_from_flag_node->getBoolValue();
+ } else {
+ has_gs = has_gs_node->getBoolValue();
+ inrange = inrange_node->getBoolValue();
+ }
bool is_loc = loc_node->getBoolValue();
double loc_dist = loc_dist_node->getDoubleValue();
+ double effective_range_m;
+ double signal_quality_norm = signal_quality_norm_node->getDoubleValue();
double az1, az2, s;
effective_range
= adjustNavRange( nav_elev, pos.getElevationM(), range );
}
+
+ effective_range_m = effective_range * SG_NM_TO_METER;
+
// cout << "nav range = " << effective_range
// << " (" << range << ")" << endl;
- if ( loc_dist < effective_range * SG_NM_TO_METER ) {
- inrange = true;
- } else if ( loc_dist < 2 * effective_range * SG_NM_TO_METER ) {
- inrange = sg_random() < ( 2 * effective_range * SG_NM_TO_METER
- - loc_dist )
- / (effective_range * SG_NM_TO_METER);
- } else {
- inrange = false;
- }
+ //////////////////////////////////////////////////////////
+ // compute signal quality
+ // 100% within effective_range
+ // decreases 1/x^2 further out
+ //////////////////////////////////////////////////////////
+ {
+ double last_signal_quality_norm = signal_quality_norm;
+
+ if ( loc_dist < effective_range_m ) {
+ signal_quality_norm = 1.0;
+ } else {
+ double range_exceed_norm = loc_dist/effective_range_m;
+ signal_quality_norm = 1/(range_exceed_norm*range_exceed_norm);
+ }
+
+ signal_quality_norm = fgGetLowPass( last_signal_quality_norm,
+ signal_quality_norm, dt );
+ }
+ signal_quality_norm_node->setDoubleValue( signal_quality_norm );
+ if ( ! nav_slaved_to_gps_node->getBoolValue() ) {
+ /* not slaved to gps */
+ inrange = signal_quality_norm > 0.2;
+ }
inrange_node->setBoolValue( inrange );
if ( !is_loc ) {
//////////////////////////////////////////////////////////
// compute to/from flag status
//////////////////////////////////////////////////////////
- double value = false;
+ bool value = false;
double offset = fabs(radial - target_radial);
if ( tofrom_serviceable ) {
if ( nav_slaved_to_gps_node->getBoolValue() ) {
// of ( -10 , 10 )
//////////////////////////////////////////////////////////
double r = 0.0;
- bool loc_bc = false; // an in-code flag indicating that we are
- // on a localizer backcourse.
+ bool loc_backside = false; // an in-code flag indicating that we are
+ // on a localizer backcourse.
if ( cdi_serviceable ) {
if ( nav_slaved_to_gps_node->getBoolValue() ) {
r = gps_cdi_deflection_node->getDoubleValue();
r = ( r<0.0 ? -r-180.0 : -r+180.0 );
} else {
if ( is_loc ) {
- loc_bc = true;
+ loc_backside = true;
}
}
r *= 4.0;
}
SG_CLAMP_RANGE( r, -10.0, 10.0 );
+ r *= signal_quality_norm;
}
}
cdi_deflection_node->setDoubleValue( r );
// compute the time to intercept selected radial (based on
// current and last cross track errors and dt
//////////////////////////////////////////////////////////
- double t = 0.0;
- if ( inrange && cdi_serviceable ) {
- double xrate_ms = (last_xtrack_error - xtrack_error) / dt;
- if ( fabs(xrate_ms) > 0.00001 ) {
- t = xtrack_error / xrate_ms;
- } else {
- t = 9999.9;
+ if (dt > 0) { // Are we paused?
+ double t = 0.0;
+ if ( inrange && cdi_serviceable ) {
+ double xrate_ms = (last_xtrack_error - xtrack_error) / dt;
+ if ( fabs(xrate_ms) > 0.00001 ) {
+ t = xtrack_error / xrate_ms;
+ } else {
+ t = 9999.9;
+ }
}
+ time_to_intercept->setDoubleValue( t );
}
- time_to_intercept->setDoubleValue( t );
//////////////////////////////////////////////////////////
// compute the amount of glide slope needle deflection
// FIXME/FINISHME, what should be set here?
} else if ( inrange ) {
double x = gs_dist_node->getDoubleValue();
- double y = (fgGetDouble("/position/altitude-ft") - nav_elev)
+ double y = (alt_node->getDoubleValue() - nav_elev)
* SG_FEET_TO_METER;
// cout << "dist = " << x << " height = " << y << endl;
- double angle = asin( y / x ) * SGD_RADIANS_TO_DEGREES;
+ double angle = atan2( y, x ) * SGD_RADIANS_TO_DEGREES;
r = (target_gs - angle) * 5.0;
+ r *= signal_quality_norm;
}
}
gs_deflection_node->setDoubleValue( r );
// compensation.
double adjustment = cdi_deflection_node->getDoubleValue() * 3.0;
SG_CLAMP_RANGE( adjustment, -30.0, 30.0 );
-
+
// determine the target heading to fly to intercept the
// tgt_radial = target radial (true) + cdi offset adjustmest -
// xtrack heading error adjustment
- double nta_hdg = 0.0;
- if ( is_loc && loc_bc ) {
- // tuned to a localizer and positioned in backcourse range
- // trtrue += 180.0; // reverse the target localizer heading
- // while ( trtrue > 360.0 ) { trtrue -= 360.0; }
- nta_hdg = trtrue + adjustment - hdg_error;
- cout << "trtrue = " << trtrue << " adj = " << adjustment
- << " hdg_error = " << hdg_error << endl;
- } else {
- // all other situations (nav or loc front course)
- nta_hdg = trtrue + adjustment - hdg_error;
+ double nta_hdg;
+ if ( is_loc && backcourse_node->getBoolValue() ) {
+ // tuned to a localizer and backcourse mode activated
+ trtrue += 180.0; // reverse the target localizer heading
+ while ( trtrue > 360.0 ) { trtrue -= 360.0; }
+ nta_hdg = trtrue - adjustment - hdg_error;
+ } else {
+ nta_hdg = trtrue + adjustment - hdg_error;
}
while ( nta_hdg < 0.0 ) { nta_hdg += 360.0; }
_time_before_search_sec = 1.0;
// cache values locally for speed
- double lon = lon_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double lat = lat_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
- double elev = alt_node->getDoubleValue() * SG_FEET_TO_METER;
-
+ SGGeod pos = SGGeod::fromDegFt(lon_node->getDoubleValue(),
+ lat_node->getDoubleValue(), alt_node->getDoubleValue());
FGNavRecord *nav = NULL;
FGNavRecord *loc = NULL;
FGNavRecord *dme = NULL;
////////////////////////////////////////////////////////////////////////
double freq = freq_node->getDoubleValue();
- nav = globals->get_navlist()->findByFreq(freq, lon, lat, elev);
- dme = globals->get_dmelist()->findByFreq(freq, lon, lat, elev);
+ nav = globals->get_navlist()->findByFreq(freq, pos);
+ dme = globals->get_dmelist()->findByFreq(freq, pos);
if ( nav == NULL ) {
- loc = globals->get_loclist()->findByFreq(freq, lon, lat, elev);
- gs = globals->get_gslist()->findByFreq(freq, lon, lat, elev);
+ loc = globals->get_loclist()->findByFreq(freq, pos);
+ gs = globals->get_gslist()->findByFreq(freq, pos);
}
string nav_id = "";
while ( target_radial > 360.0 ) { target_radial -= 360.0; }
loc_lon = loc->get_lon();
loc_lat = loc->get_lat();
- nav_xyz = loc->get_cart();
+ nav_xyz = loc->cart();
last_nav_id = nav_id;
last_nav_vor = false;
loc_node->setBoolValue( true );
nav_elev = gs->get_elev_ft();
int tmp = (int)(gs->get_multiuse() / 1000.0);
target_gs = (double)tmp / 100.0;
- gs_xyz = gs->get_cart();
+ gs_xyz = gs->cart();
// derive GS baseline (perpendicular to the runay
// along the ground)
nav_elev = nav->get_elev_ft();
twist = nav->get_multiuse();
range = nav->get_range();
- effective_range = adjustNavRange(nav_elev, elev, range);
+ effective_range = adjustNavRange(nav_elev, pos.getElevationM(), range);
target_gs = 0.0;
target_radial = sel_radial_node->getDoubleValue();
- nav_xyz = nav->get_cart();
+ nav_xyz = nav->cart();
if ( globals->get_soundmgr()->exists( nav_fx_name ) ) {
globals->get_soundmgr()->remove( nav_fx_name );
target_radial = 0;
trans_ident = "";
last_nav_id = "";
- if ( ! globals->get_soundmgr()->remove( nav_fx_name ) ) {
- SG_LOG(SG_COCKPIT, SG_WARN, "Failed to remove nav-vor-ident sound");
- }
+ globals->get_soundmgr()->remove( nav_fx_name );
globals->get_soundmgr()->remove( dme_fx_name );
- // cout << "not picking up vor1. :-(" << endl;
}
is_valid_node->setBoolValue( is_valid );