We have decided that hardcoded initialization of instruments and systems is bad. So we remove them. Hardcoded initialization is bad because it can't be overridden from config files or from the command line. We prefer to do it through config files that should be, eventually, aircraft specific (*-set.xml), not global (preferences.xml).
204 lines
6.4 KiB
C++
204 lines
6.4 KiB
C++
// dme.cxx - distance-measuring equipment.
|
|
// Written by David Megginson, started 2003.
|
|
//
|
|
// This file is in the Public Domain and comes with no warranty.
|
|
|
|
#include <simgear/compiler.h>
|
|
#include <simgear/math/sg_geodesy.hxx>
|
|
#include <simgear/math/sg_random.h>
|
|
|
|
#include <Main/fg_props.hxx>
|
|
#include <Navaids/navlist.hxx>
|
|
|
|
#include "dme.hxx"
|
|
|
|
|
|
/**
|
|
* Adjust the range.
|
|
*
|
|
* Start by calculating the radar horizon based on the elevation
|
|
* difference, then clamp to the maximum, then add a fudge for
|
|
* borderline reception.
|
|
*/
|
|
static double
|
|
adjust_range (double transmitter_elevation_ft, double aircraft_altitude_ft,
|
|
double max_range_nm)
|
|
{
|
|
double delta_elevation_ft =
|
|
fabs(aircraft_altitude_ft - transmitter_elevation_ft);
|
|
double range_nm = 1.23 * sqrt(delta_elevation_ft);
|
|
if (range_nm > max_range_nm)
|
|
range_nm = max_range_nm;
|
|
else if (range_nm < 20.0)
|
|
range_nm = 20.0;
|
|
double rand = sg_random();
|
|
return range_nm + (range_nm * rand * rand);
|
|
}
|
|
|
|
|
|
DME::DME ( SGPropertyNode *node )
|
|
: _last_distance_nm(0),
|
|
_last_frequency_mhz(-1),
|
|
_time_before_search_sec(0),
|
|
_transmitter_valid(false),
|
|
_transmitter_elevation_ft(0),
|
|
_transmitter_range_nm(0),
|
|
_transmitter_bias(0.0),
|
|
name("dme"),
|
|
num(0)
|
|
{
|
|
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 dme config logic" );
|
|
if ( name.length() ) {
|
|
SG_LOG( SG_INSTR, SG_WARN, "Section = " << name );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
DME::DME ()
|
|
: _last_distance_nm(0),
|
|
_last_frequency_mhz(-1),
|
|
_time_before_search_sec(0),
|
|
_transmitter_valid(false),
|
|
_transmitter_elevation_ft(0),
|
|
_transmitter_range_nm(0),
|
|
_transmitter_bias(0.0)
|
|
{
|
|
}
|
|
|
|
DME::~DME ()
|
|
{
|
|
}
|
|
|
|
void
|
|
DME::init ()
|
|
{
|
|
string branch;
|
|
branch = "/instrumentation/" + name;
|
|
|
|
SGPropertyNode *node = fgGetNode(branch.c_str(), num, true );
|
|
|
|
_longitude_node = fgGetNode("/position/longitude-deg", true);
|
|
_latitude_node = fgGetNode("/position/latitude-deg", true);
|
|
_altitude_node = fgGetNode("/position/altitude-ft", true);
|
|
_serviceable_node = node->getChild("serviceable", 0, true);
|
|
_electrical_node = fgGetNode("/systems/electrical/outputs/dme", true);
|
|
SGPropertyNode *fnode = node->getChild("frequencies", 0, true);
|
|
_source_node = fnode->getChild("source", 0, true);
|
|
_frequency_node = fnode->getChild("selected-mhz", 0, true);
|
|
_in_range_node = node->getChild("in-range", 0, true);
|
|
_distance_node = node->getChild("indicated-distance-nm", 0, true);
|
|
_speed_node = node->getChild("indicated-ground-speed-kt", 0, true);
|
|
_time_node = node->getChild("indicated-time-min", 0, true);
|
|
}
|
|
|
|
void
|
|
DME::update (double delta_time_sec)
|
|
{
|
|
// Figure out the source
|
|
const char * source = _source_node->getStringValue();
|
|
if (source[0] == '\0') {
|
|
string branch;
|
|
branch = "/instrumentation/" + name + "/frequencies/selected-mhz";
|
|
_source_node->setStringValue(branch.c_str());
|
|
source = _source_node->getStringValue();
|
|
}
|
|
// Get the frequency
|
|
|
|
double frequency_mhz = fgGetDouble(source, 108.0);
|
|
if (frequency_mhz != _last_frequency_mhz) {
|
|
_time_before_search_sec = 0;
|
|
_last_frequency_mhz = frequency_mhz;
|
|
}
|
|
|
|
// Get the aircraft position
|
|
double longitude_rad =
|
|
_longitude_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
|
|
double latitude_rad =
|
|
_latitude_node->getDoubleValue() * SGD_DEGREES_TO_RADIANS;
|
|
double altitude_m =
|
|
_altitude_node->getDoubleValue() * SG_FEET_TO_METER;
|
|
|
|
// On timeout, scan again
|
|
_time_before_search_sec -= delta_time_sec;
|
|
if (_time_before_search_sec < 0)
|
|
search(frequency_mhz, longitude_rad,
|
|
latitude_rad, altitude_m);
|
|
|
|
// If it's off, don't bother.
|
|
if (!_serviceable_node->getBoolValue() ||
|
|
!_electrical_node->getBoolValue() ||
|
|
!_transmitter_valid) {
|
|
_last_distance_nm = 0;
|
|
_in_range_node->setBoolValue(false);
|
|
_distance_node->setDoubleValue(0);
|
|
_speed_node->setDoubleValue(0);
|
|
_time_node->setDoubleValue(0);
|
|
return;
|
|
}
|
|
|
|
// Calculate the distance to the transmitter
|
|
Point3D location =
|
|
sgGeodToCart(Point3D(longitude_rad, latitude_rad, altitude_m));
|
|
double distance_nm = _transmitter.distance3D(location) * SG_METER_TO_NM;
|
|
|
|
double range_nm = adjust_range(_transmitter_elevation_ft,
|
|
altitude_m * SG_METER_TO_FEET,
|
|
_transmitter_range_nm);
|
|
|
|
if (distance_nm <= range_nm) {
|
|
double speed_kt = (fabs(distance_nm - _last_distance_nm) *
|
|
((1 / delta_time_sec) * 3600.0));
|
|
_last_distance_nm = distance_nm;
|
|
|
|
_in_range_node->setBoolValue(true);
|
|
double tmp_dist = distance_nm - _transmitter_bias;
|
|
if ( tmp_dist < 0.0 ) {
|
|
tmp_dist = 0.0;
|
|
}
|
|
_distance_node->setDoubleValue( tmp_dist );
|
|
_speed_node->setDoubleValue(speed_kt);
|
|
_time_node->setDoubleValue(distance_nm/speed_kt*60.0);
|
|
|
|
} else {
|
|
_last_distance_nm = 0;
|
|
_in_range_node->setBoolValue(false);
|
|
_distance_node->setDoubleValue(0);
|
|
_speed_node->setDoubleValue(0);
|
|
_time_node->setDoubleValue(0);
|
|
}
|
|
}
|
|
|
|
void
|
|
DME::search (double frequency_mhz, double longitude_rad,
|
|
double latitude_rad, double altitude_m)
|
|
{
|
|
// reset search time
|
|
_time_before_search_sec = 1.0;
|
|
|
|
// try the ILS list first
|
|
FGNavRecord *dme
|
|
= globals->get_dmelist()->findByFreq( frequency_mhz, longitude_rad,
|
|
latitude_rad, altitude_m);
|
|
|
|
_transmitter_valid = (dme != NULL);
|
|
|
|
if ( _transmitter_valid ) {
|
|
_transmitter = Point3D(dme->get_x(), dme->get_y(), dme->get_z());
|
|
_transmitter_elevation_ft = dme->get_elev_ft();
|
|
_transmitter_range_nm = dme->get_range();
|
|
_transmitter_bias = dme->get_multiuse();
|
|
}
|
|
}
|
|
|
|
// end of dme.cxx
|