Skip to content

Commit

Permalink
Merge branch 'main' into perf
Browse files Browse the repository at this point in the history
  • Loading branch information
gwbres committed Apr 20, 2024
2 parents 9f71bfc + b79e25b commit 46b4bab
Show file tree
Hide file tree
Showing 25 changed files with 1,728 additions and 403 deletions.
3 changes: 1 addition & 2 deletions rinex-cli/src/cli/fops/filegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@ pub fn subcommand() -> Command {
.long_flag("filegen")
.arg_required_else_help(false)
.about(
"RINEX Data formatting. Use this option to preprocess,
modify and dump resulting context in preserved RINEX format.
"RINEX Data formatting. Use this option to preprocess, modify and dump results as RINEX.
You can use this for example, to generate a decimated RINEX file from an input Observations file.",
)
.next_help_heading("Production Environment")
Expand Down
17 changes: 13 additions & 4 deletions rinex-cli/src/cli/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,16 +126,25 @@ impl Cli {
.value_name("FILE")
.action(ArgAction::Append)
.required_unless_present("directory")
.help("Input file. RINEX (any format, including Clock and ANTEX), and SP3 are accepted. You can load as many files as you need."))
.help("Load a single file. Use this as many times as needed.
Available operations and following behavior highly depends on input data.
Supported formats are:
- Observation RINEX
- Navigation RINEX
- Meteo RINEX
- Clock RINEX (high precision clocks)
- SP3 (high precision orbits)
- IONEX (Ionosphere Maps)
- ANTEX (antenna calibration as RINEX)
- DORIS (special Observation RINEX)"))
.arg(Arg::new("directory")
.short('d')
.long("dir")
.value_name("DIRECTORY")
.action(ArgAction::Append)
.required_unless_present("filepath")
.help("Load directory recursively. Default recursive depth is set to 5,
but you can extend that with --depth.
Again any RINEX, and SP3 are accepted. You can load as many directories as you need."))
.help("Load directory recursively. Use this as many times as needed. Default recursive depth is set to 5,
but you can extend that with --depth. Refer to -f for more information."))
.arg(Arg::new("depth")
.long("depth")
.action(ArgAction::Set)
Expand Down
7 changes: 6 additions & 1 deletion rinex/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ clock = []
# Unlocks dedicated browsing methods and antenna compensation methods.
antex = []

# Unlock support of DORIS RINEX file format, DORIS special measurements
# wrapped as RINEX observation file.
doris = []

# Unlock Processing package.
# Unlocks the preprocessing toolkit, Filtering methods and preprocessing algorithms.
processing = []
Expand All @@ -54,11 +58,12 @@ sp3 = ["dep:sp3", "walkdir"]
# Unlock all features, all at once
full = [
"antex",
"clock",
"doris",
"flate2",
"horrorshow",
"ionex",
"meteo",
"clock",
"nav",
"obs",
"processing",
Expand Down
23 changes: 22 additions & 1 deletion rinex/src/carrier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ pub enum Carrier {
B3A,
/// IRNSS S
S,
/// DORIS S1 Frequency
S1,
/// DORIS U2 Frequency
U2,
}

#[derive(Error, Debug, Clone, PartialEq)]
Expand Down Expand Up @@ -106,6 +110,9 @@ impl std::fmt::Display for Carrier {
// B3
Self::B3 => write!(f, "B3"),
Self::B3A => write!(f, "B3A"),
// DORIS
Self::S1 => write!(f, "S1"),
Self::U2 => write!(f, "U2"),
}
}
}
Expand Down Expand Up @@ -159,6 +166,13 @@ impl std::str::FromStr for Carrier {
Ok(Self::B3)
} else if content.eq("B3A") {
Ok(Self::B3A)
/*
* DORIS
*/
} else if content.eq("S1") {
Ok(Self::S1)
} else if content.eq("U2") {
Ok(Self::U2)
} else {
Err(Error::ParseError(s.to_string()))
}
Expand Down Expand Up @@ -205,13 +219,18 @@ impl Carrier {
Self::B2I | Self::B2B => 1207.140_f64,
Self::B2 => 1191.795_f64,
Self::B3 | Self::B3A => 1268.520_f64,
/*
* DORIS
*/
Self::S1 => 2036.25,
Self::U2 => 401.25,
}
}
/// Returns carrier wavelength
pub fn wavelength(&self) -> f64 {
299_792_458.0_f64 / self.frequency()
}
/// Returns channel bandwidth in MHz
/// Returns channel bandwidth in MHz.
pub fn bandwidth_mhz(&self) -> f64 {
match self {
Self::L1 | Self::G1(_) | Self::G1a | Self::E1 => 15.345_f64,
Expand All @@ -226,6 +245,8 @@ impl Carrier {
todo!("B2X bandwidth is not known to this day")
},
Self::B3 | Self::B3A => todo!("B3X bandwidth is not known to this day"),
Self::S1 => panic!("DORIS signal bandwidth"),
Self::U2 => panic!("DORIS signal bandwidth"),
}
}
///// Returns the code length (signal period) expressed in seconds,
Expand Down
4 changes: 4 additions & 0 deletions rinex/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ pub enum ProductType {
Observation,
/// Meteo sensors data wrapped as Meteo RINEX files.
MeteoObservation,
/// DORIS measurements wrapped as special RINEX observation file.
DorisRinex,
/// Broadcast Navigation message as contained in
/// Navigation RINEX files.
BroadcastNavigation,
Expand All @@ -64,6 +66,7 @@ impl std::fmt::Display for ProductType {
Self::HighPrecisionClock => write!(f, "High Precision Clock"),
Self::Antex => write!(f, "ANTEX"),
Self::Ionex => write!(f, "IONEX"),
Self::DorisRinex => write!(f, "DORIS RINEX"),
}
}
}
Expand All @@ -77,6 +80,7 @@ impl From<RinexType> for ProductType {
RinexType::ClockData => Self::HighPrecisionClock,
RinexType::IonosphereMaps => Self::Ionex,
RinexType::AntennaData => Self::Antex,
RinexType::DORIS => Self::DorisRinex,
}
}
}
Expand Down
82 changes: 82 additions & 0 deletions rinex/src/cospar.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
//! COSPAR ID number
use thiserror::Error;

#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};

#[derive(Debug, Error)]
pub enum Error {
#[error("Invalid COSPAR number")]
InvalidFormat,
}

/// COSPAR ID number
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct COSPAR {
/// Launch year
year: u16,
/// Launch number for that year, in chronological order.
launch: u16,
/// Up to three letter code representing the sequential
/// identifier of a piece in a Launch.
code: String,
}

impl std::fmt::Display for COSPAR {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{:04}-{:03}{}", self.year, self.launch, self.code)
}
}

impl std::str::FromStr for COSPAR {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() < 9 {
return Err(Error::InvalidFormat);
}
let offset = s.find('-').ok_or(Error::InvalidFormat)?;
let (year, rem) = s.split_at(offset);
let year = year.parse::<u16>().map_err(|_| Error::InvalidFormat)?;
let launch = rem[1..4]
.trim()
.parse::<u16>()
.map_err(|_| Error::InvalidFormat)?;
Ok(Self {
year,
launch,
code: rem[4..].trim().to_string(),
})
}
}

#[cfg(test)]
mod test {
use crate::cospar::COSPAR;
use std::str::FromStr;
#[test]
fn cospar() {
for (desc, expected) in [
(
"2018-080A",
COSPAR {
year: 2018,
launch: 80,
code: "A".to_string(),
},
),
(
"1996-068A",
COSPAR {
year: 1996,
launch: 68,
code: "A".to_string(),
},
),
] {
let cospar = COSPAR::from_str(desc).unwrap();
assert_eq!(cospar, expected);
let recip = cospar.to_string();
assert_eq!(recip, desc, "cospar reciprocal");
}
}
}
4 changes: 2 additions & 2 deletions rinex/src/domes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub enum Error {
}

/// DOMES site reference point.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TrackingPoint {
/// Monument (pole, pillar, geodetic marker..)
Expand All @@ -29,7 +29,7 @@ pub enum TrackingPoint {
}

/// DOMES Site identifier, see [Bibliography::IgnItrfDomes]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Domes {
/// Area / Country code (3 digits)
Expand Down
68 changes: 68 additions & 0 deletions rinex/src/doris/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::collections::HashMap;

use thiserror::Error;

use crate::{
domes::Error as DomesParsingError,
observable::Observable,
prelude::{Duration, Epoch},
};

pub(crate) mod record;
pub(crate) mod station;

pub use record::Record;
pub use station::Station;

/// DORIS Station & record parsing error
#[derive(Debug, Error)]
pub enum Error {
#[error("invalid station")]
InvalidStation,
#[error("failed to parse station id")]
IdParsing,
#[error("invalid station DOMES code")]
DomesError(#[from] DomesParsingError),
#[error("failed to parse beacon generation")]
BeaconGenerationParsing,
#[error("failed to parse `k` factor")]
KfParsing,
}

/// DORIS Record specific header fields
#[derive(Debug, Clone, Default, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct HeaderFields {
/// Time of First Measurement, expressed in TAI timescale.
pub time_of_first_obs: Option<Epoch>,
/// Time of Last Measurement, expressed in TAI timescale.
pub time_of_last_obs: Option<Epoch>,
/// List of observables
pub observables: Vec<Observable>,
/// Data scaling, almost 100% of the time present in DORIS measurements.
/// Allows some nano radians precision on phase data for example.
pub scaling: HashMap<Observable, u16>,
/// Reference stations present in this file
pub stations: Vec<Station>,
/// Constant shift between date of the U2 (401.25 MHz) phase measurement
/// and date of the S1 (2.03625 GHz) phase measurement
pub l2_l1_date_offset: Duration,
}

impl HeaderFields {
/// Retrieve station by ID#
pub(crate) fn get_station(&mut self, id: u16) -> Option<&Station> {
self.stations
.iter()
.filter(|s| s.key == id)
.reduce(|k, _| k)
}
/// Insert a data scaling
pub(crate) fn with_scaling(&mut self, observable: Observable, scaling: u16) {
self.scaling.insert(observable.clone(), scaling);
}
/// Returns scaling to applied to said Observable.
pub(crate) fn scaling(&self, observable: Observable) -> Option<&u16> {
self.scaling.get(&observable)
}
}
Loading

0 comments on commit 46b4bab

Please sign in to comment.