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.
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() {
} ```
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()); ```
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); ```