pub const OMEGA_EARTH: f64 = 7.292_115_9e-5;
pub const C_M_PER_S: f64 = 299_792_458.0;
type Vec3 = [f64; 3];
pub fn sagnac_correction(r1: Vec3, r2: Vec3) -> f64 {
OMEGA_EARTH * (r1[0] * r2[1] - r2[0] * r1[1]) / (C_M_PER_S * C_M_PER_S)
}
pub fn common_view_offset(pr_a: f64, range_a: f64, pr_b: f64, range_b: f64) -> f64 {
((pr_a - range_a) - (pr_b - range_b)) / C_M_PER_S
}
#[cfg(test)]
mod tests {
use super::*;
const RE: f64 = 6_378_137.0;
#[test]
fn sagnac_equatorial_quarter_turn_is_about_33_ns() {
let dt = sagnac_correction([RE, 0.0, 0.0], [0.0, RE, 0.0]);
assert!((dt - 3.3006e-8).abs() < 1e-11, "Δt = {} s", dt);
}
#[test]
fn sagnac_is_antisymmetric_and_zero_for_radial_or_polar_paths() {
let a = [RE, 1.0e6, 2.0e6];
let b = [-2.0e6, RE, 5.0e5];
assert!((sagnac_correction(a, b) + sagnac_correction(b, a)).abs() < 1e-20);
assert_eq!(sagnac_correction([RE, 0.0, 0.0], [2.0 * RE, 0.0, 0.0]), 0.0);
assert_eq!(sagnac_correction([0.0, 0.0, RE], [0.0, 0.0, 2.0 * RE]), 0.0);
}
#[test]
fn common_view_cancels_the_satellite_clock_and_recovers_the_offset() {
let dt_a = 1.0e-7; let dt_b = -3.0e-8; let range_a = 2.10e7;
let range_b = 2.13e7;
let pr = |range: f64, rx: f64, sv: f64| range + C_M_PER_S * (rx - sv);
for &sv in &[0.0, 1.0e-6, -5.0e-7] {
let est = common_view_offset(
pr(range_a, dt_a, sv),
range_a,
pr(range_b, dt_b, sv),
range_b,
);
assert!((est - (dt_a - dt_b)).abs() < 1e-15, "sv {sv}: est {est}");
}
}
}