]> git.mxchange.org Git - flightgear.git/commitdiff
Working on modeling more realistic VOR and ILS ranges.
authorcurt <curt>
Wed, 14 Mar 2001 07:25:14 +0000 (07:25 +0000)
committercurt <curt>
Wed, 14 Mar 2001 07:25:14 +0000 (07:25 +0000)
src/Cockpit/radiostack.cxx
src/Cockpit/radiostack.hxx
src/Navaids/ils.hxx
src/Navaids/ilslist.cxx
src/Navaids/navlist.cxx
src/Time/light.cxx
src/Time/light.hxx

index 68f7527ba9a855bec825ee52c572d5fe0d5109ff..a61b031d2d18d2632a603b9d5f9dc5b7f1bfaf6e 100644 (file)
@@ -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();
index 2c8bd081dc55af7ba93961cf07542d9b8b51c300..54b1b9f77425abdef5d2b6576fe53221e48dd7b1 100644 (file)
@@ -30,6 +30,8 @@
 
 #include <simgear/compiler.h>
 
+#include <simgear/math/interpolater.hxx>
+
 #include <Navaids/ilslist.hxx>
 #include <Navaids/navlist.hxx>
 #include <Sound/morse.hxx>
@@ -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();
index 601ffb4cb4cf0e698d946f764694aeb788d2e23c..aada9a9aa78c6a6382fbb74984229f9e14e54928 100644 (file)
@@ -44,7 +44,7 @@ FG_USING_STD(istream);
 #endif
 
 
-#define FG_ILS_DEFAULT_RANGE 30
+#define FG_ILS_DEFAULT_RANGE 18
 
 class FGILS {
 
index 3bed2ed943f8597653e508a4ab5e0028b9b5ec00..f5582ab5ff505141fb6b6f6d5250d15dd0b177fb 100644 (file)
@@ -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;
        }
index abf7e104cb1599b341513b10ec2bf66a30f915a2..6869e420d66511fa53766f6d2b1b23294bec8970 100644 (file)
@@ -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;
index beedc1eedb871dbc1d74bc081717116bdfef3e80..5d3c45852c9347e8687a438b69b23917ec8ccfd8 100644 (file)
@@ -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() );
 }
 
 
index ab8e93bc85dd773003ecea07476283030e7b8e29..fd760a972fb754368e5144f7b6623f6fc28f271b 100644 (file)
@@ -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: