From 61c8cefcf298676613ba93f96491f66c7557e890 Mon Sep 17 00:00:00 2001 From: curt Date: Wed, 14 Mar 2001 07:25:14 +0000 Subject: [PATCH] Working on modeling more realistic VOR and ILS ranges. --- src/Cockpit/radiostack.cxx | 226 +++++++++++++++++++++---------------- src/Cockpit/radiostack.hxx | 14 +++ src/Navaids/ils.hxx | 2 +- src/Navaids/ilslist.cxx | 7 +- src/Navaids/navlist.cxx | 7 +- src/Time/light.cxx | 6 +- src/Time/light.hxx | 6 +- 7 files changed, 162 insertions(+), 106 deletions(-) diff --git a/src/Cockpit/radiostack.cxx b/src/Cockpit/radiostack.cxx index 68f7527ba..a61b031d2 100644 --- a/src/Cockpit/radiostack.cxx +++ b/src/Cockpit/radiostack.cxx @@ -63,65 +63,6 @@ static double kludgeRange ( double stationElev, double aircraftElev, } -// model standard VOR/DME/TACAN service volumes as per AIM 1-1-8 -static double adjustNavRange( double stationElev, double aircraftElev, - double nominalRange ) -{ - // assumptions we model the standard service volume, plus - // ... rather than specifying a cylinder, we model a cone that - // contains the cylinder. Then we put an upside down cone on top - // to model diminishing returns at too-high altitudes. - - // altitude difference - double alt = ( aircraftElev - stationElev ) * METER_TO_FEET; - - if ( nominalRange < 25.0 + FG_EPSILON ) { - // Standard Terminal Service Volume - if ( alt <= 1000.0 ) { - return nominalRange; - } else if ( alt <= 12000.0 ) { - return nominalRange + nominalRange * ( alt - 1000.0 ) / 11000.0; - } else if ( alt <= 18000.0 ) { - return nominalRange * 2 * ( 1 - ( alt - 12000.0 ) / 6000.0 ); - } else { - return 0.0; - } - } else if ( nominalRange < 50.0 + FG_EPSILON ) { - // Standard Low Altitude Service Volume - if ( alt <= 1000.0 ) { - return nominalRange; - } else if ( alt <= 18000.0 ) { - return nominalRange + nominalRange * ( alt - 1000.0 ) / 17000.0; - } else if ( alt <= 18000.0 ) { - return nominalRange * 2 * ( 1 - ( alt - 18000.0 ) / 9000.0 ); - } else { - return 0.0; - } - } else { - // Standard High Altitude Service Volume - double lc = nominalRange * 0.31; - double mc = nominalRange * 0.77; - double hc = nominalRange; - - if ( alt <= 1000.0 ) { - return lc; - } else if ( alt <= 14500.0 ) { - return lc + (mc-lc) * ( alt - 1000.0 ) / 13500.0; - } else if ( alt <= 18000.0 ) { - return mc + (hc-mc) * ( alt - 14500.0 ) / 3500.0; - } else if ( alt <= 45000.0 ) { - return hc + hc * ( 1 - fabs(alt - 31500.0) / 13500.0 ); - } else if ( alt <= 60000.0 ) { - return mc + (hc-mc) * (60000.0 - alt) / 15000.0; - } else if ( alt <= 75000.0 ) { - return mc * ( 75000.0 - alt ) / 15000.0; - } else { - return 0.0; - } - } -} - - // periodic radio station search wrapper static void fgRadioSearch( void ) { current_radiostack->search(); @@ -155,6 +96,18 @@ FGRadioStack::init () search(); update(); + FGPath path( globals->get_fg_root() ); + FGPath term = path; + term.append( "Navaids/range.term" ); + FGPath low = path; + low.append( "Navaids/range.low" ); + FGPath high = path; + high.append( "Navaids/range.high" ); + + term_tbl = new SGInterpTable( term.str() ); + low_tbl = new SGInterpTable( low.str() ); + high_tbl = new SGInterpTable( high.str() ); + // Search radio database once per second global_events.Register( "fgRadioSearch()", fgRadioSearch, fgEVENT::FG_EVENT_READY, 1000); @@ -264,6 +217,58 @@ FGRadioStack::unbind () fgUntie("/radios/adf/rotation"); } + +// model standard VOR/DME/TACAN service volumes as per AIM 1-1-8 +double FGRadioStack::adjustNavRange( double stationElev, double aircraftElev, + double nominalRange ) +{ + // assumptions we model the standard service volume, plus + // ... rather than specifying a cylinder, we model a cone that + // contains the cylinder. Then we put an upside down cone on top + // to model diminishing returns at too-high altitudes. + + // altitude difference + double alt = ( aircraftElev * METER_TO_FEET - stationElev ); + // cout << "aircraft elev = " << aircraftElev * METER_TO_FEET + // << " station elev = " << stationElev << endl; + + if ( nominalRange < 25.0 + FG_EPSILON ) { + // Standard Terminal Service Volume + return term_tbl->interpolate( alt ); + } else if ( nominalRange < 50.0 + FG_EPSILON ) { + // Standard Low Altitude Service Volume + // table is based on range of 40, scale to actual range + return low_tbl->interpolate( alt ) * nominalRange / 40.0; + } else { + // Standard High Altitude Service Volume + // table is based on range of 130, scale to actual range + return high_tbl->interpolate( alt ) * nominalRange / 130.0; + } +} + + +// model standard ILS service volumes as per AIM 1-1-9 +double FGRadioStack::adjustILSRange( double stationElev, double aircraftElev, + double offsetDegrees, double distance ) +{ + // assumptions we model the standard service volume, plus + + // altitude difference + // double alt = ( aircraftElev * METER_TO_FEET - stationElev ); + double offset = fabs( offsetDegrees ); + + if ( offset < 10 ) { + return FG_ILS_DEFAULT_RANGE; + } else if ( offset < 35 ) { + return 10 + (35 - offset) * (FG_ILS_DEFAULT_RANGE - 10) / 25; + } else if ( offset < 45 ) { + return (45 - offset); + } else { + return 0; + } +} + + // Update the various nav values based on position and valid tuned in navs void FGRadioStack::update() @@ -297,26 +302,39 @@ FGRadioStack::update() nav1_gs_dist = 0.0; } - nav1_effective_range = kludgeRange(nav1_elev, elev, nav1_range); + // wgs84 heading + geo_inverse_wgs_84( elev, lat * RAD_TO_DEG, lon * RAD_TO_DEG, + nav1_loclat, nav1_loclon, + &az1, &az2, &s ); + // cout << "az1 = " << az1 << " magvar = " << nav1_magvar << endl; + nav1_heading = az1 - nav1_magvar; + // cout << " heading = " << nav1_heading + // << " dist = " << nav1_dist << endl; + + if ( nav1_loc ) { + double offset = nav1_heading - nav1_radial; + while ( offset < -180.0 ) { offset += 360.0; } + while ( offset > 180.0 ) { offset -= 360.0; } + cout << "ils offset = " << offset << endl; + nav1_effective_range = adjustILSRange(nav1_elev, elev, offset, + nav1_loc_dist * METER_TO_NM ); + } else { + nav1_effective_range = adjustNavRange(nav1_elev, elev, nav1_range); + } + cout << "nav1 range = " << nav1_effective_range + << " (" << nav1_range << ")" << endl; + if ( nav1_loc_dist < nav1_effective_range * NM_TO_METER ) { nav1_inrange = true; - - // wgs84 heading - geo_inverse_wgs_84( elev, lat * RAD_TO_DEG, lon * RAD_TO_DEG, - nav1_loclat, nav1_loclon, - &az1, &az2, &s ); - // cout << "az1 = " << az1 << " magvar = " << nav1_magvar << endl; - nav1_heading = az1 - nav1_magvar; - // Alex: nav1_heading = - (az1 - FGBFI::getMagVar() / RAD_TO_DEG); - - // cout << " heading = " << nav1_heading - // << " dist = " << nav1_dist << endl; + } else if ( nav1_loc_dist < 2 * nav1_effective_range * NM_TO_METER ) { + nav1_inrange = sg_random() < + ( 2 * nav1_effective_range * NM_TO_METER - nav1_loc_dist ) / + (nav1_effective_range * NM_TO_METER); } else { nav1_inrange = false; } - if ( nav1_loc ) { - } else { + if ( !nav1_loc ) { nav1_radial = nav1_sel_radial; } } else { @@ -373,19 +391,33 @@ FGRadioStack::update() nav2_gs_dist = 0.0; } - nav2_effective_range = kludgeRange(nav2_elev, elev, nav2_range); + // wgs84 heading + geo_inverse_wgs_84( elev, lat * RAD_TO_DEG, lon * RAD_TO_DEG, + nav2_loclat, nav2_loclon, + &az1, &az2, &s ); + nav2_heading = az1 - nav2_magvar; + // cout << " heading = " << nav2_heading + // << " dist = " << nav2_dist << endl; + + if ( nav2_loc ) { + double offset = nav2_heading - nav2_radial; + while ( offset < -180.0 ) { offset += 360.0; } + while ( offset > 180.0 ) { offset -= 360.0; } + cout << "ils offset = " << offset << endl; + nav2_effective_range = adjustILSRange(nav2_elev, elev, offset, + nav2_loc_dist * METER_TO_NM ); + } else { + nav2_effective_range = adjustNavRange(nav2_elev, elev, nav2_range); + } + cout << "nav2 range = " << nav2_effective_range + << " (" << nav2_range << ")" << endl; + if ( nav2_loc_dist < nav2_effective_range * NM_TO_METER ) { nav2_inrange = true; - - // wgs84 heading - geo_inverse_wgs_84( elev, lat * RAD_TO_DEG, lon * RAD_TO_DEG, - nav2_loclat, nav2_loclon, - &az1, &az2, &s ); - nav2_heading = az1 - nav2_magvar; - // Alex: nav2_heading = - (az1 - FGBFI::getMagVar() / RAD_TO_DEG); - - // cout << " heading = " << nav2_heading - // << " dist = " << nav2_dist << endl; + } else if ( nav2_loc_dist < 2 * nav2_effective_range * NM_TO_METER ) { + nav2_inrange = sg_random() < + ( 2 * nav2_effective_range * NM_TO_METER - nav2_loc_dist ) / + (nav2_effective_range * NM_TO_METER); } else { nav2_inrange = false; } @@ -395,6 +427,7 @@ FGRadioStack::update() } } else { nav2_inrange = false; + nav2_dme_dist = 0.0; // cout << "not picking up vor. :-(" << endl; } @@ -404,18 +437,21 @@ FGRadioStack::update() station = Point3D( adf_x, adf_y, adf_z ); adf_dist = aircraft.distance3D( station ); + // wgs84 heading + geo_inverse_wgs_84( elev, lat * RAD_TO_DEG, lon * RAD_TO_DEG, + adf_lat, adf_lon, + &az1, &az2, &s ); + adf_heading = az1; + // cout << " heading = " << nav2_heading + // << " dist = " << nav2_dist << endl; + adf_effective_range = kludgeRange(adf_elev, elev, adf_range); if ( adf_dist < adf_effective_range * NM_TO_METER ) { adf_inrange = true; - - // wgs84 heading - geo_inverse_wgs_84( elev, lat * RAD_TO_DEG, lon * RAD_TO_DEG, - adf_lat, adf_lon, - &az1, &az2, &s ); - adf_heading = az1; - - // cout << " heading = " << nav2_heading - // << " dist = " << nav2_dist << endl; + } else if ( adf_dist < 2 * adf_effective_range * NM_TO_METER ) { + adf_inrange = sg_random() < + ( 2 * adf_effective_range * NM_TO_METER - adf_dist ) / + (adf_effective_range * NM_TO_METER); } else { adf_inrange = false; } @@ -516,7 +552,7 @@ void FGRadioStack::search() nav1_elev = nav.get_elev(); nav1_magvar = nav.get_magvar(); nav1_range = nav.get_range(); - nav1_effective_range = kludgeRange(nav1_elev, elev, nav1_range); + nav1_effective_range = adjustNavRange(nav1_elev, elev, nav1_range); nav1_target_gs = 0.0; nav1_radial = nav1_sel_radial; nav1_x = nav1_dme_x = nav.get_x(); @@ -607,7 +643,7 @@ void FGRadioStack::search() nav2_elev = nav.get_elev(); nav2_magvar = nav.get_magvar(); nav2_range = nav.get_range(); - nav2_effective_range = kludgeRange(nav2_elev, elev, nav2_range); + nav2_effective_range = adjustNavRange(nav2_elev, elev, nav2_range); nav2_target_gs = 0.0; nav2_radial = nav2_sel_radial; nav2_x = nav2_dme_x = nav.get_x(); diff --git a/src/Cockpit/radiostack.hxx b/src/Cockpit/radiostack.hxx index 2c8bd081d..54b1b9f77 100644 --- a/src/Cockpit/radiostack.hxx +++ b/src/Cockpit/radiostack.hxx @@ -30,6 +30,8 @@ #include +#include + #include #include #include @@ -39,6 +41,10 @@ class FGRadioStack : public FGSubsystem { FGMorse morse; + SGInterpTable *term_tbl; + SGInterpTable *low_tbl; + SGInterpTable *high_tbl; + SGValue * latitudeVal; SGValue * longitudeVal; SGValue * altitudeVal; @@ -137,6 +143,14 @@ class FGRadioStack : public FGSubsystem double adf_y; double adf_z; + // model standard VOR/DME/TACAN service volumes as per AIM 1-1-8 + double adjustNavRange( double stationElev, double aircraftElev, + double nominalRange ); + + // model standard ILS service volumes as per AIM 1-1-9 + double adjustILSRange( double stationElev, double aircraftElev, + double offsetDegrees, double distance ); + public: FGRadioStack(); diff --git a/src/Navaids/ils.hxx b/src/Navaids/ils.hxx index 601ffb4cb..aada9a9aa 100644 --- a/src/Navaids/ils.hxx +++ b/src/Navaids/ils.hxx @@ -44,7 +44,7 @@ FG_USING_STD(istream); #endif -#define FG_ILS_DEFAULT_RANGE 30 +#define FG_ILS_DEFAULT_RANGE 18 class FGILS { diff --git a/src/Navaids/ilslist.cxx b/src/Navaids/ilslist.cxx index 3bed2ed94..f5582ab5f 100644 --- a/src/Navaids/ilslist.cxx +++ b/src/Navaids/ilslist.cxx @@ -135,8 +135,11 @@ bool FGILSList::query( double lon, double lat, double elev, double freq, // << ")" << endl; // cout << " dist = " << s << endl; - if ( d < (FG_ILS_DEFAULT_RANGE * NM_TO_METER - * FG_ILS_DEFAULT_RANGE * NM_TO_METER) ) { + + // match up to twice the published range so we can model + // reduced signal strength + if ( d < (2* FG_ILS_DEFAULT_RANGE * NM_TO_METER + * 2 * FG_ILS_DEFAULT_RANGE * NM_TO_METER) ) { *ils = *current; return true; } diff --git a/src/Navaids/navlist.cxx b/src/Navaids/navlist.cxx index abf7e104c..6869e420d 100644 --- a/src/Navaids/navlist.cxx +++ b/src/Navaids/navlist.cxx @@ -130,8 +130,11 @@ bool FGNavList::query( double lon, double lat, double elev, double freq, // cout << " dist = " << sqrt(d) // << " range = " << current->get_range() * NM_TO_METER << endl; - if ( d < (current->get_range() * NM_TO_METER - * current->get_range() * NM_TO_METER * 5.0) ) { + + // match up to twice the published range so we can model + // reduced signal strength + if ( d < (2 * current->get_range() * NM_TO_METER + * 2 * current->get_range() * NM_TO_METER ) ) { // cout << "matched = " << current->get_ident() << endl; *n = *current; return true; diff --git a/src/Time/light.cxx b/src/Time/light.cxx index beedc1eed..5d3c45852 100644 --- a/src/Time/light.cxx +++ b/src/Time/light.cxx @@ -84,13 +84,13 @@ void fgLIGHT::Init( void ) { sky.append( "Lighting/sky" ); // initialize ambient table - ambient_tbl = new fgINTERPTABLE( ambient.str() ); + ambient_tbl = new SGInterpTable( ambient.str() ); // initialize diffuse table - diffuse_tbl = new fgINTERPTABLE( diffuse.str() ); + diffuse_tbl = new SGInterpTable( diffuse.str() ); // initialize sky table - sky_tbl = new fgINTERPTABLE( sky.str() ); + sky_tbl = new SGInterpTable( sky.str() ); } diff --git a/src/Time/light.hxx b/src/Time/light.hxx index ab8e93bc8..fd760a972 100644 --- a/src/Time/light.hxx +++ b/src/Time/light.hxx @@ -51,9 +51,9 @@ class fgLIGHT { // Lighting look up tables (based on sun angle with local horizon) - fgINTERPTABLE *ambient_tbl; - fgINTERPTABLE *diffuse_tbl; - fgINTERPTABLE *sky_tbl; + SGInterpTable *ambient_tbl; + SGInterpTable *diffuse_tbl; + SGInterpTable *sky_tbl; public: -- 2.39.5