SP3

crates.io Rust crates.io crates.io License License

SP3 Precise GNSS Orbit files parser.

SP3 is specifid by IGS.

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!("CARGOMANIFESTDIR")) .join("data") .join("ESA0OPSRAP2023239000001D15MORB.SP3.gz");

let sp3 = SP3::fromfile(&path.tostringlossy()); assert!( sp3.isok(), "failed to parse ESA0OPSRAP2023239000001D15MORB.SP3.gz : {:?}", sp3.err() );

let sp3 = sp3.unwrap();

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

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

asserteq!(sp3.nbepochs(), 96, "bad number of epochs"); asserteq!(sp3.coordsystem, "ITRF2"); asserteq!(sp3.orbittype, OrbitType::BHN); asserteq!(sp3.timesystem, TimeScale::GPST); asserteq!(sp3.constellation, Constellation::Mixed); asserteq!(sp3.agency, "ESOC");

asserteq!(sp3.weekcounter, (2277, 0.0f64)); asserteq!(sp3.epochinterval, Duration::fromseconds(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!("CARGOMANIFESTDIR")) .join("data");

let sp3a = folder.clone() .join("ESA0OPSRAP2023239000001D15M_ORB.SP3.gz");

let sp3b = folder.clone() .join("ESA0OPSULT2023232060002D15M_ORB.SP3.gz");

let sp3 = SP3::fromfile(&sp3a.tostringlossy()) .unwrap();

let sp3b = SP3::fromfile(&sp3b.tostring_lossy()) .unwrap();

let sp3 = sp3a.merge(sp3b); 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!("CARGOMANIFESTDIR")) .join("data") .join("ESA0OPSRAP2023239000001D15MORB.SP3.gz");

let sp3 = SP3::fromfile(&path.tostring_lossy()) .unwrap();

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

let epoch = Epoch::fromstr("2023-08-27T08:15:00 GPST") .unwrap(); let interpolated = sp3.interpolate(epoch, sv!("G01"), 11); assert!(interpolated.issome()); 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); ```