nyx_space/od/process/solution/
filter_data.rs1use crate::linalg::allocator::Allocator;
20use crate::linalg::{DefaultAllocator, DimName, OMatrix};
21use crate::md::trajectory::Interpolatable;
22pub use crate::od::estimate::*;
23pub use crate::od::*;
24use indexmap::IndexSet;
25use msr::sensitivity::TrackerSensitivity;
26use std::ops::Add;
27
28use self::msr::MeasurementType;
29
30use super::ODSolution;
31
32#[derive(Clone, Debug, PartialEq)]
33#[allow(clippy::upper_case_acronyms)]
34pub struct ODRecord<StateType, EstType, MsrSize>
35where
36 StateType: Interpolatable + Add<OVector<f64, <StateType as State>::Size>, Output = StateType>,
37 EstType: Estimate<StateType>,
38 MsrSize: DimName,
39 <DefaultAllocator as Allocator<<StateType as State>::VecLength>>::Buffer<f64>: Send,
40 DefaultAllocator: Allocator<<StateType as State>::Size>
41 + Allocator<<StateType as State>::VecLength>
42 + Allocator<MsrSize>
43 + Allocator<MsrSize, <StateType as State>::Size>
44 + Allocator<MsrSize, MsrSize>
45 + Allocator<<StateType as State>::Size, <StateType as State>::Size>
46 + Allocator<<StateType as State>::Size, MsrSize>,
47{
48 pub estimate: EstType,
50 pub residual: Option<Residual<MsrSize>>,
52 pub gain: Option<OMatrix<f64, <StateType as State>::Size, MsrSize>>,
54 pub filter_smoother_ratio: Option<OVector<f64, <StateType as State>::Size>>,
56}
57
58impl<StateType, EstType, MsrSize, Trk> ODSolution<StateType, EstType, MsrSize, Trk>
59where
60 StateType: Interpolatable + Add<OVector<f64, <StateType as State>::Size>, Output = StateType>,
61 EstType: Estimate<StateType>,
62 MsrSize: DimName,
63 Trk: TrackerSensitivity<StateType, StateType>,
64 <DefaultAllocator as Allocator<<StateType as State>::VecLength>>::Buffer<f64>: Send,
65 DefaultAllocator: Allocator<<StateType as State>::Size>
66 + Allocator<<StateType as State>::VecLength>
67 + Allocator<MsrSize>
68 + Allocator<MsrSize, <StateType as State>::Size>
69 + Allocator<MsrSize, MsrSize>
70 + Allocator<<StateType as State>::Size, <StateType as State>::Size>
71 + Allocator<<StateType as State>::Size, MsrSize>,
72{
73 pub fn unique(&self) -> IndexSet<(String, MeasurementType)> {
75 let mut mapping = IndexSet::new();
76 for resid in self.residuals.iter().flatten() {
77 for k in &resid.msr_types {
78 mapping.insert((
79 resid.tracker.clone().expect("residual tracker not set!"),
80 *k,
81 ));
82 }
83 }
84 mapping
85 }
86
87 pub fn drop_time_updates(mut self) -> Self {
89 let mut estimates = Vec::new();
90 let mut residuals = Vec::new();
91 let mut gains = Vec::new();
92 let mut filter_smoother_ratios = Vec::new();
93
94 for (est, (resid_opt, (gain_opt, fsr_opt))) in self.estimates.iter().zip(
95 self.residuals
96 .iter()
97 .zip(self.gains.iter().zip(self.filter_smoother_ratios.iter())),
98 ) {
99 if resid_opt.is_none() {
100 continue;
101 }
102
103 estimates.push(est.clone());
104 residuals.push(resid_opt.clone());
105 gains.push(gain_opt.clone());
106 filter_smoother_ratios.push(fsr_opt.clone());
107 }
108
109 self.estimates = estimates;
110 self.residuals = residuals;
111 self.gains = gains;
112 self.filter_smoother_ratios = filter_smoother_ratios;
113
114 self
115 }
116
117 pub fn filter_by_msr_type(mut self, msr_type: MeasurementType) -> Self {
119 let mut estimates = Vec::new();
120 let mut residuals = Vec::new();
121 let mut gains = Vec::new();
122 let mut filter_smoother_ratios = Vec::new();
123
124 for (est, (resid_opt, (gain_opt, fsr_opt))) in self.estimates.iter().zip(
125 self.residuals
126 .iter()
127 .zip(self.gains.iter().zip(self.filter_smoother_ratios.iter())),
128 ) {
129 match resid_opt {
130 None => continue, Some(resid) => {
132 if resid.msr_types.contains(&msr_type) {
133 estimates.push(est.clone());
134 residuals.push(Some(resid.clone()));
135 gains.push(gain_opt.clone());
136 filter_smoother_ratios.push(fsr_opt.clone());
137 }
138 }
139 }
140 }
141
142 self.estimates = estimates;
143 self.residuals = residuals;
144 self.gains = gains;
145 self.filter_smoother_ratios = filter_smoother_ratios;
146
147 self
148 }
149
150 pub fn filter_by_tracker(mut self, tracker: String) -> Self {
152 let mut estimates = Vec::new();
153 let mut residuals = Vec::new();
154 let mut gains = Vec::new();
155 let mut filter_smoother_ratios = Vec::new();
156
157 for (est, (resid_opt, (gain_opt, fsr_opt))) in self.estimates.iter().zip(
158 self.residuals
159 .iter()
160 .zip(self.gains.iter().zip(self.filter_smoother_ratios.iter())),
161 ) {
162 match resid_opt {
163 None => continue, Some(resid) => {
165 if resid.tracker == Some(tracker.clone()) {
166 estimates.push(est.clone());
167 residuals.push(Some(resid.clone()));
168 gains.push(gain_opt.clone());
169 filter_smoother_ratios.push(fsr_opt.clone());
170 }
171 }
172 }
173 }
174
175 self.estimates = estimates;
176 self.residuals = residuals;
177 self.gains = gains;
178 self.filter_smoother_ratios = filter_smoother_ratios;
179
180 self
181 }
182
183 pub fn exclude_tracker(mut self, excluded_tracker: String) -> Self {
185 let mut estimates = Vec::new();
186 let mut residuals = Vec::new();
187 let mut gains = Vec::new();
188 let mut filter_smoother_ratios = Vec::new();
189
190 for (est, (resid_opt, (gain_opt, fsr_opt))) in self.estimates.iter().zip(
191 self.residuals
192 .iter()
193 .zip(self.gains.iter().zip(self.filter_smoother_ratios.iter())),
194 ) {
195 if let Some(resid) = resid_opt {
196 if resid.tracker.is_none() || resid.tracker.as_ref().unwrap() == &excluded_tracker {
197 continue;
198 }
199 }
200 estimates.push(est.clone());
202 residuals.push(resid_opt.clone());
203 gains.push(gain_opt.clone());
204 filter_smoother_ratios.push(fsr_opt.clone());
205 }
206
207 self.estimates = estimates;
208 self.residuals = residuals;
209 self.gains = gains;
210 self.filter_smoother_ratios = filter_smoother_ratios;
211
212 self
213 }
214
215 pub fn split(self) -> Vec<Self> {
217 let uniques = self.unique();
218 let mut splt = Vec::with_capacity(uniques.len());
219 for (tracker, msr_type) in uniques {
220 splt.push(
221 self.clone()
222 .filter_by_tracker(tracker)
223 .filter_by_msr_type(msr_type),
224 );
225 }
226 splt
227 }
228
229 pub fn merge(mut self, mut other: Self) -> Self {
231 self.estimates.append(&mut other.estimates);
232 self.residuals.append(&mut other.residuals);
233 self.gains.append(&mut other.gains);
234 self.filter_smoother_ratios
235 .append(&mut other.filter_smoother_ratios);
236
237 let mut indices: Vec<usize> = (0..self.estimates.len()).collect();
240
241 indices.sort_by(|&a, &b| {
243 self.estimates[a]
244 .epoch()
245 .partial_cmp(&self.estimates[b].epoch())
246 .expect("Epoch comparison failed")
247 });
248
249 for i in 0..indices.len() {
251 let current = i;
252 while indices[current] != current {
253 let target = indices[current];
254 indices.swap(current, target);
255 self.estimates.swap(current, target);
256 self.residuals.swap(current, target);
257 self.gains.swap(current, target);
258 self.filter_smoother_ratios.swap(current, target);
259 }
260 }
261
262 self
263 }
264
265 pub fn at(&self, epoch: Epoch) -> Option<ODRecord<StateType, EstType, MsrSize>> {
266 if let Ok(index) = self
267 .estimates
268 .binary_search_by(|est| est.epoch().cmp(&epoch))
269 {
270 Some(ODRecord {
271 estimate: self.estimates[index].clone(),
272 residual: self.residuals[index].clone(),
273 gain: self.gains[index].clone(),
274 filter_smoother_ratio: self.filter_smoother_ratios[index].clone(),
275 })
276 } else {
277 None
278 }
279 }
280}