rinex/navigation/rinex/
feature.rs

1use crate::{
2    navigation::{BdModel, Ephemeris, IonosphereModel, KbModel, NavKey, NgModel},
3    prelude::{
4        nav::{Almanac, AzElRange, Orbit},
5        Epoch, Rinex, SV,
6    },
7};
8
9impl Rinex {
10    /// [SV] orbital state vector determination attempt, that only applies
11    /// to Navigation [Rinex].
12    /// ## Inputs
13    /// - sv: desired [SV]
14    /// - t: desired [Epoch] to express the [Orbit]al state
15    /// ## Returns
16    /// - orbital state: expressed as ECEF [Orbit]
17    pub fn sv_orbit(&self, sv: SV, t: Epoch) -> Option<Orbit> {
18        let (_, _, eph) = self.nav_ephemeris_selection(sv, t)?;
19        eph.kepler2position(sv, t)
20    }
21
22    /// [SV] (azimuth, elevation, slant range) triplet determination,
23    /// that only applies to Navigation [Rinex].
24    /// ## Inputs
25    /// - sv: target [SV]
26    /// - t: target [Epoch]
27    /// - rx_orbit: RX position expressed as an [Orbit]
28    /// - almanac: [Almanac] context
29    /// ## Returns
30    /// - [AzElRange] on calculations success
31    pub fn nav_azimuth_elevation_range(
32        &self,
33        sv: SV,
34        t: Epoch,
35        rx_orbit: Orbit,
36        almanac: &Almanac,
37    ) -> Option<AzElRange> {
38        let sv_orbit = self.sv_orbit(sv, t)?;
39        let azelrange = almanac
40            .azimuth_elevation_range_sez(sv_orbit, rx_orbit, None, None)
41            .ok()?;
42        Some(azelrange)
43    }
44
45    /// Ephemeris selection, that only applies to Navigation [Rinex].
46    /// ## Inputs
47    /// - sv: desired [SV]
48    /// - epoch: desired [Epoch]
49    /// ## Returns
50    /// - (toc, toe, [Ephemeris]) triplet if an [Ephemeris] message
51    /// was decoded in the correct time frame.
52    /// Note that `ToE` does not exist for GEO/SBAS [SV], so `ToC` is simply
53    /// copied in this case, to maintain the API.
54    pub fn nav_ephemeris_selection(&self, sv: SV, t: Epoch) -> Option<(Epoch, Epoch, &Ephemeris)> {
55        if sv.constellation.is_sbas() {
56            self.nav_ephemeris_frames_iter()
57                .filter_map(|(k, eph)| {
58                    if k.sv == sv {
59                        Some((k.epoch, k.epoch, eph))
60                    } else {
61                        None
62                    }
63                })
64                .min_by_key(|(toc, _, _)| t - *toc)
65        } else {
66            self.nav_ephemeris_frames_iter()
67                .filter_map(|(k, eph)| {
68                    if k.sv == sv {
69                        if eph.is_valid(sv, t) {
70                            if let Some(toe) = eph.toe(k.sv) {
71                                Some((k.epoch, toe, eph))
72                            } else {
73                                None
74                            }
75                        } else {
76                            None
77                        }
78                    } else {
79                        None
80                    }
81                })
82                .min_by_key(|(_, toe, _)| (t - *toe).abs())
83        }
84    }
85
86    /// Klobuchar [KbModel] Ionosphere model [Iterator].
87    /// RINEX V4 is the true application of this, as it provides
88    /// regular model updates (reflecting radio message stream).
89    /// Klobuchar Ionosphere models exist in RINEX2 and this
90    /// method applies similarly.
91    pub fn nav_klobuchar_models_iter(&self) -> Box<dyn Iterator<Item = (&NavKey, &KbModel)> + '_> {
92        Box::new(
93            self.nav_ionosphere_models_iter()
94                .filter_map(|(k, v)| match v {
95                    IonosphereModel::Klobuchar(model) => Some((k, model)),
96                    _ => None,
97                }),
98        )
99    }
100
101    /// BDGIM [BdModel] Ionosphere model [Iterator].
102    /// Refer to [Self::nav_klobuchar_models_iter] for similar examples.
103    pub fn nav_bdgim_models_iter(&self) -> Box<dyn Iterator<Item = (&NavKey, &BdModel)> + '_> {
104        Box::new(
105            self.nav_ionosphere_models_iter()
106                .filter_map(|(k, v)| match v {
107                    IonosphereModel::Bdgim(model) => Some((k, model)),
108                    _ => None,
109                }),
110        )
111    }
112
113    /// Nequick-G [NgModel] Ionosphere model [Iterator].
114    /// Refer to [Self::nav_klobuchar_models_iter] for similar examples.
115    pub fn nav_nequickg_models_iter(&self) -> Box<dyn Iterator<Item = (&NavKey, &NgModel)> + '_> {
116        Box::new(
117            self.nav_ionosphere_models_iter()
118                .filter_map(|(k, v)| match v {
119                    IonosphereModel::NequickG(model) => Some((k, model)),
120                    _ => None,
121                }),
122        )
123    }
124}