gnss-rtk 0.8.0

GNSS position solver
Documentation
use crate::{
    prelude::{Almanac, Duration, Epoch, Frame, Orbit, OrbitSource, SV},
    tests::data::{E01, E03, E05, E09, E13, E15, E24, E31},
};

use rstest::*;

use itertools::Itertools;

use std::{collections::HashMap, str::FromStr};

const MIN_ORBITS_PER_EPOCH: usize = 4 * 2;

#[fixture]
fn build_almanac() -> Almanac {
    use crate::tests::almanac;
    almanac()
}

#[fixture]
fn build_earth_frame() -> Frame {
    use crate::tests::earth_frame;
    earth_frame()
}

#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Hash)]
pub struct OrbitsDataKey {
    pub sv: SV,
    pub epoch: Epoch,
}

pub struct OrbitsData {
    pub map: HashMap<OrbitsDataKey, Orbit>,
}

impl OrbitsData {
    pub fn new(frame: Frame) -> Self {
        let t0_gpst = Epoch::from_str("2020-06-25T00:00:00 GPST").unwrap();
        let t1_gpst = Epoch::from_str("2020-06-25T00:15:00 GPST").unwrap();
        let t2_gpst = Epoch::from_str("2020-06-25T00:30:00 GPST").unwrap();
        let t3_gpst = Epoch::from_str("2020-06-25T00:45:00 GPST").unwrap();
        let t4_gpst = Epoch::from_str("2020-06-25T01:00:00 GPST").unwrap();

        let map = HashMap::from_iter([
            (
                OrbitsDataKey {
                    sv: E01,
                    epoch: t0_gpst,
                },
                Orbit::from_position(-11562.163582, 14053.114306, 23345.128269, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E03,
                    epoch: t0_gpst,
                },
                Orbit::from_position(4577.136069, -22995.974895, 18062.640686, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E05,
                    epoch: t0_gpst,
                },
                Orbit::from_position(16577.017768, -4619.539763, 24092.494804, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E09,
                    epoch: t0_gpst,
                },
                Orbit::from_position(18846.610510, 16144.830741, 16159.863309, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E13,
                    epoch: t0_gpst,
                },
                Orbit::from_position(-15921.765341, -5400.108297, 24360.804625, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E15,
                    epoch: t0_gpst,
                },
                Orbit::from_position(-409.147663, -21456.140629, 20391.202816, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E24,
                    epoch: t0_gpst,
                },
                Orbit::from_position(26947.918853, 9320.740084, 7908.580547, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E31,
                    epoch: t0_gpst,
                },
                Orbit::from_position(11195.440434, 16391.022663, 21968.198345, t0_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E01,
                    epoch: t1_gpst,
                },
                Orbit::from_position(-13618.625154, 13865.251337, 22325.739925, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E03,
                    epoch: t1_gpst,
                },
                Orbit::from_position(5249.050928, -21427.275276, 19733.539343, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E05,
                    epoch: t1_gpst,
                },
                Orbit::from_position(17451.377203, -2644.578813, 23770.958635, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E09,
                    epoch: t1_gpst,
                },
                Orbit::from_position(19437.621892, 17372.955840, 14048.13756, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E13,
                    epoch: t1_gpst,
                },
                Orbit::from_position(-14620.483100, -7198.531437, 24709.457156, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E15,
                    epoch: t1_gpst,
                },
                Orbit::from_position(549.559454, -22943.716677, 18698.434257, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E24,
                    epoch: t1_gpst,
                },
                Orbit::from_position(26132.488800, 9133.294721, 10452.358017, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E31,
                    epoch: t1_gpst,
                },
                Orbit::from_position(9177.338648, 16128.279322, 23070.547459, t1_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E01,
                    epoch: t2_gpst,
                },
                Orbit::from_position(-15578.906571, 13828.422191, 21028.690065, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E03,
                    epoch: t2_gpst,
                },
                Orbit::from_position(6089.334963, -19783.358422, 21158.979160, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E05,
                    epoch: t2_gpst,
                },
                Orbit::from_position(18436.719493, -770.324223, 23154.020400, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E09,
                    epoch: t2_gpst,
                },
                Orbit::from_position(20017.686424, 18382.862213, 11761.922747, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E13,
                    epoch: t2_gpst,
                },
                Orbit::from_position(-13443.345950, -9101.204022, 24750.808535, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E15,
                    epoch: t2_gpst,
                },
                Orbit::from_position(1313.090113, -24357.643799, 16773.179621, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E24,
                    epoch: t2_gpst,
                },
                Orbit::from_position(25082.310095, 8993.926987, 12865.989009, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E31,
                    epoch: t2_gpst,
                },
                Orbit::from_position(7059.263844, 16006.140471, 23886.192153, t2_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E01,
                    epoch: t3_gpst,
                },
                Orbit::from_position(-17408.137167, 13927.983030, 19470.096085, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E03,
                    epoch: t3_gpst,
                },
                Orbit::from_position(7098.698927, -18099.833762, 22321.267348, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E05,
                    epoch: t3_gpst,
                },
                Orbit::from_position(19509.930356, 974.904114, 22249.348845, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E09,
                    epoch: t3_gpst,
                },
                Orbit::from_position(20553.093095, 19169.983128, 9329.608871, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E13,
                    epoch: t3_gpst,
                },
                Orbit::from_position(-12411.471925, -11074.923521, 24484.357047, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E15,
                    epoch: t3_gpst,
                },
                Orbit::from_position(1887.325160, -25661.135185, 14639.374285, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E24,
                    epoch: t3_gpst,
                },
                Orbit::from_position(23814.294414, 8933.516592, 15119.417055, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E31,
                    epoch: t3_gpst,
                },
                Orbit::from_position(4877.703417, 16036.340787, 24404.993554, t3_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E01,
                    epoch: t4_gpst,
                },
                Orbit::from_position(-19074.795786, 14143.814957, 17669.329791, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E03,
                    epoch: t4_gpst,
                },
                Orbit::from_position(8271.797755, -16412.322261, 23205.987823, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E05,
                    epoch: t4_gpst,
                },
                Orbit::from_position(20643.741422, 2567.147607, 21068.184349, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E09,
                    epoch: t4_gpst,
                },
                Orbit::from_position(21010.298836, 19735.979210, 6781.401622, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E13,
                    epoch: t4_gpst,
                },
                Orbit::from_position(-11540.233821, -13083.511580, 23913.427261, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E15,
                    epoch: t4_gpst,
                },
                Orbit::from_position(2284.385592, -26819.485051, 12323.546523, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E24,
                    epoch: t4_gpst,
                },
                Orbit::from_position(22350.983090, 8979.707681, 17184.581953, t4_gpst, frame),
            ),
            (
                OrbitsDataKey {
                    sv: E31,
                    epoch: t4_gpst,
                },
                Orbit::from_position(2670.799462, 16224.467677, 24620.497432, t4_gpst, frame),
            ),
        ]);

        Self { map }
    }
}

impl OrbitSource for OrbitsData {
    fn state_at(&self, epoch: Epoch, sv: SV, _: Frame) -> Option<Orbit> {
        let dt_1s = Duration::from_seconds(1.0);

        let orbit = self
            .map
            .iter()
            .filter_map(|(k, v)| {
                if k.sv == sv && (k.epoch - epoch).abs() < dt_1s {
                    Some(v)
                } else {
                    None
                }
            })
            .reduce(|k, _| k)?;

        Some(*orbit)
    }
}

#[test]
fn verify_min_test_orbits_per_epoch() {
    let earth_frame = build_earth_frame();

    let data = OrbitsData::new(earth_frame);

    for epoch in data.map.keys().map(|k| k.epoch).unique() {
        let collected = data
            .map
            .iter()
            .filter(|(k, _)| k.epoch == epoch)
            .collect::<Vec<_>>();

        assert!(
            collected.len() >= MIN_ORBITS_PER_EPOCH,
            "not enough valid test orbits @ {epoch}"
        );
    }
}