nyx_space/md/trajectory/
mod.rs1use anise::{
20 errors::PhysicsError,
21 math::{cartesian::CartesianState, interpolation::InterpolationError},
22};
23use snafu::prelude::*;
24
25mod interpolatable;
26mod sc_traj;
27mod traj;
28mod traj_it;
29
30pub(crate) use interpolatable::INTERPOLATION_SAMPLES;
31pub use interpolatable::Interpolatable;
32pub use traj::Traj;
33
34pub use crate::io::ExportCfg;
35
36use super::StateParameter;
37use crate::time::{Duration, Epoch};
38
39#[derive(Clone, PartialEq, Debug, Snafu)]
40pub enum TrajError {
41 #[snafu(display("Event {event} not found between {start} and {end}"))]
42 EventNotFound {
43 start: Epoch,
44 end: Epoch,
45 event: String,
46 },
47 #[snafu(display("no interpolation data at {epoch}, traj valid from {start} to {end}"))]
48 NoInterpolationData {
49 epoch: Epoch,
50 start: Epoch,
51 end: Epoch,
52 },
53 #[snafu(display("cannot interpolate empty trajectory at {epoch}"))]
54 EmptyTrajectory {
55 epoch: Epoch,
56 },
57 #[snafu(display("Failed to create trajectory: {msg}"))]
58 CreationError {
59 msg: String,
60 },
61 #[snafu(display(
62 "Probable bug: Requested epoch {req_epoch}, corresponding to an offset of {req_dur} in a spline of duration {spline_dur}"
63 ))]
64 OutOfSpline {
65 req_epoch: Epoch,
66 req_dur: Duration,
67 spline_dur: Duration,
68 },
69 #[snafu(display("Interpolation failed: {source}"))]
70 Interpolation {
71 source: InterpolationError,
72 },
73 TrajPhysics {
74 source: PhysicsError,
75 },
76 TrajGeneric {
77 err: String,
78 },
79}
80
81fn smooth_state_diff_in_place(ric_diff: &mut [CartesianState], window_size: usize) {
84 assert!(
85 window_size % 2 == 1,
86 "Window size must be odd for proper median calculation"
87 );
88 let half_window = window_size / 2;
89
90 let mut temp_buffer = vec![0.0; window_size];
92
93 for i in 0..ric_diff.len() {
95 let start = i.saturating_sub(half_window);
96 let end = (i + half_window + 1).min(ric_diff.len());
97
98 for component in 0..6 {
100 for (j, idx) in (start..end).enumerate() {
102 temp_buffer[j] = match component {
103 0 => ric_diff[idx].radius_km.x,
104 1 => ric_diff[idx].radius_km.y,
105 2 => ric_diff[idx].radius_km.z,
106 3 => ric_diff[idx].velocity_km_s.x,
107 4 => ric_diff[idx].velocity_km_s.y,
108 5 => ric_diff[idx].velocity_km_s.z,
109 _ => unreachable!(),
110 };
111 }
112
113 temp_buffer[..end - start].sort_unstable_by(|a, b| a.partial_cmp(b).unwrap());
115
116 let median = temp_buffer[(end - start) / 2];
118 match component {
119 0 => ric_diff[i].radius_km.x = median,
120 1 => ric_diff[i].radius_km.y = median,
121 2 => ric_diff[i].radius_km.z = median,
122 3 => ric_diff[i].velocity_km_s.x = median,
123 4 => ric_diff[i].velocity_km_s.y = median,
124 5 => ric_diff[i].velocity_km_s.z = median,
125 _ => unreachable!(),
126 }
127 }
128 }
129}