use crate::linalg::allocator::Allocator;
use crate::linalg::{DefaultAllocator, DimName};
use crate::md::trajectory::Interpolatable;
pub use crate::od::estimate::*;
pub use crate::od::*;
use anise::prelude::Almanac;
use log::info;
use msr::sensitivity::TrackerSensitivity;
use nalgebra::DimMin;
use std::ops::Add;
use super::ODSolution;
impl<StateType, EstType, MsrSize, Trk> ODSolution<StateType, EstType, MsrSize, Trk>
where
StateType: Interpolatable + Add<OVector<f64, <StateType as State>::Size>, Output = StateType>,
EstType: Estimate<StateType>,
MsrSize: DimName,
Trk: TrackerSensitivity<StateType, StateType>,
<StateType as State>::Size: DimMin<<StateType as State>::Size>,
<DefaultAllocator as Allocator<<StateType as State>::VecLength>>::Buffer<f64>: Send,
DefaultAllocator: Allocator<<StateType as State>::Size>
+ Allocator<<StateType as State>::VecLength>
+ Allocator<MsrSize>
+ Allocator<MsrSize, <StateType as State>::Size>
+ Allocator<MsrSize, MsrSize>
+ Allocator<<StateType as State>::Size, <StateType as State>::Size>
+ Allocator<<StateType as State>::Size, MsrSize>
+ Allocator<<<StateType as State>::Size as DimMin<<StateType as State>::Size>>::Output>,
{
pub fn smooth(self, almanac: &Almanac) -> Result<Self, ODError>
where
<StateType as State>::Size:
DimMin<<StateType as State>::Size, Output = <StateType as State>::Size>,
{
let l = self.estimates.len() - 1;
let mut smoothed = Self {
estimates: Vec::with_capacity(self.estimates.len()),
residuals: Vec::with_capacity(self.residuals.len()),
gains: Vec::with_capacity(self.estimates.len()),
filter_smoother_ratios: Vec::with_capacity(self.estimates.len()),
devices: self.devices.clone(),
measurement_types: self.measurement_types.clone(),
};
smoothed
.estimates
.push(self.estimates.last().unwrap().clone());
smoothed
.residuals
.push(self.residuals.last().unwrap().clone());
smoothed.gains.push(None);
smoothed.filter_smoother_ratios.push(None);
loop {
let k = l - smoothed.estimates.len();
let sm_est_kp1 = &self.estimates[k + 1];
let x_kp1_l = sm_est_kp1.state_deviation();
let p_kp1_l = sm_est_kp1.covar();
let est_k = &self.estimates[k];
let est_kp1 = &self.estimates[k + 1];
let phi_kp1_k = est_kp1
.stm()
.clone()
.lu()
.try_inverse()
.ok_or(ODError::SingularStateTransitionMatrix)?;
let x_k_l = &phi_kp1_k * x_kp1_l;
let p_k_l = &phi_kp1_k * p_kp1_l * &phi_kp1_k.transpose();
let mut smoothed_est_k = est_k.clone();
smoothed_est_k.set_state_deviation(x_k_l);
smoothed_est_k.set_covar(p_k_l);
if let Some(mut residual) = self.residuals[k + 1].clone() {
let tracker = residual
.tracker
.as_ref()
.expect("tracker unset in smoother process");
let device = smoothed
.devices
.get_mut(tracker)
.expect("unknown tracker in smoother process");
let new_state_est = smoothed_est_k.state();
let epoch = new_state_est.epoch();
if let Some(computed_meas) =
device.measure_instantaneous(new_state_est, None, almanac)?
{
residual.computed_obs = computed_meas
.observation::<MsrSize>(&residual.msr_types)
- device.measurement_bias_vector::<MsrSize>(&residual.msr_types, epoch)?;
residual.postfit = &residual.real_obs - &residual.computed_obs;
smoothed.residuals.push(Some(residual));
} else {
smoothed.residuals.push(None);
}
} else {
smoothed.residuals.push(None);
}
let delta_covar = est_k.covar() - smoothed_est_k.covar();
let delta_state =
est_k.state().to_state_vector() - smoothed_est_k.state().to_state_vector();
let fs_ratios = OVector::<f64, <StateType as State>::Size>::from_iterator(
delta_state
.iter()
.enumerate()
.map(|(i, dx)| dx / delta_covar[(i, i)].sqrt()),
);
smoothed.estimates.push(smoothed_est_k);
smoothed.filter_smoother_ratios.push(Some(fs_ratios));
smoothed.gains.push(None);
if smoothed.estimates.len() == self.estimates.len() {
break;
}
}
info!(
"Smoothed {} estimates (from {} to {})",
smoothed.estimates.len(),
smoothed.estimates.last().unwrap().epoch(),
smoothed.estimates[0].epoch(),
);
if smoothed.estimates.len() < self.estimates.len() {
let mut k = self.estimates.len() - smoothed.estimates.len();
loop {
smoothed.estimates.push(self.estimates[k].clone());
if k == 0 {
break;
}
k -= 1;
}
}
smoothed.estimates.reverse();
smoothed.residuals.reverse();
smoothed.filter_smoother_ratios.reverse();
Ok(smoothed)
}
}