-
Notifications
You must be signed in to change notification settings - Fork 22
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Rinex.navigation() should be available by default * Remove deprecated method. User is expected to use Rinex.snr() iterator. * Remove deprecated comments. User is expected to user the preprocessing toolkit. * improve and fix Merge operation fn merge_mut() was moved into a dedicated trait. Improved and fixed is_merged() * Observation SNR/lli - add possibility to compare SNR to value expressed in dB - add documentation * improving ionex definitions * ionex plotting * improving sbas support * sbas vehicles identification * improving the test infra * rtk opmode * rtk solver now works in mixed GPS, GAL, BDS --------- Signed-off-by: Guillaume W. Bres <[email protected]>
- Loading branch information
Showing
124 changed files
with
6,410 additions
and
4,415 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,106 @@ | ||
GNSS-RTK | ||
======== | ||
|
||
Precise position solver. | ||
[![crates.io](https://img.shields.io/crates/v/gnss-rtk.svg)](https://crates.io/crates/gnss-rtk) | ||
[![rustc](https://img.shields.io/badge/rustc-1.64%2B-blue.svg)](https://img.shields.io/badge/rustc-1.64%2B-blue.svg) | ||
[![crates.io](https://docs.rs/gnss-rtk/badge.svg)](https://docs.rs/gnss-rtk/badge.svg) | ||
|
||
RTK precise position and timing solver, in rust. | ||
|
||
The Solver can work from a RINEX context blob, defined in this crate toolsuite, but is not exclusively tied to RINEX. | ||
|
||
The solver implements precise positioning algorithms, which are based on raw GNSS signals. | ||
|
||
Performances | ||
============ | ||
|
||
I'm able to resolve every single Epoch in a modern 24h data context, in about 1 second, on my 8 core CPU. | ||
|
||
Solving method | ||
============== | ||
|
||
Only a straightforward Matrix based resolution method is implemented. | ||
Other solutions, like Kalman filter, exist and could potentially improve performances | ||
at the expense of more complexity and possibly | ||
|
||
The matrix resolution technique gives the best result for every single epoch | ||
|
||
- there are no initialization iterations | ||
- there is no iteration or recursive behavior | ||
|
||
Behavior and Output | ||
=================== | ||
|
||
The solver will try to resolve a position for every single existing Epoch. | ||
|
||
When working with RINEX, preprocessing operations may apply. | ||
If you're working with the attached "cli" application, this is done with `-P`. | ||
For example, if the input context is huge, a smoothing or decimation | ||
|
||
The solver will output a SolverEstimate object on each resolved Epoch. | ||
Refer to this structure's documentation for more information. | ||
|
||
Timing DOP and Position DOP are estimated and attached to every single result. | ||
|
||
SPP | ||
=== | ||
|
||
The solver supports the spp strategy. This strategy is the only strategy we can deploy | ||
on single carrier context. It is most likely the unique strategy you can deploy if you're working | ||
with old RINEX (like GPS only V2), or single frequency RINEX data. | ||
|
||
When using SPP : | ||
|
||
- you can only hope for residual errors of a few meters | ||
- an interpolation order above 9 makes no sense | ||
- Ionospheric delay must be considered and modeled. Refer to the related section. | ||
|
||
If you're operating this library from the "cli" application integrated to this toolsuite, | ||
a forced `--spp` mode exists. It is a convenient way to restrict this library to SPP solving | ||
and compare it to PPP. | ||
|
||
PPP | ||
=== | ||
|
||
The solver will adapt to PPP strategy if the context is sufficient (more than one carrier). | ||
PPP simplifies the solving process greatly, ionospheric delay is cancelled and does not have to be taken into account. | ||
|
||
PPP is deployed if you're typically working with modern RINEX data. | ||
|
||
We allow the possibility to deploy a PPP strategy without SP3 data. This is not a typical use case. | ||
Other tools like glab or rtklib probably do not allow this. | ||
You need to understand that in this case, you want good navigation data quality in order to reduce | ||
the error their interpolation will introduce. | ||
|
||
When working with PPP, we recommend the interpolation order to be set to 11 (or above). | ||
|
||
Ionospheric Delay | ||
================= | ||
|
||
TODO | ||
|
||
SP3 and Broadcast Ephemeris | ||
=========================== | ||
|
||
The solver will always prefer SP3 over Broadcast ephemeris. | ||
That stands whatever the solving method and strategy might be. | ||
|
||
RTK from RINEX | ||
============== | ||
|
||
The solver can be initialized from a RINEX context, defined as `QcContext` in the RINEX library suite. | ||
This structure is adaptable and quite efficient. For example it allows the combination of both | ||
SP3 and Broadcast Ephemeris. | ||
|
||
When initialized from RINEX, we can determine whether PPP is feasible or not | ||
|
||
RTK Configuration | ||
================= | ||
|
||
The RTKConfiguration structure, describes all configuration and customization | ||
the solver supports. | ||
|
||
It is important to understand how, when and what to customize depending on your goals. | ||
|
||
When working with the "cli" application, you can provide an RTKConfiguration | ||
in the form of JSON, with `--rtk-cfg`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
use crate::model::Modeling; | ||
use crate::SolverType; | ||
use hifitime::prelude::TimeScale; | ||
|
||
use std::str::FromStr; | ||
|
||
#[cfg(feature = "serde")] | ||
use serde::Deserialize; | ||
|
||
use rinex::prelude::GroundPosition; | ||
|
||
use rinex::observation::Snr; | ||
|
||
fn default_timescale() -> TimeScale { | ||
TimeScale::GPST | ||
} | ||
|
||
fn default_interp() -> usize { | ||
7 | ||
} | ||
|
||
fn default_max_sv() -> usize { | ||
10 | ||
} | ||
|
||
fn default_smoothing() -> bool { | ||
false | ||
} | ||
|
||
fn default_iono() -> bool { | ||
false | ||
} | ||
|
||
fn default_tropo() -> bool { | ||
false | ||
} | ||
|
||
#[derive(Default, Debug, Clone, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Deserialize))] | ||
pub struct RTKConfig { | ||
/// Time scale | ||
#[cfg_attr(feature = "serde", serde(default = "default_timescale"))] | ||
pub timescale: TimeScale, | ||
/// positioning mode | ||
#[cfg_attr(feature = "serde", serde(default))] | ||
pub mode: SolverMode, | ||
/// (Position) interpolation filter order. | ||
/// A minimal order must be respected for correct results. | ||
/// - 7 when working with broadcast ephemeris | ||
/// - 11 when working with SP3 | ||
#[cfg_attr(feature = "serde", serde(default = "default_interp"))] | ||
pub interp_order: usize, | ||
/// Whether the solver is working in fixed altitude mode or not | ||
#[cfg_attr(feature = "serde", serde(default))] | ||
pub fixed_altitude: Option<f64>, | ||
/// Position receveir position, if known before hand | ||
pub rcvr_position: Option<GroundPosition>, | ||
/// PR code smoothing filter before moving forward | ||
#[cfg_attr(feature = "serde", serde(default = "default_smoothing"))] | ||
pub code_smoothing: bool, | ||
/// true if we're using troposphere modeling | ||
#[cfg_attr(feature = "serde", serde(default = "default_tropo"))] | ||
pub tropo: bool, | ||
/// true if we're using ionosphere modeling | ||
#[cfg_attr(feature = "serde", serde(default = "default_iono"))] | ||
pub iono: bool, | ||
/// Minimal percentage ]0; 1[ of Sun light to be received by an SV | ||
/// for not to be considered in Eclipse. | ||
/// A value closer to 0 means we tolerate fast Eclipse exit. | ||
/// A value closer to 1 is a stringent criteria: eclipse must be totally exited. | ||
#[cfg_attr(feature = "serde", serde(default))] | ||
pub min_sv_sunlight_rate: Option<f64>, | ||
/// Minimal elevation angle. SV below that angle will not be considered. | ||
pub min_sv_elev: Option<f64>, | ||
/// Minimal SNR for an SV to be considered. | ||
pub min_sv_snr: Option<Snr>, | ||
/// modeling | ||
#[cfg_attr(feature = "serde", serde(default))] | ||
pub modeling: Modeling, | ||
/// Max. number of vehicules to consider. | ||
/// The more the merrier, but it also means heavier computations | ||
#[cfg_attr(feature = "serde", serde(default = "default_max_sv"))] | ||
pub max_sv: usize, | ||
} | ||
|
||
impl RTKConfig { | ||
pub fn default(solver: SolverType) -> Self { | ||
match solver { | ||
SolverType::SPP => Self { | ||
timescale: default_timescale(), | ||
mode: SolverMode::default(), | ||
fixed_altitude: None, | ||
rcvr_position: None, | ||
interp_order: default_interp(), | ||
code_smoothing: default_smoothing(), | ||
tropo: default_tropo(), | ||
iono: default_iono(), | ||
min_sv_sunlight_rate: None, | ||
min_sv_elev: Some(10.0), | ||
min_sv_snr: Some(Snr::from_str("weak").unwrap()), | ||
modeling: Modeling::default(), | ||
max_sv: default_max_sv(), | ||
}, | ||
SolverType::PPP => Self { | ||
timescale: default_timescale(), | ||
mode: SolverMode::default(), | ||
fixed_altitude: None, | ||
rcvr_position: None, | ||
interp_order: 11, | ||
code_smoothing: default_smoothing(), | ||
tropo: default_tropo(), | ||
iono: default_iono(), | ||
min_sv_sunlight_rate: Some(0.75), | ||
min_sv_elev: Some(25.0), | ||
min_sv_snr: Some(Snr::from_str("strong").unwrap()), | ||
modeling: Modeling::default(), | ||
max_sv: default_max_sv(), | ||
}, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Default, Debug, Clone, Copy, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Deserialize))] | ||
pub enum SolverMode { | ||
/// Receiver is kept at fixed location | ||
#[default] | ||
Static, | ||
/// Receiver is not static | ||
Kinematic, | ||
} |
Oops, something went wrong.