use super::{BandPreset, PresetSource, ShellPreset, SourceKind, SystemPreset};
use crate::leo_link::antenna::{Polarisation, SatPattern};
pub const X1_EIRP_DBW: f64 = 17.582_524;
pub const X5_EIRP_DBW: f64 = 18.351_157;
const BASIS: &str = "arXiv 2509.19551 Table 2 (frequency, bandwidth, chip rate, code length, \
data rate, received powers); EIRP derived from the published minimum received power at 10 \
deg elevation with a flat pattern; polarisation and axial ratio representative";
pub const PRESET: SystemPreset = SystemPreset {
id: "xona-pulsar",
name: "Xona Pulsar (X1, X5)",
source: PresetSource {
kind: SourceKind::Public,
citation: "Leclère, Marathe and Reid, ION GNSS+ 2025, arXiv 2509.19551, Tables 1 and 2",
urls: &["https://arxiv.org/abs/2509.19551"],
},
shells: &[
ShellPreset {
altitude_km: 1080.0,
inclination_deg: Some(53.0),
total: 192,
planes: 12,
phasing: 1,
star: false,
},
ShellPreset {
altitude_km: 1080.0,
inclination_deg: Some(97.0),
total: 66,
planes: 6,
phasing: 1,
star: false,
},
],
orbit_basis: "arXiv 2509.19551 Table 1: 1080 km, 12 planes x 16 at 53 deg and 6 planes x 11 \
at 97 deg, uniform in-plane spacing, fixed inter-plane phasing",
bands: &[
BandPreset {
name: "X1",
centre_hz: 1_593.322_5e6,
tx_bandwidth_hz: 1.77e6,
chip_rate_hz: 1.023e6,
code_length_chips: 1023.0,
data_rate_bps: 1000.0,
eirp_dbw: X1_EIRP_DBW,
pattern: SatPattern::Flat,
polarisation: Polarisation::Rhcp,
axial_ratio_db: 1.0,
allocation: "RNSS (L1 band)",
ranging: true,
basis: BASIS,
},
BandPreset {
name: "X5",
centre_hz: 1_190.516_25e6,
tx_bandwidth_hz: 17.7e6,
chip_rate_hz: 10.23e6,
code_length_chips: 10230.0,
data_rate_bps: 4000.0,
eirp_dbw: X5_EIRP_DBW,
pattern: SatPattern::Flat,
polarisation: Polarisation::Rhcp,
axial_ratio_db: 1.0,
allocation: "RNSS (L5 band)",
ranging: true,
basis: BASIS,
},
],
cold_start_bits: 1000.0,
notes: "Pulsar-0 (in-orbit validation) flies near 520 km at 97 deg: override altitude_km. \
The broadcast ephemeris model, clock type and what the company's 1.5 cm figure measures \
are not public.",
};
#[cfg(test)]
mod tests {
use super::super::{fspl_db, slant_range_m};
use super::*;
#[test]
fn the_eirps_reproduce_the_published_minimum_power_at_ten_degrees() {
let rho = slant_range_m(1080e3, 10.0);
assert!((rho - 2_913_623.0).abs() < 1.0);
for (f, pmin, eirp) in [
(1_593.322_5e6, -148.2, X1_EIRP_DBW),
(1_190.516_25e6, -144.9, X5_EIRP_DBW),
] {
assert!((eirp - fspl_db(rho, f) - pmin).abs() < 1e-5);
}
}
#[test]
fn a_flat_pattern_lands_the_zenith_power_near_the_published_maximum() {
for (f, pmax, eirp) in [
(1_593.322_5e6, -139.1, X1_EIRP_DBW),
(1_190.516_25e6, -136.2, X5_EIRP_DBW),
] {
let p = eirp - fspl_db(1080e3, f);
assert!((p - pmax).abs() < 0.5, "{p} vs {pmax}");
}
}
}