use crate::linalg::allocator::Allocator;
use crate::linalg::{DefaultAllocator, DimName, OMatrix};
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 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>,
<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>,
{
pub fn smooth(self, almanac: &Almanac) -> Result<Self, ODError> {
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 = match est_kp1.stm().clone().udu() {
Some(stm_udu) => {
match stm_udu.u.try_inverse() {
None => return Err(ODError::SingularStateTransitionMatrix),
Some(u_inv) => {
let d_inv = OMatrix::from_diagonal(&OVector::<
f64,
<StateType as State>::Size,
>::from_iterator(
stm_udu.d.iter().map(|d_ii| 1.0 / d_ii),
));
let y = d_inv * &u_inv;
u_inv.transpose() * y
}
}
}
None => return Err(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)
}
}