Skip to content

Commit b9b0686

Browse files
authored
Replace OrbitalState with ANISE::Orbit (#33)
* Replace OrbitalState with ANISE::Orbit * reestablish group delay --------- Signed-off-by: Guillaume W. Bres <guillaume.bressaix@gmail.com>
1 parent d534cb2 commit b9b0686

File tree

23 files changed

+829
-759
lines changed

23 files changed

+829
-759
lines changed

README.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,22 @@ GNSS-RTK is flexible and efficient:
2222
* you don't have to sample L1 and can navigate with modern signals
2323
* it supports navigation without phase range
2424
* a special CPP method for dual frequency pseudo range (no phase range)
25-
which is pretty much a slow converging PPP method
26-
* it can operate without apriori knowledge and is a true surveying tool
25+
which behaves like a slow converging PPP method
26+
* is a true surveying tool because it can operate without apriori knowledge
2727
* it can fulfill the challenging task of RTK / Geodetic reference station calibration
28+
by deploying a complete PPP survey
29+
30+
Other cool features:
31+
* works in all supported timescales
32+
* can navigate using a conic azimuth mask (min and max azimuth angle).
33+
In this case, we only select vehicles from that very region of the compass.
34+
* could potentially apply to other Planets, if we make some function more generic
35+
and propose better atmosphere interfaces.
36+
37+
GNSS-RTK does not care about SV or signal modulations. It cares
38+
about physics, distances, frequencies and environmental phenomena.
39+
This means you operate it from whatever data source you have at your disposal,
40+
as long as you can provide the required inputs.
2841

2942
Applications
3043
============

examples/spp/main.rs

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,24 @@
11
// SPP example (pseudo range based direct positioning).
22
// This is simply here to demonstrate how to operate the API, and does not generate actual results.
33
use gnss_rtk::prelude::{
4-
Candidate, Carrier, ClockCorrection, Config, Duration, Epoch, Error, InvalidationCause,
5-
IonoComponents, Method, Observation, OrbitalState, OrbitalStateProvider, Solver,
6-
TropoComponents, SV,
4+
Candidate, Carrier, Config, Epoch, Error, Frame, InvalidationCause, Method, Observation, Orbit,
5+
OrbitSource, Solver, EARTH_J2000, SV,
76
};
87

98
// Orbit source example
109
struct Orbits {}
1110

12-
impl OrbitalStateProvider for Orbits {
11+
impl OrbitSource for Orbits {
1312
// For each requested "t" and "sv",
14-
// if we can, we should resolve the SV [OrbitalState].
13+
// if we can, we should resolve the SV [Orbit].
1514
// If interpolation is to be used (depending on your apps), you can
1615
// use the interpolation order that we recommend here, or decide to ignore it.
17-
// If you're not in position to determine [OrbitalState], simply return None.
16+
// If you're not in position to determine [Orbit], simply return None.
1817
// If None is returned for too long, this [Epoch] will eventually be dropped out,
1918
// and we will move on to the next
20-
fn next_at(&mut self, t: Epoch, sv: SV, order: usize) -> Option<OrbitalState> {
21-
let (x, y, z) = (0.0_f64, 0.0_f64, 0.0_f64);
22-
Some(OrbitalState::from_position((x, y, z)))
19+
fn next_at(&mut self, t: Epoch, _sv: SV, _fr: Frame, _order: usize) -> Option<Orbit> {
20+
let (x_km, y_km, z_km) = (0.0_f64, 0.0_f64, 0.0_f64);
21+
Some(Orbit::from_position(x_km, y_km, z_km, t, EARTH_J2000))
2322
}
2423
}
2524

@@ -92,17 +91,10 @@ pub fn main() {
9291
while let Some((epoch, candidates)) = source.next() {
9392
match solver.resolve(epoch, &candidates) {
9493
Ok((_epoch, solution)) => {
95-
// A solution was successfully resolved for this Epoch.
96-
// The position is expressed as absolute ECEF [m].
97-
let _position = solution.position;
98-
// The velocity vector is expressed as variations of absolute ECEF positions [m/s]
99-
let _velocity = solution.velocity;
10094
// Receiver offset to preset timescale
10195
let (_clock_offset, _timescale) = (solution.dt, solution.timescale);
10296
// More infos on SVs that contributed to this solution
10397
for info in solution.sv.values() {
104-
// attitude
105-
let (_el, _az) = (info.azimuth, info.elevation);
10698
// Modeled (in this example) or simply copied ionosphere bias
10799
// impacting selected signal from this spacecraft
108100
let _bias_m = info.iono_bias;

src/bancroft.rs

Lines changed: 49 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Brancroft solver
22
use crate::{prelude::Candidate, solver::Error};
3+
use log::error;
34

45
use nalgebra::{Matrix4, Vector4};
56
use nyx_space::cosmic::SPEED_OF_LIGHT_M_S;
@@ -31,40 +32,59 @@ impl Bancroft {
3132
let m = Self::m_matrix();
3233
let mut a = Vector4::<f64>::default();
3334
let mut b = Matrix4::<f64>::default();
34-
assert!(
35-
cd.len() > 3,
36-
"can't resolve Bancroft equation: invalid input"
37-
);
38-
39-
for i in 0..4 {
40-
let state = cd[i].state.ok_or(Error::UnresolvedState)?;
41-
let (x_i, y_i, z_i) = (state.position[0], state.position[1], state.position[2]);
42-
let r_i = cd[i]
43-
.prefered_pseudorange()
44-
.ok_or(Error::MissingPseudoRange)?
45-
.pseudo
46-
.unwrap();
35+
if cd.len() < 4 {
36+
return Err(Error::NotEnoughCandidatesBancroft);
37+
}
4738

48-
let clock_corr = cd[i].clock_corr.ok_or(Error::UnknownClockCorrection)?;
49-
let dt_i = clock_corr.duration.to_seconds();
50-
let tgd_i = cd[i].tgd.unwrap_or_default().to_seconds();
39+
let mut j = 0;
40+
for i in 0..cd.len() {
41+
if let Some(orbit) = cd[i].orbit {
42+
let state = orbit.to_cartesian_pos_vel() * 1.0E3;
43+
let (x_i, y_i, z_i) = (state[0], state[1], state[2]);
5144

52-
b[(i, 0)] = x_i;
53-
b[(i, 1)] = y_i;
54-
b[(i, 2)] = z_i;
55-
let pr_i = r_i + dt_i * SPEED_OF_LIGHT_M_S - tgd_i;
56-
b[(i, 3)] = pr_i;
57-
a[i] = 0.5 * (x_i.powi(2) + y_i.powi(2) + z_i.powi(2) - pr_i.powi(2));
45+
if let Some(r_i) = cd[i].prefered_pseudorange() {
46+
let r_i = r_i.pseudo.unwrap();
47+
if let Some(clock_corr) = cd[i].clock_corr {
48+
let dt_i = clock_corr.duration.to_seconds();
49+
let tgd_i = cd[i].tgd.unwrap_or_default().to_seconds();
50+
let pr_i = r_i + dt_i * SPEED_OF_LIGHT_M_S - tgd_i;
51+
b[(j, 0)] = x_i;
52+
b[(j, 1)] = y_i;
53+
b[(j, 2)] = z_i;
54+
b[(j, 3)] = pr_i;
55+
a[j] = 0.5 * (x_i.powi(2) + y_i.powi(2) + z_i.powi(2) - pr_i.powi(2));
56+
j += 1;
57+
if j == 4 {
58+
break;
59+
}
60+
} else {
61+
error!(
62+
"{}({}) bancroft needs onboard clock correction",
63+
cd[i].t, cd[i].sv
64+
);
65+
}
66+
} else {
67+
error!("{}({}) bancroft needs 1 pseudo range", cd[i].t, cd[i].sv);
68+
}
69+
} else {
70+
error!(
71+
"{}({}) bancroft unresolved orbital state",
72+
cd[i].t, cd[i].sv
73+
);
74+
}
75+
}
76+
if j != 4 {
77+
Err(Error::BancroftError)
78+
} else {
79+
Ok(Self {
80+
a,
81+
b,
82+
m,
83+
ones: Self::one_vector(),
84+
})
5885
}
59-
Ok(Self {
60-
a,
61-
b,
62-
m,
63-
ones: Self::one_vector(),
64-
})
6586
}
6687
pub fn resolve(&self) -> Result<Vector4<f64>, Error> {
67-
let _output = Vector4::<f64>::default();
6888
let b_inv = self.b.try_inverse().ok_or(Error::MatrixInversionError)?;
6989
let b_1 = b_inv * self.ones;
7090
let b_a = b_inv * self.a;

src/bias/iono.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl KbModel {
3838
const LAMBDA_P: f64 = 291.0;
3939
const L1_F: f64 = 1575.42E6;
4040

41-
let (phi_u, lambda_u) = rtm.apriori_rad;
41+
let (phi_u, lambda_u) = rtm.rx_rad;
4242
let fract = R_EARTH / (R_EARTH + self.h_km);
4343
let (elev_rad, azim_rad) = (rtm.elevation_rad, rtm.azimuth_rad);
4444

@@ -125,7 +125,7 @@ impl IonoComponents {
125125
Self::KbModel(model) => model.value(rtm),
126126
Self::NgModel(model) => model.value(rtm),
127127
Self::BdModel(model) => model.value(rtm),
128-
Self::Stec(stec) => 0.0, //TODO
128+
Self::Stec(..) => 0.0, //TODO
129129
}
130130
}
131131
}

src/bias/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,9 @@ pub use iono::{BdModel, IonoComponents, IonosphereBias, KbModel, NgModel};
99
pub(crate) struct RuntimeParams {
1010
pub t: Epoch,
1111
pub frequency: f64,
12-
pub azimuth_deg: f64,
1312
pub elevation_deg: f64,
1413
pub azimuth_rad: f64,
1514
pub elevation_rad: f64,
16-
pub apriori_geo: (f64, f64, f64),
17-
pub apriori_rad: (f64, f64),
15+
pub rx_geo: (f64, f64, f64),
16+
pub rx_rad: (f64, f64),
1817
}

src/bias/tropo.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ impl TropoComponents {
5858
const G_M: f64 = 9.784_f64;
5959

6060
let day_of_year = rtm.t.day_of_year();
61-
let (lat_ddeg, _, h) = rtm.apriori_geo;
61+
let (lat_ddeg, _, h) = rtm.rx_geo;
6262

6363
let mut lat = 15.0_f64;
6464
let mut min_delta = 180.0_f64;
@@ -164,7 +164,7 @@ impl TropoComponents {
164164
fn niel_model(prm: &RuntimeParams) -> f64 {
165165
const NS: f64 = 324.8;
166166

167-
let (_, _, h) = prm.apriori_geo;
167+
let (_, _, h) = prm.rx_geo;
168168
let elev_rad = prm.elevation_rad;
169169
let h_km = h / 1000.0;
170170

0 commit comments

Comments
 (0)