Skip to content

Commit d618a48

Browse files
authored
Develop (#30)
* Improving Tropo and Iono interfaces --------- Signed-off-by: Guillaume W. Bres <guillaume.bressaix@gmail.com>
1 parent 79e37e3 commit d618a48

File tree

17 files changed

+515
-449
lines changed

17 files changed

+515
-449
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ Cargo.lock
1616
*.swp
1717
*.swo
1818
*.patch
19+
*.rs~

examples/spp/main.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
// This is simply here to demonstrate how to operate the API, and does not generate actual results.
33
use gnss_rtk::prelude::{
44
BaseStation as RTKBaseStation, Candidate, Carrier, ClockCorrection, Config, Duration, Epoch,
5-
Error, InvalidationCause, IonosphereBias, Method, Observation, OrbitalState,
6-
OrbitalStateProvider, Solver, TroposphereBias, SV,
5+
Error, InvalidationCause, IonoComponents, Method, Observation, OrbitalState,
6+
OrbitalStateProvider, Solver, TropoComponents, SV,
77
};
88

99
// Orbit source example
@@ -73,6 +73,10 @@ impl MyDataSource {
7373
doppler: None,
7474
ambiguity: None,
7575
}],
76+
// Provide more information if you can
77+
IonoComponents::Unknown,
78+
// Provide more information if you can
79+
TropoComponents::Unknown,
7680
),
7781
// Create all as many candidates as possible.
7882
// It's better to have more than needed, it leaves us more possibility in the election process.
@@ -112,14 +116,7 @@ pub fn main() {
112116

113117
// Browse your data source (This is an Example)
114118
while let Some((epoch, candidates)) = source.next() {
115-
// External bias sources are not very well supported yet.
116-
// We recommend you use the internal modeling.
117-
// This is done by specifying you simply have no knowledge
118-
// of the external biases:
119-
let ionod = IonosphereBias::default(); // Unknown
120-
let tropod = TroposphereBias::default(); // Unknown
121-
122-
match solver.resolve(epoch, &candidates, &ionod, &tropod) {
119+
match solver.resolve(epoch, &candidates) {
123120
Ok((_epoch, solution)) => {
124121
// A solution was successfully resolved for this Epoch.
125122
// The position is expressed as absolute ECEF [m].

src/bias/iono.rs

Lines changed: 77 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
1-
use crate::bias::RuntimeParam;
2-
use crate::prelude::TimeScale;
3-
use map_3d::deg2rad;
1+
use crate::{bias::RuntimeParams, prelude::TimeScale};
42
use std::f64::consts::PI;
53

6-
/// Ionospheric Components to attach
7-
/// any resolution attempt. Fill as much as you can.
8-
/// If this structure is empty, you should then provide observations
9-
/// on at least two carrier signals so the solver can estimate this bias.
10-
#[derive(Default)]
11-
pub struct IonosphereBias {
12-
/// Klobuchar Model to apply
13-
pub kb_model: Option<KbModel>,
14-
/// Nequick-G model to apply
15-
pub ng_model: Option<NgModel>,
16-
/// BDGIM model to apply
17-
pub bd_model: Option<BdModel>,
18-
/// Slan Total Electron Density estimate
19-
pub stec_meas: Option<f64>,
4+
#[cfg(feature = "serde")]
5+
use serde::{Deserialize, Serialize};
6+
7+
/// Ionopheric delay components to attach to any attempt.
8+
#[derive(Default, Clone, Copy)]
9+
pub enum IonoComponents {
10+
/// Unknown
11+
#[default]
12+
Unknown,
13+
/// Provide a [KbModel]
14+
KbModel(KbModel),
15+
/// Provide a [NgModel]
16+
NgModel(NgModel),
17+
/// Provide a [BdModel]
18+
BdModel(BdModel),
19+
/// Provide Slant Total Electron Density [TECu]
20+
Stec(f64),
2021
}
2122

2223
/// Klobuchar Model
@@ -31,30 +32,29 @@ pub struct KbModel {
3132
}
3233

3334
impl KbModel {
34-
pub(crate) fn bias(&self, rtm: &RuntimeParam) -> Option<f64> {
35+
pub(crate) fn value(&self, rtm: &RuntimeParams) -> f64 {
3536
const PHI_P: f64 = 78.3;
3637
const R_EARTH: f64 = 6378.0;
3738
const LAMBDA_P: f64 = 291.0;
3839
const L1_F: f64 = 1575.42E6;
3940

40-
let (lat_ddeg, lon_ddeg, _) = rtm.apriori_geo;
41-
41+
let (phi_u, lambda_u) = rtm.apriori_rad;
4242
let fract = R_EARTH / (R_EARTH + self.h_km);
43-
let (elev, azim) = (deg2rad(rtm.elevation), deg2rad(rtm.azimuth));
44-
let (phi_u, lambda_u) = (deg2rad(lat_ddeg), deg2rad(lon_ddeg));
43+
let (elev_rad, azim_rad) = (rtm.elevation_rad, rtm.azimuth_rad);
4544

46-
let t_gps = rtm
45+
let t_gpst = rtm
4746
.t
4847
.to_duration_in_time_scale(TimeScale::GPST)
4948
.to_seconds();
50-
let psi = PI / 2.0 - elev - (fract * elev.cos()).asin();
51-
let phi_i = (phi_u.sin() * psi.cos() + phi_u.cos() * psi.sin() * azim.cos()).asin();
52-
let lambda_i = lambda_u + azim.sin() * psi / phi_i.cos();
49+
50+
let psi = PI / 2.0 - elev_rad - (fract * elev_rad.cos()).asin();
51+
let phi_i = (phi_u.sin() * psi.cos() + phi_u.cos() * psi.sin() * azim_rad.cos()).asin();
52+
let lambda_i = lambda_u + azim_rad.sin() * psi / phi_i.cos();
5353
let phi_m = (phi_i.sin() * PHI_P.sin()
5454
+ phi_i.cos() * PHI_P.cos() * (lambda_i - LAMBDA_P).cos())
5555
.asin();
5656

57-
let mut t_s = 43.2E3 * lambda_i / PI + t_gps;
57+
let mut t_s = 43.2E3 * lambda_i / PI + t_gpst;
5858
if t_s > 86.4E3 {
5959
t_s -= 86.4E3;
6060
} else if t_s < 0.0 {
@@ -78,60 +78,89 @@ impl KbModel {
7878
}
7979

8080
let x_i = 2.0 * PI * (t_s - 50400.0) / p_i;
81-
let f = 1.0 / ((1.0 - fract * elev.cos()).powi(2)).sqrt();
81+
let f = 1.0 / ((1.0 - fract * elev_rad.cos()).powi(2)).sqrt();
8282
let i_1 = match x_i < PI / 2.0 {
8383
true => 5.0 * 10E-9 + a_i * x_i.cos(),
8484
false => f * 5.0 * 10E-9,
8585
};
8686

87-
Some(i_1 * (L1_F / rtm.frequency).powi(2))
87+
i_1 * (L1_F / rtm.frequency).powi(2)
8888
}
8989
}
9090

91-
/// Nequick-G Model
91+
/// Nequick-G Model: is not supported yet.
9292
#[derive(Clone, Copy, Default, Debug)]
9393
pub struct NgModel {
9494
/// alpha coefficients
9595
pub a: (f64, f64, f64),
9696
}
9797

9898
impl NgModel {
99-
pub(crate) fn bias(&self, _rtm: &RuntimeParam) -> Option<f64> {
99+
pub(crate) fn value(&self, _rtm: &RuntimeParams) -> f64 {
100100
//let phi = deg2rad(rtm.apriori_geo.0);
101101
//let mu = inclination / phi.cos().sqrt();
102-
None //TODO
102+
0.0
103103
}
104104
}
105105

106-
/// BDGIM Model
106+
/// BDGIM Model: is not supported yet.
107107
#[derive(Clone, Copy, Default, Debug)]
108108
pub struct BdModel {
109109
/// Alpha coefficients in TECu
110110
pub alpha: (f64, f64, f64, f64, f64, f64, f64, f64, f64),
111111
}
112112

113113
impl BdModel {
114-
pub(crate) fn bias(&self, _rtm: &RuntimeParam) -> Option<f64> {
114+
pub(crate) fn value(&self, _rtm: &RuntimeParams) -> f64 {
115115
//let phi = deg2rad(rtm.apriori_geo.0);
116116
//let mu = inclination / phi.cos().sqrt();
117-
None //TODO
117+
0.0
118+
}
119+
}
120+
121+
impl IonoComponents {
122+
pub(crate) fn value(&self, rtm: &RuntimeParams) -> f64 {
123+
match self {
124+
Self::Unknown => 0.0,
125+
Self::KbModel(model) => model.value(rtm),
126+
Self::NgModel(model) => model.value(rtm),
127+
Self::BdModel(model) => model.value(rtm),
128+
Self::Stec(stec) => 0.0, //TODO
129+
}
130+
}
131+
}
132+
133+
/// Modeled (estimated) or measured bias
134+
#[derive(Debug, Copy, Clone)]
135+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
136+
pub enum IonosphereBias {
137+
/// Measured bias in [m]
138+
Measured(f64),
139+
/// Modelled bias in [m]
140+
Modeled(f64),
141+
}
142+
143+
impl Default for IonosphereBias {
144+
/// Builds a Default "Modeled" Bias with 0 value
145+
fn default() -> Self {
146+
Self::Modeled(0.0)
118147
}
119148
}
120149

121150
impl IonosphereBias {
122-
pub(crate) fn bias(&self, rtm: &RuntimeParam) -> Option<f64> {
123-
if let Some(_stec) = self.stec_meas {
124-
// TODO
125-
// let alpha = 40.3 * 10E16 / frequency / frequency;
126-
None
127-
} else if let Some(kb) = self.kb_model {
128-
kb.bias(rtm)
129-
} else if let Some(ng) = self.ng_model {
130-
ng.bias(rtm)
131-
} else if let Some(bd) = self.bd_model {
132-
bd.bias(rtm)
133-
} else {
134-
None
151+
/// Returns Bias value in [m]
152+
pub fn value(&self) -> f64 {
153+
match self {
154+
Self::Measured(bias) => *bias,
155+
Self::Modeled(bias) => *bias,
135156
}
136157
}
158+
/// Builds a measured bias in [m]
159+
pub(crate) fn measured(meas_m: f64) -> Self {
160+
Self::Measured(meas_m)
161+
}
162+
/// Builds a modeled bias in [m]
163+
pub(crate) fn modeled(model_m: f64) -> Self {
164+
Self::Modeled(model_m)
165+
}
137166
}

src/bias/mod.rs

Lines changed: 9 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,18 @@
11
use crate::prelude::Epoch;
22

33
pub(crate) mod tropo;
4-
pub use tropo::{TropoModel, TroposphereBias};
4+
pub use tropo::{TropoComponents, TropoModel};
55

66
pub(crate) mod iono;
7-
pub use iono::{BdModel, IonosphereBias, KbModel, NgModel};
7+
pub use iono::{BdModel, IonoComponents, IonosphereBias, KbModel, NgModel};
88

9-
#[cfg(feature = "serde")]
10-
use serde::{Deserialize, Serialize};
11-
12-
/// Modeled (estimated) or measured bias
13-
#[derive(Debug, Copy, Clone, Default)]
14-
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
15-
pub struct Bias {
16-
/// Measured delay [meters of delay]
17-
pub measured: Option<f64>,
18-
/// Modeled delay [meters of delay]
19-
pub modeled: Option<f64>,
20-
}
21-
22-
impl Bias {
23-
/// Bias value
24-
pub fn value(&self) -> Option<f64> {
25-
if self.measured.is_none() {
26-
self.modeled
27-
} else {
28-
self.measured
29-
}
30-
}
31-
/// Builds a measured Time Delay from a measurement in [s]
32-
pub fn measured(measurement: f64) -> Self {
33-
Self {
34-
measured: Some(measurement),
35-
modeled: None,
36-
}
37-
}
38-
/// Builds a modeled Time Delay from a model in [s]
39-
pub fn modeled(model: f64) -> Self {
40-
Self {
41-
modeled: Some(model),
42-
measured: None,
43-
}
44-
}
45-
}
46-
47-
pub(crate) struct RuntimeParam {
9+
pub(crate) struct RuntimeParams {
4810
pub t: Epoch,
49-
// elevation in [°]
50-
pub elevation: f64,
51-
// azimmuth in [°]
52-
pub azimuth: f64,
53-
// Apriori geodetic coordinates with latitude
54-
// expressed as meters above sea level
55-
pub apriori_geo: (f64, f64, f64),
56-
// signal frequency
5711
pub frequency: f64,
12+
pub azimuth_deg: f64,
13+
pub elevation_deg: f64,
14+
pub azimuth_rad: f64,
15+
pub elevation_rad: f64,
16+
pub apriori_geo: (f64, f64, f64),
17+
pub apriori_rad: (f64, f64),
5818
}

0 commit comments

Comments
 (0)