Skip to content

Commit

Permalink
Merge pull request #340 from nyx-space/331-measurement-update-and-res…
Browse files Browse the repository at this point in the history
…idual-rejection-shall-account-for-each-participants-noise-level

Refactor orbit/spacecraft state generator to always use the multivariate normal
  • Loading branch information
ChristopherRabotin authored Jul 20, 2024
2 parents 97c16cd + ef77dcc commit 7103621
Show file tree
Hide file tree
Showing 29 changed files with 620 additions and 694 deletions.
22 changes: 15 additions & 7 deletions examples/02_jwst_covar_monte_carlo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ INFO anise::almanac > Loading almanac from /home/crabotin/.
INFO anise::almanac > Loading as DAF/PCK
INFO anise::almanac > Loading almanac from /home/crabotin/.local/share/nyx-space/anise/jwst_rec.bsp
INFO anise::almanac > Loading as DAF/SPK
JWST defined from 2024-03-30T22:40:09.185653761 ET to 2024-06-24T00:01:09.184303103 ET
[Earth J2000] 2024-06-24T00:01:09.184303103 ET sma = 881064.546158 km ecc = 0.989962 inc = 42.614418 deg raan = 37.843422 deg aop = 62.970831 deg ta = 180.020951 deg
total mass = 6200.000 kg @ [Earth J2000] 2024-06-24T00:01:09.184303103 ET position = [76518.064167, -1396268.919369, -1057612.565026] km velocity = [0.043331, 0.014876, -0.013649] km/s Coast
RIC Σ_x = 0.5 km Σ_y = 0.3 km Σ_z = 1.5 km
RIC Σ_vx = 0.0001 km/s Σ_vy = 0.0006 km/s Σ_vz = 0.003 km/s
Σ_cr = 0 Σ_cd = 0 Σ_mass = 0 kg
JWST defined from 2024-04-13T22:40:09.185630849 ET to 2024-07-08T00:01:09.183912447 ET
[Earth J2000] 2024-07-08T00:01:09.183912447 ET sma = 876856.027357 km ecc = 0.985029 inc = 52.340344 deg raan = 310.126394 deg aop = 130.798599 deg ta = 180.103906 deg
total mass = 6200.000 kg @ [Earth J2000] 2024-07-08T00:01:09.183912447 ET position = [119901.070276, -1389299.665421, -1041369.150539] km velocity = [0.045956, -0.013168, 0.034535] km/s Coast
RIC σ_x = 0.5 km σ_y = 0.3 km σ_z = 1.5 km
RIC σ_vx = 0.0001 km/s σ_vy = 0.0006 km/s σ_vz = 0.003 km/s
σ_cr = 0 σ_cd = 0 σ_mass = 0 kg

INFO nyx_space::od::process > Mapping covariance for 6 days 12 h with 1 min step
INFO nyx_space::od::process::export > Exporting orbit determination result to parquet file...
Expand All @@ -65,9 +65,11 @@ INFO nyx_space::mc::results > Evaluating 2 event(s)
INFO nyx_space::mc::results > Trajectory written to 02_jwst_monte_carlo.parquet in 41 s 603 ms 696 μs 128 ns
```

We then run `╰─(.venv) ⠠⠵ ipython examples/02_jwst_covar_monte_carlo/plotting.py` from the virtual environment, whose requirements are in the [requirements.txt](./requirements.txt)

## Analysis

Overall, we can confirm that the 3-sigma covariance is a good approximation of the uncertainty. Notably, however, there are some dispersed trajectories whose Keplerian orbital elements are outside of the 3-sigma bound. This is probably due to the fact that Keplerian orbital elements are defined for orbits where there is a central body, but the James Webb Space Telescope is in a three body orbit, since it's near a Lagrange point.
Overall, we can confirm that the 3-sigma covariance is a good approximation of the uncertainty. Notably, all of the dispersed trajectories fit (nearly) within the 3-σ bounds in the state space and in the Keplerian orbital element space. The rotation from the Keplerioan orbital element space into the Cartesian space is done by building the Jacobian from the desired Keplerian elements into the Cartesian space using hyperdual numbers (also called "automatic differentiation" in the machine learning world). This ensure that we don't lose any precision in the state space change, and that's shown to be the case in these plots.

### State uncertainties

Expand All @@ -83,6 +85,12 @@ As expected from any orbit determination software, Nyx can output uncertainties

![JWST MC Z (km)](./plots/jwst_mc_Z_km.png)

![JWST MC VX (km/s)](./plots/jwst_mc_VX_km_s.png)

![JWST MC VY (km/s)](./plots/jwst_mc_VY_km_s.png)

![JWST MC VZ (km/s)](./plots/jwst_mc_VZ_km_s.png)

### Keplerian uncertainties

A few tools try to provide Keplerian uncertainties, but often fail to do so correctly (<small>I'm looking at you, ODTK</small>). Nyx rotates the covariance from its Cartesian form into the Keplerian state space by computing the partial derivatives of each requested parameter with respect to the nominal state. This computation is flawless because it uses automatic differentiation (via _hyperdual numbers_). As such, the OD export also includes all of the state computations supported in Nyx, including uncommon ones like the uncertainties in the energy of the orbit or in the true anomaly.
Expand Down
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.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_X_km.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_Y_km.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_Z_km.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_aop_deg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_ecc.png
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.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_inc_deg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_raan_deg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_sma_km.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_mc_ta_deg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_ric_position.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified examples/02_jwst_covar_monte_carlo/plots/jwst_ric_velocity.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions examples/02_jwst_covar_monte_carlo/plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@

if __name__ == "__main__":
df_mc = pl.read_parquet("./02_jwst_monte_carlo.parquet")
df_mc = df_mc.with_columns(pl.col("Epoch (UTC)").str.to_datetime("%Y-%m-%dT%H:%M:%S%.f"))
df_mc = df_mc.with_columns(pl.col("Epoch (UTC)").str.to_datetime("%Y-%m-%dT%H:%M:%S%.f")).sort("Epoch (UTC)", descending=False)
print(df_mc.describe())

df_covar = pl.read_parquet("./02_jwst_covar_map.parquet")
df_covar = df_covar.with_columns(pl.col("Epoch (UTC)").str.to_datetime("%Y-%m-%dT%H:%M:%S%.f"))
df_covar = df_covar.with_columns(pl.col("Epoch (UTC)").str.to_datetime("%Y-%m-%dT%H:%M:%S%.f")).sort("Epoch (UTC)", descending=False)
print(df_covar.describe())

# Build the position plots
Expand All @@ -18,7 +18,7 @@
go.Scattergl(
x=df_mc["Epoch (UTC)"],
y=df_mc[col],
mode="lines",
mode="markers",
opacity=0.05,
showlegend=True,
name=f"[MC] {coord} (km)",
Expand Down Expand Up @@ -63,7 +63,7 @@
go.Scattergl(
x=df_mc["Epoch (UTC)"],
y=df_mc[col],
mode="lines",
mode="markers",
opacity=0.05,
showlegend=True,
name=f"[MC] {coord} (km/s)",
Expand Down Expand Up @@ -156,7 +156,7 @@
go.Scattergl(
x=df_mc["Epoch (UTC)"],
y=df_mc[col],
mode="lines",
mode="markers",
opacity=0.05,
showlegend=True,
name=f"[MC] {col}",
Expand Down
4 changes: 2 additions & 2 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ impl From<ConfigError> for NyxError {
#[derive(Debug, PartialEq, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum StateError {
#[snafu(display("{param} is unavailable for this kind of state"))]
#[snafu(display("{param} is unavailable in this context"))]
Unavailable { param: StateParameter },
#[snafu(display("{param} is read only for this kind of state"))]
#[snafu(display("{param} is read only in this context"))]
ReadOnly { param: StateParameter },
#[snafu(display("{param} computation caused {source}"))]
StateAstroError {
Expand Down
40 changes: 40 additions & 0 deletions src/mc/dispersion.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
Nyx, blazing fast astrodynamics
Copyright (C) 2018-onwards Christopher Rabotin <[email protected]>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

use crate::md::StateParameter;
use typed_builder::TypedBuilder;

/// A dispersions configuration, allows specifying min/max bounds (by default, they are not set)
#[derive(Copy, Clone, TypedBuilder)]
pub struct StateDispersion {
pub param: StateParameter,
#[builder(default, setter(strip_option))]
pub mean: Option<f64>,
#[builder(default, setter(strip_option))]
pub std_dev: Option<f64>,
}

impl StateDispersion {
pub fn zero_mean(param: StateParameter, std_dev: f64) -> Self {
Self {
param,
std_dev: Some(std_dev),
mean: Some(0.0),
}
}
}
Loading

0 comments on commit 7103621

Please sign in to comment.