use crate::rinex::RinexEphemeris;
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct GalEphemeris {
pub svid: u32,
pub iodnav: u32,
pub toe_s: f64,
pub toc_s: f64,
pub m0: f64,
pub e: f64,
pub sqrt_a: f64,
pub omega0: f64,
pub i0: f64,
pub omega: f64,
pub idot: f64,
pub omega_dot: f64,
pub delta_n: f64,
pub cuc: f64,
pub cus: f64,
pub crc: f64,
pub crs: f64,
pub cic: f64,
pub cis: f64,
pub af0: f64,
pub af1: f64,
pub af2: f64,
pub sisa_e1e5b: u32,
pub sisa_e1e5a: u32,
pub bgd_e1e5a: f64,
pub bgd_e1e5b: f64,
pub hs_e1b_e5b_e5a: [u32; 3],
pub dvs_e1b_e5b_e5a: [bool; 3],
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct GalIono {
pub ai0: f64,
pub ai1: f64,
pub ai2: f64,
pub region: [bool; 5],
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct Gst {
pub wn: u32,
pub tow: u32,
}
#[derive(Clone, Copy, Debug, Default, PartialEq)]
pub struct GalTimeConversion {
pub a0: f64,
pub a1: f64,
pub dt_ls: i32,
pub t0t: f64,
pub wn0t: u32,
pub wn_lsf: u32,
pub dn: u32,
pub dt_lsf: i32,
pub t0g: f64,
pub a0g: f64,
pub a1g: f64,
pub wn0g: u32,
}
pub fn sisa_index(m: f64) -> u32 {
let idx = if !(0.0..=6.0 + 1e-9).contains(&m) {
255.0
} else if m < 0.495 {
(m / 0.01).round()
} else if m < 0.99 {
50.0 + ((m - 0.5) / 0.02).round()
} else if m < 1.98 {
75.0 + ((m - 1.0) / 0.04).round()
} else {
100.0 + ((m - 2.0) / 0.16).round()
};
idx as u32
}
pub fn ephemeris_from_rinex(r: &RinexEphemeris) -> Result<GalEphemeris, String> {
if r.system != 'E' {
return Err(format!("record is system {}, not Galileo", r.system));
}
let h = r.sv_health.max(0.0) as u32;
let sisa = sisa_index(r.sv_accuracy);
Ok(GalEphemeris {
svid: u32::from(r.prn),
iodnav: r.iode.max(0.0) as u32,
toe_s: r.toe,
toc_s: r.toc.gps_time_of_week(),
m0: r.m0,
e: r.e,
sqrt_a: r.sqrt_a,
omega0: r.omega0,
i0: r.i0,
omega: r.omega,
idot: r.idot,
omega_dot: r.omega_dot,
delta_n: r.delta_n,
cuc: r.cuc,
cus: r.cus,
crc: r.crc,
crs: r.crs,
cic: r.cic,
cis: r.cis,
af0: r.af0,
af1: r.af1,
af2: r.af2,
sisa_e1e5b: sisa,
sisa_e1e5a: sisa,
bgd_e1e5a: r.tgd,
bgd_e1e5b: r.iodc,
hs_e1b_e5b_e5a: [(h >> 1) & 3, (h >> 7) & 3, (h >> 4) & 3],
dvs_e1b_e5b_e5a: [h & 1 == 1, (h >> 6) & 1 == 1, (h >> 3) & 1 == 1],
})
}
pub fn gst_from_gps(gps_week: u32, tow_s: u32) -> Gst {
Gst {
wn: gps_week.saturating_sub(1024) % 4096,
tow: tow_s % 604_800,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sisa_index_follows_the_table() {
assert_eq!(sisa_index(0.0), 0);
assert_eq!(sisa_index(0.49), 49);
assert_eq!(sisa_index(0.5), 50);
assert_eq!(sisa_index(0.98), 74);
assert_eq!(sisa_index(1.0), 75);
assert_eq!(sisa_index(1.96), 99);
assert_eq!(sisa_index(2.0), 100);
assert_eq!(sisa_index(3.12), 107);
assert_eq!(sisa_index(6.0), 125);
assert_eq!(sisa_index(-1.0), 255);
assert_eq!(sisa_index(100.0), 255);
}
#[test]
fn gst_week_offset() {
assert_eq!(gst_from_gps(2350, 7), Gst { wn: 1326, tow: 7 });
}
}