]> git.mxchange.org Git - flightgear.git/blobdiff - src/Radio/radio.cxx
Expose a radio function (receiveBeacon) to the Nasal subsystem
[flightgear.git] / src / Radio / radio.cxx
index e5719e0dcbc8b78622e9d3c099001f804213d391..3412a151b3fd48f1f5f6b7839073580200d13d0a 100644 (file)
@@ -37,7 +37,7 @@
 FGRadioTransmission::FGRadioTransmission() {
        
        
-       _receiver_sensitivity = -110.0; // typical AM receiver sensitivity seems to be 0.8 microVolt at 12dB SINAD
+       _receiver_sensitivity = -105.0; // typical AM receiver sensitivity seems to be 0.8 microVolt at 12dB SINAD
        
        /** AM transmitter power in dBm.
        *       Typical output powers for ATC ground equipment, VHF-UHF:
@@ -54,7 +54,7 @@ FGRadioTransmission::FGRadioTransmission() {
        _rx_antenna_height = 2.0; // RX antenna height above ground level
        
        
-       _rx_antenna_gain = 1.0; // gain expressed in dBi
+       _rx_antenna_gain = 1.0; // maximum antenna gain expressed in dBi
        _tx_antenna_gain = 1.0;
        
        _rx_line_losses = 2.0;  // to be configured for each station
@@ -66,6 +66,8 @@ FGRadioTransmission::FGRadioTransmission() {
        
        _root_node = fgGetNode("sim/radio", true);
        _terrain_sampling_distance = _root_node->getDoubleValue("sampling-distance", 90.0); // regular SRTM is 90 meters
+       
+       
 }
 
 FGRadioTransmission::~FGRadioTransmission() 
@@ -113,6 +115,28 @@ double FGRadioTransmission::receiveNav(SGGeod tx_pos, double freq, int transmiss
 
 }
 
+double FGRadioTransmission::receiveBeacon(double lat, double lon, double elev, double heading, double pitch) {
+       
+       
+       _transmitter_power = 36;
+       _tx_antenna_height += 0.0;
+       _tx_antenna_gain += 0.5; 
+       elev = elev * SG_FEET_TO_METER;
+       double freq = _root_node->getDoubleValue("station[0]/frequency", 118.0);
+       int ground_to_air = 1;
+       string text = "Beacon1";
+       double comm1 = getFrequency(1);
+       double comm2 = getFrequency(2);
+       if ( !(fabs(freq - comm1) <= 0.0001) &&  !(fabs(freq - comm2) <= 0.0001) ) {
+               return -1;
+       }
+       SGGeod tx_pos = SGGeod::fromDegM( lon, lat, elev );
+       double signal = ITM_calculate_attenuation(tx_pos, freq, ground_to_air);
+       
+       return signal;
+}
+
+
 /*** Receive ATC radio communication as text
 ***/
 void FGRadioTransmission::receiveATC(SGGeod tx_pos, double freq, string text, int ground_to_air) {
@@ -202,11 +226,8 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        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;
+       double frq_mhz = freq;
+       
        int radio_climate = 5;          // continental temperate
        int pol= _polarization; 
        double conf = 0.90;     // 90% of situations and time, take into account speed
@@ -233,10 +254,11 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        double own_lat = fgGetDouble("/position/latitude-deg");
        double own_lon = fgGetDouble("/position/longitude-deg");
        double own_alt_ft = fgGetDouble("/position/altitude-ft");
+       double own_heading = fgGetDouble("/orientation/heading-deg");
        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 );
@@ -253,10 +275,11 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        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= _terrain_sampling_distance; 
        double course = SGGeodesy::courseRad(own_pos_c, sender_pos_c);
+       double reverse_course = SGGeodesy::courseRad(sender_pos_c, own_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 */
@@ -276,7 +299,7 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        int max_points = (int)floor(distance_m / point_distance);
        double delta_last = fmod(distance_m, point_distance);
        
-       deque<double> _elevations;
+       deque<double> elevations;
        deque<string> materials;
        
 
@@ -307,7 +330,7 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        
        unsigned int e_size = (deque<unsigned>::size_type)max_points;
        
-       while (_elevations.size() <= e_size) {
+       while (elevations.size() <= e_size) {
                probe_distance += point_distance;
                SGGeod probe = SGGeod::fromGeoc(center.advanceRadM( course, probe_distance ));
                const SGMaterial *mat = 0;
@@ -315,7 +338,7 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        
                if (scenery->get_elevation_m( probe, elevation_m, &mat )) {
                        if((transmission_type == 3) || (transmission_type == 4)) {
-                               _elevations.push_back(elevation_m);
+                               elevations.push_back(elevation_m);
                                if(mat) {
                                        const std::vector<string> mat_names = mat->get_names();
                                        materials.push_back(mat_names[0]);
@@ -325,7 +348,7 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
                                }
                        }
                        else {
-                                _elevations.push_front(elevation_m);
+                                elevations.push_front(elevation_m);
                                 if(mat) {
                                         const std::vector<string> mat_names = mat->get_names();
                                         materials.push_front(mat_names[0]);
@@ -337,54 +360,57 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
                }
                else {
                        if((transmission_type == 3) || (transmission_type == 4)) {
-                               _elevations.push_back(0.0);
+                               elevations.push_back(0.0);
                                materials.push_back("None");
                        }
                        else {
-                               _elevations.push_front(0.0);
+                               elevations.push_front(0.0);
                                materials.push_front("None");
                        }
                }
        }
        if((transmission_type == 3) || (transmission_type == 4)) {
-               _elevations.push_front(elevation_under_pilot);
+               elevations.push_front(elevation_under_pilot);
                if (delta_last > (point_distance / 2) )                 // only add last point if it's farther than half point_distance
-                       _elevations.push_back(elevation_under_sender);
+                       elevations.push_back(elevation_under_sender);
        }
        else {
-               _elevations.push_back(elevation_under_pilot);
+               elevations.push_back(elevation_under_pilot);
                if (delta_last > (point_distance / 2) )
-                       _elevations.push_front(elevation_under_sender);
+                       elevations.push_front(elevation_under_sender);
        }
        
        
-       double num_points= (double)_elevations.size();
+       double num_points= (double)elevations.size();
 
-       _elevations.push_front(point_distance);
-       _elevations.push_front(num_points -1);
-       
-    int size = _elevations.size();
-    double itm_elev[10000];
+
+       elevations.push_front(point_distance);
+       elevations.push_front(num_points -1);
+
+       int size = elevations.size();
+       double *itm_elev;
+       itm_elev = new double[size];
 
        for(int i=0;i<size;i++) {
-               itm_elev[i]=_elevations[i];
-               //cerr << "ITM:: itm_elev: " << _elevations[i] << endl;
-       }
+               itm_elev[i]=elevations[i];
+               
 
+       }
+       
        if((transmission_type == 3) || (transmission_type == 4)) {
                // the sender and receiver roles are switched
                point_to_point(itm_elev, receiver_height, transmitter_height,
                        eps_dielect, sgm_conductivity, eno, frq_mhz, radio_climate,
                        pol, conf, rel, dbloss, strmode, p_mode, horizons, errnum);
                if( _root_node->getBoolValue( "use-clutter-attenuation", false ) )
-                       clutterLoss(frq_mhz, itm_elev, materials, receiver_height, transmitter_height, p_mode, horizons, clutter_loss);
+                       calculate_clutter_loss(frq_mhz, itm_elev, materials, receiver_height, transmitter_height, p_mode, horizons, clutter_loss);
        }
        else {
                point_to_point(itm_elev, transmitter_height, receiver_height,
                        eps_dielect, sgm_conductivity, eno, frq_mhz, radio_climate,
                        pol, conf, rel, dbloss, strmode, p_mode, horizons, errnum);
                if( _root_node->getBoolValue( "use-clutter-attenuation", false ) )
-                       clutterLoss(frq_mhz, itm_elev, materials, transmitter_height, receiver_height, p_mode, horizons, clutter_loss);
+                       calculate_clutter_loss(frq_mhz, itm_elev, materials, transmitter_height, receiver_height, p_mode, horizons, clutter_loss);
        }
        
        double pol_loss = 0.0;
@@ -399,16 +425,44 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
        _root_node->setStringValue("station[0]/prop-mode", strmode);
        _root_node->setDoubleValue("station[0]/clutter-attenuation", clutter_loss);
        _root_node->setDoubleValue("station[0]/polarization-attenuation", pol_loss);
-       //cerr << "Clutter loss: " << clutter_loss << endl;
        //if (errnum == 4)      // if parameters are outside sane values for lrprop, the alternative method is used
        //      return -1;
-       signal = link_budget - dbloss - clutter_loss + pol_loss;
-       double signal_strength_dbm = signal_strength - dbloss - clutter_loss + pol_loss;
+       double tx_pattern_gain = 0.0;
+       double rx_pattern_gain = 0.0;
+       if (_root_node->getBoolValue("use-antenna-pattern", false)) {
+               double sender_heading = 270.0; // due West
+               double tx_antenna_bearing = sender_heading - reverse_course * SGD_RADIANS_TO_DEGREES;
+               double rx_antenna_bearing = own_heading - course * SGD_RADIANS_TO_DEGREES;
+               double rx_elev_angle = atan((itm_elev[2] + transmitter_height - itm_elev[(int)itm_elev[0] + 2] + receiver_height) / distance_m) * SGD_RADIANS_TO_DEGREES;
+               double tx_elev_angle = 0.0 - rx_elev_angle;
+               FGRadioAntenna* TX_antenna;
+               FGRadioAntenna* RX_antenna;
+               TX_antenna = new FGRadioAntenna("Plot2");
+               TX_antenna->set_heading(sender_heading);
+               TX_antenna->set_elevation_angle(0);
+               tx_pattern_gain = TX_antenna->calculate_gain(tx_antenna_bearing, tx_elev_angle);
+               RX_antenna = new FGRadioAntenna("Plot2");
+               RX_antenna->set_heading(own_heading);
+               RX_antenna->set_elevation_angle(fgGetDouble("/orientation/pitch-deg"));
+               rx_pattern_gain = RX_antenna->calculate_gain(rx_antenna_bearing, rx_elev_angle);
+               
+               delete TX_antenna;
+               delete RX_antenna;
+       }
+       
+       signal = link_budget - dbloss - clutter_loss + pol_loss + rx_pattern_gain + tx_pattern_gain;
+       double signal_strength_dbm = signal_strength - dbloss - clutter_loss + pol_loss + rx_pattern_gain + tx_pattern_gain;
        double field_strength_uV = dbm_to_microvolt(signal_strength_dbm);
        _root_node->setDoubleValue("station[0]/signal-dbm", signal_strength_dbm);
        _root_node->setDoubleValue("station[0]/field-strength-uV", field_strength_uV);
        _root_node->setDoubleValue("station[0]/signal", signal);
        _root_node->setDoubleValue("station[0]/tx-erp", tx_erp);
+
+       //_root_node->setDoubleValue("station[0]/tx-pattern-gain", tx_pattern_gain);
+       //_root_node->setDoubleValue("station[0]/rx-pattern-gain", rx_pattern_gain);
+
+       delete[] itm_elev;
+
        return signal;
 
 }
@@ -417,7 +471,7 @@ double FGRadioTransmission::ITM_calculate_attenuation(SGGeod pos, double freq, i
 *       We are only worried about clutter loss, terrain influence 
 *       on the first Fresnel zone is calculated in the ITM functions
 ***/
-void FGRadioTransmission::clutterLoss(double freq, double itm_elev[], deque<string> materials,
+void FGRadioTransmission::calculate_clutter_loss(double freq, double itm_elev[], deque<string> &materials,
        double transmitter_height, double receiver_height, int p_mode,
        double horizons[], double &clutter_loss) {