1
0
Fork 0

begin work on radio subsystem

This commit is contained in:
adrian 2011-09-06 10:29:54 +03:00
parent 80e5585cc3
commit f96123de1c
7 changed files with 353 additions and 200 deletions

View file

@ -5,7 +5,6 @@ set(SOURCES
atcdialog.cxx
trafficcontrol.cxx
CommStation.cxx
itm.cpp
)
flightgear_component(ATC "${SOURCES}")

View file

@ -25,9 +25,6 @@
#endif
#include <algorithm>
#include <math.h>
#include <stdlib.h>
#include <deque>
#include <osg/Geode>
#include <osg/Geometry>
@ -50,8 +47,6 @@
#include <Airports/groundnetwork.hxx>
#include <Airports/dynamics.hxx>
#include <Airports/simple.hxx>
#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<double> _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<unsigned>::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<double>::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<size;i++) {
itm_elev[i]=_elevations[i];
//cerr << "ITM:: itm_elev: " << _elevations[i] << endl;
}
////////////// ITM default parameters //////////////
// later perhaps take them from tile materials?
double eps_dielect=15.0;
double sgm_conductivity = 0.005;
double eno = 301.0;
double frq_mhz = 125.0; // middle of bandplan
int radio_climate = 5; // continental temperate
int pol=1; // assuming vertical polarization although this is more complex in reality
double conf = 0.90; // my own tests in Radiomobile have worked best with these values
double rel = 0.80; // ^^
double dbloss;
char strmode[150];
int errnum;
/////////// radio parameters ///////////
double 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
double transmitter_power = 43.0;
double antenna_gain = 2.0; //real-life gain for conventional monopole/dipole antenna
if(ground_to_air)
transmitter_power = 49.0;
else
transmitter_power = 43.0;
if(ground_to_air)
antenna_gain = 5.0; //pilot plane's antenna gain + ground station antenna gain
else
antenna_gain = 2.0; //pilot plane's antenna gain + AI aircraft antenna gain
double link_budget = transmitter_power - receiver_sensitivity + antenna_gain;
// 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, transmitter_height, receiver_height,
eps_dielect, sgm_conductivity, eno, frq_mhz, radio_climate,
pol, conf, rel, dbloss, strmode, errnum);
cerr << "ITM:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm, " << strmode << ", Error: " << errnum << endl;
//if (errnum !=0 && errnum !=1)
// return -1;
double snr = link_budget - dbloss;
return snr;
}
string FGATCController::formatATCFrequency3_2(int freq)
{

View file

@ -304,7 +304,6 @@ public:
string getGateName(FGAIAircraft *aircraft);
virtual void render(bool) = 0;
virtual string getName() = 0;
double calculate_attenuation(FGTrafficRecord * rec, FGAirportDynamics *parent, int ground_to_air);
private:

View file

@ -1,6 +1,7 @@
include(FlightGearComponent)
set(SOURCES
itm.cpp
adf.cxx
agradar.cxx
airspeed_indicator.cxx

View file

@ -0,0 +1,282 @@
// commradio.cxx -- implementation of FGCommRadio
//
// Written by Adrian Musceac, started August 2011.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include <stdlib.h>
#include <deque>
#include <Scenery/scenery.hxx>
#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<double> _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<unsigned>::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<double>::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<size;i++) {
itm_elev[i]=_elevations[i];
//cerr << "ITM:: itm_elev: " << _elevations[i] << endl;
}
// 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, transmitter_height, receiver_height,
eps_dielect, sgm_conductivity, eno, frq_mhz, radio_climate,
pol, conf, rel, dbloss, strmode, errnum);
cerr << "ITM:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm, " << strmode << ", Error: " << errnum << endl;
//if (errnum == 4)
// return -1;
signal = link_budget - dbloss;
return signal;
}

View file

@ -0,0 +1,69 @@
// commradio.hxx -- class to manage a comm radio instance
//
// Written by Adrian Musceac, started August 2011.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include <simgear/structure/subsystem_mgr.hxx>
#include <Main/fg_props.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/debug/logstream.hxx>
#include <string>
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; };
};