1use crate::linalg::allocator::Allocator;
20use crate::linalg::{DefaultAllocator, DimName, OVector};
21use crate::od::msr::MeasurementType;
22use hifitime::Epoch;
23use indexmap::IndexSet;
24use std::fmt;
25
26#[derive(Debug, Clone, PartialEq)]
28pub struct Residual<M>
29where
30 M: DimName,
31 DefaultAllocator: Allocator<M>,
32{
33 pub epoch: Epoch,
35 pub prefit: OVector<f64, M>,
37 pub postfit: OVector<f64, M>,
39 pub whitened_resid: OVector<f64, M>,
42 pub ratio: f64,
46 pub tracker_msr_noise: OVector<f64, M>,
48 pub rejected: bool,
50 pub tracker: Option<String>,
52 pub msr_types: IndexSet<MeasurementType>,
54 pub real_obs: OVector<f64, M>,
56 pub computed_obs: OVector<f64, M>,
58}
59
60impl<M> Residual<M>
61where
62 M: DimName,
63 DefaultAllocator: Allocator<M>,
64{
65 pub fn zeros() -> Self {
67 Self {
68 epoch: Epoch::from_tai_seconds(0.0),
69 prefit: OVector::<f64, M>::zeros(),
70 postfit: OVector::<f64, M>::zeros(),
71 whitened_resid: OVector::<f64, M>::zeros(),
72 tracker_msr_noise: OVector::<f64, M>::zeros(),
73 ratio: 0.0,
74 rejected: true,
75 tracker: None,
76 msr_types: IndexSet::new(),
77 real_obs: OVector::<f64, M>::zeros(),
78 computed_obs: OVector::<f64, M>::zeros(),
79 }
80 }
81
82 pub fn rejected(
84 epoch: Epoch,
85 prefit: OVector<f64, M>,
86 whitened_resid: OVector<f64, M>,
87 ratio: f64,
88 tracker_msr_noise: OVector<f64, M>,
89 real_obs: OVector<f64, M>,
90 computed_obs: OVector<f64, M>,
91 ) -> Self {
92 Self {
93 epoch,
94 prefit,
95 postfit: OVector::<f64, M>::zeros() * f64::NAN,
96 whitened_resid,
97 ratio,
98 tracker_msr_noise,
99 rejected: true,
100 tracker: None,
101 msr_types: IndexSet::new(),
102 real_obs,
103 computed_obs,
104 }
105 }
106
107 pub fn accepted(
108 epoch: Epoch,
109 prefit: OVector<f64, M>,
110 whitened_resid: OVector<f64, M>,
111 postfit: OVector<f64, M>,
112 ratio: f64,
113 tracker_msr_noise: OVector<f64, M>,
114 real_obs: OVector<f64, M>,
115 computed_obs: OVector<f64, M>,
116 ) -> Self {
117 Self {
118 epoch,
119 prefit,
120 whitened_resid,
121 postfit,
122 ratio,
123 tracker_msr_noise,
124 rejected: false,
125 tracker: None,
126 msr_types: IndexSet::new(),
127 real_obs,
128 computed_obs,
129 }
130 }
131
132 pub fn prefit(&self, msr_type: MeasurementType) -> Option<f64> {
134 self.msr_types
135 .get_index_of(&msr_type)
136 .map(|idx| self.prefit[idx])
137 }
138
139 pub fn postfit(&self, msr_type: MeasurementType) -> Option<f64> {
141 self.msr_types
142 .get_index_of(&msr_type)
143 .map(|idx| self.postfit[idx])
144 }
145
146 pub fn trk_noise(&self, msr_type: MeasurementType) -> Option<f64> {
148 self.msr_types
149 .get_index_of(&msr_type)
150 .map(|idx| self.tracker_msr_noise[idx])
151 }
152
153 pub fn real_obs(&self, msr_type: MeasurementType) -> Option<f64> {
155 self.msr_types
156 .get_index_of(&msr_type)
157 .map(|idx| self.real_obs[idx])
158 }
159
160 pub fn computed_obs(&self, msr_type: MeasurementType) -> Option<f64> {
162 self.msr_types
163 .get_index_of(&msr_type)
164 .map(|idx| self.computed_obs[idx])
165 }
166
167 pub fn whitened_resid(&self, msr_type: MeasurementType) -> Option<f64> {
169 self.msr_types
170 .get_index_of(&msr_type)
171 .map(|idx| self.whitened_resid[idx])
172 }
173
174 pub fn nis(&self) -> f64 {
176 self.whitened_resid.norm_squared()
177 }
178}
179
180impl<M> fmt::Display for Residual<M>
181where
182 M: DimName,
183 DefaultAllocator: Allocator<M> + Allocator<M>,
184{
185 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
186 write!(
187 f,
188 "Residual of {:?} from {} at {}: ratio = {:.3}\nPrefit {} Postfit {}",
189 self.msr_types,
190 self.tracker.as_ref().unwrap_or(&"Unknown".to_string()),
191 self.epoch,
192 self.ratio,
193 &self.prefit,
194 &self.postfit
195 )
196 }
197}
198
199impl<M> fmt::LowerExp for Residual<M>
200where
201 M: DimName,
202 DefaultAllocator: Allocator<M> + Allocator<M>,
203{
204 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
205 write!(f, "Prefit {:e} Postfit {:e}", &self.prefit, &self.postfit)
206 }
207}