#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) struct ParameterLayout {
geometry: usize,
clocks: usize,
ztd: usize,
tropo_gradients: usize,
residual_ionosphere: usize,
ambiguities: usize,
}
impl ParameterLayout {
pub(crate) const fn spp(clocks: usize) -> Self {
Self {
geometry: 3,
clocks,
ztd: 0,
tropo_gradients: 0,
residual_ionosphere: 0,
ambiguities: 0,
}
}
pub(crate) const fn rtk(ambiguities: usize) -> Self {
Self {
geometry: 3,
clocks: 0,
ztd: 0,
tropo_gradients: 0,
residual_ionosphere: 0,
ambiguities,
}
}
pub(crate) const fn ppp(
epoch_clocks: usize,
ztd: usize,
tropo_gradients: usize,
residual_ionosphere: usize,
ambiguities: usize,
) -> Self {
Self {
geometry: 3,
clocks: epoch_clocks,
ztd,
tropo_gradients,
residual_ionosphere,
ambiguities,
}
}
pub(crate) const fn dim(&self) -> usize {
self.geometry
+ self.clocks
+ self.ztd
+ self.tropo_gradients
+ self.residual_ionosphere
+ self.ambiguities
}
#[cfg(test)]
pub(crate) const fn ambiguity_offset(&self) -> usize {
self.geometry + self.clocks + self.ztd + self.tropo_gradients + self.residual_ionosphere
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub(crate) struct UndifferencedDesignOptions {
pub(crate) ztd_mapping: Option<f64>,
pub(crate) tropo_gradient_mapping: Option<[f64; 2]>,
pub(crate) residual_ionosphere_columns: usize,
pub(crate) active_residual_ionosphere: Option<(usize, f64)>,
pub(crate) ambiguity_columns: usize,
pub(crate) active_ambiguity: Option<usize>,
}
pub(crate) fn undifferenced_design_row(
los_base: [f64; 3],
epoch_idx: usize,
n_epochs: usize,
options: UndifferencedDesignOptions,
) -> Vec<f64> {
let mut row = vec![los_base[0], los_base[1], los_base[2]];
row.extend((0..n_epochs).map(|idx| if idx == epoch_idx { 1.0 } else { 0.0 }));
if let Some(mapping) = options.ztd_mapping {
row.push(mapping);
}
if let Some(mapping) = options.tropo_gradient_mapping {
row.extend(mapping);
}
row.extend((0..options.residual_ionosphere_columns).map(|idx| {
if let Some((active, coefficient)) = options.active_residual_ionosphere {
if idx == active {
return coefficient;
}
}
0.0
}));
row.extend((0..options.ambiguity_columns).map(|idx| {
if Some(idx) == options.active_ambiguity {
1.0
} else {
0.0
}
}));
row
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn dims_match_open_coded_unknown_counts() {
assert_eq!(ParameterLayout::spp(1).dim(), 4);
assert_eq!(ParameterLayout::spp(2).dim(), 5);
assert_eq!(ParameterLayout::rtk(0).dim(), 3);
assert_eq!(ParameterLayout::rtk(7).dim(), 10);
assert_eq!(ParameterLayout::ppp(5, 0, 0, 0, 4).dim(), 12);
assert_eq!(ParameterLayout::ppp(5, 1, 0, 0, 4).dim(), 13);
assert_eq!(ParameterLayout::ppp(5, 1, 2, 0, 4).dim(), 15);
assert_eq!(ParameterLayout::ppp(5, 1, 2, 3, 4).dim(), 18);
}
#[test]
fn ambiguity_offset_follows_geometry_clocks_ztd() {
assert_eq!(
ParameterLayout::ppp(5, 1, 2, 3, 4).ambiguity_offset(),
3 + 5 + 1 + 2 + 3
);
assert_eq!(ParameterLayout::rtk(7).ambiguity_offset(), 3);
}
#[test]
fn undifferenced_design_row_lays_columns_in_layout_order() {
let float_phase = undifferenced_design_row(
[-0.1, -0.2, -0.3],
1,
2,
UndifferencedDesignOptions {
ztd_mapping: Some(1.5),
tropo_gradient_mapping: Some([0.4, -0.7]),
residual_ionosphere_columns: 3,
active_residual_ionosphere: Some((2, -1.0)),
ambiguity_columns: 3,
active_ambiguity: Some(2),
},
);
assert_eq!(
float_phase,
vec![-0.1, -0.2, -0.3, 0.0, 1.0, 1.5, 0.4, -0.7, 0.0, 0.0, -1.0, 0.0, 0.0, 1.0]
);
let float_code = undifferenced_design_row(
[-0.1, -0.2, -0.3],
1,
2,
UndifferencedDesignOptions {
ztd_mapping: Some(1.5),
tropo_gradient_mapping: Some([0.4, -0.7]),
residual_ionosphere_columns: 3,
active_residual_ionosphere: Some((2, 1.0)),
ambiguity_columns: 3,
active_ambiguity: None,
},
);
assert_eq!(
float_code,
vec![-0.1, -0.2, -0.3, 0.0, 1.0, 1.5, 0.4, -0.7, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0]
);
let fixed = undifferenced_design_row(
[-0.1, -0.2, -0.3],
0,
2,
UndifferencedDesignOptions {
ztd_mapping: None,
tropo_gradient_mapping: None,
residual_ionosphere_columns: 0,
active_residual_ionosphere: None,
ambiguity_columns: 0,
active_ambiguity: None,
},
);
assert_eq!(fixed, vec![-0.1, -0.2, -0.3, 1.0, 0.0]);
}
}