nyx_space/od/msr/
measurement.rs1use super::MeasurementType;
20use hifitime::Epoch;
21use indexmap::{IndexMap, IndexSet};
22use log::debug;
23use nalgebra::{DefaultAllocator, DimName, OVector, allocator::Allocator};
24use std::fmt;
25
26#[cfg(feature = "python")]
27use pyo3::prelude::*;
28
29#[cfg_attr(
34 feature = "python",
35 pyclass(from_py_object),
36 pyo3(module = "nyx_space.od")
37)]
38#[derive(Clone, Debug)]
39pub struct Measurement {
40 pub tracker: String,
42 pub epoch: Epoch,
44 pub data: IndexMap<MeasurementType, f64>,
46 pub rejected: bool,
48}
49
50#[cfg_attr(feature = "python", pymethods)]
51impl Measurement {
52 pub fn correct(&mut self, msr_type: MeasurementType, correction: f64) {
54 if let Some(cur_value) = self.data.get_mut(&msr_type) {
55 let new_value = *cur_value + correction;
56 debug!("corrected {msr_type:?} from {cur_value} to {new_value}");
57 *cur_value = new_value;
58 }
59 }
60
61 pub fn push(&mut self, msr_type: MeasurementType, msr_value: f64) {
62 self.data.insert(msr_type, msr_value);
63 }
64}
65
66impl Measurement {
67 pub fn new(tracker: String, epoch: Epoch) -> Self {
68 Self {
69 tracker,
70 epoch,
71 data: IndexMap::new(),
72 rejected: false,
73 }
74 }
75
76 pub fn with(mut self, msr_type: MeasurementType, msr_value: f64) -> Self {
77 self.push(msr_type, msr_value);
78 self
79 }
80
81 pub fn observation<S: DimName>(&self, types: &IndexSet<MeasurementType>) -> OVector<f64, S>
85 where
86 DefaultAllocator: Allocator<S>,
87 {
88 let mut obs = OVector::zeros();
90 for (i, t) in types.iter().enumerate() {
91 if let Some(msr_value) = self.data.get(t) {
92 obs[i] = *msr_value;
93 }
94 }
95 obs
96 }
97
98 pub fn availability(&self, types: &IndexSet<MeasurementType>) -> Vec<bool> {
100 let mut rtn = vec![false; types.len()];
101 for (i, t) in types.iter().enumerate() {
102 if self.data.contains_key(t) {
103 rtn[i] = true;
104 }
105 }
106 rtn
107 }
108}
109
110impl fmt::Display for Measurement {
111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112 let msrs = self
113 .data
114 .iter()
115 .map(|(msr_type, msr_value)| format!("{msr_type:?} = {msr_value} {}", msr_type.unit()))
116 .collect::<Vec<String>>()
117 .join(", ");
118
119 write!(f, "{} measured {} on {}", self.tracker, msrs, self.epoch)
120 }
121}
122
123impl PartialEq for Measurement {
124 fn eq(&self, other: &Self) -> bool {
125 self.tracker == other.tracker
126 && self.epoch == other.epoch
127 && self.data.iter().all(|(key, &value)| {
128 if let Some(&other_value) = other.data.get(key) {
129 (value - other_value).abs() < 1e-10
130 } else {
131 false
132 }
133 })
134 }
135}