#![cfg(sidereon_repo_tests)]
use std::time::Instant;
use sidereon_core::ephemeris::Sp3;
use sidereon_core::observables::{
predict_ranges, transmit_time_satellite_state, PredictOptions, RangePrediction,
RangePredictionRequest, TransmitTimeOptions,
};
use sidereon_core::{GnssSatelliteId, GnssSystem};
fn sp3_fixture() -> Sp3 {
let path = concat!(
env!("CARGO_MANIFEST_DIR"),
"/tests/fixtures/sp3/GRG0MGXFIN_20201760000_01D_15M_ORB.SP3"
);
let bytes = std::fs::read(path).unwrap_or_else(|e| panic!("read SP3 fixture {path}: {e}"));
Sp3::parse(&bytes).expect("parse SP3 fixture")
}
fn requests(sp3: &Sp3) -> Vec<RangePredictionRequest> {
let sat = GnssSatelliteId::new(GnssSystem::Gps, 21).expect("valid satellite id");
let rx = [3_512_900.0, 780_500.0, 5_248_700.0];
let epochs = sp3.epochs_j2000_seconds();
let mut times = Vec::new();
for w in epochs.windows(2) {
times.push(w[0]);
times.push(0.5 * (w[0] + w[1]));
}
assert!(!times.is_empty(), "fixture has no covered epochs");
(0..2_000)
.map(|i| RangePredictionRequest {
sat,
receiver_ecef_m: rx,
t_rx_j2000_s: times[i % times.len()],
})
.collect()
}
#[test]
#[ignore = "manual throughput bench; run with --ignored --release"]
fn predict_ranges_throughput() {
let sp3 = sp3_fixture();
let requests = requests(&sp3);
let options = PredictOptions::default();
let tt_options = TransmitTimeOptions {
light_time: options.light_time,
sagnac: options.sagnac,
};
let zero = RangePrediction {
geometric_range_m: 0.0,
sat_clock_s: None,
transmit_time_j2000_s: 0.0,
sat_pos_ecef_m: [0.0; 3],
};
let passes = 40usize;
let total = passes * requests.len();
let mut out = vec![zero; requests.len()];
predict_ranges(&sp3, &requests, options, &mut out).expect("warmup");
let mut acc = 0.0f64;
let start = Instant::now();
for _ in 0..passes {
for request in &requests {
let state = transmit_time_satellite_state(
&sp3,
request.sat,
request.receiver_ecef_m,
request.t_rx_j2000_s,
tt_options,
)
.expect("transmit-time state");
acc += state.geometric_range_m;
}
}
let full_elapsed = start.elapsed();
let start = Instant::now();
for _ in 0..passes {
predict_ranges(&sp3, &requests, options, &mut out).expect("batch ranges");
acc += out[0].geometric_range_m;
}
let batch_elapsed = start.elapsed();
std::hint::black_box(acc);
let full_us = full_elapsed.as_secs_f64() * 1.0e6 / total as f64;
let batch_us = batch_elapsed.as_secs_f64() * 1.0e6 / total as f64;
let speedup = full_us / batch_us;
eprintln!(
"predict_ranges: {total} requests\n full transmit-time (velocity): {full_us:.4} \
us/request\n vectorized range batch: {batch_us:.4} us/request\n speedup: \
{speedup:.2}x"
);
}