Skip to content

Commit 61dc7d4

Browse files
authored
Dep/hifitime (#345)
* update deps * Improved SBAS formatting * Improved header processing * Improved docs * Fixed SBAS formatting & compression * dep/hifitime integration for testing --------- Signed-off-by: Guillaume W. Bres <[email protected]>
1 parent 117f740 commit 61dc7d4

File tree

8 files changed

+164
-30
lines changed

8 files changed

+164
-30
lines changed

Cargo.toml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,20 +135,21 @@ bitflags = { version = "2.3", features = ["serde"] }
135135
serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] }
136136

137137
geo = { version = "0.28", optional = true }
138-
wkt = { version = "0.10.0", default-features = false, optional = true }
139138
flate2 = { version = "1", optional = true }
139+
wkt = { version = "0.10.0", default-features = false, optional = true }
140140

141-
anise = { version = "0.5.3", optional = true }
142141
nalgebra = { version = "0.33.0", optional = true }
143-
hifitime = { version = "4.0.0", features = ["serde", "std"] }
144-
gnss-rs = { version = "2.3.5", features = ["serde", "domes", "cospar"] }
145142

143+
anise = { git = "https://github.com/nyx-space/anise", branch = "dep/hifitime-github", optional = true }
144+
hifitime = { git = "https://github.com/nyx-space/hifitime", branch = "master", features = ["serde", "std"] }
145+
146+
gnss-rs = { git = "https://github.com/rtk-rs/gnss", branch = "main", features = ["serde", "domes", "cospar"] }
146147
gnss-qc-traits = { git = "https://github.com/rtk-rs/qc-traits", branch = "main", features = ["html"], optional = true }
147148

148149
maud = { version = "0.26", optional = true }
149150

150151
# BINEX
151-
binex = { version = "0.4.2", optional = true }
152+
binex = { git = "https://github.com/rtk-rs/binex", branch = "main", optional = true }
152153

153154
# RTCM
154155
rtcm-rs = { version = "0.11", optional = true }

src/hatanaka/compressor.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use crate::{
55
error::FormattingError,
66
hatanaka::{NumDiff, TextDiff},
77
observation::{HeaderFields, Record},
8-
prelude::{Observable, SV},
8+
prelude::{Constellation, Observable, SV},
99
BufWriter,
1010
};
1111

@@ -147,12 +147,30 @@ impl<const M: usize> CompressorExpert<M> {
147147
// For each SV
148148
for sv in svnn.iter() {
149149
// Following header specs
150-
let observables = header
151-
.codes
152-
.get(&sv.constellation)
153-
.ok_or(FormattingError::MissingObservableDefinition)?;
150+
let sv_observables = header.codes.get(&sv.constellation);
151+
152+
let sv_observables = match sv_observables {
153+
Some(observables) => observables, // correctly identified,
154+
None => {
155+
// handles SBAS case
156+
if sv.constellation.is_sbas() {
157+
match header.codes.get(&Constellation::SBAS) {
158+
Some(observables) => observables,
159+
None => {
160+
// correctly formatted RINEX will never
161+
// end up here
162+
continue;
163+
},
164+
}
165+
} else {
166+
// correctly formatted RINEX will never
167+
// end up here
168+
continue;
169+
}
170+
},
171+
};
154172

155-
for observable in observables.iter() {
173+
for observable in sv_observables.iter() {
156174
if let Some(signal) = v
157175
.signals
158176
.iter()

src/hatanaka/decompressor/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -859,7 +859,12 @@ impl<const M: usize> DecompressorExpert<M> {
859859
if let Some(mixed) = self.gnss_observables.get(&Constellation::Mixed) {
860860
Some(mixed)
861861
} else {
862-
self.gnss_observables.get(constell)
862+
// SBAS special case
863+
if constell.is_sbas() {
864+
self.gnss_observables.get(&Constellation::SBAS)
865+
} else {
866+
self.gnss_observables.get(constell)
867+
}
863868
}
864869
}
865870

src/header/processing.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ fn header_mask_eq(hd: &mut Header, item: &FilterItem) {
99
hd.pcv_compensations
1010
.retain(|pcv| constellations.contains(&pcv.constellation));
1111

12+
if constellations.len() == 1 {
13+
hd.constellation = Some(constellations[0]);
14+
}
15+
1216
if !constellations.contains(&Constellation::Glonass) {
13-
// remove glonass specs
17+
// remove glonass specs in case it is no longer contained
1418
hd.glo_channels.clear();
1519
}
1620
},

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1076,7 +1076,7 @@ impl Rinex {
10761076
}
10771077
}
10781078

1079-
/// Returns [SV] iterator.
1079+
/// Returns a [SV] iterator, from all satellites encountered in this [Rinex].
10801080
pub fn sv_iter(&self) -> Box<dyn Iterator<Item = SV> + '_> {
10811081
if self.is_observation_rinex() {
10821082
Box::new(

src/observation/formatting.rs

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl Observations {
3636
}
3737
}
3838

39-
/// Format [Observations] according to V2 RINEX format
39+
/// Formats [Observations] according to RINEXv2 standards.
4040
fn format_v2<W: Write>(
4141
&self,
4242
w: &mut BufWriter<W>,
@@ -53,22 +53,29 @@ impl Observations {
5353
self.format_epoch_v2(w, key, sv_list, numsat)?;
5454

5555
for sv in sv_list.iter() {
56-
// V2 is too badly specified to permit correct SBAS handling
57-
let observables = if sv.constellation.is_sbas() {
58-
observables.get(&Constellation::SBAS)
59-
} else {
60-
observables.get(&sv.constellation)
61-
};
62-
63-
let observables = match observables {
64-
Some(observables) => observables, // correctly identified
65-
None => continue, // abort
56+
let sv_observables = observables.get(&sv.constellation);
57+
58+
let sv_observables = match sv_observables {
59+
Some(sv_observables) => sv_observables, // correctly identified
60+
None => {
61+
// handles SBAS case
62+
if sv.constellation.is_sbas() {
63+
match observables.get(&Constellation::SBAS) {
64+
Some(sv_observables) => sv_observables,
65+
_ => continue, // abort
66+
}
67+
} else {
68+
// abort: normally formatted RINEX
69+
// will never end up here
70+
continue;
71+
}
72+
},
6673
};
6774

6875
let mut modulo = 0;
6976

7077
// following header specs (strictly)
71-
for (nth, observable) in observables.iter().enumerate() {
78+
for (nth, observable) in sv_observables.iter().enumerate() {
7279
// retrieve observed signal (if any)
7380
if let Some(observation) = self
7481
.signals
@@ -153,6 +160,7 @@ impl Observations {
153160
Ok(())
154161
}
155162

163+
/// Formats [Observations] according to RINEXv3 standards.
156164
fn format_v3<W: Write>(
157165
&self,
158166
w: &mut BufWriter<W>,
@@ -183,14 +191,26 @@ impl Observations {
183191
write!(w, "{:x}", sv)?;
184192

185193
// following header definitions
186-
let observables = observables.get(&sv.constellation);
194+
let sv_observables = observables.get(&sv.constellation);
187195

188-
let observables = match observables {
196+
let sv_observables = match sv_observables {
189197
Some(observables) => observables, // correctly identified
190-
None => continue, // abort
198+
None => {
199+
// handles SBAS case
200+
if sv.constellation.is_sbas() {
201+
match observables.get(&Constellation::SBAS) {
202+
Some(sv_observables) => sv_observables,
203+
_ => continue, // abort
204+
}
205+
} else {
206+
// abort: normally formatted RINEX
207+
// will never end up here
208+
continue;
209+
}
210+
},
191211
};
192212

193-
for observable in observables.iter() {
213+
for observable in sv_observables.iter() {
194214
if let Some(observation) = self
195215
.signals
196216
.iter()

src/tests/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ mod filename;
88
pub mod formatting;
99
mod parsing;
1010

11+
#[cfg(feature = "flate2")]
12+
mod sbas;
13+
1114
#[cfg(feature = "flate2")]
1215
mod production;
1316

src/tests/sbas.rs

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// SBAS specific tests
2+
use crate::prelude::{Constellation, Rinex, SV};
3+
use qc_traits::{Filter, FilterItem, MaskOperand, Preprocessing};
4+
use std::str::FromStr;
5+
6+
// Formatting issue
7+
#[test]
8+
#[cfg(feature = "flate2")]
9+
fn test_sbas_obs_v3_formatting() {
10+
let rinex =
11+
Rinex::from_gzip_file("data/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz").unwrap();
12+
13+
// basic initial verifications..
14+
let (mut s23_found, mut s25_found, mut s36_found) = (false, false, false);
15+
let s23 = SV::from_str("S23").unwrap();
16+
let s25 = SV::from_str("S25").unwrap();
17+
let s36 = SV::from_str("S36").unwrap();
18+
19+
for sv in rinex.sv_iter() {
20+
s23_found |= sv == s23;
21+
s25_found |= sv == s25;
22+
s36_found |= sv == s36;
23+
}
24+
25+
assert!(s23_found, "S23 not present in initial setup!");
26+
assert!(s25_found, "S25 not present in initial setup!");
27+
assert!(s36_found, "S36 not present in initial setup!");
28+
29+
let geo_only = Filter::mask(
30+
MaskOperand::Equals,
31+
FilterItem::ConstellationItem(vec![Constellation::SBAS]),
32+
);
33+
34+
let mut geo_only = rinex.filter(&geo_only);
35+
36+
// RINEX
37+
let rinex_geo_only = geo_only.crnx2rnx();
38+
39+
// dump
40+
rinex_geo_only
41+
.to_file("test_geo-only.txt")
42+
.unwrap_or_else(|e| panic!("SBAS only formatting issue: {}", e));
43+
44+
// parse back
45+
let dut = Rinex::from_file("test_geo-only.txt")
46+
.unwrap_or_else(|e| panic!("SABS only: failed to parse back: {}", e));
47+
48+
// test
49+
let (mut s23_found, mut s25_found, mut s36_found) = (false, false, false);
50+
for sv in dut.sv_iter() {
51+
s23_found |= sv == s23;
52+
s25_found |= sv == s25;
53+
s36_found |= sv == s36;
54+
}
55+
56+
assert!(s23_found, "S23 not present in parsed-back RINEX!");
57+
assert!(s25_found, "S25 not present in parsed-back RINEX!");
58+
assert!(s36_found, "S36 not present in parsed-back RINEX!");
59+
60+
// CRINEX dump
61+
geo_only
62+
.to_file("test_geo-only.txt")
63+
.unwrap_or_else(|e| panic!("SBAS only CRINEX formatting issue: {}", e));
64+
65+
// parse back
66+
let dut = Rinex::from_file("test_geo-only.txt")
67+
.unwrap_or_else(|e| panic!("SABS only: failed to parse back: {}", e));
68+
69+
// test
70+
let (mut s23_found, mut s25_found, mut s36_found) = (false, false, false);
71+
for sv in dut.sv_iter() {
72+
s23_found |= sv == s23;
73+
s25_found |= sv == s25;
74+
s36_found |= sv == s36;
75+
}
76+
77+
assert!(s23_found, "S23 not present in parsed-back RINEX!");
78+
assert!(s25_found, "S25 not present in parsed-back RINEX!");
79+
assert!(s36_found, "S36 not present in parsed-back RINEX!");
80+
81+
// delete
82+
let _ = std::fs::remove_file("test_geo-only.txt");
83+
}

0 commit comments

Comments
 (0)