use super::serde::ser::SerializeSeq;
use super::serde::{Serialize, Serializer};
use super::serde_derive::Deserialize;
use super::EpochFormat;
use crate::cosmic::{Cosm, Frame, Orbit};
use crate::linalg::allocator::Allocator;
use crate::linalg::DefaultAllocator;
use crate::md::StateParameter;
use crate::od::estimate::NavSolution;
use crate::{NyxError, State};
use std::cmp::PartialEq;
use std::collections::HashMap;
use std::fmt;
use std::str::FromStr;
use std::sync::Arc;
#[derive(Deserialize)]
pub struct OutputSerde {
pub filename: String,
pub headers: Option<Vec<String>>,
}
impl OutputSerde {
pub fn to_state_formatter(&self, cosm: Arc<Cosm>) -> Result<StateFormatter, NyxError> {
match &self.headers {
Some(hdr) => StateFormatter::from_headers(
hdr.iter().map(|s| s.as_str()).collect::<Vec<&str>>(),
self.filename.clone(),
cosm,
),
None => Ok(StateFormatter::default(self.filename.clone(), cosm)),
}
}
pub fn to_nav_sol_formatter(&self, cosm: Arc<Cosm>) -> Result<NavSolutionFormatter, NyxError> {
match &self.headers {
Some(hdr) => {
NavSolutionFormatter::from_headers(hdr.to_vec(), self.filename.clone(), cosm)
}
None => Ok(NavSolutionFormatter::default(self.filename.clone(), cosm)),
}
}
}
#[allow(non_camel_case_types)]
#[derive(Clone, Debug, PartialEq)]
pub struct StateHeader {
pub param: StateParameter,
pub frame_name: Option<String>,
pub epoch_fmt: Option<EpochFormat>,
}
impl From<StateParameter> for StateHeader {
fn from(param: StateParameter) -> Self {
StateHeader {
param,
frame_name: None,
epoch_fmt: if param == StateParameter::Epoch {
Some(EpochFormat::GregorianUtc)
} else {
None
},
}
}
}
impl fmt::Display for StateHeader {
fn fmt(&self, fh: &mut fmt::Formatter) -> fmt::Result {
let fmtd = match self.param {
StateParameter::X
| StateParameter::Y
| StateParameter::Z
| StateParameter::ApoapsisRadius
| StateParameter::PeriapsisRadius
| StateParameter::GeodeticHeight
| StateParameter::SemiMinorAxis
| StateParameter::SemiParameter
| StateParameter::SMA
| StateParameter::Rmag => {
format!("{:?} (km)", self.param)
}
StateParameter::VX | StateParameter::VY | StateParameter::VZ | StateParameter::Vmag => {
format!("{:?} (km/s)", self.param)
}
StateParameter::AoL
| StateParameter::AoP
| StateParameter::Declination
| StateParameter::EccentricAnomaly
| StateParameter::GeodeticLatitude
| StateParameter::GeodeticLongitude
| StateParameter::Inclination
| StateParameter::MeanAnomaly
| StateParameter::RightAscension
| StateParameter::RAAN
| StateParameter::TrueAnomaly
| StateParameter::TrueLongitude => {
format!("{:?} (deg)", self.param)
}
_ => format!("{:?}", self.param),
};
write!(fh, "{}", fmtd)?;
if let Some(frame) = &self.frame_name {
write!(fh, ":{}", frame)?;
} else if let Some(epoch_fmt) = self.epoch_fmt {
write!(fh, ":{:?}", epoch_fmt)?;
}
Ok(())
}
}
impl Serialize for StateHeader {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&format!("{}", self))
}
}
#[allow(non_camel_case_types)]
#[derive(Clone, Debug, PartialEq)]
pub enum NavSolutionHeader {
Epoch(EpochFormat),
EstimatedState(Vec<StateHeader>),
NominalState(Vec<StateHeader>),
Delta_x,
Delta_y,
Delta_z,
Delta_vx,
Delta_vy,
Delta_vz,
Cx_x { frame: Option<String> },
Cy_x { frame: Option<String> },
Cy_y { frame: Option<String> },
Cz_x { frame: Option<String> },
Cz_y { frame: Option<String> },
Cz_z { frame: Option<String> },
Cx_dot_x { frame: Option<String> },
Cx_dot_y { frame: Option<String> },
Cx_dot_z { frame: Option<String> },
Cx_dot_x_dot { frame: Option<String> },
Cy_dot_x { frame: Option<String> },
Cy_dot_y { frame: Option<String> },
Cy_dot_z { frame: Option<String> },
Cy_dot_x_dot { frame: Option<String> },
Cy_dot_y_dot { frame: Option<String> },
Cz_dot_x { frame: Option<String> },
Cz_dot_y { frame: Option<String> },
Cz_dot_z { frame: Option<String> },
Cz_dot_x_dot { frame: Option<String> },
Cz_dot_y_dot { frame: Option<String> },
Cz_dot_z_dot { frame: Option<String> },
Prediction,
Covar_pos,
Covar_vel,
}
impl fmt::Display for NavSolutionHeader {
fn fmt(&self, fh: &mut fmt::Formatter) -> fmt::Result {
match self {
NavSolutionHeader::Epoch(efmt) => write!(fh, "Epoch:{:?}", efmt),
NavSolutionHeader::EstimatedState(hdr) => {
let mut seq = Vec::with_capacity(hdr.len());
for element in hdr {
seq.push(format!("Estimate:{}", element));
}
write!(fh, "{}", seq.join(","))
}
NavSolutionHeader::NominalState(hdr) => {
let mut seq = Vec::with_capacity(hdr.len());
for element in hdr {
seq.push(format!("Nominal:{}", element));
}
write!(fh, "{}", seq.join(","))
}
NavSolutionHeader::Delta_x => write!(fh, "delta_x"),
NavSolutionHeader::Delta_y => write!(fh, "delta_y"),
NavSolutionHeader::Delta_z => write!(fh, "delta_z"),
NavSolutionHeader::Delta_vx => write!(fh, "delta_vx"),
NavSolutionHeader::Delta_vy => write!(fh, "delta_vy"),
NavSolutionHeader::Delta_vz => write!(fh, "delta_vz"),
NavSolutionHeader::Cx_x { frame } => {
if let Some(f) = frame {
write!(fh, "cx_x:{}", f)
} else {
write!(fh, "cx_x")
}
}
NavSolutionHeader::Cy_x { frame } => {
if let Some(f) = frame {
write!(fh, "cy_x:{}", f)
} else {
write!(fh, "cy_x")
}
}
NavSolutionHeader::Cy_y { frame } => {
if let Some(f) = frame {
write!(fh, "cy_y:{}", f)
} else {
write!(fh, "cy_y")
}
}
NavSolutionHeader::Cz_x { frame } => {
if let Some(f) = frame {
write!(fh, "cz_x:{}", f)
} else {
write!(fh, "cz_x")
}
}
NavSolutionHeader::Cz_y { frame } => {
if let Some(f) = frame {
write!(fh, "cz_y:{}", f)
} else {
write!(fh, "cz_y")
}
}
NavSolutionHeader::Cz_z { frame } => {
if let Some(f) = frame {
write!(fh, "cz_z:{}", f)
} else {
write!(fh, "cz_z")
}
}
NavSolutionHeader::Cx_dot_x { frame } => {
if let Some(f) = frame {
write!(fh, "cx_dot_x:{}", f)
} else {
write!(fh, "cx_dot_x")
}
}
NavSolutionHeader::Cx_dot_y { frame } => {
if let Some(f) = frame {
write!(fh, "cx_dot_y:{}", f)
} else {
write!(fh, "cx_dot_y")
}
}
NavSolutionHeader::Cx_dot_z { frame } => {
if let Some(f) = frame {
write!(fh, "cx_dot_z:{}", f)
} else {
write!(fh, "cx_dot_z")
}
}
NavSolutionHeader::Cx_dot_x_dot { frame } => {
if let Some(f) = frame {
write!(fh, "cx_dot_x_dot:{}", f)
} else {
write!(fh, "cx_dot_x_dot")
}
}
NavSolutionHeader::Cy_dot_x { frame } => {
if let Some(f) = frame {
write!(fh, "cy_dot_x:{}", f)
} else {
write!(fh, "cy_dot_x")
}
}
NavSolutionHeader::Cy_dot_y { frame } => {
if let Some(f) = frame {
write!(fh, "cy_dot_y:{}", f)
} else {
write!(fh, "cy_dot_y")
}
}
NavSolutionHeader::Cy_dot_z { frame } => {
if let Some(f) = frame {
write!(fh, "cy_dot_z:{}", f)
} else {
write!(fh, "cy_dot_z")
}
}
NavSolutionHeader::Cy_dot_x_dot { frame } => {
if let Some(f) = frame {
write!(fh, "cy_dot_x_dot:{}", f)
} else {
write!(fh, "cy_dot_x_dot")
}
}
NavSolutionHeader::Cy_dot_y_dot { frame } => {
if let Some(f) = frame {
write!(fh, "cy_dot_y_dot:{}", f)
} else {
write!(fh, "cy_dot_y_dot")
}
}
NavSolutionHeader::Cz_dot_x { frame } => {
if let Some(f) = frame {
write!(fh, "cz_dot_x:{}", f)
} else {
write!(fh, "cz_dot_x")
}
}
NavSolutionHeader::Cz_dot_y { frame } => {
if let Some(f) = frame {
write!(fh, "cz_dot_y:{}", f)
} else {
write!(fh, "cz_dot_y")
}
}
NavSolutionHeader::Cz_dot_z { frame } => {
if let Some(f) = frame {
write!(fh, "cz_dot_z:{}", f)
} else {
write!(fh, "cz_dot_z")
}
}
NavSolutionHeader::Cz_dot_x_dot { frame } => {
if let Some(f) = frame {
write!(fh, "cz_dot_x_dot:{}", f)
} else {
write!(fh, "cz_dot_x_dot")
}
}
NavSolutionHeader::Cz_dot_y_dot { frame } => {
if let Some(f) = frame {
write!(fh, "cz_dot_y_dot:{}", f)
} else {
write!(fh, "cz_dot_y_dot")
}
}
NavSolutionHeader::Cz_dot_z_dot { frame } => {
if let Some(f) = frame {
write!(fh, "cz_dot_z_dot:{}", f)
} else {
write!(fh, "cz_dot_z_dot")
}
}
NavSolutionHeader::Prediction => write!(fh, "prediction"),
NavSolutionHeader::Covar_pos => write!(fh, "covar_position"),
NavSolutionHeader::Covar_vel => write!(fh, "covar_velocity"),
}
}
}
impl Serialize for NavSolutionHeader {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
NavSolutionHeader::EstimatedState(hdr) => {
let mut seq = serializer.serialize_seq(Some(hdr.len()))?;
for element in hdr {
seq.serialize_element(&format!("Estimate:{}", element))?;
}
seq.end()
}
NavSolutionHeader::NominalState(hdr) => {
let mut seq = serializer.serialize_seq(Some(hdr.len()))?;
for element in hdr {
seq.serialize_element(&format!("Nominal:{}", element))?;
}
seq.end()
}
_ => serializer.serialize_str(&format!("{}", self)),
}
}
}
#[derive(Clone)]
pub struct StateFormatter {
pub filename: String,
pub headers: Vec<StateHeader>,
frames: HashMap<String, Frame>,
cosm: Arc<Cosm>,
}
impl StateFormatter {
pub fn from_headers(
headers: Vec<&str>,
filename: String,
cosm: Arc<Cosm>,
) -> Result<Self, NyxError> {
let mut frames = HashMap::new();
let mut hdrs = Vec::with_capacity(20);
for hdr in &headers {
let splt: Vec<&str> = hdr.split(':').collect();
match splt[0].to_lowercase().as_str() {
"epoch" => {
let epoch_fmt = if splt.len() == 2 {
match EpochFormat::from_str(splt[1]) {
Ok(e) => e,
Err(_) => {
return Err(NyxError::LoadingError(format!(
"Unknown epoch format {}",
splt[1]
)))
}
}
} else {
EpochFormat::GregorianUtc
};
let hdr = StateHeader {
param: StateParameter::Epoch,
frame_name: None,
epoch_fmt: Some(epoch_fmt),
};
hdrs.push(hdr);
}
_ => {
let frame_name = if splt.len() == 2 {
Some(splt[1].to_owned())
} else {
None
};
let param = StateParameter::from_str(splt[0].to_lowercase().as_str())?;
let hdr = StateHeader {
param,
frame_name,
epoch_fmt: None,
};
hdrs.push(hdr);
}
}
if splt.len() == 2 && splt[0].to_lowercase() != "epoch" {
match splt[1].to_lowercase().as_str() {
"ric" => frames.insert(splt[1].to_string(), Frame::RIC),
"rcn" => frames.insert(splt[1].to_string(), Frame::RCN),
"vnc" => frames.insert(splt[1].to_string(), Frame::VNC),
_ => frames.insert(splt[1].to_string(), cosm.try_frame(splt[1])?),
};
}
}
Ok(Self {
filename,
headers: hdrs,
frames,
cosm,
})
}
pub fn default(filename: String, cosm: Arc<Cosm>) -> Self {
Self {
filename,
headers: vec![
From::from(StateParameter::Epoch),
From::from(StateParameter::X),
From::from(StateParameter::Y),
From::from(StateParameter::Z),
From::from(StateParameter::VX),
From::from(StateParameter::VY),
From::from(StateParameter::VZ),
],
frames: HashMap::new(),
cosm,
}
}
pub fn fmt(&self, orbit: &Orbit) -> Vec<String> {
let mut mapped = HashMap::new();
for (name, frame) in &self.frames {
let mapped_orbit = match frame {
Frame::RCN | Frame::RIC | Frame::VNC => {
orbit.with_position_rotated_by(orbit.dcm_from_traj_frame(*frame).unwrap())
}
_ => self.cosm.frame_chg(orbit, *frame),
};
mapped.insert(name.to_lowercase(), mapped_orbit);
}
let mut formatted = Vec::with_capacity(self.headers.len());
for hdr in &self.headers {
let orbit = if hdr.frame_name.is_some() {
&mapped[&hdr.frame_name.as_ref().unwrap().to_lowercase()]
} else {
orbit
};
formatted.push(match hdr.param {
StateParameter::Epoch => hdr.epoch_fmt.as_ref().unwrap().format(orbit.dt),
_ => match orbit.value(&hdr.param) {
Ok(value) => format!("{:.16}", value),
Err(e) => {
unimplemented!("{:?} cannot yet be formatted (yet): {}", hdr.param, e)
}
},
});
}
formatted
}
}
pub struct NavSolutionFormatter {
pub filename: String,
pub headers: Vec<NavSolutionHeader>,
pub estimated_headers: StateFormatter,
pub nominal_headers: StateFormatter,
frames: HashMap<String, Frame>,
cosm: Arc<Cosm>,
}
impl NavSolutionFormatter {
pub fn from_headers(
headers: Vec<String>,
filename: String,
cosm: Arc<Cosm>,
) -> Result<Self, NyxError> {
let mut frames = HashMap::new();
let mut hdrs = Vec::with_capacity(40);
let mut est_hdrs = Vec::with_capacity(20);
let mut nom_hdrs = Vec::with_capacity(20);
for hdr in &headers {
let lowered = hdr.to_lowercase();
let splt: Vec<&str> = lowered.split(':').collect();
let frame_name = if splt.len() == 3 {
let name = splt[2].to_owned();
frames.insert(name.clone(), cosm.try_frame(&name)?);
Some(name)
} else if splt.len() == 2
&& splt[0].to_lowercase() != "epoch"
&& splt[0].to_lowercase() != "nominal"
&& splt[0].to_lowercase() != "estimate"
{
match splt[1].to_lowercase().as_str() {
"ric" => frames.insert(splt[1].to_string(), Frame::RIC),
"rcn" => frames.insert(splt[1].to_string(), Frame::RCN),
"vnc" => frames.insert(splt[1].to_string(), Frame::VNC),
_ => {
if let Ok(frame) = cosm.try_frame(splt[1]) {
frames.insert(splt[1].to_string(), frame)
} else {
None
}
}
};
Some(splt[1].to_string())
} else {
None
};
match splt[0].to_lowercase().as_str() {
"epoch" => {
hdrs.push(NavSolutionHeader::Epoch(if splt.len() == 2 {
EpochFormat::from_str(splt[1]).unwrap()
} else {
EpochFormat::GregorianUtc
}));
}
"delta_x" => hdrs.push(NavSolutionHeader::Delta_x),
"delta_y" => hdrs.push(NavSolutionHeader::Delta_y),
"delta_z" => hdrs.push(NavSolutionHeader::Delta_z),
"delta_vx" => hdrs.push(NavSolutionHeader::Delta_vx),
"delta_vy" => hdrs.push(NavSolutionHeader::Delta_vy),
"delta_vz" => hdrs.push(NavSolutionHeader::Delta_vz),
"cx_x" => hdrs.push(NavSolutionHeader::Cx_x { frame: frame_name }),
"cy_x" => hdrs.push(NavSolutionHeader::Cy_x { frame: frame_name }),
"cy_y" => hdrs.push(NavSolutionHeader::Cy_y { frame: frame_name }),
"cz_x" => hdrs.push(NavSolutionHeader::Cz_x { frame: frame_name }),
"cz_y" => hdrs.push(NavSolutionHeader::Cz_y { frame: frame_name }),
"cz_z" => hdrs.push(NavSolutionHeader::Cz_z { frame: frame_name }),
"cx_dot_x" => hdrs.push(NavSolutionHeader::Cx_dot_x { frame: frame_name }),
"cx_dot_y" => hdrs.push(NavSolutionHeader::Cx_dot_y { frame: frame_name }),
"cx_dot_z" => hdrs.push(NavSolutionHeader::Cx_dot_z { frame: frame_name }),
"cx_dot_x_dot" => hdrs.push(NavSolutionHeader::Cx_dot_x_dot { frame: frame_name }),
"cy_dot_x" => hdrs.push(NavSolutionHeader::Cy_dot_x { frame: frame_name }),
"cy_dot_y" => hdrs.push(NavSolutionHeader::Cy_dot_y { frame: frame_name }),
"cy_dot_z" => hdrs.push(NavSolutionHeader::Cy_dot_z { frame: frame_name }),
"cy_dot_x_dot" => hdrs.push(NavSolutionHeader::Cy_dot_x_dot { frame: frame_name }),
"cy_dot_y_dot" => hdrs.push(NavSolutionHeader::Cy_dot_y_dot { frame: frame_name }),
"cz_dot_x" => hdrs.push(NavSolutionHeader::Cz_dot_x { frame: frame_name }),
"cz_dot_y" => hdrs.push(NavSolutionHeader::Cz_dot_y { frame: frame_name }),
"cz_dot_z" => hdrs.push(NavSolutionHeader::Cz_dot_z { frame: frame_name }),
"cz_dot_x_dot" => hdrs.push(NavSolutionHeader::Cz_dot_x_dot { frame: frame_name }),
"cz_dot_y_dot" => hdrs.push(NavSolutionHeader::Cz_dot_y_dot { frame: frame_name }),
"cz_dot_z_dot" => hdrs.push(NavSolutionHeader::Cz_dot_z_dot { frame: frame_name }),
"prediction" => hdrs.push(NavSolutionHeader::Prediction),
"covar_position" => hdrs.push(NavSolutionHeader::Covar_pos),
"covar_velocity" => hdrs.push(NavSolutionHeader::Covar_vel),
"estimate" | "nominal" => {
let param = StateParameter::from_str(splt[1].to_lowercase().as_str())
.expect("Unknown paramater");
let state_hdr = StateHeader {
param,
frame_name,
epoch_fmt: None,
};
if splt[0] == "estimate" {
est_hdrs.push(state_hdr);
} else {
nom_hdrs.push(state_hdr);
}
}
_ => {
return Err(NyxError::CustomError(format!(
"unknown header `{}`",
splt[0]
)))
}
}
}
hdrs.push(NavSolutionHeader::EstimatedState(est_hdrs.clone()));
hdrs.push(NavSolutionHeader::NominalState(nom_hdrs.clone()));
Ok(Self {
filename,
headers: hdrs,
nominal_headers: StateFormatter {
filename: "file_should_not_exist".to_owned(),
headers: nom_hdrs,
frames: frames.clone(),
cosm: cosm.clone(),
},
estimated_headers: StateFormatter {
filename: "file_should_not_exist".to_owned(),
headers: est_hdrs,
frames: frames.clone(),
cosm: cosm.clone(),
},
frames,
cosm,
})
}
pub fn default(filename: String, cosm: Arc<Cosm>) -> Self {
let est_hdrs = vec![
From::from(StateParameter::X),
From::from(StateParameter::Y),
From::from(StateParameter::Z),
From::from(StateParameter::VX),
From::from(StateParameter::VY),
From::from(StateParameter::VZ),
];
Self {
filename,
headers: vec![
NavSolutionHeader::Epoch(EpochFormat::GregorianTai),
NavSolutionHeader::Delta_x,
NavSolutionHeader::Delta_y,
NavSolutionHeader::Delta_z,
NavSolutionHeader::Delta_vx,
NavSolutionHeader::Delta_vy,
NavSolutionHeader::Delta_vz,
NavSolutionHeader::Cx_x { frame: None },
NavSolutionHeader::Cy_y { frame: None },
NavSolutionHeader::Cz_z { frame: None },
NavSolutionHeader::Cx_dot_x_dot { frame: None },
NavSolutionHeader::Cy_dot_y_dot { frame: None },
NavSolutionHeader::Cz_dot_z_dot { frame: None },
NavSolutionHeader::EstimatedState(est_hdrs.clone()),
NavSolutionHeader::Prediction,
],
nominal_headers: StateFormatter {
filename: "file_should_not_exist".to_owned(),
headers: Vec::new(),
frames: HashMap::new(),
cosm: cosm.clone(),
},
estimated_headers: StateFormatter {
filename: "file_should_not_exist".to_owned(),
headers: est_hdrs,
frames: HashMap::new(),
cosm: cosm.clone(),
},
frames: HashMap::new(),
cosm,
}
}
pub fn fmt<T: State, S: NavSolution<T>>(&self, sol: &S) -> Vec<String>
where
DefaultAllocator: Allocator<f64, <T as State>::Size>
+ Allocator<f64, <T as State>::Size, <T as State>::Size>
+ Allocator<f64, <T as State>::VecLength>,
{
let mut dcms = HashMap::new();
let orbit = sol.orbital_state();
for (name, frame) in &self.frames {
let mapping_dcm = match frame {
Frame::RCN | Frame::RIC | Frame::VNC => {
orbit.dcm6x6_from_traj_frame(*frame).unwrap()
}
_ => self
.cosm
.try_dcm_from_to(&orbit.frame, frame, orbit.dt)
.unwrap(),
};
dcms.insert(name.to_lowercase(), mapping_dcm);
}
let mut formatted = Vec::new();
for hdr in &self.headers {
match hdr {
NavSolutionHeader::EstimatedState(_) => {
for fmtval in self.estimated_headers.fmt(&sol.orbital_state()) {
formatted.push(fmtval);
}
}
NavSolutionHeader::NominalState(_) => {
for fmtval in self.nominal_headers.fmt(&sol.expected_state()) {
formatted.push(fmtval);
}
}
NavSolutionHeader::Epoch(efmt) => formatted.push(efmt.format(sol.epoch())),
NavSolutionHeader::Delta_x => {
formatted.push(format!("{:.16e}", sol.state_deviation()[0]))
}
NavSolutionHeader::Delta_y => {
formatted.push(format!("{:.16e}", sol.state_deviation()[1]))
}
NavSolutionHeader::Delta_z => {
formatted.push(format!("{:.16e}", sol.state_deviation()[2]))
}
NavSolutionHeader::Delta_vx => {
formatted.push(format!("{:.16e}", sol.state_deviation()[3]))
}
NavSolutionHeader::Delta_vy => {
formatted.push(format!("{:.16e}", sol.state_deviation()[4]))
}
NavSolutionHeader::Delta_vz => {
formatted.push(format!("{:.16e}", sol.state_deviation()[5]))
}
NavSolutionHeader::Cx_x { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(0, 0)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(0, 0))),
},
NavSolutionHeader::Cy_x { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(1, 0)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(1, 0))),
},
NavSolutionHeader::Cy_y { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(1, 1)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(1, 1))),
},
NavSolutionHeader::Cz_x { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(2, 0)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(2, 0))),
},
NavSolutionHeader::Cz_y { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(2, 1)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(2, 1))),
},
NavSolutionHeader::Cz_z { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(2, 2)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(2, 2))),
},
NavSolutionHeader::Cx_dot_x { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(3, 0)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(3, 0))),
},
NavSolutionHeader::Cx_dot_y { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(3, 1)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(3, 1))),
},
NavSolutionHeader::Cx_dot_z { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(3, 2)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(3, 2))),
},
NavSolutionHeader::Cx_dot_x_dot { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(3, 3)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(3, 3))),
},
NavSolutionHeader::Cy_dot_x { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(4, 0)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(4, 0))),
},
NavSolutionHeader::Cy_dot_y { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(4, 1)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(4, 1))),
},
NavSolutionHeader::Cy_dot_z { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(4, 2)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(4, 2))),
},
NavSolutionHeader::Cy_dot_x_dot { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(4, 3)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(4, 3))),
},
NavSolutionHeader::Cy_dot_y_dot { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(4, 4)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(4, 4))),
},
NavSolutionHeader::Cz_dot_x { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(5, 0)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(5, 0))),
},
NavSolutionHeader::Cz_dot_y { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(5, 1)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(5, 1))),
},
NavSolutionHeader::Cz_dot_z { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(5, 2)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(5, 2))),
},
NavSolutionHeader::Cz_dot_x_dot { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(5, 3)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(5, 3))),
},
NavSolutionHeader::Cz_dot_y_dot { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(5, 4)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(5, 4))),
},
NavSolutionHeader::Cz_dot_z_dot { frame } => match frame {
Some(frame_name) => {
let covar = dcms[frame_name] * sol.covar() * dcms[frame_name].transpose();
formatted.push(format!("{:.16e}", covar[(5, 5)]))
}
None => formatted.push(format!("{:.16e}", sol.covar_ij(5, 5))),
},
NavSolutionHeader::Prediction => formatted.push(format!("{}", sol.predicted())),
NavSolutionHeader::Covar_pos => formatted.push(format!(
"{:.16e}",
(sol.covar_ij(0, 0).powi(2)
+ sol.covar_ij(1, 1).powi(2)
+ sol.covar_ij(2, 2).powi(2))
.sqrt()
)),
NavSolutionHeader::Covar_vel => formatted.push(format!(
"{:.16e}",
(sol.covar_ij(3, 3).powi(2)
+ sol.covar_ij(4, 4).powi(2)
+ sol.covar_ij(5, 5).powi(2))
.sqrt()
)),
};
}
formatted
}
}