From f96123de1cc50af660d00036b70b88cbc3bedf3f Mon Sep 17 00:00:00 2001 From: adrian Date: Tue, 6 Sep 2011 10:29:54 +0300 Subject: [PATCH] begin work on radio subsystem --- src/ATC/CMakeLists.txt | 1 - src/ATC/trafficcontrol.cxx | 199 +------------------ src/ATC/trafficcontrol.hxx | 1 - src/Instrumentation/CMakeLists.txt | 1 + src/Instrumentation/commradio.cxx | 282 +++++++++++++++++++++++++++ src/Instrumentation/commradio.hxx | 69 +++++++ src/{ATC => Instrumentation}/itm.cpp | 0 7 files changed, 353 insertions(+), 200 deletions(-) create mode 100644 src/Instrumentation/commradio.cxx create mode 100644 src/Instrumentation/commradio.hxx rename src/{ATC => Instrumentation}/itm.cpp (100%) diff --git a/src/ATC/CMakeLists.txt b/src/ATC/CMakeLists.txt index 26ccaadbf..e055ec6dd 100644 --- a/src/ATC/CMakeLists.txt +++ b/src/ATC/CMakeLists.txt @@ -5,7 +5,6 @@ set(SOURCES atcdialog.cxx trafficcontrol.cxx CommStation.cxx - itm.cpp ) flightgear_component(ATC "${SOURCES}") diff --git a/src/ATC/trafficcontrol.cxx b/src/ATC/trafficcontrol.cxx index 37586233a..0f67094b8 100644 --- a/src/ATC/trafficcontrol.cxx +++ b/src/ATC/trafficcontrol.cxx @@ -25,9 +25,6 @@ #endif #include -#include -#include -#include #include #include @@ -50,8 +47,6 @@ #include #include #include -#define WITH_POINT_TO_POINT -#include "itm.cpp" using std::sort; @@ -736,25 +731,7 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, || (onBoardRadioFreqI1 == stationFreq)) { if (rec->allowTransmissions()) { - double snr = calculate_attenuation(rec, parent, ground_to_air); - if (snr <= 0) - return; - if (snr > 0 && snr < 12) { - //for low SNR values implement a way to make the conversation - //hard to understand but audible - //how this works in the real world, is the receiver AGC fails to capture the slope - //and the signal, due to being amplitude modulated, decreases volume after demodulation - //the implementation below is more akin to what would happen on a FM transmission - //therefore the correct way would be to work on the volume - string hash_noise = " "; - int reps = fabs((int)snr - 11); - int t_size = text.size(); - for (int n=1;n<=reps * 2;n++) { - int pos = rand() % t_size -1; - text.replace(pos,1, hash_noise); - } - - } + fgSetString("/sim/messages/atc", text.c_str()); } } @@ -765,180 +742,6 @@ void FGATCController::transmit(FGTrafficRecord * rec, FGAirportDynamics *parent, } } -double FGATCController::calculate_attenuation(FGTrafficRecord * rec, FGAirportDynamics *parent, - int ground_to_air) { - - /// 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; - - //cerr << "ITM:: pilot Lat: " << own_lat << ", Lon: " << own_lon << ", Alt: " << own_alt << endl; - - 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 ); - SGGeoc own_pos_c = SGGeoc::fromGeod( own_pos ); - - // position of sender radio antenna (HAAT) - // sender can be aircraft or ground station - double ATC_HAAT = 30.0; - double Aircraft_HAAT = 5.0; - double sender_alt_ft,sender_alt; - double transmitter_height=0.0; - double receiver_height=0.0; - SGGeod sender_pos; - SGGeod max_sender_pos; - if(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 ); - max_sender_pos = SGGeod::fromDegM( parent->getLongitude(), - parent->getLatitude(), SG_MAX_ELEVATION_M ); - } - 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 ); - max_sender_pos = SGGeod::fromDegM( rec->getLongitude(), - rec->getLatitude(), SG_MAX_ELEVATION_M ); - } - SGGeoc sender_pos_c = SGGeoc::fromGeod( sender_pos ); - //cerr << "ITM:: sender Lat: " << parent->getLatitude() << ", Lon: " << parent->getLongitude() << ", Alt: " << sender_alt << endl; - - double point_distance= 90.0; // regular SRTM is 90 meters - double course = SGGeodesy::courseRad(own_pos_c, sender_pos_c); - double distance_m = SGGeodesy::distanceM(own_pos, sender_pos); - double probe_distance = 0.0; - // If distance larger than this value (300 km), assume reception imposssible - // technically 300 km is no problem if LOS conditions exist, - // but we do this to spare resources - if (distance_m > 300000) - return -1.0; - - - double max_points = distance_m / point_distance; - deque _elevations; - - - double elevation_under_pilot = 0.0; - if (scenery->get_elevation_m( max_own_pos, elevation_under_pilot, NULL )) { - receiver_height = own_alt - elevation_under_pilot + 3; //assume antenna located 3 meters above ground - } - - - double elevation_under_sender = 0.0; - if (scenery->get_elevation_m( max_sender_pos, elevation_under_sender, NULL )) { - transmitter_height = sender_alt - elevation_under_sender; - } - else { - transmitter_height = sender_alt; - } - if(ground_to_air) - transmitter_height += ATC_HAAT; - else - transmitter_height += Aircraft_HAAT; - - cerr << "ITM:: RX-height: " << receiver_height << ", TX-height: " << transmitter_height << ", Distance: " << distance_m << endl; - - - unsigned int e_size = (deque::size_type)max_points; - - while (_elevations.size() <= e_size) { - probe_distance += point_distance; - SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, probe_distance )); - - double elevation_m = 0.0; - - if (scenery->get_elevation_m( probe, elevation_m, NULL )) { - _elevations.push_front(elevation_m); - //cerr << "ITM:: Probe elev: " << elevation_m << endl; - } - else { - _elevations.push_front(0.0); - } - } - _elevations.push_back(elevation_under_pilot); - _elevations.push_front(elevation_under_sender); - double max_alt_between=0.0; - for( deque::size_type i = 0; i < _elevations.size(); i++ ) { - if (_elevations[i] > max_alt_between) { - max_alt_between = _elevations[i]; - } - } - - double num_points= (double)_elevations.size(); - //cerr << "ITM:: Max alt between: " << max_alt_between << ", num points:" << num_points << endl; - _elevations.push_front(point_distance); - _elevations.push_front(num_points -1); - int size = _elevations.size(); - double itm_elev[size]; - for(int i=0;i +#endif + +#include +#include +#include + +#include + +#define WITH_POINT_TO_POINT 1 +#include "itm.cpp" + + +FGCommRadio::FGCommRadio(SGPropertyNode *node) { + + /////////// radio parameters /////////// + _receiver_sensitivity = -110.0; // typical AM receiver sensitivity seems to be 0.8 microVolt at 12dB SINAD + // 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 + _transmitter_power = 43.0; + //pilot plane's antenna gain + AI aircraft antenna gain + //real-life gain for conventional monopole/dipole antenna + _antenna_gain = 2.0; + _propagation_model = 2; // in the future choose between models via option: realistic radio on/off + +} + +FGCommRadio::~FGCommRadio() +{ +} + +void FGCommRadio::init () +{ +} + + +void FGCommRadio::bind () +{ +} + + +void FGCommRadio::update () +{ +} + +double FGCommRadio::getFrequency(int radio) { + double freq = 118.0; + switch (radio) { + case 1: + freq = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz"); + break; + case 2: + freq = fgGetDouble("/instrumentation/comm[1]/frequencies/selected-mhz"); + break; + default: + freq = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz"); + + } + return freq; +} + + + + +void FGCommRadio::receive(SGGeod tx_pos, double freq, string text, + int ground_to_air) { + + comm1 = getFrequency(1); + comm2 = getFrequency(2); + if ( (freq != comm1) && (freq != comm2) ) { + return; + } + else { + double signal = ITM_calculate_attenuation(tx_pos, freq, ground_to_air); + if (signal <= 0) + return; + if ((signal > 0) && (signal < 12)) { + //for low SNR values implement a way to make the conversation + //hard to understand but audible + //how this works in the real world, is the receiver AGC fails to capture the slope + //and the signal, due to being amplitude modulated, decreases volume after demodulation + //the implementation below is more akin to what would happen on a FM transmission + //therefore the correct way would be to work on the volume + string hash_noise = " "; + int reps = fabs((int)signal - 11); + int t_size = text.size(); + for (int n=1;n<=reps * 2;n++) { + int pos = rand() % t_size -1; + text.replace(pos,1, hash_noise); + } + + } + fgSetString("/sim/messages/atc", text.c_str()); + } + +} + +double FGCommRadio::ITM_calculate_attenuation(SGGeod pos, double freq, + int ground_to_air) { + + /// Implement radio attenuation + /// based on the Longley-Rice propagation model + + ////////////// ITM default parameters ////////////// + // in the future perhaps take them from tile materials? + double eps_dielect=15.0; + double sgm_conductivity = 0.005; + double eno = 301.0; + double frq_mhz; + if( (freq < 118.0) || (freq > 137.0) ) + frq_mhz = 125.0; // sane value, middle of bandplan + else + frq_mhz = freq; + int radio_climate = 5; // continental temperate + int pol=1; // assuming vertical polarization although this is more complex in reality + double conf = 0.90; // 90% of situations and time, take into account speed + double rel = 0.90; // ^^ + double dbloss; + char strmode[150]; + int errnum; + + double tx_pow,ant_gain; + double signal = 0.0; + + if(ground_to_air) + tx_pow = _transmitter_power + 6.0; + + if(ground_to_air) + ant_gain = _antenna_gain + 3.0; //pilot plane's antenna gain + ground station antenna gain + + double link_budget = tx_pow - _receiver_sensitivity + ant_gain; + + FGScenery * scenery = globals->get_scenery(); + + 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; + + + //cerr << "ITM:: pilot Lat: " << own_lat << ", Lon: " << own_lon << ", Alt: " << own_alt << endl; + + 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 ); + SGGeoc own_pos_c = SGGeoc::fromGeod( own_pos ); + + // position of sender radio antenna (HAAT) + // sender can be aircraft or ground station + double ATC_HAAT = 30.0; + double Aircraft_HAAT = 5.0; + double sender_alt_ft,sender_alt; + double transmitter_height=0.0; + double receiver_height=0.0; + SGGeod sender_pos = pos; + + sender_alt_ft = sender_pos.getElevationFt(); + sender_alt = sender_alt_ft * SG_FEET_TO_METER; + SGGeod max_sender_pos = SGGeod::fromGeodM( pos, SG_MAX_ELEVATION_M ); + SGGeoc sender_pos_c = SGGeoc::fromGeod( sender_pos ); + //cerr << "ITM:: sender Lat: " << parent->getLatitude() << ", Lon: " << parent->getLongitude() << ", Alt: " << sender_alt << endl; + + double point_distance= 90.0; // regular SRTM is 90 meters + double course = SGGeodesy::courseRad(own_pos_c, sender_pos_c); + double distance_m = SGGeodesy::distanceM(own_pos, sender_pos); + double probe_distance = 0.0; + // If distance larger than this value (300 km), assume reception imposssible to preserve resources + if (distance_m > 300000) + return -1.0; + // If above 9000, consider LOS mode and calculate free-space att + if (own_alt > 9000) { + dbloss = 20 * log10(distance_m) +20 * log10(frq_mhz) -27.55; + signal = link_budget - dbloss; + return signal; + } + + + double max_points = distance_m / point_distance; + deque _elevations; + + double elevation_under_pilot = 0.0; + if (scenery->get_elevation_m( max_own_pos, elevation_under_pilot, NULL )) { + receiver_height = own_alt - elevation_under_pilot + 3; //assume antenna located 3 meters above ground + } + + double elevation_under_sender = 0.0; + if (scenery->get_elevation_m( max_sender_pos, elevation_under_sender, NULL )) { + transmitter_height = sender_alt - elevation_under_sender; + } + else { + transmitter_height = sender_alt; + } + + if(ground_to_air) + transmitter_height += ATC_HAAT; + else + transmitter_height += Aircraft_HAAT; + + cerr << "ITM:: RX-height: " << receiver_height << ", TX-height: " << transmitter_height << ", Distance: " << distance_m << endl; + + unsigned int e_size = (deque::size_type)max_points; + + while (_elevations.size() <= e_size) { + probe_distance += point_distance; + SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, probe_distance )); + + double elevation_m = 0.0; + + if (scenery->get_elevation_m( probe, elevation_m, NULL )) { + _elevations.push_front(elevation_m); + //cerr << "ITM:: Probe elev: " << elevation_m << endl; + } + else { + _elevations.push_front(0.0); + } + } + _elevations.push_back(elevation_under_pilot); + _elevations.push_front(elevation_under_sender); + + double max_alt_between=0.0; + for( deque::size_type i = 0; i < _elevations.size(); i++ ) { + if (_elevations[i] > max_alt_between) { + max_alt_between = _elevations[i]; + } + } + + double num_points= (double)_elevations.size(); + //cerr << "ITM:: Max alt between: " << max_alt_between << ", num points:" << num_points << endl; + _elevations.push_front(point_distance); + _elevations.push_front(num_points -1); + int size = _elevations.size(); + double itm_elev[size]; + for(int i=0;i +#include + +#include
+ +#include +#include +#include + + +using std::string; + + +class FGCommRadio : public SGSubsystem, public SGPropertyChangeListener +{ +private: + bool isOperable() const + { return _operable; } + bool _operable; ///< is the unit serviceable, on, powered, etc + + double _receiver_sensitivity; + double _transmitter_power; + double _antenna_gain; + + int _propagation_model; /// 0 none, 1 round Earth, 2 ITM + double ITM_calculate_attenuation(SGGeod tx_pos, double freq, int ground_to_air) + +public: + + FGCommRadio(SGPropertyNode *node); + ~FGCommRadio(); + + void init (); + void bind (); + void unbind (); + void update (double dt); + + void setFrequency(double freq, int radio); + double getFrequency(int radio); + void setTxPower(double txpower) { _transmitter_power = txpower; }; + void receive_text(SGGeod tx_pos, double freq, string text, int ground_to_air); + void setPropagationModel(int model) { _propagation_model = model; }; + +}; + + diff --git a/src/ATC/itm.cpp b/src/Instrumentation/itm.cpp similarity index 100% rename from src/ATC/itm.cpp rename to src/Instrumentation/itm.cpp -- 2.39.5