compute radio transmission attenuation according to
the Longley-Rice Irregular Terrain Model propagation mode.
This commit is contained in:
parent
a2972051a9
commit
c9ef773d98
4 changed files with 1968 additions and 3 deletions
|
@ -5,6 +5,7 @@ set(SOURCES
|
||||||
atcdialog.cxx
|
atcdialog.cxx
|
||||||
trafficcontrol.cxx
|
trafficcontrol.cxx
|
||||||
CommStation.cxx
|
CommStation.cxx
|
||||||
|
itm.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
flightgear_component(ATC "${SOURCES}")
|
flightgear_component(ATC "${SOURCES}")
|
||||||
|
|
1833
src/ATC/itm.cpp
Normal file
1833
src/ATC/itm.cpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -25,6 +25,8 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <math.h>
|
||||||
|
#include <deque>
|
||||||
|
|
||||||
#include <osg/Geode>
|
#include <osg/Geode>
|
||||||
#include <osg/Geometry>
|
#include <osg/Geometry>
|
||||||
|
@ -48,6 +50,8 @@
|
||||||
#include <Airports/dynamics.hxx>
|
#include <Airports/dynamics.hxx>
|
||||||
#include <Airports/simple.hxx>
|
#include <Airports/simple.hxx>
|
||||||
|
|
||||||
|
#include "itm.cpp"
|
||||||
|
|
||||||
using std::sort;
|
using std::sort;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
|
@ -496,7 +500,7 @@ bool FGATCController::isUserAircraft(FGAIAircraft* ac)
|
||||||
return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
|
return (ac->getCallSign() == fgGetString("/sim/multiplay/callsign")) ? true : false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
|
void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, AtcMsgId msgId,
|
||||||
AtcMsgDir msgDir, bool audible)
|
AtcMsgDir msgDir, bool audible)
|
||||||
{
|
{
|
||||||
string sender, receiver;
|
string sender, receiver;
|
||||||
|
@ -724,8 +728,18 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
|
||||||
// Display ATC message only when one of the radios is tuned
|
// Display ATC message only when one of the radios is tuned
|
||||||
// the relevant frequency.
|
// the relevant frequency.
|
||||||
// Note that distance attenuation is currently not yet implemented
|
// Note that distance attenuation is currently not yet implemented
|
||||||
|
|
||||||
if ((onBoardRadioFreqI0 == stationFreq)
|
if ((onBoardRadioFreqI0 == stationFreq)
|
||||||
|| (onBoardRadioFreqI1 == stationFreq)) {
|
|| (onBoardRadioFreqI1 == stationFreq)) {
|
||||||
|
double snr = calculate_attenuation(rec, parent, msgDir);
|
||||||
|
if (snr <= 0)
|
||||||
|
return;
|
||||||
|
if (snr > 0 && snr < 10) {
|
||||||
|
//for low snr values implement a way to make the conversation
|
||||||
|
//hard to understand (perhaps eliminate letters from words or such
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (rec->allowTransmissions()) {
|
if (rec->allowTransmissions()) {
|
||||||
fgSetString("/sim/messages/atc", text.c_str());
|
fgSetString("/sim/messages/atc", text.c_str());
|
||||||
}
|
}
|
||||||
|
@ -737,6 +751,123 @@ void FGATCController::transmit(FGTrafficRecord * rec, AtcMsgId msgId,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int calculate_attenuation(FGTrafficRecord * rec, FGAirportDynamics *parent,
|
||||||
|
AtcMsgDir msgDir) {
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
/// Implement radio attenuation
|
||||||
|
/// based on the Longley-Rice propagation model
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
|
||||||
|
FGScenery * scenery = globals->get_scenery();
|
||||||
|
// player aircraft position
|
||||||
|
double own_lat = fgGetDouble("/position/latitude-deg");
|
||||||
|
double own_lon = fgGetDouble("/position/longitude-deg");
|
||||||
|
double own_alt_ft = fgGetDouble("/position/altitude-ft");
|
||||||
|
double own_alt= own_alt_ft * SG_FEET_TO_METER;
|
||||||
|
|
||||||
|
SGGeod own_pos = SGGeod::fromDegM( own_lon, own_lat, own_alt );
|
||||||
|
SGGeod max_own_pos = SGGeod::fromDegM( own_lon, own_lat, SG_MAX_ELEVATION_M );
|
||||||
|
SGGeoc center = SGGeoc::fromGeod( max_own_pos );
|
||||||
|
|
||||||
|
// position of sender
|
||||||
|
// sender can be aircraft or ground station
|
||||||
|
double sender_alt_ft,sender_alt;
|
||||||
|
SGGeod sender_pos;
|
||||||
|
if(msgDir == ATC_GROUND_TO_AIR) {
|
||||||
|
sender_alt_ft = parent->getElevation();
|
||||||
|
sender_alt = sender_alt_ft * SG_FEET_TO_METER;
|
||||||
|
sender_pos= SGGeod::fromDegM( parent->getLongitude(), parent->getLatitude(), sender_alt );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
sender_alt_ft = rec->getAltitude();
|
||||||
|
sender_alt = sender_alt_ft * SG_FEET_TO_METER;
|
||||||
|
sender_pos= SGGeod::fromDegM( rec->getLongitude(), rec->getLatitude(), sender_alt );
|
||||||
|
}
|
||||||
|
double point_distance= 100.0; // regular SRTM is 90 meters
|
||||||
|
double course = SGGeodesy::courseDeg(own_pos, sender_pos);
|
||||||
|
double distance_m = SGGeodesy::distanceM(own_pos, sender_pos);
|
||||||
|
double max_points = distance_m / point_distance;
|
||||||
|
deque<double> _elevations;
|
||||||
|
|
||||||
|
// If distance larger than this value (400 km), assume reception imposssible
|
||||||
|
// technically 400 km is no problem if LOS conditions exist,
|
||||||
|
// but we do this to spare resources
|
||||||
|
if (distance_m > 400000)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
while (_elevations.size() < (deque<double>::size_type)max_points) {
|
||||||
|
SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, point_distance ));
|
||||||
|
|
||||||
|
double elevation_m = 0.0;
|
||||||
|
|
||||||
|
if (scenery->get_elevation_m( probe, elevation_m, NULL )) {
|
||||||
|
_elevations.push_front(elevation_m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
double max_alt_between=0.0;
|
||||||
|
for( deque<double>::size_type i = 0; i < _elevations.size(); i++ ) {
|
||||||
|
if (_elevations[i] > max_alt_between) {
|
||||||
|
max_alt_between = _elevations[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
double num_points= (int)_elevations.size();
|
||||||
|
_elevations.push_front(distance_m);
|
||||||
|
_elevations.push_front(num_points -1);
|
||||||
|
int size= _elevations.size();
|
||||||
|
double itm_elev[];
|
||||||
|
for(int i=0;i<size;i++) {
|
||||||
|
itm_elev[i]=_elevations[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////// ITM default parameters //////////////
|
||||||
|
// later perhaps take them from tile materials?
|
||||||
|
double eps_dielect=15.0;
|
||||||
|
double sgm_conductivity = 0.005;
|
||||||
|
double eno_ns_surfref = 301.0;
|
||||||
|
double frq_mhz = 125.0; // middle of bandplan
|
||||||
|
int radio_climate = 5; // continental temperate
|
||||||
|
int pol=1; // assuming vertical polarization
|
||||||
|
double conf = 0.70; // my own tests in Radiomobile have worked best with these values
|
||||||
|
double rel = 0.70; // ^^
|
||||||
|
double dbloss;
|
||||||
|
char strmode[150];
|
||||||
|
int errnum;
|
||||||
|
|
||||||
|
/////////// radio parameters ///////////
|
||||||
|
double receiver_sensitivity = -112.0; // typical AM receiver sensitivity in dBm
|
||||||
|
// AM transmitter power in dBm.
|
||||||
|
// Note this value is calculated from the typical final transistor stage output
|
||||||
|
// !!! small aircraft have portable transmitters which operate at 36 dBm output (4 Watts)
|
||||||
|
// later store this value in aircraft description
|
||||||
|
// ATC comms usually operate high power equipment, thus making the link asymetrical; this is ignored for now
|
||||||
|
double transmitter_power = 43.0;
|
||||||
|
double link_budget = transmitter_power - receiver_sensitivity;
|
||||||
|
|
||||||
|
// first Fresnel zone radius
|
||||||
|
// frequency in the middle of the bandplan, more accuracy is not necessary
|
||||||
|
double fz_clr= 8.657 * sqrt(distance_m / 0.125);
|
||||||
|
|
||||||
|
// TODO: If we clear the first Fresnel zone, we are into line of sight teritory
|
||||||
|
|
||||||
|
// else we need to calculate point to point link loss
|
||||||
|
|
||||||
|
point_to_point(itm_elev, sender_alt, own_alt,
|
||||||
|
eps_dielect, sgm_conductivity, eno, frq_mhz, radio_climate,
|
||||||
|
pol, conf, rel, dbloss, strmode, errnum)
|
||||||
|
|
||||||
|
cerr << "Attenuation: " << dbloss << ", Mode: " << strmode << ", Error: " << errnum << endl;
|
||||||
|
|
||||||
|
if (errnum !=0 && errnum !=1)
|
||||||
|
return -1;
|
||||||
|
double snr = link_budget - dbloss;
|
||||||
|
return snr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
string FGATCController::formatATCFrequency3_2(int freq)
|
string FGATCController::formatATCFrequency3_2(int freq)
|
||||||
{
|
{
|
||||||
char buffer[7];
|
char buffer[7];
|
||||||
|
@ -1155,7 +1286,7 @@ bool FGStartupController::checkTransmissionState(int st, time_t now, time_t star
|
||||||
atc->getATCDialog()->removeEntry(1);
|
atc->getATCDialog()->removeEntry(1);
|
||||||
} else {
|
} else {
|
||||||
//cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
|
//cerr << "creading message for " << i->getAircraft()->getCallSign() << endl;
|
||||||
transmit(&(*i), msgId, msgDir, false);
|
transmit(&(*i), parent, msgId, msgDir, false);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -300,7 +300,7 @@ public:
|
||||||
|
|
||||||
double getDt() { return dt_count; };
|
double getDt() { return dt_count; };
|
||||||
void setDt(double dt) { dt_count = dt;};
|
void setDt(double dt) { dt_count = dt;};
|
||||||
void transmit(FGTrafficRecord *rec, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
|
void transmit(FGTrafficRecord *rec, FGAirportDynamics *parent, AtcMsgId msgId, AtcMsgDir msgDir, bool audible);
|
||||||
string getGateName(FGAIAircraft *aircraft);
|
string getGateName(FGAIAircraft *aircraft);
|
||||||
virtual void render(bool) = 0;
|
virtual void render(bool) = 0;
|
||||||
virtual string getName() = 0;
|
virtual string getName() = 0;
|
||||||
|
|
Loading…
Add table
Reference in a new issue