gnss_qc/context/navigation/
mod.rs1use thiserror::Error;
15
16use log::error;
17
18use anise::{
19 almanac::{
20 metaload::{MetaAlmanacError, MetaFile},
21 planetary::PlanetaryDataError,
22 },
23 constants::frames::{EARTH_ITRF93, EARTH_J2000},
24 errors::AlmanacError,
25 prelude::{Almanac, Frame, MetaAlmanac},
26};
27
28use crate::{
29 navigation::{NavFilter, NavFilterType},
30 prelude::{Constellation, QcContext},
31};
32
33#[cfg(feature = "navigation")]
34use crate::prelude::{Orbit, ReferenceEcefPosition};
35
36#[derive(Debug, Error)]
37pub enum NavigationError {
38 #[error("almanac error: {0}")]
39 Almanac(#[from] AlmanacError),
40 #[error("meta error: {0}")]
41 MetaAlmanac(#[from] MetaAlmanacError),
42 #[error("planetary data error")]
43 PlanetaryData(#[from] PlanetaryDataError),
44}
45
46impl QcContext {
47 fn anise_de440s_bsp() -> MetaFile {
48 MetaFile {
49 crc32: Some(0x7286750a),
50 uri: String::from("http://public-data.nyxspace.com/anise/de440s.bsp"),
51 }
52 }
53
54 fn anise_pck11_pca() -> MetaFile {
55 MetaFile {
56 crc32: Some(0x8213b6e9),
57 uri: String::from("http://public-data.nyxspace.com/anise/v0.5/pck11.pca"),
58 }
59 }
60
61 fn anise_jpl_bpc() -> MetaFile {
62 MetaFile {
63 crc32: None,
64 uri:
65 "https://naif.jpl.nasa.gov/pub/naif/generic_kernels/pck/earth_latest_high_prec.bpc"
66 .to_string(),
67 }
68 }
69
70 fn default_meta_almanac() -> MetaAlmanac {
72 MetaAlmanac {
73 files: vec![Self::anise_pck11_pca(), Self::anise_de440s_bsp()],
74 }
75 }
76
77 fn high_precision_meta_almanac() -> MetaAlmanac {
79 MetaAlmanac {
80 files: vec![
81 Self::anise_pck11_pca(),
82 Self::anise_de440s_bsp(),
83 Self::anise_jpl_bpc(),
84 ],
85 }
86 }
87
88 pub fn new_alamac_frame(almanac: Almanac, frame: Frame) -> Self {
93 Self {
94 files: Default::default(),
95 blob: Default::default(),
96 almanac,
97 earth_cef: frame,
98 }
99 }
100
101 pub(crate) fn default_almanac_frame() -> (Almanac, Frame) {
103 let mut meta = Self::default_meta_almanac();
104
105 let almanac = match meta.process(false) {
106 Ok(almanac) => almanac,
107 Err(e) => {
108 error!("anise error: {}", e);
109 Almanac::default()
110 }
111 };
112
113 let frame = almanac
114 .frame_from_uid(EARTH_J2000)
115 .unwrap_or_else(|e| panic!("anise internal error: {}", e));
116
117 (almanac, frame)
118 }
119
120 pub fn reference_rx_position(&self) -> Option<ReferenceEcefPosition> {
125 let obs_rinex = self.observation()?;
126 let t = obs_rinex.first_epoch()?;
127 let rx_orbit = obs_rinex.header.rx_orbit(t, self.earth_cef)?;
128 let pos = ReferenceEcefPosition::from_orbit(&rx_orbit);
129 Some(pos)
130 }
131
132 pub fn reference_rx_orbit(&self) -> Option<Orbit> {
137 let obs_rinex = self.observation()?;
138 let t = obs_rinex.first_epoch()?;
139 obs_rinex.header.rx_orbit(t, self.earth_cef)
140 }
141
142 pub fn nav_filter_mut(&mut self, filter: &NavFilter) {
144 if let Some(brdc) = self.brdc_navigation_mut() {
146 let any_constellation = filter.constellations.is_empty();
147 let broad_sbas = filter.constellations.contains(&Constellation::SBAS);
148
149 let brdc_rec = brdc.record.as_mut_nav().unwrap();
150
151 brdc_rec.retain(|k, data| {
152 if let Some(eph) = data.as_ephemeris() {
153 match filter.filter {
154 NavFilterType::Healthy => {
155 if k.sv.constellation.is_sbas() && broad_sbas {
156 eph.sv_healthy()
157 } else {
158 if any_constellation {
159 eph.sv_healthy()
160 } else {
161 if filter.constellations.contains(&k.sv.constellation) {
162 eph.sv_healthy()
163 } else {
164 true
165 }
166 }
167 }
168 }
169 NavFilterType::Testing => {
170 if k.sv.constellation.is_sbas() && broad_sbas {
171 eph.sv_in_testing()
172 } else {
173 if any_constellation {
174 eph.sv_in_testing()
175 } else {
176 if filter.constellations.contains(&k.sv.constellation) {
177 eph.sv_in_testing()
178 } else {
179 true
180 }
181 }
182 }
183 }
184 NavFilterType::Unhealthy => {
185 if k.sv.constellation.is_sbas() && broad_sbas {
186 !eph.sv_healthy()
187 } else {
188 if any_constellation {
189 !eph.sv_healthy()
190 } else {
191 if filter.constellations.contains(&k.sv.constellation) {
192 !eph.sv_healthy()
193 } else {
194 true
195 }
196 }
197 }
198 }
199 }
200 } else {
201 true
203 }
204 });
205 }
206 }
207
208 pub fn with_jpl_bpc(&self) -> Result<(), NavigationError> {
210 let mut s = self.clone();
211
212 let mut meta = Self::high_precision_meta_almanac();
213 let almanac = meta.process(true)?;
214
215 s.almanac = almanac;
216
217 let mut meta = Self::default_meta_almanac();
218 let almanac = meta.process(true)?;
219
220 let frame = almanac.frame_from_uid(EARTH_ITRF93)?;
221 s.earth_cef = frame;
222
223 Ok(())
224 }
225}