}
-// 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();
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);
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()
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 {
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;
}
}
} else {
nav2_inrange = false;
+ nav2_dme_dist = 0.0;
// cout << "not picking up vor. :-(" << endl;
}
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;
}
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();
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();