From 2750ad8fcd90b9d591322c3b777497201474a88f Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Tue, 6 Aug 2024 17:31:31 +0200 Subject: [PATCH 01/14] improve , update bias interface Signed-off-by: Guillaume W. Bres --- rinex-cli/src/positioning/cggtts/mod.rs | 52 +++++++++++-------- rinex-cli/src/positioning/cggtts/report.rs | 58 +++++++++++++++++++++- rinex-cli/src/positioning/ppp/mod.rs | 42 ++++++++-------- rinex-cli/src/positioning/ppp/report.rs | 20 ++++---- 4 files changed, 122 insertions(+), 50 deletions(-) diff --git a/rinex-cli/src/positioning/cggtts/mod.rs b/rinex-cli/src/positioning/cggtts/mod.rs index 35198dd2..9f0409d8 100644 --- a/rinex-cli/src/positioning/cggtts/mod.rs +++ b/rinex-cli/src/positioning/cggtts/mod.rs @@ -14,8 +14,8 @@ use gnss::prelude::{Constellation, SV}; use rinex::{carrier::Carrier, prelude::Observable}; use gnss_rtk::prelude::{ - BaseStation, Candidate, Duration, Epoch, IonosphereBias, Method, Observation, - OrbitalStateProvider, Solver, TroposphereBias, + BaseStation, Candidate, Duration, Epoch, IonoComponents, IonosphereBias, Method, Observation, + OrbitalStateProvider, Solver, TropoComponents, SPEED_OF_LIGHT_M_S, }; use cggtts::{ @@ -128,17 +128,18 @@ pub fn resolve<'a, 'b, CK: ClockStateProvider, O: OrbitalStateProvider, B: BaseS debug!("{} ({}) - tgd: {}", *t, *sv, tgd); } - let iono_bias = IonosphereBias { - kb_model: kb_model(nav_data, *t), - bd_model: bd_model(nav_data, *t), - ng_model: ng_model(nav_data, *t), - stec_meas: None, //TODO + let iono_components = if let Some(model) = kb_model(nav_data, *t) { + IonoComponents::KbModel(model) + } else if let Some(model) = bd_model(nav_data, *t) { + IonoComponents::BdModel(model) + } else if let Some(model) = ng_model(nav_data, *t) { + IonoComponents::NgModel(model) + } else { + // TODO STEC/IONEX + IonoComponents::Unknown }; - let tropo_bias = TroposphereBias { - total: None, //TODO - zwd_zdd: None, // TODO - }; + let tropo_components = TropoComponents::Unknown; //TODO METEO // tries to form a candidate for each signal for (observable, data) in observations { @@ -237,9 +238,17 @@ pub fn resolve<'a, 'b, CK: ClockStateProvider, O: OrbitalStateProvider, B: BaseS } } - let candidate = Candidate::new(*sv, *t, clock_corr, tgd, rtk_obs); - - match solver.resolve(*t, &vec![candidate], &iono_bias, &tropo_bias) { + let candidate = Candidate::new( + *sv, + *t, + clock_corr, + tgd, + rtk_obs, + iono_components, + tropo_components, + ); + + match solver.resolve(*t, &vec![candidate]) { Ok((t, pvt_solution)) => { let pvt_data = pvt_solution.sv.get(sv).unwrap(); // infaillible @@ -253,13 +262,16 @@ pub fn resolve<'a, 'b, CK: ClockStateProvider, O: OrbitalStateProvider, B: BaseS * TROPO : always present * convert to time delay (CGGTTS) */ - let mdtr = match pvt_data.tropo_bias.value() { - Some(tropo) => tropo / 299792458.0, - None => 0.0_f64, - }; + let mdtr = pvt_data.tropo_bias.unwrap_or_default() / SPEED_OF_LIGHT_M_S; - let mdio = pvt_data.iono_bias.modeled; - let msio = pvt_data.iono_bias.measured; + let mdio = match pvt_data.iono_bias { + Some(IonosphereBias::Modeled(bias)) => Some(bias), + _ => None, + }; + let msio = match pvt_data.iono_bias { + Some(IonosphereBias::Measured(bias)) => Some(bias), + _ => None, + }; debug!( "{:?} : new {}:{} solution (elev={:.2}°, azi={:.2}°, refsv={:.3E}, refsys={:.3E})", t, sv, observable, elevation, azimuth, refsv, refsys diff --git a/rinex-cli/src/positioning/cggtts/report.rs b/rinex-cli/src/positioning/cggtts/report.rs index 5b7a05ba..363dfebb 100644 --- a/rinex-cli/src/positioning/cggtts/report.rs +++ b/rinex-cli/src/positioning/cggtts/report.rs @@ -202,8 +202,64 @@ impl ReportContent { plot }, ionod_plot: { - let plot = + let mut plot = Plot::timedomain_plot("ionod_plot", "Ionospheric Delay", "Delay [s]", true); + for sv in summary.satellites.iter() { + let x = solutions + .iter() + .filter_map(|trk| if trk.sv == *sv { Some(trk.epoch) } else { None }) + .collect::>(); + let y = solutions + .iter() + .filter_map(|trk| { + if trk.sv == *sv { + Some(trk.data.mdio) + } else { + None + } + }) + .collect::>(); + let trace = Plot::timedomain_chart( + &format!("{}(mdio)", sv), + Mode::Markers, + MarkerSymbol::Cross, + &x, + y, + true, + ); + plot.add_trace(trace); + + let x = solutions + .iter() + .filter_map(|trk| { + if trk.sv == *sv && trk.iono.is_some() { + Some(trk.epoch) + } else { + None + } + }) + .collect::>(); + let y = solutions + .iter() + .filter_map(|trk| { + if trk.sv == *sv { + let iono = trk.iono?; + Some(iono.msio) + } else { + None + } + }) + .collect::>(); + let trace = Plot::timedomain_chart( + &format!("{}(mdio)", sv), + Mode::Markers, + MarkerSymbol::Cross, + &x, + y, + true, + ); + plot.add_trace(trace); + } plot }, tropod_plot: { diff --git a/rinex-cli/src/positioning/ppp/mod.rs b/rinex-cli/src/positioning/ppp/mod.rs index fa358e39..4d5cef76 100644 --- a/rinex-cli/src/positioning/ppp/mod.rs +++ b/rinex-cli/src/positioning/ppp/mod.rs @@ -21,8 +21,8 @@ pub use report::Report; pub mod post_process; use gnss_rtk::prelude::{ - BaseStation, Candidate, Epoch, IonosphereBias, Observation, OrbitalStateProvider, PVTSolution, - Solver, TroposphereBias, + BaseStation, Candidate, Epoch, IonoComponents, Observation, OrbitalStateProvider, PVTSolution, + Solver, TropoComponents, }; pub fn resolve<'a, 'b, CK: ClockStateProvider, O: OrbitalStateProvider, B: BaseStation>( @@ -134,27 +134,29 @@ pub fn resolve<'a, 'b, CK: ClockStateProvider, O: OrbitalStateProvider, B: BaseS } } } - let candidate = - Candidate::new(*sv, *t, clock_corr, Default::default(), rtk_obs.clone()); + let iono_components = if let Some(model) = kb_model(nav_data, *t) { + IonoComponents::KbModel(model) + } else if let Some(model) = ng_model(nav_data, *t) { + IonoComponents::NgModel(model) + } else if let Some(model) = bd_model(nav_data, *t) { + IonoComponents::BdModel(model) + } else { + //TODO STEC/IONEX + IonoComponents::Unknown + }; + let candidate = Candidate::new( + *sv, + *t, + clock_corr, + Default::default(), + rtk_obs.clone(), + iono_components, + TropoComponents::Unknown, // TODO: meteo + ); candidates.push(candidate); } - // grab possible tropo components - // let zwd_zdd = tropo_components(meteo_data, *t, rx_lat_ddeg); - - let iono_bias = IonosphereBias { - kb_model: kb_model(nav_data, *t), - bd_model: bd_model(nav_data, *t), - ng_model: ng_model(nav_data, *t), - stec_meas: None, //TODO - }; - - let tropo_bias = TroposphereBias { - total: None, //TODO - zwd_zdd: None, //TODO - }; - - match solver.resolve(*t, &candidates, &iono_bias, &tropo_bias) { + match solver.resolve(*t, &candidates) { Ok((t, pvt)) => { debug!("{} : {:?}", t, pvt); solutions.insert(t, pvt); diff --git a/rinex-cli/src/positioning/ppp/report.rs b/rinex-cli/src/positioning/ppp/report.rs index 6cc2beca..64049aac 100644 --- a/rinex-cli/src/positioning/ppp/report.rs +++ b/rinex-cli/src/positioning/ppp/report.rs @@ -415,7 +415,7 @@ impl ReportContent { MarkerSymbol::Cross, &epochs, long, - true, + false, ); plot.add_trace(trace); plot @@ -510,7 +510,8 @@ impl ReportContent { if let Some(value) = sol.sv.iter().filter(|(s, _)| *s == sv).reduce(|k, _| k) { - value.1.tropo_bias.value() + let bias = value.1.tropo_bias?; + Some(bias) } else { None } @@ -547,7 +548,8 @@ impl ReportContent { if let Some(value) = sol.sv.iter().filter(|(s, _)| *s == sv).reduce(|k, _| k) { - value.1.iono_bias.value() + let bias = value.1.iono_bias?; + Some(bias) } else { None } @@ -899,22 +901,22 @@ impl Render for ReportContent { } tr { th class="is-info" { - button aria-label="Error due to Ionospheric delay" data-balloon-pos="right" { - "Ionosphere" + button aria-label="Error due to Tropospheric delay" data-balloon-pos="right" { + "Troposphere" } } td { - (self.ionod_plot.render()) + (self.tropod_plot.render()) } } tr { th class="is-info" { - button aria-label="Error due to Tropospheric delay" data-balloon-pos="right" { - "Troposphere" + button aria-label="Error due to Ionospheric delay" data-balloon-pos="right" { + "Ionosphere" } } td { - (self.tropod_plot.render()) + (self.ionod_plot.render()) } } } From a090d329f486d977bc0da8851680c84310111519 Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 10:46:22 +0200 Subject: [PATCH 02/14] Working on GEO & BDS examples Signed-off-by: Guillaume W. Bres --- tutorials/BDS/esbjerg-brdc.sh | 6 +++--- tutorials/GAL+SBAS/esbjerg.sh | 23 +++++++++++++++-------- tutorials/GAL/mojdnk.sh | 1 + tutorials/GEO/esbjerg.sh | 4 ++-- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/tutorials/BDS/esbjerg-brdc.sh b/tutorials/BDS/esbjerg-brdc.sh index ad4701ba..b43ecafa 100755 --- a/tutorials/BDS/esbjerg-brdc.sh +++ b/tutorials/BDS/esbjerg-brdc.sh @@ -3,15 +3,14 @@ DATA_DIR=test_resources CONF=tutorials/config/survey/cpp_kf.json SYSTEM=BeiDou # All BeiDou -#SIGNALS=C2I,C6I -SIGNALS=C2I,C7I +SIGNALS=C2I,C6I # Analysis + ppp solutions # -q: silent (open only on last run) # -f: force new synthesis # -P: filter example ./target/release/rinex-cli \ - -q -f \ + -q -f -o "BRDC-BDS-B2i-B3" \ -P $SYSTEM -P $SIGNALS \ --fp $DATA_DIR/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz \ --fp $DATA_DIR/NAV/V3/ESBC00DNK_R_20201770000_01D_MN.rnx.gz \ @@ -19,6 +18,7 @@ SIGNALS=C2I,C7I # append cggtts solutions +open ./target/release/rinex-cli \ + -o "BRDC-BDS-B2i-B3" \ -P $SYSTEM -P $SIGNALS \ --fp $DATA_DIR/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz \ --fp $DATA_DIR/NAV/V3/ESBC00DNK_R_20201770000_01D_MN.rnx.gz \ diff --git a/tutorials/GAL+SBAS/esbjerg.sh b/tutorials/GAL+SBAS/esbjerg.sh index ca6f0c41..e4b19d49 100755 --- a/tutorials/GAL+SBAS/esbjerg.sh +++ b/tutorials/GAL+SBAS/esbjerg.sh @@ -1,21 +1,28 @@ #!/bin/sh -# Post processing: -# +3 week surveying of this lab station +# Surveying with Galileo and 1 GEO + +# In this example, we use signals E1+E5(PR), but that does not matter. +# We use Galileo and 1 geostationnary vehicle. +# By using 4 GEO vehicles are observed (see other analysis examples) +# By using >S35 in the filter, we make sure that only one is kept. +# This is BRDC nav ("real time") surveying augmented with one GEO. +# Compare this one to esbjerg-ppp-x1 where we move to precise post processing, augmented with one GEO. +# Comare also to esbjerg-brdc and esbjerg-precise (in this very folder) when use GEO and GAL in equal proportion DATA_DIR=test_resources -# In this example, we use signals E1+E5(PR) for Galileo SV PRN>08 (example) -# and one EGNOS vehicle. You should compare these results to tutorial/GAL/esbcdnk-cpp.sh -FILTER="Gal,GEO;>E08;C1C,C5Q" -CONF=tutorials/config/survey/cpp_kf.json # basic CPP+Kf +FILTER="Gal,GEO; Date: Wed, 7 Aug 2024 10:48:02 +0200 Subject: [PATCH 03/14] Fix workspace / features Signed-off-by: Guillaume W. Bres --- Cargo.toml | 4 ++- rinex-qc/Cargo.toml | 4 +-- rinex-qc/src/cfg.rs | 11 +++--- rinex-qc/src/report/mod.rs | 66 ++++++++++++++++++++++++++++++++++++ rinex-qc/src/report/orbit.rs | 62 +++++++++++++++++++++++++++++++-- rinex/Cargo.toml | 1 + rinex/src/meteo/sensor.rs | 1 + sp3/Cargo.toml | 1 + 8 files changed, 139 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7cc428e1..e28fab03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,4 +13,6 @@ members = [ "ublox-rnx", ] -exclude = ["./test_resources"] +exclude = [ + "./test_resources", +] diff --git a/rinex-qc/Cargo.toml b/rinex-qc/Cargo.toml index a0bf3692..700f49fa 100644 --- a/rinex-qc/Cargo.toml +++ b/rinex-qc/Cargo.toml @@ -36,8 +36,8 @@ thiserror = "1" strum = "0.26" itertools = "0.13.0" strum_macros = "0.26" -anise = "0.4.2" -serde = { version = "1.0", optional = true, default-features = false, features = ["derive"] } +anise = { version = "0.4.2", features = ["embed_ephem"] } +serde = { version = "1.0", default-features = false, features = ["derive"] } statrs = { version = "0.16", optional = true } diff --git a/rinex-qc/src/cfg.rs b/rinex-qc/src/cfg.rs index 5f5d7908..0f895a92 100644 --- a/rinex-qc/src/cfg.rs +++ b/rinex-qc/src/cfg.rs @@ -2,7 +2,6 @@ use maud::{html, Markup, Render}; use rinex::prelude::*; use thiserror::Error; -#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; /// Configuration Error @@ -17,7 +16,7 @@ use std::str::FromStr; /// [QcReportType] #[derive(Default, Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Serialize, Deserialize)] pub enum QcReportType { /// In [Summary] mode, only the summary section /// of the report is to be generated. It is the lightest @@ -51,13 +50,13 @@ impl Display for QcReportType { } #[derive(Debug, Clone, Default)] -#[cfg_attr(feature = "serde", derive(Deserialize))] +#[derive(Deserialize)] pub struct QcConfig { - #[cfg_attr(feature = "serde", serde(default))] + #[serde(default)] pub report: QcReportType, - #[cfg_attr(feature = "serde", serde(default))] + #[serde(default)] pub manual_reference: Option, - #[cfg_attr(feature = "serde", serde(default))] + #[serde(default)] /// When both SP3 and BRDC NAV are present, /// SP3 is prefered for skyplot project: set true here to /// also compute for BRDC NAV. diff --git a/rinex-qc/src/report/mod.rs b/rinex-qc/src/report/mod.rs index 069ee1df..3d97a7a3 100644 --- a/rinex-qc/src/report/mod.rs +++ b/rinex-qc/src/report/mod.rs @@ -211,6 +211,19 @@ impl QcReport { } items }, + #[cfg(not(feature = "sp3"))] + orbit: { + if context.has_brdc_navigation() && !summary_only { + Some(OrbitReport::new( + context, + ref_position, + cfg.force_brdc_skyplot, + )) + } else { + None + } + }, + #[cfg(feature = "sp3")] orbit: { if (context.has_sp3() || context.has_brdc_navigation()) && !summary_only { Some(OrbitReport::new( @@ -230,6 +243,58 @@ impl QcReport { self.custom_chapters.push(chapter); } /// Generates a menu bar to nagivate [Self] + #[cfg(not(feature = "sp3"))] + fn menu_bar(&self) -> Markup { + html! { + aside class="menu" { + p class="menu-label" { + (format!("RINEX-QC v{}", env!("CARGO_PKG_VERSION"))) + } + ul class="menu-list" { + li { + a id="menu:summary" { + span class="icon" { + i class="fa fa-home" {} + } + "Summary" + } + } + @for product in self.products.keys().sorted() { + @if let Some(report) = self.products.get(&product) { + li { + (report.html_inline_menu_bar()) + } + } + } + @for chapter in self.custom_chapters.iter() { + li { + (chapter.tab.render()) + } + } + p class="menu-label" { + a href="https://github.com/georust/rinex/wiki" style="margin-left:29px" { + "Documentation" + } + } + p class="menu-label" { + a href="https://github.com/georust/rinex/issues" style="margin-left:29px" { + "Bug Report" + } + } + p class="menu-label" { + a href="https://github.com/georust/rinex" { + span class="icon" { + i class="fa-brands fa-github" {} + } + "Sources" + } + } + } // menu-list + }//menu + } + } + /// Generates a menu bar to nagivate [Self] + #[cfg(feature = "sp3")] fn menu_bar(&self) -> Markup { html! { aside class="menu" { @@ -327,6 +392,7 @@ impl Render for QcReport { } } } + // TODO: it should be feasible to run without SP3 support @if let Some(orbit) = &self.orbit { div id="orbit" class="container is-main" style="display:none" { (orbit.render()) diff --git a/rinex-qc/src/report/orbit.rs b/rinex-qc/src/report/orbit.rs index f3fa786b..7d006067 100644 --- a/rinex-qc/src/report/orbit.rs +++ b/rinex-qc/src/report/orbit.rs @@ -1,8 +1,7 @@ use rinex::{ navigation::Ephemeris, - prelude::{GroundPosition, Orbit, Rinex}, + prelude::{GroundPosition, Orbit, Rinex, SV, Constellation, Epoch}, }; -use sp3::prelude::{Constellation, Epoch, SP3, SV}; use std::collections::{BTreeMap, HashMap}; use qc_traits::processing::{Filter, Preprocessing}; @@ -12,12 +11,17 @@ use crate::{ prelude::{html, Markup, Plot, QcContext, Render}, }; +#[cfg(feature = "sp3")] +use sp3::prelude::SP3; + +#[cfg(feature = "sp3")] struct BrdcSp3Report { x_err_plot: Plot, y_err_plot: Plot, z_err_plot: Plot, } +#[cfg(feature = "sp3")] impl BrdcSp3Report { fn new(sp3: &SP3, brdc: &Rinex) -> Self { let mut errors = BTreeMap::>::new(); @@ -106,6 +110,7 @@ impl BrdcSp3Report { } } +#[cfg(feature = "sp3")] impl Render for BrdcSp3Report { fn render(&self) -> Markup { html! { @@ -146,6 +151,7 @@ pub struct OrbitReport { elev_plot: Plot, map_proj: Plot, // globe_proj: Plot, + #[cfg(feature = "sp3")] brdc_sp3_err: HashMap, } @@ -153,8 +159,12 @@ impl OrbitReport { pub fn new(ctx: &QcContext, reference: Option, force_brdc_sky: bool) -> Self { let (x0, y0, z0) = reference.unwrap_or_default().to_ecef_wgs84(); let (x0_km, y0_km, z0_km) = (x0 / 1000.0, y0 / 1000.0, z0 / 1000.0); + // TODO: brdc needs a timeserie.. + #[cfg(feature = "sp3")] let brdc_skyplot = ctx.has_brdc_navigation() && ctx.has_sp3() && force_brdc_sky; + #[cfg(not(feature = "sp3"))] + let brdc_skyplot = ctx.has_brdc_navigation(); let max_sv_visible = if brdc_skyplot { 2 } else { 4 }; @@ -166,6 +176,7 @@ impl OrbitReport { let mut elev_brdc = BTreeMap::>::new(); let mut azim_brdc = BTreeMap::>::new(); + #[cfg(feature = "sp3")] if let Some(sp3) = ctx.sp3() { for (t, sv_sp3, pos_sp3) in sp3.sv_position() { let (x_sp3_km, y_sp3_km, z_sp3_km) = (pos_sp3.0, pos_sp3.1, pos_sp3.2); @@ -297,6 +308,7 @@ impl OrbitReport { 1, true, ); + #[cfg(feature = "sp3")] if let Some(sp3) = ctx.sp3() { for (sv_index, sv) in sp3.sv().enumerate() { let orbits = sp3 @@ -358,6 +370,7 @@ impl OrbitReport { // ); // map_proj //}, + #[cfg(feature = "sp3")] brdc_sp3_err: { let mut reports = HashMap::::new(); if let Some(sp3) = ctx.sp3() { @@ -395,6 +408,7 @@ impl OrbitReport { } } +#[cfg(feature = "sp3")] impl Render for OrbitReport { fn render(&self) -> Markup { html! { @@ -449,3 +463,47 @@ impl Render for OrbitReport { } } } + +#[cfg(not(feature = "sp3"))] +impl Render for OrbitReport { + fn render(&self) -> Markup { + html! { + div class="table-container" { + table class="table is-bordered" { + tr { + th class="is-info" { + "Map projection" + } + td { + (self.map_proj.render()) + } + } + //tr { + // th class="is-info" { + // "Globe projection" + // } + // td { + // (self.globe_proj.render()) + // } + //} + tr { + th class="is-info" { + "Sky plot" + } + td { + (self.sky_plot.render()) + } + } + tr { + th class="is-info" { + "Elevation" + } + td { + (self.elev_plot.render()) + } + } + } + } + } + } +} diff --git a/rinex/Cargo.toml b/rinex/Cargo.toml index df86a3a0..2c326730 100644 --- a/rinex/Cargo.toml +++ b/rinex/Cargo.toml @@ -58,6 +58,7 @@ qc = [ # Unlock Processing package. # Unlocks the preprocessing toolkit, Filtering methods and preprocessing algorithms. processing = [ + "qc", "rinex-qc-traits/processing", ] diff --git a/rinex/src/meteo/sensor.rs b/rinex/src/meteo/sensor.rs index 6010266d..e153549f 100644 --- a/rinex/src/meteo/sensor.rs +++ b/rinex/src/meteo/sensor.rs @@ -26,6 +26,7 @@ pub struct Sensor { pub height: Option, } +#[cfg(feature = "qc")] impl Render for Sensor { fn render(&self) -> Markup { html! { diff --git a/sp3/Cargo.toml b/sp3/Cargo.toml index 43cffcba..6a5070d0 100644 --- a/sp3/Cargo.toml +++ b/sp3/Cargo.toml @@ -22,6 +22,7 @@ qc = [ # Unlock processing features processing = [ + "qc", "rinex-qc-traits/processing", ] From 1f4d4719e0ac312e567df62e5994971753a34f73 Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 10:48:13 +0200 Subject: [PATCH 04/14] Prepare for next release Signed-off-by: Guillaume W. Bres --- rinex-cli/Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rinex-cli/Cargo.toml b/rinex-cli/Cargo.toml index 3b813d65..cba3edfa 100644 --- a/rinex-cli/Cargo.toml +++ b/rinex-cli/Cargo.toml @@ -35,18 +35,18 @@ serde = { version = "1.0", default-features = false, features = ["derive"] } kml = { version = "0.8", optional = true } gpx = { version = "0.10", optional = true } -# plotly = "0.9" +plotly = "0.9" # plotly = { path = "../../plotly-rs/plotly" } -plotly = { git = "https://github.com/gwbres/plotly", branch = "scattergeo" } +# plotly = { git = "https://github.com/gwbres/plotly", branch = "scattergeo" } anise = { version = "0.4.2", features = ["embed_ephem"] } hifitime = { version = "4.0.0-alpha", features = ["serde", "std"] } gnss-rs = { version = "2.2.1", features = ["serde"] } -# gnss-rtk = { version = "0.5.0", features = ["serde"] } -# gnss-rtk = { path = "../../rtk-rs/gnss-rtk", features = ["serde"] } -gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "main", features = ["serde"] } +gnss-rtk = { version = "0.6.0", features = ["serde"] } +# gnss-rtk = { path = "../../rtk-rs/gnss-rtk", features = ["serde"] } +# gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "main", features = ["serde"] } cggtts = { version = "4.1.5", features = ["serde", "scheduler"], optional = true } # cggtts = { path = "../../cggtts/cggtts", features = ["serde", "scheduler"], optional = true } From a69d5894a21b542f0c83a676f1a93d6ebd0191ee Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 10:48:37 +0200 Subject: [PATCH 05/14] prepare for SBAS/GEO support Signed-off-by: Guillaume W. Bres --- rinex-cli/src/positioning/eph.rs | 38 +++++++----- rinex/src/lib.rs | 31 ++++++---- rinex/src/navigation/ephemeris.rs | 96 ++++++++++++++++++++++--------- 3 files changed, 114 insertions(+), 51 deletions(-) diff --git a/rinex-cli/src/positioning/eph.rs b/rinex-cli/src/positioning/eph.rs index 672977f3..76adc90c 100644 --- a/rinex-cli/src/positioning/eph.rs +++ b/rinex-cli/src/positioning/eph.rs @@ -56,21 +56,33 @@ impl<'a> EphemerisSource<'a> { self.consume_one(); } } - fn try_select(&self, t: Epoch, sv: SV) -> Option<(Epoch, Epoch, Ephemeris)> { + fn try_select(&self, t: Epoch, sv: SV) -> Option<(Epoch, Epoch, &Ephemeris)> { let buffer = self.buffer.get(&sv)?; let sv_ts = sv.constellation.timescale()?; - let (toc_i, toe_i, eph_i) = buffer - .iter() - .filter_map(|(toc_i, eph_i)| { - if eph_i.is_valid(sv, t) && t >= *toc_i { - let toe_i = eph_i.toe(sv_ts)?; - Some((*toc_i, toe_i, eph_i)) - } else { - None - } - }) - .min_by_key(|(toc_i, _, _)| (t - *toc_i).abs())?; - Some((toc_i, toe_i, eph_i.clone())) + if sv.constellation.is_sbas() { + buffer + .iter() + .filter_map(|(toc_i, eph_i)| { + if t >= *toc_i { + Some((*toc_i, *toc_i, eph_i)) + } else { + None + } + }) + .min_by_key(|(toc_i, _, _)| (t - *toc_i).abs()) + } else { + buffer + .iter() + .filter_map(|(toc_i, eph_i)| { + if eph_i.is_valid(sv, t) && t >= *toc_i { + let toe_i = eph_i.toe(sv_ts)?; + Some((*toc_i, toe_i, eph_i)) + } else { + None + } + }) + .min_by_key(|(toc_i, _, _)| (t - *toc_i).abs()) + } } pub fn select(&mut self, t: Epoch, sv: SV) -> Option<(Epoch, Epoch, Ephemeris)> { let mut attempt = 0; diff --git a/rinex/src/lib.rs b/rinex/src/lib.rs index 50b5a639..3e2d83bf 100644 --- a/rinex/src/lib.rs +++ b/rinex/src/lib.rs @@ -51,7 +51,6 @@ extern crate num_derive; extern crate lazy_static; pub mod reader; -// use anise::almanac::Almanac; use reader::BufferedReader; pub mod writer; @@ -2347,20 +2346,28 @@ impl Rinex { /// Note that ToE = ToC for GEO/SBAS vehicles, because this field does not exist. pub fn sv_ephemeris(&self, sv: SV, t: Epoch) -> Option<(Epoch, Epoch, &Ephemeris)> { let sv_ts = sv.constellation.timescale()?; - self.ephemeris() - .filter_map(|(t_i, (_, sv_i, eph_i))| { - if sv_i == sv { - if eph_i.is_valid(sv, t) && t >= *t_i { - let toe = eph_i.toe(sv_ts)?; - Some((*t_i, toe, eph_i)) + if sv.constellation.is_sbas() { + let (toc, (_, _, eph)) = self + .ephemeris() + .filter(|(t_i, (_, sv_i, eph_i))| sv == *sv_i) + .reduce(|k, _| k)?; + Some((*toc, *toc, eph)) + } else { + self.ephemeris() + .filter_map(|(t_i, (_, sv_i, eph_i))| { + if sv_i == sv { + if eph_i.is_valid(sv, t) && t >= *t_i { + let toe = eph_i.toe(sv_ts)?; + Some((*t_i, toe, eph_i)) + } else { + None + } } else { None } - } else { - None - } - }) - .min_by_key(|(toc_i, _, _)| (t - *toc_i).abs()) + }) + .min_by_key(|(toc_i, _, _)| (t - *toc_i).abs()) + } } /// [SV] embedded clock offset (s), drift (s.s⁻¹) and drift rate (s.s⁻²) Iterator. /// ``` diff --git a/rinex/src/navigation/ephemeris.rs b/rinex/src/navigation/ephemeris.rs index 73561d9b..77a5e682 100644 --- a/rinex/src/navigation/ephemeris.rs +++ b/rinex/src/navigation/ephemeris.rs @@ -2,10 +2,14 @@ use super::{orbits::closest_nav_standards, NavMsgType, OrbitItem}; use crate::constants::Constants; use crate::{ constants, epoch, - prelude::{Almanac, Constellation, Duration, Epoch, TimeScale, SV}, + prelude::{Constellation, Duration, Epoch, TimeScale, SV}, version::Version, }; +#[cfg(feature = "nav")] +use crate::prelude::Almanac; + +#[cfg(feature = "nav")] use anise::{ astro::AzElRange, constants::frames::EARTH_J2000, @@ -25,6 +29,7 @@ use crate::epoch::{ #[cfg(feature = "nav")] use nalgebra::{self as na, Matrix3, Rotation, Rotation3, Vector3, Vector4}; + /// Parsing errors #[derive(Debug, Error)] pub enum Error { @@ -293,7 +298,9 @@ pub struct Kepler { pub m_0: f64, /// argument of perigee (semicircles) pub omega: f64, - /// time of issue of ephemeris + /// Time of issue of ephemeris. + /// NB GEO and GLO ephemerides do not have the notion of ToE, we set 0 here. + /// Any calculations that imply ToE for those is incorrect anyways. pub toe: f64, } @@ -332,8 +339,13 @@ impl Ephemeris { } /// Retrieves orbit data field expressed as f64 value, if such field exists. pub fn get_orbit_f64(&self, field: &str) -> Option { - if let Some(v) = self.orbits.get(field) { - v.as_f64() + if let Some(value) = self.orbits.get(field) { + let value = value.as_f64()?; + if value != 0.0 { + Some(value) + } else { + None + } } else { None } @@ -501,7 +513,8 @@ impl Ephemeris { #[cfg(feature = "nav")] impl Ephemeris { - /// Retrieves Orbit Keplerian parameters + /// Retrieves Orbit Keplerian parameters. + /// This only applies to MEO Ephemerides, not GEO and Glonass. pub fn kepler(&self) -> Option { Some(Kepler { a: self.get_orbit_f64("sqrta")?.powf(2.0), @@ -563,22 +576,23 @@ impl Ephemeris { s.set_orbit_f64("omegaDot", perturbations.omega_dot); s } - /// Total seconds elapsed between `t` and ToE, expressed in GPS timescale. - fn t_k_gpst_s(&self, sv: SV, t: Epoch) -> Option { - let sv_ts = sv.timescale()?; - let toe_gpst = self.toe(sv_ts)?.to_time_scale(TimeScale::GPST); - let dt = t.to_time_scale(TimeScale::GPST) - toe_gpst; + /// Total seconds elapsed between `t` and ToE, expressed in appropriate timescale. + /// NB: this does not apply to GEO Ephemerides but only MEO. + fn t_k(&self, sv: SV, t: Epoch) -> Option { + let mut sv_ts = sv.timescale()?; + let toe = self.toe(sv_ts)?; + let dt = t.to_time_scale(sv_ts) - toe; Some(dt.to_seconds()) } - - /// Form ephemerisHelper + /// Form ephemerisHelper. + /// This does not apply to SBAS and Glonass. fn ephemeris_helper(&self, sv: SV, t_sv: Epoch, t: Epoch) -> Option { // const let gm_m3_s2 = Constants::gm(sv); let omega = Constants::omega(sv); let dtr_f = Constants::dtr_f(sv); - let t_k = self.t_k_gpst_s(sv, t)?; + let t_k = self.t_k(sv, t)?; if t_k < 0.0 { error!("t_k < 0.0: bad op"); return None; @@ -760,9 +774,18 @@ impl Ephemeris { /// Self must be correctly selected from navigation record. /// See [Bibliography::AsceAppendix3], [Bibliography::JLe19] and [Bibliography::BeiDouICD] pub fn kepler2position(&self, sv: SV, t_sv: Epoch, t: Epoch) -> Option<(f64, f64, f64)> { - let helper = self.ephemeris_helper(sv, t_sv, t)?; - let pos = helper.ecef_position(); - Some((pos.x, pos.y, pos.z)) + if sv.constellation.is_sbas() || sv.constellation == Constellation::Glonass { + let (pos_x_km, pos_y_km, pos_z_km) = ( + self.get_orbit_f64("satPosX")?, + self.get_orbit_f64("satPosY")?, + self.get_orbit_f64("satPosZ")?, + ); + Some((pos_x_km, pos_y_km, pos_z_km)) + } else { + let helper = self.ephemeris_helper(sv, t_sv, t)?; + let pos = helper.ecef_position(); + Some((pos.x, pos.y, pos.z)) + } } /// Kepler ECEF [km] position and velocity [km/s] solver at desired instant "t" for given "sv" /// based off Self. Self must be correctly selected in navigation @@ -774,12 +797,26 @@ impl Ephemeris { t_sv: Epoch, t: Epoch, ) -> Option<((f64, f64, f64), (f64, f64, f64))> { - let helper = self.ephemeris_helper(sv, t_sv, t)?; - let (pos, vel) = helper.position_velocity()?; - Some(( - (pos.x / 1000.0, pos.y / 1000.0, pos.z / 1000.0), - (vel.x, vel.y, vel.z), - )) + if sv.constellation.is_sbas() || sv.constellation == Constellation::Glonass { + let (pos_x_km, pos_y_km, pos_z_km) = ( + self.get_orbit_f64("satPosX")?, + self.get_orbit_f64("satPosY")?, + self.get_orbit_f64("satPosZ")?, + ); + let (vel_x_km, vel_y_km, vel_z_km) = ( + self.get_orbit_f64("velX")?, + self.get_orbit_f64("velY")?, + self.get_orbit_f64("velZ")?, + ); + Some(((pos_x_km, pos_y_km, pos_z_km), (vel_x_km, vel_y_km, vel_z_km))) + } else { + let helper = self.ephemeris_helper(sv, t_sv, t)?; + let (pos, vel) = helper.position_velocity()?; + Some(( + (pos.x, pos.y, pos.z), + (vel.x, vel.y, vel.z), + )) + } } /// [AzElRange] calculation attempt, for following SV as observed at RX, /// both coordinates expressed as [km] in fixed body [Frame] centered on Earth. @@ -797,7 +834,9 @@ impl Ephemeris { Orbit::from_position(rx_x_km, rx_y_km, rx_z_km, t, fixed_body_frame), ) } - /// Returns True if Self is Valid at specified `t` + /// Returns True if Self is Valid at specified `t`. + /// NB: this only applies to MEO Ephemerides, not GEO Ephemerides, + /// which should always be considered "valid". pub fn is_valid(&self, sv: SV, t: Epoch) -> bool { if let Some(max_dt) = Self::max_dtoe(sv.constellation) { if let Some(sv_ts) = sv.constellation.timescale() { @@ -816,7 +855,7 @@ impl Ephemeris { false } } - /// Returns Ephemeris validity duration for this Constellation + /// Ephemeris validity period for this [Constellation] pub fn max_dtoe(c: Constellation) -> Option { match c { Constellation::GPS | Constellation::QZSS => Some(Duration::from_seconds(7200.0)), @@ -826,8 +865,13 @@ impl Ephemeris { Constellation::Glonass => Some(Duration::from_seconds(1800.0)), c => { if c.is_sbas() { - // tolerate one publication per day - Some(Duration::from_seconds(86.4E3)) + // Tolerate one publication per day. + // Typical RINEX apps will load one set per 24 hr. + // GEO Orbits are very special, with a single entry per day. + // Therefore, in typical RINEX apps, we will have one entry for every day. + // GEO Ephemerides cannot be handled like other Ephemerides anyway, they require + // a complete different logic and calculations + Some(Duration::from_days(1.0)) } else { None } From 2dbe35bdc7f073bec151bdaf76c9adcd7a3762ee Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:15:35 +0200 Subject: [PATCH 06/14] Upgrade CI scripts Signed-off-by: Guillaume W. Bres --- .github/workflows/rust.yml | 137 ++++++++++++++++++++++++++----------- 1 file changed, 97 insertions(+), 40 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index aae02e68..5ecdeaf0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,8 +13,8 @@ env: CARGO_TERM_COLOR: always jobs: - build: - name: Build + linter: + name: Linter runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -23,52 +23,118 @@ jobs: with: toolchain: stable override: true - - - name: UBX2RNX dependencies - run: | - sudo apt-get update - sudo apt-get install -y libudev-dev - - - uses: actions-rs/cargo@v1 - name: Cargo update - with: - command: update - - uses: actions-rs/cargo@v1 name: Linter with: command: fmt args: --all -- --check - - - uses: actions-rs/cargo@v1 - name: Build (all features) + + build: + name: Build + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + include: + - name: Workspace default + folder: "." + opts: -r + - name: Workspace All-features + folder: "." + opts: --all-features + - name: RINEX Default + folder: rinex + opts: -r + - name: RINEX Observations + folder: rinex + opts: --features "obs" + - name: RINEX Navigation + folder: rinex + opts: --features "nav" + - name: RINEX QC + folder: rinex + opts: --features "qc" + - name: RINEX Meteo + folder: rinex + opts: --features "meteo" + - name: RINEX Clock + folder: rinex + opts: --features "clock" + - name: ANTEX + folder: rinex + opts: --features "antex" + - name: DORIS RINEX + folder: rinex + opts: --features "doris" + - name: RINEX Processing + folder: rinex + opts: --features "processing" + - name: RINEX Full + folder: rinex + opts: --features "full" + - name: RINEX All-features + folder: rinex + opts: --all-features + - name: SP3 default + folder: sp3 + opts: -r + - name: SP3 QC + folder: sp3 + opts: --features "qc" + - name: SP3 Processing + folder: sp3 + opts: --features "processing" + - name: SP3 All-features + folder: sp3 + opts: --all-features + - name: RINEX-QC Default + folder: rinex-qc + opts: -r + - name: RINEX-QC SP3 + folder: rinex-qc + opts: --features "sp3" + - name: RINEX-QC All-features + folder: rinex-qc + opts: --all-features + + steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + name: Install Rust with: - command: build - args: --all-features --release - - - uses: actions-rs/cargo@v1 - name: Test + toolchain: stable + override: true + + - name: ${{ matrix.name }} with: - command: test - args: --verbose - + run: | + cd ${{ matrix.folder }} && cargo clean && cargo build ${{ matrix.opts }} + + test: + name: Tests + runs-on: ubuntu-latest + steps: - uses: actions-rs/cargo@v1 name: Test (all features) with: command: test - args: --verbose --all-features + args: --all-features + documentation: + name: Documentation + runs-on: ubuntu-latest + steps: - uses: actions-rs/toolchain@v1 name: Install nightly with: toolchain: nightly override: true - - name: Documentation run: | ./tools/builddoc.sh windows-build: + name: Windows runs-on: windows-latest steps: - uses: actions/checkout@v3 @@ -78,24 +144,20 @@ jobs: toolchain: stable override: true - - uses: actions-rs/cargo@v1 - name: Cargo update - with: - command: update - - uses: actions-rs/cargo@v1 name: Build (default) with: command: build - args: --release --verbose + args: --release - uses: actions-rs/cargo@v1 name: Build (all features) with: command: build - args: --all-features --release --verbose + args: --all-features --release macos-build: + name: MacOS runs-on: macos-latest steps: - uses: actions/checkout@v3 @@ -105,19 +167,14 @@ jobs: toolchain: stable override: true - - uses: actions-rs/cargo@v1 - name: Cargo update - with: - command: update - - uses: actions-rs/cargo@v1 name: Build (default) with: command: build - args: --release --verbose + args: --release - uses: actions-rs/cargo@v1 name: Build (all features) with: command: build - args: --all-features --release --verbose + args: --all-features --release From af830c853d00286960dea1f24c0a7d0672aeccc8 Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:16:54 +0200 Subject: [PATCH 07/14] Upgrade ci scripts Signed-off-by: Guillaume W. Bres --- .github/workflows/rust.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 5ecdeaf0..02891be5 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -106,7 +106,6 @@ jobs: override: true - name: ${{ matrix.name }} - with: run: | cd ${{ matrix.folder }} && cargo clean && cargo build ${{ matrix.opts }} From 8667101e61e0e6ec7bf9101a808091fb16808eff Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:20:59 +0200 Subject: [PATCH 08/14] Run Linter Signed-off-by: Guillaume W. Bres --- rinex-qc/src/cfg.rs | 6 ++---- rinex-qc/src/report/orbit.rs | 2 +- rinex/src/navigation/ephemeris.rs | 13 ++++++------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/rinex-qc/src/cfg.rs b/rinex-qc/src/cfg.rs index 0f895a92..c631741d 100644 --- a/rinex-qc/src/cfg.rs +++ b/rinex-qc/src/cfg.rs @@ -15,8 +15,7 @@ use std::fmt::Display; use std::str::FromStr; /// [QcReportType] -#[derive(Default, Debug, Clone, PartialEq)] -#[derive(Serialize, Deserialize)] +#[derive(Default, Debug, Clone, PartialEq, Serialize, Deserialize)] pub enum QcReportType { /// In [Summary] mode, only the summary section /// of the report is to be generated. It is the lightest @@ -49,8 +48,7 @@ impl Display for QcReportType { } } -#[derive(Debug, Clone, Default)] -#[derive(Deserialize)] +#[derive(Debug, Clone, Default, Deserialize)] pub struct QcConfig { #[serde(default)] pub report: QcReportType, diff --git a/rinex-qc/src/report/orbit.rs b/rinex-qc/src/report/orbit.rs index 7d006067..0e814a90 100644 --- a/rinex-qc/src/report/orbit.rs +++ b/rinex-qc/src/report/orbit.rs @@ -1,6 +1,6 @@ use rinex::{ navigation::Ephemeris, - prelude::{GroundPosition, Orbit, Rinex, SV, Constellation, Epoch}, + prelude::{Constellation, Epoch, GroundPosition, Orbit, Rinex, SV}, }; use std::collections::{BTreeMap, HashMap}; diff --git a/rinex/src/navigation/ephemeris.rs b/rinex/src/navigation/ephemeris.rs index 77a5e682..5d4cb590 100644 --- a/rinex/src/navigation/ephemeris.rs +++ b/rinex/src/navigation/ephemeris.rs @@ -29,7 +29,6 @@ use crate::epoch::{ #[cfg(feature = "nav")] use nalgebra::{self as na, Matrix3, Rotation, Rotation3, Vector3, Vector4}; - /// Parsing errors #[derive(Debug, Error)] pub enum Error { @@ -808,15 +807,15 @@ impl Ephemeris { self.get_orbit_f64("velY")?, self.get_orbit_f64("velZ")?, ); - Some(((pos_x_km, pos_y_km, pos_z_km), (vel_x_km, vel_y_km, vel_z_km))) + Some(( + (pos_x_km, pos_y_km, pos_z_km), + (vel_x_km, vel_y_km, vel_z_km), + )) } else { let helper = self.ephemeris_helper(sv, t_sv, t)?; let (pos, vel) = helper.position_velocity()?; - Some(( - (pos.x, pos.y, pos.z), - (vel.x, vel.y, vel.z), - )) - } + Some(((pos.x, pos.y, pos.z), (vel.x, vel.y, vel.z))) + } } /// [AzElRange] calculation attempt, for following SV as observed at RX, /// both coordinates expressed as [km] in fixed body [Frame] centered on Earth. From c52ec506532e8234b018715c5d130e9aa88b929c Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:27:08 +0200 Subject: [PATCH 09/14] Add cargo update * this would help in cases where we temporarily point to git servers Signed-off-by: Guillaume W. Bres --- .github/workflows/rust.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 02891be5..209ee503 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -107,7 +107,7 @@ jobs: - name: ${{ matrix.name }} run: | - cd ${{ matrix.folder }} && cargo clean && cargo build ${{ matrix.opts }} + cd ${{ matrix.folder }} && cargo clean && cargo update && cargo build ${{ matrix.opts }} test: name: Tests From 09bb2314da2be0a1235ad347b27926b1b878119b Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:27:33 +0200 Subject: [PATCH 10/14] minor fixes * point to latest RTK * fix cli/qc dependencies Signed-off-by: Guillaume W. Bres --- rinex-cli/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rinex-cli/Cargo.toml b/rinex-cli/Cargo.toml index cba3edfa..7e706ad3 100644 --- a/rinex-cli/Cargo.toml +++ b/rinex-cli/Cargo.toml @@ -44,9 +44,9 @@ hifitime = { version = "4.0.0-alpha", features = ["serde", "std"] } gnss-rs = { version = "2.2.1", features = ["serde"] } -gnss-rtk = { version = "0.6.0", features = ["serde"] } +# gnss-rtk = { version = "0.6.0", features = ["serde"] } # gnss-rtk = { path = "../../rtk-rs/gnss-rtk", features = ["serde"] } -# gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "main", features = ["serde"] } +gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "main", features = ["serde"] } cggtts = { version = "4.1.5", features = ["serde", "scheduler"], optional = true } # cggtts = { path = "../../cggtts/cggtts", features = ["serde", "scheduler"], optional = true } @@ -54,4 +54,4 @@ cggtts = { version = "4.1.5", features = ["serde", "scheduler"], optional = true rinex = { path = "../rinex", version = "=0.16.1", features = ["full"] } sp3 = { path = "../sp3", version = "=1.0.8", features = ["serde", "flate2"] } -rinex-qc = { path = "../rinex-qc", version = "=0.1.14", features = ["serde", "sp3"] } +rinex-qc = { path = "../rinex-qc", version = "=0.1.14", features = ["sp3"] } From bc6e12f40e2135ef49e53f93773cee17ffb19d18 Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:32:33 +0200 Subject: [PATCH 11/14] fix ci scripts Signed-off-by: Guillaume W. Bres --- .github/workflows/rust.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 209ee503..48567ae3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -33,7 +33,7 @@ jobs: name: Build runs-on: ubuntu-latest strategy: - fail-fast: false + fail-fast: true matrix: include: - name: Workspace default @@ -104,6 +104,10 @@ jobs: with: toolchain: stable override: true + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y libudev-dev - name: ${{ matrix.name }} run: | @@ -113,6 +117,12 @@ jobs: name: Tests runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 + - uses: actions-rs/toolchain@v1 + name: Install Rust + with: + toolchain: stable + override: true - uses: actions-rs/cargo@v1 name: Test (all features) with: @@ -123,6 +133,7 @@ jobs: name: Documentation runs-on: ubuntu-latest steps: + - uses: actions/checkout@v3 - uses: actions-rs/toolchain@v1 name: Install nightly with: From a102e96000b39dba4813202532bde6ce7c10265e Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:37:27 +0200 Subject: [PATCH 12/14] Install lib dependencies on Linux Signed-off-by: Guillaume W. Bres --- .github/workflows/rust.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 48567ae3..ef74c226 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -123,6 +123,10 @@ jobs: with: toolchain: stable override: true + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y libudev-dev - uses: actions-rs/cargo@v1 name: Test (all features) with: @@ -139,6 +143,10 @@ jobs: with: toolchain: nightly override: true + - name: Install Dependencies + run: | + sudo apt-get update + sudo apt-get install -y libudev-dev - name: Documentation run: | ./tools/builddoc.sh From ba75a0bab6cfc7001322779789f2063e8d5ed11c Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 11:54:39 +0200 Subject: [PATCH 13/14] Ephemeris.get() has been reworked to match RINEX specs * any null field means missing data Signed-off-by: Guillaume W. Bres --- rinex/src/navigation/ephemeris.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/rinex/src/navigation/ephemeris.rs b/rinex/src/navigation/ephemeris.rs index 5d4cb590..94524e77 100644 --- a/rinex/src/navigation/ephemeris.rs +++ b/rinex/src/navigation/ephemeris.rs @@ -1066,10 +1066,7 @@ mod test { ephemeris.get_orbit_f64("bgdE5aE1"), Some(-1.303851604462e-08) ); - assert_eq!( - ephemeris.get_orbit_f64("bgdE5bE1"), - Some(0.000000000000e+00) - ); + assert!(ephemeris.get_orbit_f64("bgdE5bE1").is_none()); assert_eq!(ephemeris.get_orbit_f64("t_tm"), Some(3.555400000000e+05)); } @@ -1127,7 +1124,7 @@ mod test { ephemeris.get_orbit_f64("svAccuracy"), Some(0.200000000000e+01) ); - assert_eq!(ephemeris.get_orbit_f64("satH1"), Some(0.0)); + assert!(ephemeris.get_orbit_f64("satH1").is_none()); assert_eq!( ephemeris.get_orbit_f64("tgd1b1b3"), Some(-0.599999994133e-09) @@ -1137,8 +1134,8 @@ mod test { Some(-0.900000000000e-08) ); + assert!(ephemeris.get_orbit_f64("aodc").is_none()); assert_eq!(ephemeris.get_orbit_f64("t_tm"), Some(0.432000000000e+06)); - assert_eq!(ephemeris.get_orbit_f64("aodc"), Some(0.0)); } #[test] fn glonass_orbit_v2() { From da0d1c89f8eae6e07dc2611a1f3869ff05050dd4 Mon Sep 17 00:00:00 2001 From: "Guillaume W. Bres" Date: Wed, 7 Aug 2024 12:11:47 +0200 Subject: [PATCH 14/14] fix proposed tutorial Signed-off-by: Guillaume W. Bres --- tutorials/GPS/esbjerg.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tutorials/GPS/esbjerg.sh b/tutorials/GPS/esbjerg.sh index 864b11ca..dfaa699d 100755 --- a/tutorials/GPS/esbjerg.sh +++ b/tutorials/GPS/esbjerg.sh @@ -26,16 +26,15 @@ CONF=tutorials/config/survey/cpp_kf.json --fp $DATA_DIR/CLK/V3/GRG0MGXFIN_20201770000_01D_30S_CLK.CLK.gz \ ppp -c $CONF -exit 0 # cggtts solutions (+open). # Since we're using strict identical options, # the report is preserved and new solutions are appended. # The report is automatically opened. -# ./target/release/rinex-cli \ -# -P $FILTER \ -# -o "GPS-L1L5" \ -# --fp $DATA_DIR/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz \ -# --fp $DATA_DIR/NAV/V3/ESBC00DNK_R_20201770000_01D_MN.rnx.gz \ -# --fp $DATA_DIR/SP3/GRG0MGXFIN_20201770000_01D_15M_ORB.SP3.gz \ -# --fp $DATA_DIR/CLK/V3/GRG0MGXFIN_20201770000_01D_30S_CLK.CLK.gz \ -# ppp --cggtts -c $CONF +./target/release/rinex-cli \ + -P $FILTER \ + -o "GPS-L1L5" \ + --fp $DATA_DIR/CRNX/V3/ESBC00DNK_R_20201770000_01D_30S_MO.crx.gz \ + --fp $DATA_DIR/NAV/V3/ESBC00DNK_R_20201770000_01D_MN.rnx.gz \ + --fp $DATA_DIR/SP3/GRG0MGXFIN_20201770000_01D_15M_ORB.SP3.gz \ + --fp $DATA_DIR/CLK/V3/GRG0MGXFIN_20201770000_01D_30S_CLK.CLK.gz \ + ppp --cggtts -c $CONF