Skip to content

Commit 439f0fd

Browse files
Fix step in OD with overlapping measurement
1 parent 4a403e5 commit 439f0fd

File tree

3 files changed

+39
-30
lines changed

3 files changed

+39
-30
lines changed

Diff for: src/od/msr/arc.rs

+12-9
Original file line numberDiff line numberDiff line change
@@ -204,17 +204,20 @@ where
204204
/// Returns the minimum duration between two subsequent measurements.
205205
/// This is important to correctly set up the propagator and not miss any measurement.
206206
pub fn min_duration_sep(&self) -> Option<Duration> {
207-
let mut windows = self.measurements.windows(2);
208-
let first_window = windows.next()?;
209-
let mut min_interval = first_window[1].1.epoch() - first_window[0].1.epoch();
210-
for window in windows {
211-
let interval = window[1].1.epoch() - window[0].1.epoch();
212-
if interval != Duration::ZERO && interval < min_interval {
213-
min_interval = interval;
207+
if self.measurements.is_empty() {
208+
None
209+
} else {
210+
let mut windows = self.measurements.windows(2);
211+
let first_window = windows.next()?;
212+
let mut min_interval = first_window[1].1.epoch() - first_window[0].1.epoch();
213+
for window in windows {
214+
let interval = window[1].1.epoch() - window[0].1.epoch();
215+
if interval != Duration::ZERO && interval < min_interval {
216+
min_interval = interval;
217+
}
214218
}
219+
Some(min_interval)
215220
}
216-
217-
Some(min_interval)
218221
}
219222

220223
/// If this tracking arc has devices that can be used to generate simulated measurements,

Diff for: src/od/process/mod.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -433,8 +433,7 @@ where
433433
let mut devices = arc.rebuild_devices::<S, Dev>(self.cosm.clone()).unwrap();
434434

435435
let measurements = &arc.measurements;
436-
let step_size = Duration::ZERO;
437-
match arc.min_duration_sep() {
436+
let step_size = match arc.min_duration_sep() {
438437
Some(step_size) => step_size,
439438
None => {
440439
return Err(NyxError::CustomError(
@@ -451,12 +450,13 @@ where
451450
/// # Argument details
452451
/// + The measurements must be a list mapping the name of the measurement device to the measurement itself.
453452
/// + The name of all measurement devices must be present in the provided devices, i.e. the key set of `devices` must be a superset of the measurement device names present in the list.
453+
/// + The maximum step size to ensure we don't skip any measurements.
454454
#[allow(clippy::erasing_op)]
455455
pub fn process<Dev>(
456456
&mut self,
457457
measurements: &[(String, Msr)],
458458
devices: &mut HashMap<String, Dev>,
459-
step_size: Duration,
459+
max_step: Duration,
460460
) -> Result<(), NyxError>
461461
where
462462
Dev: TrackingDeviceSim<S, Msr>,
@@ -465,16 +465,19 @@ where
465465
measurements.len() >= 2,
466466
"must have at least two measurements"
467467
);
468+
469+
assert!(
470+
max_step.abs() > (0.0 * Unit::Nanosecond),
471+
"step size is zero"
472+
);
473+
468474
// Start by propagating the estimator (on the same thread).
469475
let num_msrs = measurements.len();
470476

471-
// Update the step size of the navigation propagator if it isn't already fixed step
472-
if !self.prop.fixed_step {
473-
self.prop.set_step(step_size, false);
474-
}
477+
self.prop.set_step(max_step, self.prop.fixed_step);
475478

476479
let prop_time = measurements[num_msrs - 1].1.epoch() - self.kf.previous_estimate().epoch();
477-
info!("Navigation propagating for a total of {prop_time} with step size {step_size}");
480+
info!("Navigation propagating for a total of {prop_time} with step size {max_step}");
478481

479482
let mut epoch = self.prop.state.epoch();
480483

@@ -501,16 +504,12 @@ where
501504
loop {
502505
let delta_t = next_msr_epoch - epoch;
503506

504-
// Propagator for the minimum time between the step size and the duration to the next measurement.
505-
// Ensure that we don't go backward if the previous step we took was indeed backward.
506-
let next_step_size = delta_t.min(if self.prop.details.step.is_negative() {
507-
step_size
508-
} else {
509-
self.prop.details.step
510-
});
507+
// Propagator for the minimum time between the maximum step size and the duration to the next measurement.
511508

512-
// Remove old states from the trajectory (this is a manual implementation of `retaint` because we know it's a sorted vec)
513-
// traj.states.retain(|state: &S| state.epoch() <= epoch);
509+
let next_step_size = delta_t.min(max_step);
510+
511+
// Remove old states from the trajectory
512+
// This is a manual implementation of `retaint` because we know it's a sorted vec, so no need to resort every time
514513
let mut index = traj.states.len();
515514
while index > 0 {
516515
index -= 1;
@@ -520,9 +519,14 @@ where
520519
}
521520
traj.states.truncate(index);
522521

523-
debug!("advancing propagator by {next_step_size} (Δt to next msr: {delta_t})");
522+
debug!("propagate for {next_step_size} (Δt to next msr: {delta_t})");
524523
let (_, traj_covar) = self.prop.for_duration_with_traj(next_step_size)?;
525524

525+
// Restore the step size if needed
526+
// if let Some(prev_step) = saved_step {
527+
// self.prop.set_step(prev_step, false);
528+
// }
529+
526530
for state in traj_covar.states {
527531
traj.states.push(S::extract(state));
528532
}

Diff for: tests/orbit_determination/two_body.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,8 @@ fn od_tb_val_ekf_fixed_step_perfect_stations() {
127127
println!("Final estimate:\n{est}");
128128
assert!(
129129
est.state_deviation().norm() < 1e-12,
130-
"In perfect modeling, the state deviation should be near zero"
130+
"In perfect modeling, the state deviation should be near zero, got {:.3e}",
131+
est.state_deviation().norm()
131132
);
132133
for i in 0..6 {
133134
assert!(
@@ -295,8 +296,9 @@ fn od_tb_val_with_arc() {
295296
let est = &odp.estimates[odp.estimates.len() - 1];
296297
println!("Final estimate:\n{est}");
297298
assert!(
298-
dbg!(est.state_deviation().norm()) < f64::EPSILON,
299-
"In perfect modeling, the state deviation should be near zero"
299+
est.state_deviation().norm() < f64::EPSILON,
300+
"In perfect modeling, the state deviation should be near zero, got {:.3e}",
301+
est.state_deviation().norm()
300302
);
301303
for i in 0..6 {
302304
assert!(

0 commit comments

Comments
 (0)