RINEX

Rust package to parse and analyze Rinex files

Rust crates.io crates.io codecov

Getting started

Many RINEX file types exist, the RinexType enum (refer to API) describes the types of RINEX currently supported:

RINEX files contain a lot of information, and this library exposes all data contained by supported Rinex Types, that means: a lot.

To learn how to operate this library, refer to: * the examples delivered with the library are detailed and compelling * extracted examples on this page * autotest methods delivered by src/lib.rs

Supported RINEX revisions

Running the examples

shell cargo run --example basic cargo run --example nav-simple cargo run --example nav-mixed

Parsing a RINEX

The ::from_file method lets you parse a local RINEX file:

rust use rinex::*; let path = std::path::PathBuf::from("amel0010.21g"); let rinex = Rinex::from_file(&path).unwrap();

RINEX Header

The Rinex Header contains high level information

```rust use rinex::*;

let rinex = Rinex::fromfile(&PathBuf::from("amel0010.21g")).unwrap(); let header = rinex.getheader(); println!("{:#?}", header);

asserteq!(header.getrinextype(), RinexType::NavigationMessage); asserteq!(header.getconstellation(), constellation::Constellation::Mixed); println!("{:#?}", header.getrinex_version()); println!("Record size: {}", rinex.len()); ```

"Comments" are currently discarded and not exposed by the parser.

length of a Rinex file returns the record size:

RINEX Record and File types

The Record (file content) depends on the file type and constellation.
To learn how to operate the library for the Rinex type you are interested in, refer to the following section.

Data identification

Most data is labelized by keys.json refer to that list to determine which fields are available for which Constellation & RINEX revision. Refer to RINEX specifications to interpret each field correctly.

Situation may vary depending on the Rinex File type, this is precisely explained in the following sections.

⚠ ⚠ keys.json is partial
➡ contributions are welcomed, current description might not match your needs (missing keys, etc..)

⚠ ⚠ keys.json might include some mistakes that lead to

➡ corrections are welcomed,

keys.json: data identification

```json keys.json

"NavigationMessage": { <<-- rinex type
  "LNVA": <-- a new category should be introduced
              to describe V ≥ 4 correctly
    "GPS": { <<-- constellation
        format is "id": "type",
        // this one describes how item1 is identified
        "iode": "d19.12", // follow RINEX specifications
        "crs": "d19.12", // item2
        // [..]
        "idot": "d19.12", // item10
        "spare": "xxxx", // orbit empty field, 
                       // but continue parsing..
        "tgd": "d19.12" // item11
        // parsing stops there
    }
}

```

Item labelization: follow naming convention & match RINEX specifications closely.

Item types:

Remember:

Navigation Message (NAV)

NAV records expose the following keys to manipulate & search through the records: * sv : Satellite Vehicule ID (src/record.rs::Sv) * svClockBias: clock bias (s) * svClockDrift: clock drift (s.s⁻¹) * svClockDriftRate: clock drift (s.s⁻²) * all keys contained in keys.json for related Rinex revision & constellation

Two main cases for RinexType::NavigationMessage: + Unique constellation (e.g Constellation::GPS) + Constellation::Mixed (modern use case?)

NAV: determine encountered Sattelite Vehicules (Sv)

rust // 'example --nav-simple' let vehicules: Vec<_> = rinex.get_record().iter() .map(|s| s["sv"]) .collect();

NAV (mixed): extract all Sv tied to Glonass

```rust // 'example --nav-simple' let vehicules: Vec<_> = rinex.get_record().iter() .map(|s| s["sv"]) .collect();

let glo_vehicules: Vec<_> = vehicules.iter()
    .filter(|s| s.Sv().unwrap()
        .get_constellation() == Constellation::Glonass)
    .collecr();

```

NAV (mixed): extract svClockBias(s) and svClockDrift (s.s⁻¹) for R03

``rust // 'example --nav-simple' let sv = Sv::new(Constellation::Glonass, 0x03); //R03` let svtomatch = RecordItem::Sv(sv); // filter item let r03data: Vec<_> = rinex.getrecord().iter() .map(|s| s["sv"] == svtomatch) .collect();

let (clk_bias, clk_drift) = (r03_data["svClockBias"], r03_data["svClockDrift"]);

```

NAV (mixed): extract specific data

WorkInProgress svHealth exists for GPS for instance (keys.json) and is a binary word:

rust // 'example --nav-mixed'

NAV (mixed): complex pattern

WorkInProgress

Observation data (OBS)

WorkInProgress

OBS records expose mainly: * raw carrier phase measurements * pseudo ranges estimates * doppler measurements

OBS: determine which measurements we have

WorkInProgress

First thing to do is to determine which data a given file actually contains

rust // 'example --obs-simple' let obs_types = header.get_obs_types();

OBS (GPS): extract pseudo range

WorkInProgress

Extract pseudo range for a unique vehicule

`̀rust // 'example --obs-simple' let sv = Sv::new(Constellation::GPS, 0x01); // "G01" let tomatch = RecordItem::Sv(sv); // filter item let matching: Vec<_> = rinex.getrecord().iter() .filter(|s| s["sv"] == tomatch) .collect(); let (pseudorange, raw_phase) = matching["C1C"]; ```

Sometimes data is scaled:
TODO

rust // 'example --obs-mixed'

OBS: complex data extract on SigStrength condition

WorkInProgress

Extract phase + pseudo range

Use LeapSecond information

WorkInProgress

rust // 'example --nav-mixed'

Ionosphere compensation

WorkInProgress

rust // 'example --nav-mixed'

System time compensation

WorkInProgress

rust // 'example --'