apsis-rs/crates/rf/apsis-rf/tests/free_space.rs

144 lines
5.5 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//! Tests for free space propagation.
//!
//! 自由空间传播的测试。
use apsis_core::constant::SPEED_OF_LIGHT;
use apsis_rf::{Gain, free_space_path_loss, free_space_received_ratio, wavelength};
const TOLERANCE: f64 = 1e-9;
#[test]
fn wavelength_is_the_speed_of_light_over_frequency() {
assert!((wavelength(SPEED_OF_LIGHT).expect("valid") - 1.0).abs() < TOLERANCE);
// A frequency of 300 MHz has a wavelength of about one meter.
// 300 MHz 的频率波长约为米。
assert!((wavelength(300.0e6).expect("valid") - 0.999_308).abs() < 1e-5);
// The same relation holds for a microwave frequency.
// 同一关系对微波频率也成立。
assert!((wavelength(12.0e9).expect("valid") - 0.024_982_7).abs() < 1e-6);
}
#[test]
fn wavelength_rejects_invalid_frequencies() {
assert_eq!(wavelength(0.0), None);
assert_eq!(wavelength(-1.0), None);
assert_eq!(wavelength(f64::NAN), None);
assert_eq!(wavelength(f64::INFINITY), None);
}
#[test]
fn path_loss_matches_the_closed_form() {
// Attenuation over one meter at one meter wavelength: the ratio is
// (4 pi)^2, about 21.98 dB.
// 一米波长下一米距离的衰减:比值为 (4 pi)^2,约 21.98 dB。
let loss = free_space_path_loss(1.0, SPEED_OF_LIGHT).expect("valid arguments");
let expected = 10.0 * (4.0 * core::f64::consts::PI).powi(2).log10();
assert!((loss.db() - expected).abs() < 1e-9, "loss {}", loss.db());
assert!((loss.db() - 21.984).abs() < 0.001);
}
#[test]
fn path_loss_matches_the_engineering_form() {
// The form used in link budgets, with distance in kilometers and
// frequency in megahertz,
// 链路预算中所用的形式,距离以千米、频率以兆赫兹计,
//
// L = 32.44 + 20 log10(d_km) + 20 log10(f_MHz)
// L = 32.44 + 20 log10(d_km) + 20 log10(f_MHz)
// L = 32.44 + 20 log10(d_km) + 20 log10(f_MHz)
//
// has a constant that follows from the speed of light rounded to
// 299 792 458 m/s, and agrees with the expression used here to the
// precision of that constant.
// 其常数由舍入到 299 792 458 m/s 的光速得出,并在该常量的精度内与此处所用的
// 表达式一致。
let distance_km = 1_000.0;
let frequency_mhz = 12_000.0;
let loss = free_space_path_loss(distance_km * 1_000.0, frequency_mhz * 1.0e6)
.expect("valid arguments");
let engineering = 32.44 + 20.0 * distance_km.log10() + 20.0 * frequency_mhz.log10();
assert!(
(loss.db() - engineering).abs() < 0.01,
"loss {} engineering {}",
loss.db(),
engineering
);
}
#[test]
fn a_larger_distance_increases_the_loss_by_six_decibels_per_doubling() {
let near = free_space_path_loss(1_000.0, 1.0e9).expect("valid");
let far = free_space_path_loss(2_000.0, 1.0e9).expect("valid");
assert!((far.db() - near.db() - 6.020_6).abs() < 1e-3);
}
#[test]
fn a_higher_frequency_increases_the_loss() {
let low = free_space_path_loss(1_000.0, 1.0e9).expect("valid");
let high = free_space_path_loss(1_000.0, 2.0e9).expect("valid");
assert!(high.db() > low.db());
assert!((high.db() - low.db() - 6.020_6).abs() < 1e-3);
}
#[test]
fn a_zero_or_negative_distance_is_rejected() {
// A zero distance is outside the far field range where the expression
// applies, and would give an infinite loss in decibels.
// 零距离在该表达式所适用的远场范围之外,会给出以分贝计的无穷损耗。
assert_eq!(free_space_path_loss(0.0, 1.0e9), None);
assert_eq!(free_space_path_loss(-1.0, 1.0e9), None);
}
#[test]
fn invalid_arguments_are_rejected() {
assert_eq!(free_space_path_loss(-1.0, 1.0e9), None);
assert_eq!(free_space_path_loss(f64::NAN, 1.0e9), None);
assert_eq!(free_space_path_loss(1_000.0, 0.0), None);
assert_eq!(free_space_path_loss(1_000.0, -1.0), None);
}
#[test]
fn received_ratio_combines_gains_and_loss() {
let distance = 1_000_000.0;
let frequency = 12.0e9;
let transmitter = Gain::from_dbi(30.0).expect("valid");
let receiver = Gain::from_dbi(40.0).expect("valid");
let ratio =
free_space_received_ratio(distance, frequency, transmitter, receiver).expect("valid");
let loss = free_space_path_loss(distance, frequency).expect("valid");
assert!((ratio.db() - (30.0 + 40.0 - loss.db())).abs() < 1e-9);
}
#[test]
fn a_large_receive_gain_can_exceed_the_spreading_loss() {
// Two dishes of 40 dBi at ten meters and 12 GHz. The spreading loss
// there is about 74 dB, so the 80 dB of combined gain leaves a positive
// ratio. This is the near field of a large antenna pair and is the
// reason a link budget cannot be read without also checking the
// distance regime.
// 两个 40 dBi 的天线,在十米与 12 GHz 下。那里的扩散损耗约为 74 dB,故 80 dB 的
// 合成增益留下正的比值。这是一对大天线的近场,也正是链路预算不能在不检查距离
// 区间的情况下阅读的原因。
let ratio = free_space_received_ratio(
10.0,
12.0e9,
Gain::from_dbi(40.0).expect("valid"),
Gain::from_dbi(40.0).expect("valid"),
)
.expect("valid");
assert!(ratio.db() > 0.0, "ratio {}", ratio.db());
assert!((ratio.db() - 5.969).abs() < 0.01, "ratio {}", ratio.db());
}
#[test]
fn invalid_received_ratio_arguments_are_rejected() {
assert_eq!(
free_space_received_ratio(-1.0, 1.0e9, Gain::ISOTROPIC, Gain::ISOTROPIC),
None
);
assert_eq!(
free_space_received_ratio(1_000.0, 0.0, Gain::ISOTROPIC, Gain::ISOTROPIC),
None
);
}