X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FInstrumentation%2Fnavradio.cxx;h=dc9c094b9871af5e0a2a2b1b622804710b65ca4f;hb=61812ef4b88f5aa74e9cc0630c84d6fc6b4a51cd;hp=0a32ec97cdf330545e5e6531f754f750e13c09ad;hpb=d4f56af242fe3c16cf54953ef1480f02beb73127;p=flightgear.git diff --git a/src/Instrumentation/navradio.cxx b/src/Instrumentation/navradio.cxx index 0a32ec97c..dc9c094b9 100644 --- a/src/Instrumentation/navradio.cxx +++ b/src/Instrumentation/navradio.cxx @@ -16,7 +16,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // $Id$ @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -40,7 +41,7 @@ #include "navradio.hxx" #include -SG_USING_STD(string); +using std::string; // Constructor @@ -48,19 +49,21 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) : lon_node(fgGetNode("/position/longitude-deg", true)), lat_node(fgGetNode("/position/latitude-deg", true)), alt_node(fgGetNode("/position/altitude-ft", true)), + is_valid_node(NULL), power_btn_node(NULL), freq_node(NULL), alt_freq_node(NULL), - fmt_freq_node(NULL), - fmt_alt_freq_node(NULL), sel_radial_node(NULL), 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), tofrom_serviceable_node(NULL), + fmt_freq_node(NULL), + fmt_alt_freq_node(NULL), heading_node(NULL), radial_node(NULL), recip_radial_node(NULL), @@ -98,8 +101,8 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) : 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() ); @@ -113,25 +116,6 @@ FGNavRadio::FGNavRadio(SGPropertyNode *node) : 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 ); - } - } - } - } @@ -150,14 +134,15 @@ FGNavRadio::init () 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); power_btn_node = node->getChild("power-btn", 0, true); power_btn_node->setBoolValue( true ); vol_btn_node = node->getChild("volume", 0, true); @@ -165,6 +150,8 @@ FGNavRadio::init () 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); @@ -217,9 +204,9 @@ FGNavRadio::init () gps_from_flag_node = fgGetNode("/instrumentation/gps/from-flag", 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(); } @@ -228,8 +215,8 @@ FGNavRadio::bind () { std::ostringstream temp; string branch; - temp << num; - branch = "/instrumentation/" + name + "[" + temp.str() + "]"; + temp << _num; + branch = "/instrumentation/" + _name + "[" + temp.str() + "]"; } @@ -238,8 +225,8 @@ FGNavRadio::unbind () { std::ostringstream temp; string branch; - temp << num; - branch = "/instrumentation/" + name + "[" + temp.str() + "]"; + temp << _num; + branch = "/instrumentation/" + _name + "[" + temp.str() + "]"; } @@ -312,10 +299,18 @@ double FGNavRadio::adjustILSRange( double stationElev, double aircraftElev, void FGNavRadio::update(double dt) { + // Do a nav station search only once a second to reduce + // unnecessary work. (Also, make sure to do this before caching + // any values!) + _time_before_search_sec -= dt; + if ( _time_before_search_sec < 0 ) { + search(); + } + // cache a few strategic 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()); bool power_btn = power_btn_node->getBoolValue(); bool nav_serviceable = nav_serviceable_node->getBoolValue(); bool cdi_serviceable = cdi_serviceable_node->getBoolValue(); @@ -325,8 +320,6 @@ FGNavRadio::update(double dt) bool is_loc = loc_node->getBoolValue(); double loc_dist = loc_dist_node->getDoubleValue(); - Point3D aircraft = sgGeodToCart( Point3D( lon, lat, elev ) ); - Point3D station; double az1, az2, s; // Create "formatted" versions of the nav frequencies for @@ -337,13 +330,6 @@ FGNavRadio::update(double dt) sprintf( tmp, "%.2f", alt_freq_node->getDoubleValue() ); fmt_alt_freq_node->setStringValue(tmp); - // Do a nav station search only once a second to reduce - // unnecessary work. - _time_before_search_sec -= dt; - if ( _time_before_search_sec < 0 ) { - search(); - } - // cout << "is_valid = " << is_valid // << " power_btn = " << power_btn // << " bus_power = " << bus_power_node->getDoubleValue() @@ -353,31 +339,22 @@ FGNavRadio::update(double dt) if ( is_valid && power_btn && (bus_power_node->getDoubleValue() > 1.0) && nav_serviceable ) { - station = Point3D( nav_x, nav_y, nav_z ); - loc_dist = aircraft.distance3D( station ); + SGVec3d aircraft = SGVec3d::fromGeod(pos); + loc_dist = dist(aircraft, nav_xyz); loc_dist_node->setDoubleValue( loc_dist ); - // cout << "station = " << station << " dist = " << loc_dist << endl; + // cout << "dt = " << dt << " dist = " << loc_dist << endl; if ( has_gs ) { // find closest distance to the gs base line - sgdVec3 p; - sgdSetVec3( p, aircraft.x(), aircraft.y(), aircraft.z() ); - sgdVec3 p0; - sgdSetVec3( p0, gs_x, gs_y, gs_z ); - double dist = sgdClosestPointToLineDistSquared( p, p0, - gs_base_vec ); + SGVec3d p = aircraft; + double dist = sgdClosestPointToLineDistSquared(p.sg(), gs_xyz.sg(), + gs_base_vec.sg()); gs_dist_node->setDoubleValue( sqrt( dist ) ); // cout << "gs_dist = " << gs_dist_node->getDoubleValue() // << endl; - Point3D tmp( gs_x, gs_y, gs_z ); - // cout << " (" << aircraft.distance3D( tmp ) << ")" << endl; - // wgs84 heading to glide slope (to determine sign of distance) - geo_inverse_wgs_84( elev, - lat * SGD_RADIANS_TO_DEGREES, - lon * SGD_RADIANS_TO_DEGREES, - gs_lat, gs_lon, + geo_inverse_wgs_84( pos, SGGeod::fromDeg(gs_lon, gs_lat), &az1, &az2, &s ); double r = az1 - target_radial; while ( r > 180.0 ) { r -= 360.0;} @@ -400,10 +377,7 @@ FGNavRadio::update(double dt) // compute forward and reverse wgs84 headings to localizer ////////////////////////////////////////////////////////// double hdg; - geo_inverse_wgs_84( elev, - lat * SGD_RADIANS_TO_DEGREES, - lon * SGD_RADIANS_TO_DEGREES, - loc_lat, loc_lon, + geo_inverse_wgs_84( pos, SGGeod::fromDeg(loc_lon, loc_lat), &hdg, &az2, &s ); // cout << "az1 = " << az1 << " magvar = " << nav_magvar << endl; heading_node->setDoubleValue( hdg ); @@ -434,6 +408,8 @@ FGNavRadio::update(double dt) ////////////////////////////////////////////////////////// // adjust reception range for altitude + // FIXME: make sure we are using the navdata range now that + // it is valid in the data file ////////////////////////////////////////////////////////// if ( is_loc ) { double offset = radial - target_radial; @@ -441,10 +417,11 @@ FGNavRadio::update(double dt) while ( offset > 180.0 ) { offset -= 360.0; } // cout << "ils offset = " << offset << endl; effective_range - = adjustILSRange( nav_elev, elev, offset, + = adjustILSRange( nav_elev, pos.getElevationM(), offset, loc_dist * SG_METER_TO_NM ); } else { - effective_range = adjustNavRange( nav_elev, elev, range ); + effective_range + = adjustNavRange( nav_elev, pos.getElevationM(), range ); } // cout << "nav range = " << effective_range // << " (" << range << ")" << endl; @@ -467,7 +444,7 @@ FGNavRadio::update(double dt) ////////////////////////////////////////////////////////// // 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() ) { @@ -505,13 +482,14 @@ FGNavRadio::update(double dt) // of ( -10 , 10 ) ////////////////////////////////////////////////////////// double r = 0.0; + 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(); // We want +- 5 dots deflection for the gps, so clamp // to -12.5/12.5 - if ( r < -12.5 ) { r = -12.5; } - if ( r > 12.5 ) { r = 12.5; } + SG_CLAMP_RANGE( r, -12.5, 12.5 ); } else if ( inrange ) { r = radial - target_radial; // cout << "Target radial = " << target_radial @@ -521,14 +499,19 @@ FGNavRadio::update(double dt) while ( r < -180.0 ) { r += 360.0;} if ( fabs(r) > 90.0 ) { r = ( r<0.0 ? -r-180.0 : -r+180.0 ); + } else { + if ( is_loc ) { + loc_backside = true; + } } - // According to Robin Peel, the ILS is 4x more - // sensitive than a vor r = -r; // reverse, since radial is outbound - if ( is_loc ) { r *= 4.0; } - if ( r < -10.0 ) { r = -10.0; } - if ( r > 10.0 ) { r = 10.0; } + if ( is_loc ) { + // According to Robin Peel, the ILS is 4x more + // sensitive than a vor + r *= 4.0; + } + SG_CLAMP_RANGE( r, -10.0, 10.0 ); } } cdi_deflection_node->setDoubleValue( r ); @@ -562,24 +545,17 @@ FGNavRadio::update(double dt) ////////////////////////////////////////////////////////// double hdg_error = 0.0; if ( inrange && cdi_serviceable ) { - double ddist = last_loc_dist - loc_dist; - double dxtrack = last_xtrack_error - xtrack_error; - double a = atan2( dxtrack, ddist ) * SGD_RADIANS_TO_DEGREES; - if ( from_flag_node->getBoolValue() ) { - a = 180.0 - a; - if ( a > 180.0 ) { a -= 360.0; } - if ( a < -180.0 ) { a += 360.0; } - } + double vn = fgGetDouble( "/velocities/speed-north-fps" ); + double ve = fgGetDouble( "/velocities/speed-east-fps" ); + double gnd_trk_true = atan2( ve, vn ) * SGD_RADIANS_TO_DEGREES; + if ( gnd_trk_true < 0.0 ) { gnd_trk_true += 360.0; } + SGPropertyNode *true_hdg = fgGetNode("/orientation/heading-deg", true); - // cout << "true heading = " << true_hdg->getDoubleValue() - // << " selrad = " << sel_radial_node->getDoubleValue() - // << " artr = " << a - // << endl; - double est_hdg = trtrue + a; - if ( est_hdg < 0.0 ) { est_hdg += 360.0; } - if ( est_hdg >= 360.0 ) { est_hdg -= 360.0; } - hdg_error = est_hdg - true_hdg->getDoubleValue(); + hdg_error = gnd_trk_true - true_hdg->getDoubleValue(); + + // cout << "ground track = " << gnd_trk_true + // << " orientation = " << true_hdg->getDoubleValue() << endl; } cdi_xtrack_hdg_err_node->setDoubleValue( hdg_error ); @@ -601,6 +577,13 @@ FGNavRadio::update(double dt) ////////////////////////////////////////////////////////// // compute the amount of glide slope needle deflection // (.i.e. the number of degrees we are off the glide slope * 5.0 + // + // CLO - 13 Mar 2006: The glide slope needle should peg at + // +/-0.7 degrees off the ideal glideslope. I'm not sure why + // we compute the factor the way we do (5*gs_error), but we + // need to compensate for our 'odd' number in the glideslope + // needle animation. This means that the needle should peg + // when this values is +/-3.5. ////////////////////////////////////////////////////////// r = 0.0; if ( has_gs && gs_serviceable_node->getBoolValue() ) { @@ -654,30 +637,31 @@ FGNavRadio::update(double dt) // a nav/ils radial. ////////////////////////////////////////////////////////// - // FIXME: this smells odd, there must be a better (or more - // linear) solution + // Now that we have cross track heading adjustment built in, + // we shouldn't need to overdrive the heading angle within 8km + // of the station. // - // determine the heading adjustment needed. - // over 8km scale by 3.0 - // (3 is chosen because max deflection is 10 - // and 30 is clamped angle to radial) - // under 8km scale by 10.0 - // because the overstated error helps drive it to the radial in a - // moderate cross wind. - double adjustment = 0.0; - if ( loc_dist > 8000 ) { - adjustment = cdi_deflection_node->getDoubleValue() * 3.0; - } else { - adjustment = cdi_deflection_node->getDoubleValue() * 10.0; - } + // The cdi deflection should be +/-10 for a full range of deflection + // so multiplying this by 3 gives us +/- 30 degrees heading + // 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 = 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; } - while ( nta_hdg > 360.0 ) { nta_hdg -= 360.0; } + while ( nta_hdg >= 360.0 ) { nta_hdg -= 360.0; } target_auto_hdg_node->setDoubleValue( nta_hdg ); last_xtrack_error = xtrack_error; @@ -799,9 +783,7 @@ void FGNavRadio::search() while ( target_radial > 360.0 ) { target_radial -= 360.0; } loc_lon = loc->get_lon(); loc_lat = loc->get_lat(); - nav_x = loc->get_x(); - nav_y = loc->get_y(); - nav_z = loc->get_z(); + nav_xyz = loc->get_cart(); last_nav_id = nav_id; last_nav_vor = false; loc_node->setBoolValue( true ); @@ -813,32 +795,26 @@ void FGNavRadio::search() nav_elev = gs->get_elev_ft(); int tmp = (int)(gs->get_multiuse() / 1000.0); target_gs = (double)tmp / 100.0; - gs_x = gs->get_x(); - gs_y = gs->get_y(); - gs_z = gs->get_z(); + gs_xyz = gs->get_cart(); // derive GS baseline (perpendicular to the runay // along the ground) double tlon, tlat, taz; geo_direct_wgs_84 ( 0.0, gs_lat, gs_lon, - target_radial + 90, + target_radial + 90, 100.0, &tlat, &tlon, &taz ); // cout << "target_radial = " << target_radial << endl; // cout << "nav_loc = " << loc_node->getBoolValue() << endl; // cout << gs_lon << "," << gs_lat << " " // << tlon << "," << tlat << " (" << nav_elev << ")" // << endl; - Point3D p1 = sgGeodToCart( Point3D(tlon*SGD_DEGREES_TO_RADIANS, - tlat*SGD_DEGREES_TO_RADIANS, - nav_elev*SG_FEET_TO_METER) - ); - // cout << gs_x << "," << gs_y << "," << gs_z - // << endl; + SGGeod tpos = SGGeod::fromDegFt(tlon, tlat, nav_elev); + SGVec3d p1 = SGVec3d::fromGeod(tpos); + + // cout << gs_xyz << endl; // cout << p1 << endl; - sgdSetVec3( gs_base_vec, - p1.x()-gs_x, p1.y()-gs_y, p1.z()-gs_z ); - // cout << gs_base_vec[0] << "," << gs_base_vec[1] << "," - // << gs_base_vec[2] << endl; + gs_base_vec = p1 - gs_xyz; + // cout << gs_base_vec << endl; } else { has_gs_node->setBoolValue( false ); nav_elev = loc->get_elev_ft(); @@ -895,39 +871,41 @@ void FGNavRadio::search() effective_range = adjustNavRange(nav_elev, elev, range); target_gs = 0.0; target_radial = sel_radial_node->getDoubleValue(); - nav_x = nav->get_x(); - nav_y = nav->get_y(); - nav_z = nav->get_z(); + nav_xyz = nav->get_cart(); if ( globals->get_soundmgr()->exists( nav_fx_name ) ) { globals->get_soundmgr()->remove( nav_fx_name ); } - SGSoundSample *sound; - sound = morse.make_ident( trans_ident, LO_FREQUENCY ); - sound->set_volume( 0.3 ); - if ( globals->get_soundmgr()->add( sound, nav_fx_name ) ) { - // cout << "Added nav-vor-ident sound" << endl; - } else { - 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 ); - } - sound = morse.make_ident( trans_ident, HI_FREQUENCY ); - sound->set_volume( 0.3 ); - globals->get_soundmgr()->add( sound, dme_fx_name ); - - int offset = (int)(sg_random() * 30.0); - play_count = offset / 4; - last_time = globals->get_time_params()->get_cur_time() - offset; - // cout << "offset = " << offset << " play_count = " - // << play_count << " last_time = " - // << last_time << " current time = " - // << globals->get_time_params()->get_cur_time() << endl; + try { + SGSoundSample *sound; + sound = morse.make_ident( trans_ident, LO_FREQUENCY ); + sound->set_volume( 0.3 ); + if ( globals->get_soundmgr()->add( sound, nav_fx_name ) ) { + // cout << "Added nav-vor-ident sound" << endl; + } else { + SG_LOG(SG_COCKPIT, SG_WARN, "Failed to add v1-vor-ident sound"); + } - // cout << "Found a vor station in range" << endl; - // cout << " id = " << nav->get_ident() << endl; + if ( globals->get_soundmgr()->exists( dme_fx_name ) ) { + globals->get_soundmgr()->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 ); + + int offset = (int)(sg_random() * 30.0); + play_count = offset / 4; + last_time = globals->get_time_params()->get_cur_time() - offset; + // cout << "offset = " << offset << " play_count = " + // << play_count << " last_time = " + // << last_time << " current time = " + // << globals->get_time_params()->get_cur_time() << endl; + + // cout << "Found a vor station in range" << endl; + // cout << " id = " << nav->get_ident() << endl; + } catch ( sg_io_exception &e ) { + SG_LOG(SG_GENERAL, SG_ALERT, e.getFormattedMessage()); + } } } else { is_valid = false; @@ -935,13 +913,12 @@ void FGNavRadio::search() 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 ); + char tmpid[5]; strncpy( tmpid, nav_id.c_str(), 5 ); id_c1_node->setIntValue( (int)tmpid[0] );