gnss_qc/context/time.rs
1use crate::prelude::{ProductType, QcContext, TimeScale};
2
3use qc_traits::{Merge, TimeCorrectionError, TimeCorrectionsDB, Timeshift};
4
5impl QcContext {
6 /// Collect a [TimeCorrectionDB] from this [QcContext], that you can then
7 /// use for precise temporal correction. The database will contain
8 /// all time corrections available and described by this dataset.
9 /// This requires both navigation feature and navigation compatibility to truly be effective.
10 pub fn time_corrections_database(&self) -> Option<TimeCorrectionsDB> {
11 let mut db = Option::<TimeCorrectionsDB>::None;
12
13 if let Some(brdc) = self.brdc_navigation() {
14 if let Some(nav_db) = brdc.time_corrections_database() {
15 if let Some(db) = &mut db {
16 db.merge_mut(&nav_db).unwrap(); // infaillble
17 } else {
18 db = Some(nav_db);
19 }
20 }
21 }
22
23 db
24 }
25
26 /// Infaillible transposition of the temporal products to desired [TimeScale].
27 /// This only applies to the following products:
28 /// - Observation RINEX
29 /// - SP3
30 /// ```
31 /// use gnss_qc::prelude::{QcContext, TimeScale};
32 ///
33 /// let mut context = QcContext::new();
34 ///
35 /// // GPST observations
36 /// context.load_gzip_rinex_file("data/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz")
37 /// .unwrap();
38 ///
39 /// // GPST sP3
40 /// context.load_sp3_file("data/SP3/D/example.txt")
41 /// .unwrap();
42 ///
43 /// // convert both to GST
44 /// context.timescale_transposition_mut(TimeScale::GST);
45 /// ```
46 pub fn timescale_transposition_mut(&mut self, timescale: TimeScale) {
47 for (product_type, data) in self.blob.iter_mut() {
48 match product_type {
49 ProductType::Observation => {
50 let rinex = data.as_mut_rinex().unwrap();
51 rinex.timeshift_mut(timescale);
52 }
53 #[cfg(feature = "sp3")]
54 ProductType::HighPrecisionOrbit => {
55 let sp3 = data.as_mut_sp3().unwrap();
56 sp3.timeshift_mut(timescale);
57 }
58 _ => {}
59 }
60 }
61 }
62
63 /// Precise temporal transposition of each individual products contained in current [QcContext].
64 /// NB: transposition might not be feasible for some components, therefore
65 /// you should double check the newly obtained [QcContext].
66 ///
67 /// This may apply to your [SP3] products, if feature is activated.
68 ///
69 /// Example (1): precise RINEX transpositions
70 /// ```
71 /// use gnss_qc::prelude::{QcContext, TimeScale};
72 ///
73 /// let mut context = QcContext::new();
74 ///
75 /// // GPST observations
76 /// context.load_gzip_rinex_file("data/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz")
77 /// .unwrap();
78 ///
79 /// // this setup is not compatible
80 /// assert!(context.time_corrections_database().is_none());
81 ///
82 /// // stack NAV RINEX
83 /// context.load_gzip_rinex_file("data/NAV/V3/ESBC00DNK_R_20201770000_01D_MN.rnx.gz")
84 /// .unwrap();
85 ///
86 /// let database = context.time_corrections_database()
87 /// .unwrap();
88 ///
89 /// context.precise_time_correction_mut(&database, TimeScale::GST);
90 ///
91 /// // verify we shifted all observations to GST
92 /// let transposed_obs = context.observation().unwrap();
93 ///
94 /// for t in transposed_obs.epoch_iter() {
95 /// assert_eq!(t.time_scale, TimeScale::GST);
96 /// }
97 /// ```
98 ///
99 /// Example (2): SP3 transposition.
100 /// SP3 are totally valid in any GNSS timescale, you can use this framework
101 /// to reformat as desired !
102 ///
103 pub fn precise_time_correction_mut(
104 &mut self,
105 db: &TimeCorrectionsDB,
106 timescale: TimeScale,
107 ) -> Result<(), TimeCorrectionError> {
108 if let Some(observations) = self.observation_mut() {
109 observations.precise_correction_mut(db, timescale)?;
110 }
111
112 #[cfg(feature = "sp3")]
113 if let Some(sp3) = self.sp3_mut() {
114 sp3.precise_correction_mut(db, timescale)?;
115 }
116
117 Ok(())
118 }
119}