Skip to content

Commit

Permalink
rebase
Browse files Browse the repository at this point in the history
Signed-off-by: Guillaume W. Bres <[email protected]>
  • Loading branch information
gwbres committed Sep 15, 2023
2 parents 2d4524e + f00effd commit f81a4f4
Show file tree
Hide file tree
Showing 37 changed files with 11,916 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
debug/
target/

test_resources/

Cargo.lock

*.png
*.jpg
*.swp
*.swo
**/*.rs.bk
.DS_Store

rinex/merge.rnx
rinex/test.crx
DATA/
13 changes: 12 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
[workspace]
members = ["rinex", "crx2rnx", "rnx2crx", "qc-traits", "rinex-qc", "rinex-cli", "ublox-rnx", "sinex"]
resolver = "2"
members = [
"rinex",
"crx2rnx",
"rnx2crx",
"qc-traits",
"rinex-qc",
"rinex-cli",
"ublox-rnx",
"sinex",
"sp3",
]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ It can be used to process RINEX files and perform operations similar to `teqc`.
The application is auto-generated for a few architectures, download it from the
[release portal](https://github.com/gwbres/rinex/releases)

* [`sp3`](sp3/) High Precision Orbits (by IGS)
* [`rnx2crx`](rnx2crx/) is a RINEX compressor (RINEX to Compact RINEX)
* [`crx2rnx`](crx2rnx/) is a CRINEX decompresor (Compact RINEX to RINEX)
* [`rinex-qc`](rinex-qc/) is a library dedicated to RINEX files analysis
Expand Down
2 changes: 1 addition & 1 deletion qc-traits/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rinex-qc-traits"
version = "0.1.0"
version = "0.1.1"
license = "MIT OR Apache-2.0"
authors = ["Guillaume W. Bres <[email protected]>"]
description = "RINEX quality analysis specific traits"
Expand Down
6 changes: 3 additions & 3 deletions rinex-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ pretty_env_logger = "0.5"
clap = { version = "4", features = ["derive", "color"] }
rand = "0.8"
serde_json = "1"
sp3 = { version = "1.0.2", features = ["serde", "flate2"] }
rinex-qc = { version = "0.1.1", features = ["serde"] }
rinex = { version = "0.13.1", features = ["serde", "flate2", "sbas", "obs", "nav", "qc", "processing"] }
sp3 = { path = "../sp3", features = ["serde", "flate2"] }
rinex-qc = { path = "../rinex-qc", features = ["serde"] }
rinex = { path = "../rinex", features = ["serde", "flate2", "sbas", "obs", "nav", "qc", "processing"] }
thiserror = "1"
itertools = "0.11"
plotly = "0.8.4"
Expand Down
8 changes: 4 additions & 4 deletions rinex-qc/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rinex-qc"
version = "0.1.1"
version = "0.1.2"
license = "MIT OR Apache-2.0"
authors = ["Guillaume W. Bres <[email protected]>"]
description = "RINEX data analysis"
Expand All @@ -26,9 +26,9 @@ strum_macros = "0.25"
horrorshow = "0.8"
itertools = "0.11.0"
statrs = "0.16"
sp3 = { version = "1.0.2", features = ["serde"] }
rinex-qc-traits = "0.1.0"
rinex = { version = "0.13.1", features = ["obs", "nav", "qc", "processing"] }
sp3 = { path = "../sp3", features = ["serde"] }
rinex-qc-traits = { path = "../qc-traits" }
rinex = { path = "../rinex", features = ["obs", "nav", "qc", "processing", "serde", "flate2"] }

[dev-dependencies]
serde_json = "1"
4 changes: 2 additions & 2 deletions rinex/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rinex"
version = "0.13.1"
version = "0.13.2"
license = "MIT OR Apache-2.0"
authors = ["Guillaume W. Bres <[email protected]>"]
description = "Package to parse and analyze RINEX data"
Expand Down Expand Up @@ -47,7 +47,7 @@ serde = { version = "1.0", optional = true, default-features = false, features =
flate2 = { version = "1.0.24", optional = true, default-features = false, features = ["zlib"] }
hifitime = { version = "3.8", features = ["serde", "std"] }
horrorshow = { version = "0.8", optional = true }
rinex-qc-traits = { version = "0.1", optional = true }
rinex-qc-traits = { path = "../rinex", optional = true }

[dev-dependencies]
serde_json = "1"
Expand Down
1 change: 1 addition & 0 deletions rinex/src/tests/decompression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,7 @@ mod test {
}
}
#[test]
#[cfg(feature = "flate2")]
fn v3_mojn00dnk_sig_strength_regression() {
let crnx =
Rinex::from_file("../test_resources/CRNX/V3/MOJN00DNK_R_20201770000_01D_30S_MO.crx.gz");
Expand Down
8 changes: 8 additions & 0 deletions rinex/src/tests/production.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ mod test {
let _ = std::fs::remove_file(tmp_path);
}
#[test]
#[cfg(feature = "flate2")]
fn obs_v2() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/OBS/V2/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -27,6 +28,7 @@ mod test {
}
}
#[test]
#[cfg(feature = "flate2")]
fn obs_v3() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/OBS/V3/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -36,6 +38,7 @@ mod test {
}
}
#[test]
#[cfg(feature = "flate2")]
fn meteo_v2() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/MET/V2/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -45,6 +48,7 @@ mod test {
}
}
#[test]
#[cfg(feature = "flate2")]
fn meteo_v4() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/MET/V4/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -54,6 +58,7 @@ mod test {
}
}
//#[test]
//#[cfg(feature = "flate2")]
fn clocks_v2() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/CLK/V2/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -63,6 +68,7 @@ mod test {
}
}
#[test]
#[cfg(feature = "flate2")]
fn nav_v2() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/NAV/V2/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -72,6 +78,7 @@ mod test {
}
}
#[test]
#[cfg(feature = "flate2")]
fn nav_v3() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/NAV/V3/";
for file in std::fs::read_dir(folder).unwrap() {
Expand All @@ -82,6 +89,7 @@ mod test {
}
/*
#[test]
#[cfg(feature = "flate2")]
fn nav_v4() {
let folder = env!("CARGO_MANIFEST_DIR").to_owned() + "/../test_resources/NAV/V4/";
for file in std::fs::read_dir(folder).unwrap() {
Expand Down
31 changes: 31 additions & 0 deletions sp3/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
[package]
name = "sp3"
version = "1.0.3"
license = "MIT OR Apache-2.0"
authors = ["Guillaume W. Bres <[email protected]>"]
description = "IGS SP3 file parser"
homepage = "https://github.com/georust/sp3"
repository = "https://github.com/georust/sp3"
documentation = "https://docs.rs/sp3/"
keywords = ["gnss", "timing", "gps", "glonass", "galileo", "igs"]
categories = ["science", "science::geo", "parsing"]
edition = "2021"
readme = "README.md"

[features]
default = [] # no features by default

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docrs", "--generate-link-to-definition"]

[build-dependencies]

[dependencies]
rinex = { path = "../rinex", features = ["serde"] }
hifitime = "3.8.4"
thiserror = "1"
serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] }
flate2 = { version = "1.0.24", optional = true, default-features = false, features = ["zlib"] }

[dev-dependencies]
147 changes: 147 additions & 0 deletions sp3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
# SP3

[![crates.io](https://img.shields.io/crates/v/sp3.svg)](https://crates.io/crates/sp3)
[![Rust](https://github.com/georust/rinex/actions/workflows/rust.yml/badge.svg)](https://github.com/georust/rinex/actions/workflows/rust.yml)
[![crates.io](https://docs.rs/sp3/badge.svg)](https://docs.rs/sp3/)
[![crates.io](https://img.shields.io/crates/d/sp3.svg)](https://crates.io/crates/sp3)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue?style=flat-square)](https://github.com/georust/rinex/sp3/blob/main/LICENSE-APACHE)
[![License](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](https://github.com/georust/rinex/sp3/blob/main/LICENSE-MIT)

SP3 Precise GNSS Orbit files parser.

SP3 is specifid by [IGS](https://igs.org/products/#orbits_clocks).

The parser only supports Revisions C & D at the moment and rejects revisions A & B.

## Getting started

Add "sp3" to you cargo file

```toml
[dependencies]
sp3 = "1"
```

Parse an SP3 file

```rust
use crate::prelude::*;
use rinex::prelude::Constellation;
use std::path::PathBuf;
use std::str::FromStr;

let path = PathBuf::new()
.join(env!("CARGO_MANIFEST_DIR"))
.join("data")
.join("ESA0OPSRAP_20232390000_01D_15M_ORB.SP3.gz");

let sp3 = SP3::from_file(&path.to_string_lossy());
assert!(
sp3.is_ok(),
"failed to parse ESA0OPSRAP_20232390000_01D_15M_ORB.SP3.gz : {:?}",
sp3.err()
);

let sp3 = sp3.unwrap();

/*
* Test general infos
*/
assert_eq!(sp3.version, Version::C);
assert_eq!(sp3.data_type, DataType::Position);

assert_eq!(
sp3.first_epoch(),
Some(Epoch::from_str("2023-08-27T00:00:00 GPST").unwrap())
);

assert_eq!(sp3.nb_epochs(), 96, "bad number of epochs");
assert_eq!(sp3.coord_system, "ITRF2");
assert_eq!(sp3.orbit_type, OrbitType::BHN);
assert_eq!(sp3.time_system, TimeScale::GPST);
assert_eq!(sp3.constellation, Constellation::Mixed);
assert_eq!(sp3.agency, "ESOC");

assert_eq!(sp3.week_counter, (2277, 0.0_f64));
assert_eq!(sp3.epoch_interval, Duration::from_seconds(900.0_f64));

// browse SV positions
for (epoch, sv, (x, y, z)) in sp3.sv_position() {

}

// browse SV clock
for (epoch, sv, clock) in sp3.sv_clock() {

}
```

## File Merge

Merge files together, for example to create a context spanning 48 hours

```rust
let folder = PathBuf::new()
.join(env!("CARGO_MANIFEST_DIR"))
.join("data");

let sp3_a = folder.clone()
.join("ESA0OPSRAP_20232390000_01D_15M_ORB.SP3.gz");

let sp3_b = folder.clone()
.join("ESA0OPSULT_20232320600_02D_15M_ORB.SP3.gz");

let sp3 = SP3::from_file(&sp3_a.to_string_lossy())
.unwrap();

let sp3_b = SP3::from_file(&sp3_b.to_string_lossy())
.unwrap();

let sp3 = sp3_a.merge(sp3_b);
assert!(sp3.is_ok());
```

## Position Vector Interpolation

Interpolate SV position at desired Epoch.
In order to preserve the high (+/- 1mm precision) for SP3 datasets,
we recommend using at least an interpolation order of 9 for typical SP3 files
with 15' epoch intervals.

The current implementation restricts the interpolatable Epochs at
[tmin, tmax] = [(N +1)/2 * τ, T(n-1) - (N +1)/2 * τ],
both included, where N is the interpolation order, τ the epoch interval, and T(n-1)
the last Epoch in this file.

Refer to the online API for more information

```rust
use sp3::prelude::*;
use rinex::sv;
use std::str::FromStr;
use std::path::PathBuf;
use rinex::prelude::Sv;

let path = PathBuf::new()
.join(env!("CARGO_MANIFEST_DIR"))
.join("data")
.join("ESA0OPSRAP_20232390000_01D_15M_ORB.SP3.gz");

let sp3 = SP3::from_file(&path.to_string_lossy())
.unwrap();

let epoch = Epoch::from_str("2023-08-27T00:00:00 GPST")
.unwrap();
let interpolated = sp3.interpolate(epoch, sv!("G01"), 11);
assert!(interpolated.is_none(), "too early in this file");

let epoch = Epoch::from_str("2023-08-27T08:15:00 GPST")
.unwrap();
let interpolated = sp3.interpolate(epoch, sv!("G01"), 11);
assert!(interpolated.is_some());
let (x, y, z) = interpolated.unwrap();
// demonstrate error is still sub cm
assert!((x - 13281.083885).abs() * 1.0E3 < 1.0E-2); // distances are expressed in km in all SP3
assert!((y - -11661.887057).abs() * 1.0E3 < 1.0E-2);
assert!((z - 19365.687261).abs() * 1.0E3 < 1.0E-2);
```
14 changes: 14 additions & 0 deletions sp3/src/bibliography.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
pub enum Bibliography {
/// SP3 -D revision specifications
/// [DOI]()
SP3dRev,
/// SP3 -C revision specifications
/// [DOI]()
SP3cRev,
/// C. Japhet, 2021 * Méthodes Numériques II - Interpolation Polynomiale *
/// [DOI]()
Japhet2021,
/// Univ. Rennes UFR Maths, * Interpolation polynomiale, Interpolation de Lagrange *
/// [DOI]()
UFRRennes,
}
Loading

0 comments on commit f81a4f4

Please sign in to comment.