Skip to content

Commit

Permalink
remove "observation" trait, rely on statrs and mark Mp as work in pro…
Browse files Browse the repository at this point in the history
…gress

Signed-off-by: Guillaume W. Bres <[email protected]>
  • Loading branch information
gwbres committed Sep 7, 2023
1 parent 86f642d commit 6c679d6
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 886 deletions.
24 changes: 12 additions & 12 deletions rinex-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,18 +270,18 @@ pub fn main() -> Result<(), rinex::Error> {
* Code Multipath analysis
*/
if cli.multipath() {
let data = ctx
.primary_data()
.observation_phase_align_origin()
.observation_phase_carrier_cycles()
.mp();
plot::plot_gnss_dcb(
&mut plot_ctx,
"Code Multipath Biases",
"Meters of delay",
&data,
);
info!("--mp analysis");
//let data = ctx
// .primary_data()
// .observation_phase_align_origin()
// .observation_phase_carrier_cycles()
// .mp();
//plot::plot_gnss_dcb(
// &mut plot_ctx,
// "Code Multipath Biases",
// "Meters of delay",
// &data,
//);
warn!("--mp analysis not available yet");
}
/*
* [GF] recombination visualization requested
Expand Down
125 changes: 82 additions & 43 deletions rinex/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -984,36 +984,6 @@ impl Rinex {
results
}
*/
/*
/// Extracts Raw Carrier Phase observations,
/// from this Observation record, on an epoch basis an per space vehicle.
/// Does not produce anything if self is not an Observation RINEX.
pub fn observation_phase(&self) -> BTreeMap<(Epoch, EpochFlag), HashMap<Sv, Vec<(String, f64)>>> {
let mut ret: BTreeMap<Epoch, BTreeMap<Sv, Vec<(String, f64)>>> = BTreeMap::new();
if let Some(r) = self.record.as_obs() {
for ((e, _), (_, sv)) in record.iter() {
let mut map: BTreeMap<Sv, Vec<(String, f64)>> = BTreeMap::new();
for (sv, obs) in sv.iter() {
let mut v: Vec<(String, f64)> = Vec::new();
for (observable, data) in obs.iter() {
if observable.is_phase_observation() {
v.push((code.clone(), data.obs));
}
}
if v.len() > 0 {
// did come with at least 1 Phase obs
map.insert(*sv, v);
}
}
if map.len() > 0 {
// did produce something
results.insert(*e, map);
}
}
}
ret
}
*/
/*
/// Extracts Carrier phases without Ionospheric path delay contributions,
/// by extracting [carrier_phases] and using the differential (dual frequency) compensation.
Expand Down Expand Up @@ -2882,19 +2852,88 @@ impl Dcb for Rinex {
}
}

#[cfg(feature = "obs")]
use observation::Mp;

#[cfg(feature = "obs")]
impl Mp for Rinex {
fn mp(&self) -> HashMap<String, BTreeMap<Sv, BTreeMap<(Epoch, EpochFlag), f64>>> {
if let Some(r) = self.record.as_obs() {
r.dcb()
} else {
panic!("wrong rinex type");
}
}
}
//#[cfg(feature = "obs")]
//use observation::Mp;
//
//#[cfg(feature = "obs")]
//impl Mp for Rinex {
// fn mp(&self) -> HashMap<String, BTreeMap<Sv, BTreeMap<(Epoch, EpochFlag), f64>>> {
// /*
// * Determine mean value of all observed Phase and Pseudo Range
// * observations, for all Sv
// */
// let mut mean: HashMap<Sv, HashMap<Observable, f64>> = HashMap::new();
// /*
// * Associate a Phase code to all PR codes
// */
// let mut associations: HashMap<Observable, Observable> = HashMap::new();
//
// let pr_codes: Vec<Observable> = self.observable()
// .filter_map(|obs|
// if obs.is_pseudorange_observable() {
// Some(obs.clone())
// } else {
// None
// })
// .collect();
//
// for observable in self.observable() {
// if !observable.is_phase_observable() {
// if !observable.is_pseudorange_observable() {
// continue;
// }
// }
// // code associations (for future combianations)
// if observable.is_phase_observable() {
// for pr_code in &pr_codes {
//
// }
// }
//
// for sv in self.sv() {
// /*
// * average phase values
// */
// let phases: Vec<f64> = self.carrier_phase()
// .filter_map(|(_, svnn, obs, ph)| {
// if sv == svnn && observable == obs {
// Some(ph)
// } else {
// None
// }
// })
// .collect();
// if let Some(data) = mean.get_mut(&sv) {
// data.insert(observable.clone(), phases.mean());
// } else {
// let mut map: HashMap<Observable, f64> = HashMap::new();
// map.insert(observable.clone(), phases.mean());
// mean.insert(sv, map);
// }
// /*
// * average PR values
// */
// let pr: Vec<f64> = self.pseudo_range()
// .filter_map(|(_, svnn, obs, pr)| {
// if sv == svnn && observable == obs {
// Some(pr)
// } else {
// None
// }
// })
// .collect();
// if let Some(data) = mean.get_mut(&sv) {
// data.insert(observable.clone(), pr.mean());
// } else {
// let mut map: HashMap<Observable, f64> = HashMap::new();
// map.insert(observable.clone(), pr.mean());
// mean.insert(sv, map);
// }
// }
// }
// HashMap::new()
// }
//}

#[cfg(feature = "obs")]
use observation::Combine;
Expand Down
66 changes: 0 additions & 66 deletions rinex/src/meteo/record.rs
Original file line number Diff line number Diff line change
Expand Up @@ -436,69 +436,3 @@ impl Interpolate for Record {
unimplemented!("meteo:record:interpolate_mut()")
}
}

#[cfg(feature = "obs")]
use crate::observation::{Observation, StatisticalOps};

#[cfg(feature = "obs")]
use statrs::statistics::Statistics;

#[cfg(feature = "obs")]
fn statistical_estimate(rec: &Record, ops: StatisticalOps) -> HashMap<Observable, f64> {
let mut ret: HashMap<Observable, f64> = HashMap::new();
let mut dataset: HashMap<Observable, Vec<f64>> = HashMap::new();
for (_t, observables) in rec {
for (observable, point) in observables {
if let Some(data) = dataset.get_mut(&observable) {
data.push(*point);
} else {
dataset.insert(observable.clone(), vec![*point]);
}
}
}
for (observable, data) in dataset {
let stats = match ops {
StatisticalOps::Min => data.min(),
StatisticalOps::Max => data.max(),
StatisticalOps::Mean => data.mean(),
StatisticalOps::StdDev => data.std_dev(),
StatisticalOps::StdVar => data.variance(),
};
ret.insert(observable.clone(), stats);
}
ret
}

#[cfg(feature = "obs")]
impl Observation for Record {
fn min(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>) {
unimplemented!("only on OBS RINEX!");
}
fn max(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>) {
unimplemented!("only on OBS RINEX!");
}
fn mean(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>) {
unimplemented!("only on OBS RINEX!");
}
fn std_var(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>) {
unimplemented!("only on OBS RINEX!");
}
fn std_dev(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>) {
unimplemented!("only on OBS RINEX!");
}
fn min_observable(&self) -> HashMap<Observable, f64> {
statistical_estimate(self, StatisticalOps::Min)
}
fn max_observable(&self) -> HashMap<Observable, f64> {
statistical_estimate(self, StatisticalOps::Max)
}
fn std_dev_observable(&self) -> HashMap<Observable, f64> {
statistical_estimate(self, StatisticalOps::StdDev)
}
fn std_var_observable(&self) -> HashMap<Observable, f64> {
statistical_estimate(self, StatisticalOps::StdVar)
}
fn mean_observable(&self) -> HashMap<Observable, f64> {
statistical_estimate(self, StatisticalOps::Mean)
}
}
113 changes: 0 additions & 113 deletions rinex/src/observation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,122 +174,9 @@ impl HeaderFields {
}
}

#[cfg(feature = "obs")]
#[derive(Debug, Clone, Copy)]
pub(crate) enum StatisticalOps {
Min,
Max,
Mean,
StdDev,
StdVar,
}

#[cfg(feature = "obs")]
use std::collections::BTreeMap;

/// OBS RINEX specific analysis trait.
/// Include this trait to unlock Observation analysis, mainly statistical analysis.
#[cfg(feature = "obs")]
#[cfg_attr(docrs, doc(cfg(feature = "obs")))]
pub trait Observation {
/// Returns minimum value observed, throughout all epochs, sorted by Observable.
/// This also applies to clock receiver estimate,
/// when requested on OBS RINEX files, not METEO files.
/// ```
/// use rinex::*; // prelude + macros
/// use rinex::prelude::*;
/// use std::str::FromStr; // observable!
/// use rinex::observation::Observation; // .min_observable()
///
/// // OBS RINEX example
/// let rinex = Rinex::from_file("../test_resources/OBS/V3/DUTH0630.22O")
/// .unwrap();
/// let min_values = rinex.min_observable();
/// for (observable, min_value) in min_values {
/// if observable == observable!("S1C") {
/// // minimum signal strength for carrier 1
/// assert_eq!(min_value, 37.75); // L1 carrier min (worst) RSSI
/// }
/// }
///
/// // METEO RINEX example
/// let rinex = Rinex::from_file("../test_resources/MET/V2/clar0020.00m")
/// .unwrap();
/// let min_values = rinex.min_observable();
/// for (observable, min_value) in min_values {
/// if observable == Observable::Temperature {
/// assert_eq!(min_value, 8.4); // min value encountered on that day
/// }
/// }
/// ```
fn min_observable(&self) -> HashMap<Observable, f64>;

/// Returns maximal value observed, throughout all epochs, sorted by Observable.
/// See [Self::min_observable()] for API example.
fn max_observable(&self) -> HashMap<Observable, f64>;

/// Returns mean observation, throughout all epochs, sorted by Observable.
/// See [Self::min_observable()] for API example.
fn mean_observable(&self) -> HashMap<Observable, f64>;

/// Returns standard deviation for all Observables.
/// See [Self::min_observable()] for API example.
fn std_dev_observable(&self) -> HashMap<Observable, f64>;

/// Returns standard variance for all Observables.
/// See [Self::min_observable()] for API example.
fn std_var_observable(&self) -> HashMap<Observable, f64>;

/// Returns minimum value observed throughout all epochs sorted by
/// Satellite vehicle and Observable. This does not apply to METEO
/// RINEX files.
/// ```
/// use rinex::*;
/// use rinex::prelude::*; // basics
/// use std::str::FromStr; // sv!, observable!
/// use rinex::observation::Observation; // .min()
///
/// // OBS RINEX example
/// let rinex = Rinex::from_file("../test_resources/OBS/V3/DUTH0630.22O")
/// .unwrap();
///
/// let (min_clock, min_values) = rinex.min();
/// assert!(min_clock.is_none()); // we don't have an example file with such information yet
///
/// for (sv, observables) in min_values {
/// if sv == sv!("G08") {
/// for (observable, min_value) in observables {
/// if observable == observable!("S1C") {
/// // minimum signal strength for carrier 1
/// // for that particular vehicle
/// }
/// }
/// }
/// }
/// ```
fn min(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>);

/// Returns maximal value observed throughout all epochs sorted by
/// Satellite vehicle and Observable. This does not apply to METEO
/// RINEX files. See [Self::min()] for API example.
fn max(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>);

/// Returns mean value observed throughout all epochs sorted by
/// Satellite vehicle and Observable. This does not apply to METEO
/// RINEX files. See [Self::min()] for API example.
fn mean(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>);

/// Returns observations deviation throughout all epochs sorted by
/// Satellite vehicle and Observable. This does not apply to METEO
/// RINEX files. See [Self::min()] for API example.
fn std_dev(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>);

/// Returns observations variance throughout all epochs sorted by
/// Satellite vehicle and Observable. This does not apply to METEO
/// RINEX files. See [Self::min()] for API example.
fn std_var(&self) -> (Option<f64>, HashMap<Sv, HashMap<Observable, f64>>);
}

/// GNSS signal recombination trait.
/// Import this to recombine OBS RINEX with usual recombination methods.
/// This only applies to OBS RINEX records.
Expand Down
Loading

0 comments on commit 6c679d6

Please sign in to comment.