Skip to content

Commit be7bf0c

Browse files
gwbresvicalloy
andauthored
Develop (#29)
* improve readme * Rename schedule to tracker feature * improve MJD UTC calculations (scheduling process) * fix example * docs and api need some improvements * rename rcvr to 'hardware' * API upgrade: * provide Read parser * propose flate2 option for gzip compressed files * Library update * New CRC and buffering capabilities * Add more tests * Take CRC into account in parsing from now on * Update docs * Introducing CommonViewCalendar * Enhancement of the CommonViewPeriod (#30) * CommonViewPeriod::first_track_offset_nanos() returns zero if it is not a bipm_common_view_period * CommonViewPeriod::next_period_start() adds a return value to indicate whether the next CommonViewPeriod is `t0` --------- Signed-off-by: Guillaume W. Bres <[email protected]> Co-authored-by: vicalloy <[email protected]>
1 parent ccffbc8 commit be7bf0c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+3084
-2089
lines changed

README.md

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,26 @@ Rust package to parse and generate CGGTTS data.
88
[![crates.io](https://docs.rs/cggtts/badge.svg)](https://docs.rs/cggtts/)
99
[![crates.io](https://img.shields.io/crates/d/cggtts.svg)](https://crates.io/crates/cggtts)
1010

11-
CGGTTS is a file format designed to describe the state of a local clock with respect to spacecraft that belong
12-
to GNSS constellation, ie., a GNSS timescale.
11+
CGGTTS is a file format designed to describe the state of a local clock with respect to clocks
12+
onboard spacecrafts that belong to a GNSS constellation (ie., a GNSS timescale).
1313
Exchanging CGGTTS files allows direct clock comparison between two remote sites, by comparing how the clock behaves
14-
with respect to a specific spacecraft (ie., on board clock).
15-
This is called the _common view_ time transfer technique. Although it is more accurate to say CGGTTS is just the comparison method,
16-
what you do from the final results is up to end application. Usually, the final end goal is to have the B site track the A site
17-
and replicate the remote clock. It is for example, one option to generate a UTC replica.
14+
with respect to the spacecraft (more specifically, its onboard clock), which is technically
15+
a constant observed from both sites.
16+
17+
Exchanging CGGTTS files allows a posteriori _common view_ time transfer.
18+
Although it is more accurate to say CGGTTS just offers the comparison method,
19+
what you do from the final results is up to the application.
20+
21+
One typical application of common view time transfer by means of CGGTTS files exchange,
22+
is to have a track a reference site from a remote site. CGGTTS files exchange is also used
23+
when creating local copies of UTC or potentially in designing UTC itself.
1824

1925
CGGTTS is specified by the Bureau International des Poids & des Mesures (BIPM):
2026
[CGGTTS 2E specifications](https://www.bipm.org/documents/20126/52718503/G1-2015.pdf/f49995a3-970b-a6a5-9124-cc0568f85450)
2127

22-
This library only supports revision **2E**, and will _reject_ other revisions.
28+
## File Revisions
29+
30+
This library only supports revision **2E** (latest) and will _reject_ other revisions.
2331

2432
## Set of tools
2533

@@ -58,4 +66,4 @@ A built in API allows accurate system delay description as defined in CGGTTS.
5866

5967
## CGGTTS-CLI
6068

61-
[A command line application](gnss_cli/README.md) is developed to process one or two CGGTTS file for clock comparison.
69+
[A command line application](gnss-cli/README.md) is developed to process one or two CGGTTS file for clock comparison.

cggtts-cli/src/main.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,18 +109,18 @@ pub fn main() {
109109

110110
if cli.identification() {
111111
for p in pool {
112-
info!("STATION \"{}\"", p.station);
112+
info!("STATION \"{}\"", p.header.station);
113113
info!("NUMBER OF TRACKS {}", p.tracks.len());
114114
info!(
115115
"CODES {:?}",
116-
p.tracks()
116+
p.tracks_iter()
117117
.map(|trk| trk.frc.clone())
118118
.unique()
119119
.collect::<Vec<_>>()
120120
);
121121
info!(
122122
"SV {:?}",
123-
p.tracks()
123+
p.tracks_iter()
124124
.map(|trk| trk.sv.to_string())
125125
.unique()
126126
.collect::<Vec<_>>()

cggtts-cli/src/processing.rs

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,28 @@ use crate::plot::{
1313
};
1414

1515
pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
16-
let sv: Vec<_> = cggtts.tracks().map(|trk| trk.sv).unique().collect();
16+
let sv: Vec<_> = cggtts.tracks_iter().map(|trk| trk.sv).unique().collect();
1717
let codes: Vec<_> = cggtts
18-
.tracks()
18+
.tracks_iter()
1919
.map(|trk| trk.frc.clone())
2020
.unique()
2121
.collect();
2222

2323
//REFSV/SRSV analysis
2424
ctx.add_timedomain_2y_plot(
25-
&format!("{} REFSV/SRSV", cggtts.station),
25+
&format!("{} REFSV/SRSV", cggtts.header.station),
2626
"REFSV [s]",
2727
"SRSV [s/s]",
2828
);
2929
for sv in &sv {
3030
for code in &codes {
3131
let epochs: Vec<_> = cggtts
32-
.tracks()
32+
.tracks_iter()
3333
.filter_map(|trk| if trk.sv == *sv { Some(trk.epoch) } else { None })
3434
.collect();
3535

3636
let refsv: Vec<_> = cggtts
37-
.tracks()
37+
.tracks_iter()
3838
.filter_map(|trk| {
3939
if trk.sv == *sv {
4040
Some(trk.data.refsv)
@@ -45,7 +45,7 @@ pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
4545
.collect();
4646

4747
let srsv: Vec<_> = cggtts
48-
.tracks()
48+
.tracks_iter()
4949
.filter_map(|trk| {
5050
if trk.sv == *sv {
5151
Some(trk.data.srsv)
@@ -76,19 +76,19 @@ pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
7676

7777
//REFSYS/SRSYS analysis
7878
ctx.add_timedomain_2y_plot(
79-
&format!("{} REFSYS/SRSYS", cggtts.station),
79+
&format!("{} REFSYS/SRSYS", cggtts.header.station),
8080
"REFSYS [s]",
8181
"SRSYS [s/s]",
8282
);
8383
for sv in &sv {
8484
for code in &codes {
8585
let epochs: Vec<_> = cggtts
86-
.tracks()
86+
.tracks_iter()
8787
.filter_map(|trk| if trk.sv == *sv { Some(trk.epoch) } else { None })
8888
.collect();
8989

9090
let refsys: Vec<_> = cggtts
91-
.tracks()
91+
.tracks_iter()
9292
.filter_map(|trk| {
9393
if trk.sv == *sv {
9494
Some(trk.data.refsys)
@@ -99,7 +99,7 @@ pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
9999
.collect();
100100

101101
let srsys: Vec<_> = cggtts
102-
.tracks()
102+
.tracks_iter()
103103
.filter_map(|trk| {
104104
if trk.sv == *sv {
105105
Some(trk.data.srsys)
@@ -130,19 +130,19 @@ pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
130130

131131
//TROPO
132132
ctx.add_timedomain_2y_plot(
133-
&format!("{} MDTR/SMDT", cggtts.station),
133+
&format!("{} MDTR/SMDT", cggtts.header.station),
134134
"MDTR [s]",
135135
"SMDT [s/s]",
136136
);
137137
for sv in &sv {
138138
for code in &codes {
139139
let epochs: Vec<_> = cggtts
140-
.tracks()
140+
.tracks_iter()
141141
.filter_map(|trk| if trk.sv == *sv { Some(trk.epoch) } else { None })
142142
.collect();
143143

144144
let mdtr: Vec<_> = cggtts
145-
.tracks()
145+
.tracks_iter()
146146
.filter_map(|trk| {
147147
if trk.sv == *sv {
148148
Some(trk.data.mdtr)
@@ -153,7 +153,7 @@ pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
153153
.collect();
154154

155155
let smdt: Vec<_> = cggtts
156-
.tracks()
156+
.tracks_iter()
157157
.filter_map(|trk| {
158158
if trk.sv == *sv {
159159
Some(trk.data.smdt)
@@ -185,28 +185,28 @@ pub fn single_clock(cggtts: &CGGTTS, ctx: &mut PlotContext) {
185185

186186
pub fn clock_comparison(workspace: &Path, pool: &Vec<CGGTTS>, ctx: &mut PlotContext) {
187187
let ref_clock = &pool[0];
188-
info!("{} is considered reference clock", ref_clock.station);
188+
info!("{} is considered reference clock", ref_clock.header.station);
189189

190-
let ref_sv: Vec<_> = ref_clock.tracks().map(|trk| trk.sv).unique().collect();
190+
let ref_sv: Vec<_> = ref_clock.tracks_iter().map(|trk| trk.sv).unique().collect();
191191
let ref_codes: Vec<_> = ref_clock
192-
.tracks()
192+
.tracks_iter()
193193
.map(|trk| trk.frc.clone())
194194
.unique()
195195
.collect();
196196
let refsys: HashMap<Epoch, f64> = ref_clock
197-
.tracks()
197+
.tracks_iter()
198198
.map(|trk| (trk.epoch, trk.data.refsys))
199199
.collect();
200200

201201
for i in 1..pool.len() {
202202
ctx.add_timedomain_plot(
203-
&format!("{}-{}", ref_clock.station, pool[i].station),
203+
&format!("{}-{}", ref_clock.header.station, pool[i].header.station),
204204
"Delta [s]",
205205
);
206206
for sv in &ref_sv {
207207
for code in &ref_codes {
208208
let x_err: Vec<_> = ref_clock
209-
.tracks()
209+
.tracks_iter()
210210
.filter_map(|trk| {
211211
if trk.sv == *sv && &trk.frc == code {
212212
if refsys.get(&trk.epoch).is_some() {
@@ -220,7 +220,7 @@ pub fn clock_comparison(workspace: &Path, pool: &Vec<CGGTTS>, ctx: &mut PlotCont
220220
})
221221
.collect();
222222
let t_err: Vec<_> = ref_clock
223-
.tracks()
223+
.tracks_iter()
224224
.filter_map(|trk| {
225225
if trk.sv == *sv && &trk.frc == code {
226226
refsys
@@ -243,31 +243,31 @@ pub fn clock_comparison(workspace: &Path, pool: &Vec<CGGTTS>, ctx: &mut PlotCont
243243
}
244244
}
245245

246-
let mut fd = File::create(workspace.join(&pool[0].station))
246+
let mut fd = File::create(workspace.join(&pool[0].header.station))
247247
.expect("failed to create textfile: permission denied");
248248

249249
writeln!(fd, "t, CLOCK(A), CLOCK(B), SV, (elev[°], azi[°]) @REF, (elev[°], azi[°]) @CLOCK, SIGNAL, CLOCK(A) - CLOCK(B) [s]")
250250
.expect("failed to generate textfile");
251251

252-
for trk in ref_clock.tracks() {
252+
for trk in ref_clock.tracks_iter() {
253253
let ref_t = trk.epoch;
254254
let ref_sv = trk.sv;
255-
let (ref_elev, ref_azim) = (trk.elevation, trk.azimuth);
255+
let (ref_elev, ref_azim) = (trk.elevation_deg, trk.azimuth_deg);
256256
let ref_frc = &trk.frc;
257257
for i in 1..pool.len() {
258258
let track = pool[i]
259-
.tracks()
259+
.tracks_iter()
260260
.filter(|trk| trk.epoch == ref_t && trk.sv == ref_sv && trk.frc == *ref_frc)
261261
.reduce(|trk, _| trk);
262262
if let Some(b_trk) = track {
263-
let (b_elev, b_azim) = (b_trk.elevation, b_trk.azimuth);
263+
let (b_elev, b_azim) = (b_trk.elevation_deg, b_trk.azimuth_deg);
264264
let dt = b_trk.data.refsys - trk.data.refsys;
265265
writeln!(
266266
fd,
267267
"{:?}, {}, {}, {}, ({:.2E}, {:.2E}), ({:.2E}, {:.2E}), {}, {:.3E}",
268268
ref_t,
269-
pool[i].station,
270-
pool[0].station,
269+
pool[i].header.station,
270+
pool[0].header.station,
271271
ref_sv,
272272
ref_elev,
273273
ref_azim,

cggtts/Cargo.toml

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,43 @@ name = "cggtts"
33
version = "4.1.7"
44
license = "MIT OR Apache-2.0"
55
authors = ["Guillaume W. Bres <[email protected]>"]
6-
description = "Package to analyze and create CGGTTS data"
6+
description = "CGGTTS files parsing and production"
77
homepage = "https://github.com/gwbres/cggtts"
8-
keywords = ["positionning","bipm","gnss","timing","satellites"]
8+
keywords = ["navigation", "gnss", "timing", "space"]
99
categories = ["science","parsing"]
1010
edition = "2018"
1111
readme = "../README.md"
1212

1313
[features]
14-
default = [] # no features by default
14+
default = []
1515

16-
# unlock the Track Scheduling and data production helpers
17-
scheduler = ["polyfit-rs"]
16+
# unlock gzip file native support
17+
flate2 = ["dep:flate2"]
18+
19+
# unlock serdes operations
20+
serde = [
21+
"dep:serde",
22+
"hifitime/serde",
23+
"gnss-rs/serde",
24+
]
25+
26+
# unlock helper to fit several measurements during
27+
# a CommonViewPeriod, following BIPM recommendations.
28+
polyfit-rs = ["dep:polyfit-rs"]
1829

1930
[dependencies]
2031
thiserror = "2"
2132
scan_fmt = "0.1.3"
2233
strum = "0.26"
2334
itertools = "0.13"
2435
strum_macros = "0.26"
36+
flate2 = { version = "1", optional = true }
2537
serde = { version = "1.0", optional = true, features = ["derive"] }
2638

27-
hifitime = { version = "4.0", features = ["serde", "std"] }
39+
hifitime = { version = "4.0", features = ["std"] }
2840

29-
# gnss-rs = { version = "2.2.4", features = ["serde"] }
30-
gnss-rs = { git = "https://github.com/rtk-rs/gnss", branch = "main", features = ["serde"] }
41+
# gnss-rs = "2.2.4"
42+
gnss-rs = { git = "https://github.com/rtk-rs/gnss", branch = "main" }
3143

3244
# track scheduling
3345
polyfit-rs = { version = "0.2", optional = true }

cggtts/README.md

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,55 @@ Add "cggtts" to your Cargo.toml
2424
cggtts = "4"
2525
```
2626

27-
Use CGGTTS to parse local files
27+
## Crate features
28+
29+
`CGGTTS` supports several features:
30+
31+
- `serde` will unlock the serdes operation
32+
of many internal structures.
33+
- `flate2` will unlock native support
34+
of gzip compressed files.
35+
- `polyfit-rs` will unlock one fitting helper
36+
that help fit observation according to the BIPM track
37+
fitting method
38+
39+
## Parsing
40+
41+
Parse a local CGGTTS file:
2842

2943
```rust
3044
use cggtts::prelude::CGGTTS;
3145

32-
let cggtts = CGGTTS::from_file("../data/dual/GZGTR560.258");
33-
assert!(cggtts.is_ok());
46+
let path = format!(
47+
"{}/../data/dual/GZGTR560.258",
48+
env!("CARGO_MANIFEST_DIR"),
49+
);
3450

35-
let cggtts = cggtts.unwrap();
36-
assert_eq!(cggtts.station, "LAB");
51+
let cggtts = CGGTTS::from_file("../data/dual/GZGTR560.258")
52+
.unwrap();
53+
54+
assert_eq!(cggtts.header.station, "LAB");
3755
assert_eq!(cggtts.tracks.len(), 2097);
3856
```
57+
58+
Refer to online API for more examples and further information
59+
about [CGGTTS].
60+
61+
## Formatting
62+
63+
Parse, modify, dump, parse back then verify:
64+
65+
```rust
66+
use cggtts::prelude::CGGTTS;
67+
68+
let cggtts = CGGTTS::from_file("../data/dual/GZGTR560.258")
69+
.unwrap();
70+
71+
cggtts.to_file("/tmp/test.txt")
72+
.unwrap();
73+
74+
let parsed = CGGTTS::from_file("/tmp/test.txt")
75+
.unwrap();
76+
77+
assert_eq!(parsed.tracks.len(), cggtts.tracks.len());
78+
```

0 commit comments

Comments
 (0)