Skip to content

Commit 804fdbe

Browse files
Serde + Stochastic constant biases + moduli in data
Add serde almost everywhere, focusing on inputs: Outputs, such as event details, should be stored differently, e.g. in a column based storage Add constant offset to noises, add multiplier in TDM parsing/formatting, better check on TDM parsing Add optional moduli on all OD data type and support reading range moduli
1 parent 0f9ed48 commit 804fdbe

24 files changed

+280
-97
lines changed

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "nyx-space"
33
build = "build.rs"
4-
version = "2.0.0"
4+
version = "2.1.0"
55
edition = "2021"
66
authors = ["Christopher Rabotin <[email protected]>"]
77
description = "A high-fidelity space mission toolkit, with orbit propagation, estimation and some systems engineering"

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ For Python projects, get started by installing the library via `pip`: `pip insta
6262

6363
Nyx is provided under the [AGPLv3 License](./LICENSE). By using this software, you assume responsibility for adhering to the license. Refer to [the pricing page](https://nyxspace.com/pricing/?utm_source=readme-price) for an FAQ on the AGPLv3 license. Notably, any software that incorporates, links to, or depends on Nyx must also be released under the AGPLv3 license, even if you distribute an unmodified version of Nyx.
6464

65+
# Versioning
66+
67+
Nyx mostly adheres to SemVer. New patch versions should be rare. Updated dependencies trigger a new minor version. _However_ new fields in structures and new behavior may also be added with minor releases, but the public facing initializers and functions should not significantly change (but may still change).
68+
69+
Major releases are for dramatic changes.
70+
6571

6672
[cratesio-image]: https://img.shields.io/crates/v/nyx-space.svg
6773
[cratesio]: https://crates.io/crates/nyx-space
+2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
range_noise_model:
22
tau: 12 h 159 ms
33
process_noise: 5.0e-3 # 5 m
4+
constant: 0
45

56
doppler_noise_model:
67
tau: 11 h 59 min
78
process_noise: 50.0e-6 # 5 cm/s
9+
constant: 0

data/tests/config/many_ground_stations.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
bias:
1111
tau: 24 h
1212
process_noise: 5.0e-3 # 5 m
13+
constant: 0
1314
doppler_km_s:
1415
bias:
1516
tau: 24 h
1617
process_noise: 50.0e-6 # 5 cm/s
18+
constant: 0
1719
light_time_correction: false
1820
latitude_deg: 2.3522
1921
longitude_deg: 48.8566
@@ -37,10 +39,12 @@
3739
bias:
3840
tau: 24 h
3941
process_noise: 5.0e-3 # 5 m
42+
constant: 0
4043
doppler_km_s:
4144
bias:
4245
tau: 24 h
4346
process_noise: 50.0e-6 # 5 cm/s
47+
constant: 0
4448
light_time_correction: false
4549
measurement_types:
4650
- range_km

data/tests/config/one_ground_station.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@ stochastic_noises:
1313
bias:
1414
tau: 24 h
1515
process_noise: 5.0e-3 # 5 m
16+
constant: 0
1617
doppler_km_s:
1718
bias:
1819
tau: 24 h
1920
process_noise: 50.0e-6 # 5 cm/s
21+
constant: 0
2022
light_time_correction: false
2123
measurement_types:
2224
- range_km

src/dynamics/guidance/ruggiero.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
*/
1818

1919
use anise::prelude::Almanac;
20+
use serde::{Deserialize, Serialize};
2021
use snafu::ResultExt;
2122

2223
use super::{
@@ -32,7 +33,7 @@ use std::fmt;
3233
use std::sync::Arc;
3334

3435
/// Ruggiero defines the closed loop guidance law from IEPC 2011-102
35-
#[derive(Copy, Clone, Default)]
36+
#[derive(Copy, Clone, Default, Serialize, Deserialize)]
3637
pub struct Ruggiero {
3738
/// Stores the objectives
3839
pub objectives: [Option<Objective>; 5],

src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ pub mod cosmic;
4141
/// Utility functions shared by different modules, and which may be useful to engineers.
4242
pub mod utils;
4343

44-
mod errors;
44+
pub mod errors;
4545
/// Nyx will (almost) never panic and functions which may fail will return an error.
4646
pub use self::errors::NyxError;
4747

src/mc/dispersion.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@
1717
*/
1818

1919
use crate::md::StateParameter;
20+
use serde::{Deserialize, Serialize};
2021
use typed_builder::TypedBuilder;
2122

2223
/// A dispersions configuration, allows specifying min/max bounds (by default, they are not set)
23-
#[derive(Copy, Clone, TypedBuilder)]
24+
#[derive(Copy, Clone, TypedBuilder, Serialize, Deserialize)]
2425
pub struct StateDispersion {
2526
pub param: StateParameter,
2627
#[builder(default, setter(strip_option))]

src/md/events/details.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,13 @@ use crate::md::prelude::{Interpolatable, Traj};
2525
use crate::md::EventEvaluator;
2626
use crate::time::Duration;
2727
use core::fmt;
28+
use serde::{Deserialize, Serialize};
2829
use std::sync::Arc;
2930

3031
/// Enumerates the possible edges of an event in a trajectory.
3132
///
3233
/// `EventEdge` is used to describe the nature of a trajectory event, particularly in terms of its temporal dynamics relative to a specified condition or threshold. This enum helps in distinguishing whether the event is occurring at a rising edge, a falling edge, or if the edge is unclear due to insufficient data or ambiguous conditions.
33-
#[derive(Copy, Clone, Debug, PartialEq)]
34+
#[derive(Copy, Clone, Debug, PartialEq, Serialize, Deserialize)]
3435
pub enum EventEdge {
3536
/// Represents a rising edge of the event. This indicates that the event is transitioning from a lower to a higher evaluation of the event. For example, in the context of elevation, a rising edge would indicate an increase in elevation from a lower angle.
3637
Rising,
@@ -73,14 +74,14 @@ where
7374
{
7475
/// Generates detailed information about an event at a specific epoch in a trajectory.
7576
///
76-
/// This takes an `Epoch` as an input and returns a `Result<Self, NyxError>`.
77+
/// This takes an `Epoch` as an input and returns a `Result<Self, EventError>`.
7778
/// It is designed to determine the state of a trajectory at a given epoch, evaluate the specific event at that state, and ascertain the nature of the event (rising, falling, or unclear).
7879
/// The initialization intelligently determines the edge type of the event by comparing the event's value at the current, previous, and next epochs.
7980
/// It ensures robust event characterization in trajectories.
8081
///
8182
/// # Returns
8283
/// - `Ok(EventDetails<S>)` if the state at the given epoch can be determined and the event details are successfully evaluated.
83-
/// - `Err(NyxError)` if there is an error in retrieving the state at the specified epoch.
84+
/// - `Err(EventError)` if there is an error in retrieving the state at the specified epoch.
8485
///
8586
pub fn new<E: EventEvaluator<S>>(
8687
state: S,

src/md/events/mod.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ use crate::time::{Duration, Unit};
2727
use crate::State;
2828
use anise::prelude::{Almanac, Frame};
2929
use anise::structure::planetocentric::ellipsoid::Ellipsoid;
30+
use serde::{Deserialize, Serialize};
3031

3132
use std::default::Default;
3233
use std::fmt;
@@ -59,15 +60,14 @@ where
5960
}
6061

6162
/// Defines a state parameter event finder
62-
#[derive(Clone, Debug)]
63-
63+
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
6464
pub struct Event {
6565
/// The state parameter
6666
pub parameter: StateParameter,
6767
/// The desired self.desired_value, must be in the same units as the state parameter
6868
pub desired_value: f64,
69-
/// The time precision after which the solver will report that it cannot find any more precise
70-
pub epoch_precision: Unit,
69+
/// The duration precision after which the solver will report that it cannot find any more precise
70+
pub epoch_precision: Duration,
7171
/// The precision on the desired value
7272
pub value_precision: f64,
7373
/// An optional frame in which to search this -- it IS recommended to convert the whole trajectory instead of searching in a given frame!
@@ -133,12 +133,12 @@ impl Event {
133133
parameter: StateParameter,
134134
desired_value: f64,
135135
value_precision: f64,
136-
epoch_precision: Unit,
136+
unit_precision: Unit,
137137
) -> Self {
138138
Self {
139139
parameter,
140140
desired_value,
141-
epoch_precision,
141+
epoch_precision: 1 * unit_precision,
142142
value_precision,
143143
obs_frame: None,
144144
}
@@ -166,7 +166,7 @@ impl Event {
166166
Self {
167167
parameter,
168168
desired_value,
169-
epoch_precision: Unit::Millisecond,
169+
epoch_precision: Unit::Millisecond * 1,
170170
value_precision: 1e-3,
171171
obs_frame: Some(target_frame),
172172
}
@@ -179,7 +179,7 @@ impl Default for Event {
179179
parameter: StateParameter::Periapsis,
180180
desired_value: 0.0,
181181
value_precision: 1e-3,
182-
epoch_precision: Unit::Second,
182+
epoch_precision: Unit::Second * 1,
183183
obs_frame: None,
184184
}
185185
}

src/md/objective.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@
1818

1919
use super::StateParameter;
2020
use crate::{errors::StateError, Spacecraft, State};
21+
use serde::{Deserialize, Serialize};
2122
use std::fmt;
2223

2324
/// Defines a state parameter event finder
24-
#[derive(Copy, Clone, Debug)]
25+
#[derive(Copy, Clone, Debug, Serialize, Deserialize)]
2526
pub struct Objective {
2627
/// The state parameter to target
2728
pub parameter: StateParameter,

src/od/ground_station/trk_device.rs

+16
Original file line numberDiff line numberDiff line change
@@ -174,4 +174,20 @@ impl TrackingDevice<Spacecraft> for GroundStation {
174174
})?
175175
.covariance(epoch))
176176
}
177+
178+
fn measurement_bias(&self, msr_type: MeasurementType, _epoch: Epoch) -> Result<f64, ODError> {
179+
let stochastics = self.stochastic_noises.as_ref().unwrap();
180+
181+
if let Some(gm) = stochastics
182+
.get(&msr_type)
183+
.ok_or(ODError::NoiseNotConfigured {
184+
kind: format!("{msr_type:?}"),
185+
})?
186+
.bias
187+
{
188+
Ok(gm.constant)
189+
} else {
190+
Ok(0.0)
191+
}
192+
}
177193
}

src/od/msr/measurement.rs

+19-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ use nalgebra::{allocator::Allocator, DefaultAllocator, DimName, OVector};
2323
use std::fmt;
2424

2525
/// A type-agnostic simultaneous measurement storage structure. Allows storing any number of simultaneous measurement of a given taker.
26-
#[derive(Clone, Debug, PartialEq)]
26+
///
27+
/// Note that two measurements are considered equal if the tracker and epoch match exactly, and if both have the same measurement types,
28+
/// and those measurements are equal to within 1e-10 (this allows for some leeway in TDM producers).
29+
#[derive(Clone, Debug)]
2730
pub struct Measurement {
2831
/// Tracker alias which made this measurement
2932
pub tracker: String,
@@ -58,6 +61,7 @@ impl Measurement {
5861
where
5962
DefaultAllocator: Allocator<S>,
6063
{
64+
// Consider adding a modulo modifier here, any bias should be configured by each ground station.
6165
let mut obs = OVector::zeros();
6266
for (i, t) in types.iter().enumerate() {
6367
if let Some(msr_value) = self.data.get(t) {
@@ -91,3 +95,17 @@ impl fmt::Display for Measurement {
9195
write!(f, "{} measured {} on {}", self.tracker, msrs, self.epoch)
9296
}
9397
}
98+
99+
impl PartialEq for Measurement {
100+
fn eq(&self, other: &Self) -> bool {
101+
self.tracker == other.tracker
102+
&& self.epoch == other.epoch
103+
&& self.data.iter().all(|(key, &value)| {
104+
if let Some(&other_value) = other.data.get(key) {
105+
(value - other_value).abs() < 1e-12
106+
} else {
107+
false
108+
}
109+
})
110+
}
111+
}

0 commit comments

Comments
 (0)