153 lines
4.6 KiB
Rust
153 lines
4.6 KiB
Rust
//! Writes link budget inputs and the figures this workspace computes for
|
|
//! them.
|
|
//!
|
|
//! The output is CSV on standard output, with a header row. It is consumed
|
|
//! by `validation/python/link/check_link.py`, which recomputes the same
|
|
//! quantities from the link equation and compares.
|
|
//!
|
|
//! Usage:
|
|
//!
|
|
//! ```text
|
|
//! cargo run -p apsis-rs --features rf --example dump_link \
|
|
//! > validation/data/expected/rust_link.csv
|
|
//! ```
|
|
|
|
use apsis_link::{LinkBudget, LinkGeometry};
|
|
use apsis_rf::{Decibel, Gain, Power};
|
|
|
|
/// One link scenario, named so that the fields stay readable at each use.
|
|
///
|
|
/// The unit of each field is in its name: powers and gains in decibels,
|
|
/// temperature in kelvin, and everything else in SI base units.
|
|
struct Scenario {
|
|
transmit_dbw: f64,
|
|
transmit_dbi: f64,
|
|
transmit_loss_db: f64,
|
|
receive_dbi: f64,
|
|
receive_loss_db: f64,
|
|
temperature_k: f64,
|
|
bandwidth_hz: f64,
|
|
distance_m: f64,
|
|
frequency_hz: f64,
|
|
}
|
|
|
|
/// The scenarios checked. They cover a Ku band downlink, an S band link, a
|
|
/// wideband Ka link, and an L band link with a warmer receiver.
|
|
const SCENARIOS: &[Scenario] = &[
|
|
Scenario {
|
|
transmit_dbw: 10.0,
|
|
transmit_dbi: 30.0,
|
|
transmit_loss_db: 1.0,
|
|
receive_dbi: 35.0,
|
|
receive_loss_db: 0.5,
|
|
temperature_k: 150.0,
|
|
bandwidth_hz: 36.0e6,
|
|
distance_m: 38.0e6,
|
|
frequency_hz: 12.0e9,
|
|
},
|
|
Scenario {
|
|
transmit_dbw: 0.0,
|
|
transmit_dbi: 20.0,
|
|
transmit_loss_db: 2.0,
|
|
receive_dbi: 25.0,
|
|
receive_loss_db: 1.0,
|
|
temperature_k: 290.0,
|
|
bandwidth_hz: 1.0e6,
|
|
distance_m: 1_000_000.0,
|
|
frequency_hz: 2.2e9,
|
|
},
|
|
Scenario {
|
|
transmit_dbw: 20.0,
|
|
transmit_dbi: 45.0,
|
|
transmit_loss_db: 0.5,
|
|
receive_dbi: 50.0,
|
|
receive_loss_db: 0.2,
|
|
temperature_k: 80.0,
|
|
bandwidth_hz: 500.0e6,
|
|
distance_m: 400_000.0,
|
|
frequency_hz: 20.0e9,
|
|
},
|
|
Scenario {
|
|
transmit_dbw: 5.0,
|
|
transmit_dbi: 15.0,
|
|
transmit_loss_db: 3.0,
|
|
receive_dbi: 10.0,
|
|
receive_loss_db: 2.0,
|
|
temperature_k: 500.0,
|
|
bandwidth_hz: 10.0e6,
|
|
distance_m: 36_000_000.0,
|
|
frequency_hz: 1.5e9,
|
|
},
|
|
];
|
|
|
|
fn main() {
|
|
println!(
|
|
"transmit_dbw,transmit_dbi,transmit_loss_db,receive_dbi,receive_loss_db,\
|
|
temperature_k,bandwidth_hz,distance_m,frequency_hz,eirp_dbw,carrier_dbw,\
|
|
cn0_db,cn_db,ebn0_db"
|
|
);
|
|
|
|
for scenario in SCENARIOS {
|
|
let Scenario {
|
|
transmit_dbw,
|
|
transmit_dbi,
|
|
transmit_loss_db: transmit_loss,
|
|
receive_dbi,
|
|
receive_loss_db: receive_loss,
|
|
temperature_k: temperature,
|
|
bandwidth_hz: bandwidth,
|
|
distance_m: distance,
|
|
frequency_hz: frequency,
|
|
} = *scenario;
|
|
|
|
let Some(transmit_power) = Power::from_dbw(transmit_dbw) else {
|
|
continue;
|
|
};
|
|
let Some(transmit_gain) = Gain::from_dbi(transmit_dbi) else {
|
|
continue;
|
|
};
|
|
let Some(receive_gain) = Gain::from_dbi(receive_dbi) else {
|
|
continue;
|
|
};
|
|
|
|
let budget = LinkBudget {
|
|
transmit_power,
|
|
transmit_gain,
|
|
transmit_loss: Decibel::from_db(transmit_loss),
|
|
receive_gain,
|
|
receive_loss: Decibel::from_db(receive_loss),
|
|
system_temperature: apsis_link::NoiseTemperature::from_kelvin(temperature),
|
|
bandwidth,
|
|
geometry: LinkGeometry {
|
|
distance,
|
|
frequency,
|
|
},
|
|
};
|
|
|
|
let eirp = budget.eirp().and_then(|power| power.dbw());
|
|
let carrier = budget.received_power().and_then(|power| power.dbw());
|
|
let cn0 = budget.carrier_to_noise_density().map(|value| value.db());
|
|
let cn = budget.carrier_to_noise().map(|value| value.db());
|
|
// The energy per bit ratio is reported at a fixed data rate equal to
|
|
// the bandwidth, which makes it the carrier to noise ratio.
|
|
let ebn0 = budget
|
|
.energy_per_bit_over_noise(bandwidth)
|
|
.map(|value| value.db());
|
|
|
|
let field = |value: Option<f64>| match value {
|
|
Some(value) => format!("{value:.12}"),
|
|
None => "nan".to_string(),
|
|
};
|
|
println!(
|
|
"{transmit_dbw},{transmit_dbi},{transmit_loss},{receive_dbi},{receive_loss},\
|
|
{temperature},{bandwidth:.6},{distance:.6},{frequency:.6},\
|
|
{},{},{},{},{}",
|
|
field(eirp),
|
|
field(carrier),
|
|
field(cn0),
|
|
field(cn),
|
|
field(ebn0)
|
|
);
|
|
}
|
|
}
|