1
0
Fork 0

Working on modeling more realistic VOR and ILS ranges.

This commit is contained in:
curt 2001-03-14 07:25:14 +00:00
parent 6e0a10b757
commit 61c8cefcf2
7 changed files with 162 additions and 106 deletions

View 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();

View 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();

View file

@ -44,7 +44,7 @@ FG_USING_STD(istream);
#endif
#define FG_ILS_DEFAULT_RANGE 30
#define FG_ILS_DEFAULT_RANGE 18
class FGILS {

View 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;
}

View 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;

View 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() );
}

View 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: