Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #194

Merged
merged 52 commits into from
Dec 26, 2023
Merged
Show file tree
Hide file tree
Changes from 50 commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
0d8dcea
corrected dop calculations
gwbres Dec 3, 2023
2ab2867
plot brdc clock corrections
gwbres Dec 3, 2023
de71f0b
take sp3 into account in clock state too
gwbres Dec 3, 2023
f5f5bfd
apc correction
gwbres Dec 3, 2023
7212f0c
bump rtk to v0.4.0
gwbres Dec 3, 2023
a5acfd1
run linter
gwbres Dec 3, 2023
ce5dcab
bump cggtts to v4.1.0
gwbres Dec 4, 2023
990da89
Merge branch 'main' into develop
gwbres Dec 4, 2023
1fb0d0c
antex: defining support of ATX files
gwbres Dec 4, 2023
e685147
Merge branch 'main' into develop
gwbres Dec 5, 2023
fa08e18
Merge branch 'main' into atx-dev
gwbres Dec 5, 2023
bd0efa2
Merge branch 'develop' into atx-dev
gwbres Dec 6, 2023
6d4ba0c
improving atx support
gwbres Dec 6, 2023
b471166
reworking atx records
gwbres Dec 7, 2023
d403005
reworking atx records
gwbres Dec 7, 2023
f93d3e4
redefining atx types
gwbres Dec 7, 2023
60d3c11
redefining atx types
gwbres Dec 8, 2023
4ef3b1f
use mjd as x axis labels, and improve x axis display
gwbres Dec 8, 2023
a8bb80a
ignore patch files
gwbres Dec 9, 2023
619b837
improved rtk and positioning definitions
gwbres Dec 10, 2023
9a2f17a
Merge branch 'atx-dev' into develop
gwbres Dec 10, 2023
87d5be5
improving atx record support
gwbres Dec 10, 2023
45c9f47
improving atx record support
gwbres Dec 10, 2023
6edb766
high level atx methods
gwbres Dec 10, 2023
746ddc6
improved interpolation api
gwbres Dec 10, 2023
b5e67ec
working on apc coordinates
gwbres Dec 11, 2023
4d9391d
remove rinex from crate dependencies
gwbres Dec 12, 2023
1900af2
calibration validity parsing
gwbres Dec 12, 2023
d5c497b
test new features
gwbres Dec 12, 2023
5e6bd17
prepare rinex 0.15.2
gwbres Dec 16, 2023
bd4ecaf
clippy; prepare new release
gwbres Dec 16, 2023
190cf09
clippy; prepare new release
gwbres Dec 16, 2023
a3a1588
update readme
gwbres Dec 17, 2023
66d07c8
update readme
gwbres Dec 17, 2023
c8179b3
update readme
gwbres Dec 17, 2023
47768a5
Introduce Channel Number Pseudo Observable
gwbres Dec 17, 2023
7f1a0b6
run linter
gwbres Dec 17, 2023
a3fe71a
RINEX3: IONOSPHERIC CORR header support
gwbres Dec 17, 2023
a83a3e0
advance in iono corr visualization
gwbres Dec 17, 2023
83ec706
iono corr visualization solution
gwbres Dec 17, 2023
4dd2efa
post processing -p: fix default configuration to be used
gwbres Dec 17, 2023
fb939ce
post processing -p: possible ionod correction (RINEX3) case
gwbres Dec 17, 2023
751bdba
simplify code combinations
gwbres Dec 18, 2023
fb7fab2
update documentation
gwbres Dec 26, 2023
02d3c03
atx feature and related ci tests
gwbres Dec 26, 2023
1cbe96f
prepare release
gwbres Dec 26, 2023
84c7c83
update todo
gwbres Dec 26, 2023
39c506c
new release
gwbres Dec 26, 2023
0c0e202
add new test resource
gwbres Dec 26, 2023
d28ac7a
remove non needed file
gwbres Dec 26, 2023
bb6b1b2
antex record: re-enable record merging, introduce dedicated test
gwbres Dec 26, 2023
709db17
fix warning, fix missing include
gwbres Dec 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Cargo.lock
*.html
*.swp
*.swo
*.patch
**/*.rs.bk
.DS_Store

Expand Down
67 changes: 36 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,45 +11,50 @@ RINEX

Rust tool suites to parse, analyze and process [RINEX Data](https://en.wikipedia.org/wiki/RINEX).

Our Wiki contains [several tutorials and applications](https://github.com/georust/rinex/wiki): it will get you started quickly.
The [Wiki pages](https://github.com/georust/rinex/wiki) contain all the documentation of this project, including several examples spanning different applications of GNSS.

For any question or problems you may experience:

- open a new issue
- drop us a message [on Discord](https://discord.gg/Fp2aape)
If you have any question or experience any problems, feel free to open an issue on Github.
You can also contact us [on our Discord channel](https://discord.gg/Fp2aape)

## Advantages :rocket:

- Fast
- Fast :crab:
- Open sources
- Native Hatanaka decompression and compression
- Seamless .gzip decompression with `flate2` compilation feature
- RINEX V4 full support, that includes modern Navigation messages
- Seamless Hatanaka compression and decompression
- Seamless Gzip decompression with `flate2` build option
- RINEX V4 full support
- Meteo RINEX full support
- IONEX (2D) support, partial 3D support
- IONEX 2D support. Partial IONEX 3D support.
- Clock RINEX partial support: to be concluded soon
- File merging, splitting and pre processing
- Modern constellations like BeiDou, Galileo and IRNSS
- Supported time scales are GPST, BDT, GST, UTC
- Several pre processing operations:
- File merging
- Time beaning
- Filtering..
- Several post processing operations
- All modern GNSS constellations
- Modern GNSS codes and signals
- Time scales: GPST, BDT, GST, UTC
- Supports many SBAS, refer to online documentation
- Full support of Military codes : if you're working with such signals you can
at least run a -qc analysis, and possibly the position solver once it is merged
- Supports high precision RINEX (scaled phase data with micro cycle precision)
- RINEX post processing like SNR, DCB analysis, Broadcast ephemeris interpolation,
high precision orbit interpolation (SP3)..
- RINEX-qc: statistical analysis that you can request in the "cli" application directly.
Analysis can run on modern GNSS signals and SP3 high precision data.
Emulates "teqc" historical application.
- An SPP/PPP position solver (under development), in the form of the "gnss-rtk" library that you can
summon from the "cli" application directly.

## Known weaknesses :warning:

- QZNSST is represented as GPST at the moment
- GLONASST and IRNSST are not supported : calculations (mostly orbits) will not be accurate
- The command line tool does not accept BINEX or other proprietary formats
- File production is not fully concluded to this day, some formats are still not correctly supported
(mostly NAV).
- High precision RINEX (carrier phase micro cycle precision)
- High precision orbit support (SP3)
- Quality Check (QC): file quality and statistical analysis to help precise positioning
(historical `teqc` function).
- SPP: Single Point Positioning
- PPP: Precise Point Positioning is work in progress :warning:

## Disadvantages :warning:

- QZNSST is represented as GPST at the moment.
- We're waiting for Hifitime V4 to support GLONASST and IRNSST.
Until then, orbital calculations on these systems are not feasible.
In other term, positioning is not feasible and you're limited to basic analysis.
- These tools are oriented towards the latest revisions of the RINEX format.
RINEX4 is out and we already support it.
Some minor features in the RINEX2 or 3 revisions may not be supported.
- Our command line applications do not accept BINEX or other proprietary formats
- File production is not fully concluded to this day. We're currently focused
on RINEX post processing rather than RINEX data production. Do not hesitate to fork and submit
your improvements

## Architecture

Expand Down
4 changes: 2 additions & 2 deletions crx2rnx/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "crx2rnx"
version = "2.2.0"
version = "2.2.1"
license = "MIT OR Apache-2.0"
authors = ["Guillaume W. Bres <[email protected]>"]
description = "RINEX data decompressor"
Expand All @@ -12,4 +12,4 @@ readme = "README.md"

[dependencies]
clap = { version = "4.4.10", features = ["derive", "color"] }
rinex = { path = "../rinex", version = "=0.15.1", features = ["serde"] }
rinex = { path = "../rinex", version = "=0.15.2", features = ["serde"] }
16 changes: 7 additions & 9 deletions crx2rnx/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ fn workspace(cli: &Cli) -> PathBuf {
}

fn create_workspace(path: &PathBuf) {
std::fs::create_dir_all(&path).unwrap_or_else(|_| {
std::fs::create_dir_all(path).unwrap_or_else(|_| {
panic!(
"failed to create workspace \"{}\": permission denied",
path.to_string_lossy(),
Expand All @@ -39,7 +39,7 @@ fn input_name(path: &PathBuf) -> String {
}

// deduce output name, from input name
fn output_filename<'a>(stem: &'a str, path: &PathBuf) -> String {
fn output_filename(stem: &str, path: &PathBuf) -> String {
let filename = path
.file_name()
.expect("failed to determine input file name")
Expand All @@ -52,14 +52,12 @@ fn output_filename<'a>(stem: &'a str, path: &PathBuf) -> String {
.expect("failed to determine output file name")
.replace("crx", "rnx")
.to_string()
} else if filename.ends_with('d') {
filename.replace('d', "o").to_string()
} else if filename.ends_with('D') {
filename.replace('D', "O").to_string()
} else {
if filename.ends_with('d') {
filename.replace('d', "o").to_string()
} else if filename.ends_with('D') {
filename.replace('D', "O").to_string()
} else {
format!("{}.rnx", stem)
}
format!("{}.rnx", stem)
}
}

Expand Down
6 changes: 3 additions & 3 deletions rinex-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ horrorshow = "0.8"
clap = { version = "4.4.10", features = ["derive", "color"] }
hifitime = { version = "3.8.4", features = ["serde", "std"] }
gnss-rs = { version = "2.1.2" , features = ["serde"] }
rinex = { path = "../rinex", version = "=0.15.1", features = ["full"] }
rinex-qc = { path = "../rinex-qc", version = "=0.1.6", features = ["serde"] }
rinex = { path = "../rinex", version = "=0.15.2", features = ["full"] }
rinex-qc = { path = "../rinex-qc", version = "=0.1.7", features = ["serde"] }
sp3 = { path = "../sp3", version = "=1.0.6", features = ["serde", "flate2"] }
serde = { version = "1.0", default-features = false, features = ["derive"] }

Expand All @@ -41,6 +41,6 @@ plotly = "0.8.4"
# plotly = { git = "https://github.com/gwbres/plotly", branch = "density-mapbox" }

# solver
gnss-rtk = { version = "0.4.0", features = ["serde"] }
gnss-rtk = { version = "0.4.1", features = ["serde"] }
# gnss-rtk = { git = "https://github.com/rtk-rs/gnss-rtk", branch = "develop", features = ["serde"] }
# gnss-rtk = { path = "../../rtk-rs/gnss-rtk", features = ["serde"] }
3 changes: 3 additions & 0 deletions rinex-cli/config/rtk/gpst_10sv_basic.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
"max_sv": 10,
"min_sv_elev": 20.0,
"min_snr": 20.0,
"solver": {
"gdop_threshold": 3.0
},
"modeling": {
"sv_clock_bias": true,
"sv_total_group_delay": true,
Expand Down
2 changes: 1 addition & 1 deletion rinex-cli/src/analysis/sampling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use rinex::prelude::RnxContext;
* Sampling histogram
*/
pub fn histogram(ctx: &RnxContext, plot_ctx: &mut PlotContext) {
plot_ctx.add_cartesian2d_plot("Sampling Histogram", "Count");
plot_ctx.add_timedomain_plot("Sampling Histogram", "Count");
if let Some(data) = ctx.obs_data() {
let histogram = data.sampling_histogram().sorted();
let durations: Vec<_> = histogram.clone().map(|(dt, _)| dt.to_string()).collect();
Expand Down
57 changes: 11 additions & 46 deletions rinex-cli/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,19 @@ use std::str::FromStr;
use rinex::prelude::*;
use rinex_qc::QcOpts;

use gnss_rtk::prelude::{Config, Mode as SolverMode};
use gnss_rtk::prelude::Config;

pub struct Cli {
/// Arguments passed by user
matches: ArgMatches,
}

impl Default for Cli {
fn default() -> Self {
Self::new()
}
}

impl Cli {
/// Build new command line interface
pub fn new() -> Self {
Expand Down Expand Up @@ -238,36 +244,12 @@ The summary report by default is integrated to the global HTML report."))
.action(ArgAction::SetTrue)
.help("Activates QC mode and disables all other features: quickest qc rendition."))
.next_help_heading("Positioning")
.arg(Arg::new("spp")
.long("spp")
.conflicts_with("ppp")
.conflicts_with("lsqspp")
.action(ArgAction::SetTrue)
.help("Enable Single Point Positioning.
Use with ${RUST_LOG} env logger for more information.
Refer to the positioning documentation."))
.arg(Arg::new("lsqspp")
.long("lsqspp")
.conflicts_with("ppp")
.conflicts_with("spp")
.action(ArgAction::SetTrue)
.help("Recursive Weighted Least Square SPP strategy.
Use with ${RUST_LOG} env logger for more information.
Refer to the positioning documentation."))
.arg(Arg::new("ppp")
.long("ppp")
.conflicts_with("spp")
.conflicts_with("lsqspp")
.arg(Arg::new("positioning")
.short('p')
.action(ArgAction::SetTrue)
.help("Enable Precise Point Positioning.
.help("Activate positioning mode. Disables all other modes.
Use with ${RUST_LOG} env logger for more information.
Refer to the positioning documentation."))
.arg(Arg::new("pos-only")
.long("pos-only")
.short('p')
.action(ArgAction::SetTrue)
.help("Disable context analysis and run position solver only.
This is the most performant mode to solve a position."))
.arg(Arg::new("config")
.long("cfg")
.short('c')
Expand Down Expand Up @@ -453,25 +435,8 @@ Primary RINEX was either loaded with `-f`, or is Observation RINEX loaded with `
pub fn quiet(&self) -> bool {
self.matches.get_flag("quiet")
}
/* returns RTK solver mode to implement */
pub fn solver_mode(&self) -> Option<SolverMode> {
if self.matches.get_flag("spp") {
Some(SolverMode::SPP)
} else if self.matches.get_flag("lsqspp") {
Some(SolverMode::LSQSPP)
} else if self.matches.get_flag("ppp") {
Some(SolverMode::PPP)
} else {
None
}
}
pub fn positioning(&self) -> bool {
self.matches.get_flag("spp")
|| self.matches.get_flag("lsqspp")
|| self.matches.get_flag("ppp")
}
pub fn positioning_only(&self) -> bool {
self.matches.get_flag("pos-only")
self.matches.get_flag("positioning")
}
pub fn gpx(&self) -> bool {
self.matches.get_flag("gpx")
Expand Down
2 changes: 1 addition & 1 deletion rinex-cli/src/identification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ struct SSIReport {

fn report_sampling_histogram(data: &Vec<(Duration, usize)>) {
let data: HashMap<String, usize> = data
.into_iter()
.iter()
.map(|(dt, pop)| (dt.to_string(), *pop))
.collect();
println!("{:#?}", data);
Expand Down
23 changes: 8 additions & 15 deletions rinex-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ pub(crate) fn context_stem(ctx: &RnxContext) -> String {
*/
pub fn workspace_path(ctx: &RnxContext, cli: &Cli) -> PathBuf {
match cli.workspace() {
Some(w) => Path::new(w).join(&context_stem(ctx)),
Some(w) => Path::new(w).join(context_stem(ctx)),
None => Path::new(env!("CARGO_MANIFEST_DIR"))
.join("..")
.join("WORKSPACE")
.join(&context_stem(ctx)),
.join(context_stem(ctx)),
}
}

Expand Down Expand Up @@ -133,7 +133,7 @@ fn build_context(cli: &Cli) -> RnxContext {
* Returns true if Skyplot view if feasible and allowed
*/
fn skyplot_allowed(ctx: &RnxContext, cli: &Cli) -> bool {
if cli.quality_check_only() || cli.positioning_only() {
if cli.quality_check_only() || cli.positioning() {
/*
* Special modes: no plots allowed
*/
Expand Down Expand Up @@ -240,12 +240,7 @@ pub fn main() -> Result<(), Error> {
let qc_only = cli.quality_check_only();
let qc = cli.quality_check() || qc_only;

let positioning_only = cli.positioning_only();
let positioning = cli.positioning() || positioning_only;

if !positioning {
warn!("position solver currently turned off");
}
let positioning = cli.positioning();

// Initiate plot context
let mut plot_ctx = PlotContext::new();
Expand Down Expand Up @@ -337,7 +332,7 @@ pub fn main() -> Result<(), Error> {
None => String::from("merged.rnx"),
};

let path = workspace.clone().join(&filename);
let path = workspace.clone().join(filename);

let path = path
.as_path()
Expand Down Expand Up @@ -406,10 +401,8 @@ pub fn main() -> Result<(), Error> {
let ground_pos = ctx.ground_position().unwrap(); // infaillible
plot::skyplot(nav, ground_pos, &mut plot_ctx);
info!("skyplot view generated");
} else {
if !no_graph {
info!("skyplot view is not feasible");
}
} else if !no_graph {
info!("skyplot view is not feasible");
}
}
/*
Expand All @@ -431,7 +424,7 @@ pub fn main() -> Result<(), Error> {
* Record analysis / visualization
* analysis depends on the provided record type
*/
if !qc_only && !positioning_only && !no_graph {
if !qc_only && !positioning && !no_graph {
info!("entering record analysis");
plot::plot_record(&ctx, &mut plot_ctx);

Expand Down
4 changes: 2 additions & 2 deletions rinex-cli/src/plot/combination.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub fn plot_gnss_combination(
y_title: &str,
) {
// add a plot
plot_context.add_cartesian2d_plot(plot_title, y_title);
plot_context.add_timedomain_plot(plot_title, y_title);

// generate 1 marker per OP
let markers = generate_markers(data.len());
Expand Down Expand Up @@ -49,7 +49,7 @@ pub fn plot_gnss_dcb_mp(
y_title: &str,
) {
// add a plot
plot_context.add_cartesian2d_plot(plot_title, y_title);
plot_context.add_timedomain_plot(plot_title, y_title);
// generate 1 marker per OP
let markers = generate_markers(data.len());
// plot all ops
Expand Down
16 changes: 8 additions & 8 deletions rinex-cli/src/plot/context.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::{
build_default_2y_plot, build_default_3d_plot, build_default_plot, build_default_polar_plot,
build_world_map, Plot,
build_default_3d_plot, build_default_polar_plot, build_timedomain_2y_plot,
build_timedomain_plot, build_world_map, Plot,
};
//use log::trace;
use plotly::{layout::MapboxStyle, Trace};
Expand All @@ -21,8 +21,12 @@ impl PlotContext {
let len = self.plots.len() - 1;
self.plots.get_mut(len)
}*/
pub fn add_cartesian2d_plot(&mut self, title: &str, y_label: &str) {
self.plots.push(build_default_plot(title, y_label));
pub fn add_timedomain_plot(&mut self, title: &str, y_label: &str) {
self.plots.push(build_timedomain_plot(title, y_label));
}
pub fn add_timedomain_2y_plot(&mut self, title: &str, y1_label: &str, y2_label: &str) {
self.plots
.push(build_timedomain_2y_plot(title, y1_label, y2_label));
}
pub fn add_cartesian3d_plot(
&mut self,
Expand All @@ -34,10 +38,6 @@ impl PlotContext {
self.plots
.push(build_default_3d_plot(title, x_label, y_label, z_label));
}
pub fn add_cartesian2d_2y_plot(&mut self, title: &str, y1_label: &str, y2_label: &str) {
self.plots
.push(build_default_2y_plot(title, y1_label, y2_label));
}
pub fn add_polar2d_plot(&mut self, title: &str) {
self.plots.push(build_default_polar_plot(title));
}
Expand Down
Loading
Loading