_polarization = 1; // default vertical
_propagation_model = 2;
- _terrain_sampling_distance = fgGetDouble("/sim/radio/sampling-distance", 90.0); // regular SRTM is 90 meters
+
+ _root_node = fgGetNode("sim/radio", true);
+ _terrain_sampling_distance = _root_node->getDoubleValue("sampling-distance", 90.0); // regular SRTM is 90 meters
}
FGRadioTransmission::~FGRadioTransmission()
if(ground_to_air == 1) {
- _transmitter_power += 6.0;
+ _transmitter_power += 4.0;
_tx_antenna_height += 30.0;
- _tx_antenna_gain += 3.0;
+ _tx_antenna_gain += 2.0;
}
else {
if ( _propagation_model == 0) {
+ // skip propagation routines entirely
fgSetString("/sim/messages/atc", text.c_str());
}
else if ( _propagation_model == 1 ) {
- // TODO: free space, round earth
+ // Use free-space, round earth
double signal = LOS_calculate_attenuation(tx_pos, freq, ground_to_air);
if (signal <= 0.0) {
return;
else {
fgSetString("/sim/messages/atc", text.c_str());
- /** write signal strength above threshold to the property tree
- * to implement a simple S-meter just divide by 3 dB per grade (VHF norm)
- **/
- fgSetDouble("/sim/radio/comm1-signal", signal);
+
}
}
else if ( _propagation_model == 2 ) {
//cerr << "Usable signal at limit: " << signal << endl;
fgSetDouble("/sim/sound/voices/voice/volume", volume);
fgSetString("/sim/messages/atc", text.c_str());
- fgSetDouble("/sim/radio/comm1-signal", signal);
fgSetDouble("/sim/sound/voices/voice/volume", old_volume);
}
else {
fgSetString("/sim/messages/atc", text.c_str());
- /** write signal strength above threshold to the property tree
- * to implement a simple S-meter just divide by 3 dB per grade (VHF norm)
- **/
- fgSetDouble("/sim/radio/comm1-signal", signal);
}
}
double link_budget = tx_pow - _receiver_sensitivity - _rx_line_losses - _tx_line_losses + ant_gain;
+ double signal_strength = tx_pow - _rx_line_losses - _tx_line_losses + ant_gain;
+ double tx_erp = dbm_to_watt(tx_pow + _tx_antenna_gain - _tx_line_losses);
+
FGScenery * scenery = globals->get_scenery();
SG_LOG(SG_GENERAL, SG_BULK,
"ITM:: RX-height: " << receiver_height << " meters, TX-height: " << transmitter_height << " meters, Distance: " << distance_m << " meters");
- cerr << "ITM:: RX-height: " << receiver_height << " meters, TX-height: " << transmitter_height << " meters, Distance: " << distance_m << " meters" << endl;
+ //cerr << "ITM:: RX-height: " << receiver_height << " meters, TX-height: " << transmitter_height << " meters, Distance: " << distance_m << " meters" << endl;
+ _root_node->setDoubleValue("station[0]/rx-height", receiver_height);
+ _root_node->setDoubleValue("station[0]/tx-height", transmitter_height);
+ _root_node->setDoubleValue("station[0]/distance", distance_m / 1000);
unsigned int e_size = (deque<unsigned>::size_type)max_points;
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( fgGetBool( "/sim/radio/use-clutter-attenuation", false ) )
+ if( _root_node->getBoolValue( "use-clutter-attenuation", false ) )
clutterLoss(frq_mhz, distance_m, 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( fgGetBool( "/sim/radio/use-clutter-attenuation", false ) )
+ if( _root_node->getBoolValue( "use-clutter-attenuation", false ) )
clutterLoss(frq_mhz, distance_m, itm_elev, materials, transmitter_height, receiver_height, p_mode, horizons, clutter_loss);
}
+
+ double pol_loss = 0.0;
+ if (_polarization == 1) {
+ pol_loss = polarization_loss();
+ }
SG_LOG(SG_GENERAL, SG_BULK,
"ITM:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm, " << strmode << ", Error: " << errnum);
- cerr << "ITM:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm, " << strmode << ", Error: " << errnum << endl;
-
- cerr << "Clutter loss: " << clutter_loss << endl;
+ //cerr << "ITM:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm, " << strmode << ", Error: " << errnum << endl;
+ _root_node->setDoubleValue("station[0]/link-budget", link_budget);
+ _root_node->setDoubleValue("station[0]/terrain-attenuation", dbloss);
+ _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;
+ signal = link_budget - dbloss - clutter_loss + pol_loss;
+ double signal_strength_dbm = signal_strength - dbloss - clutter_loss + pol_loss;
+ 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);
return signal;
}
if (distance_m > total_horizon) {
return -1;
}
-
+ double pol_loss = 0.0;
+ if (_polarization == 1) {
+ pol_loss = polarization_loss();
+ }
// free-space loss (distance calculation should be changed)
dbloss = 20 * log10(distance_m) +20 * log10(frq_mhz) -27.55;
- signal = link_budget - dbloss;
+ signal = link_budget - dbloss + pol_loss;
SG_LOG(SG_GENERAL, SG_BULK,
"LOS:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm ");
//cerr << "LOS:: Link budget: " << link_budget << ", Attenuation: " << dbloss << " dBm " << endl;
double theta_deg;
double roll = fgGetDouble("/orientation/roll-deg");
+ if (fabs(roll) > 85.0)
+ roll = 85.0;
double pitch = fgGetDouble("/orientation/pitch-deg");
- double theta = acos( sqrt( cos(roll) * cos(roll) + cos(pitch) * cos(pitch) ));
- if (_polarization == 1)
+ if (fabs(pitch) > 85.0)
+ pitch = 85.0;
+ double theta = fabs( atan( sqrt(
+ pow(tan(roll * SGD_DEGREES_TO_RADIANS), 2) +
+ pow(tan(pitch * SGD_DEGREES_TO_RADIANS), 2) )) * SGD_RADIANS_TO_DEGREES);
+
+ if (_polarization == 0)
theta_deg = 90.0 - theta;
else
theta_deg = theta;
- if (fabs(theta_deg) > 85.0) // we don't want to converge into infinity
+ if (theta_deg > 85.0) // we don't want to converge into infinity
theta_deg = 85.0;
- return 10 * log10(cos(theta_deg) * cos(theta_deg));
+
+ double loss = 10 * log10( pow(cos(theta_deg * SGD_DEGREES_TO_RADIANS), 2) );
+ //cerr << "Polarization loss: " << loss << " dBm " << endl;
+ return loss;
+}
+
+
+double FGRadioTransmission::watt_to_dbm(double power_watt) {
+ return 10 * log10(1000 * power_watt); // returns dbm
+}
+
+double FGRadioTransmission::dbm_to_watt(double dbm) {
+ return exp( (dbm-30) * log(10) / 10); // returns Watts
+}
+
+double FGRadioTransmission::dbm_to_microvolt(double dbm) {
+ return sqrt(dbm_to_watt(dbm) * 50) * 1000000; // returns microvolts
}