1
2use num_traits::float::Float;
3
4#[derive(Debug, Clone, Copy)]
7pub struct KalmanState<T> {
8 pub estimate: T,pub uncertainty: T,measurement_variance: T, process_variance: T, }
13
14impl<T> KalmanState<T>
15 where T: Float
16{
17 pub fn new_float(
18 estimate: T,
19 uncertainty: T,
20 measurement_variance: T,
21 process_variance: T) -> KalmanState<T>
22 {
23 KalmanState {
24 estimate,
25 uncertainty: uncertainty.abs(),
26 measurement_variance: measurement_variance.abs(),
27 process_variance: process_variance.abs(),
28 }
29 }
30}
31
32
33
34pub fn kalman_update_float<T>(state: &KalmanState<T>, observation: T) -> KalmanState<T>
36 where
37 T: Float,
38{
39 let kalman_gain = state.uncertainty / (state.uncertainty + state.measurement_variance);
41
42 let new_estimate = state.estimate + kalman_gain * (observation - state.estimate);
44
45 let mut new_uncertainty = (T::one() - kalman_gain) * state.uncertainty;
47 new_uncertainty = new_uncertainty + state.process_variance*(state.estimate - new_estimate).abs();
50
51 KalmanState::new_float(new_estimate, new_uncertainty,
52 state.measurement_variance,state.process_variance)
53
54}
55
56use fixed::traits::{ Fixed };
57
58impl<T> KalmanState<T>
59 where T: Fixed
60{
61 pub fn new_fixed (
62 estimate: T,
63 uncertainty: T,
64 measurement_variance: T,
65 process_variance: T) -> KalmanState<T>
66 {
67 if T::IS_SIGNED {
68 KalmanState {
69 estimate,
70 uncertainty:
71 if uncertainty < 0 { T::ZERO - uncertainty } else { uncertainty },
72
73 measurement_variance:
74 if measurement_variance < 0 { T::ZERO - measurement_variance } else { measurement_variance },
75
76 process_variance:
77 if process_variance < 0 { T::ZERO - process_variance } else { process_variance },
78 }
79 }
80 else {
81 KalmanState {
82 estimate,
83 uncertainty,
84 measurement_variance,
85 process_variance,
86 }
87 }
88 }
89}
90
91
92
93pub fn kalman_update_fixed<T>(state: &KalmanState<T>, observation: T) -> KalmanState<T>
95 where
96 T: Fixed ,
97{
98 let kalman_gain = state.uncertainty / (state.uncertainty + state.measurement_variance);
100
101 let new_estimate = state.estimate + kalman_gain * (observation - state.estimate);
103
104 let mut new_uncertainty = (T::TRY_ONE.unwrap() - kalman_gain) * state.uncertainty;
106 new_uncertainty = new_uncertainty + state.process_variance;
108 let est_diff =
109 if state.estimate > new_estimate { state.estimate - new_estimate }
110 else { new_estimate - state.estimate };
111 new_uncertainty = new_uncertainty + state.process_variance*est_diff;
112
113 KalmanState::new_fixed(new_estimate, new_uncertainty,
114 state.measurement_variance, state.process_variance)
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 fn assert_near_eq(a: f64, b: f64, tol: f64) {
123 assert!(
124 (a - b).abs() < tol,
125 "assertion failed: `(left !== right)`\n left: `{:?}`,\n right: `{:?}`",
126 a,
127 b
128 );
129 }
130
131 fn assert_near_eq_fixed<T: Fixed>(a: T, b: T, tol: T) {
132 let diff = if a > b { a - b } else { b - a };
133 assert!(
134 diff < tol,
135 "assertion failed: `(left !== right)`\n left: `{:?}`,\n right: `{:?}`",
136 a,
137 b
138 );
139 }
140
141 #[test]
142 fn test_kalman_filter_f64() {
143 let mut kstate = KalmanState {
144 estimate: 0.5f64,
145 uncertainty: 0.1,
146 measurement_variance: 1E-4,
147 process_variance: 1.0,
148 };
149
150 for _i in 0..10 {
151 kstate = kalman_update_float(&kstate, 1.0);
152 }
153 println!("{}", kstate.estimate);
154 assert_near_eq(kstate.estimate, 1.0, 1E-4);
155 }
156
157 #[test]
158 fn test_with_monotonic_increasing_f64() {
159 let mut kstate = KalmanState::new_float(
160 0.0f64,
161 1.0,
162 1E-6,
163 1E-3
164 );
165
166 const MAX_ITERATIONS: usize = 1000;
167 for i in 1..=MAX_ITERATIONS {
168 kstate = kalman_update_float(&kstate, i as f64);
169 }
170
171 println!("est: {} uncert: {}", kstate.estimate, kstate.uncertainty);
173 assert_near_eq(kstate.estimate, MAX_ITERATIONS as f64, 1E-3);
174 assert_near_eq(kstate.uncertainty, 0.001, 1E-4);
175 }
176
177 use fixed::types::{I16F16, I8F24, U32F32};
178
179 #[test]
180 fn test_kalman_filter_i8f24() {
181 let mut kstate = KalmanState {
182 estimate: I8F24::from_num(0.5),
183 uncertainty: I8F24::from_num(0.1),
184 measurement_variance: I8F24::from_num(1E-4),
185 process_variance: I8F24::from_num(1.0),
186 };
187
188 for _i in 0..10 {
189 kstate = kalman_update_fixed(&kstate, I8F24::from_num(1.0));
190 }
191 println!("{}", kstate.estimate);
192 assert_near_eq(kstate.estimate.into(), 1.0, 1E-4);
193 }
194
195 #[test]
196 fn test_with_monotonic_increasing_i8f24() {
197 type TestType = I8F24;
198 let mut kstate = KalmanState::new_fixed(
199 TestType::from_num(0),
200 TestType::from_num(1),
201 TestType::from_num(1E-3),
202 TestType::from_num(1E-3),
203 );
204
205 let max_iterations: usize = TestType::MAX.to_num::<u32>() as usize;
206 for i in 1..=max_iterations {
207 kstate = kalman_update_fixed(&kstate, TestType::from_num(i));
208 }
209
210 println!("est: {} uncert: {}", kstate.estimate, kstate.uncertainty);
212 assert_near_eq_fixed(
213 kstate.estimate,
214 TestType::from_num(max_iterations),
215 TestType::from_num( 4E-1),
216 );
217 assert_near_eq_fixed(
218 kstate.uncertainty,
219 TestType::from_num(0.002),
220 TestType::from_num(1E-3),
221 );
222 }
223
224 #[test]
225 fn test_with_monotonic_increasing_i16f16() {
226 type TestType = I16F16;
227 let mut kstate = KalmanState::new_fixed(
228 TestType::from_num(0.0),
229 TestType::from_num(1.0),
230 TestType::from_num(1E-3),
231 TestType::from_num(1E-3),
232 );
233
234 let max_iterations: usize = TestType::MAX.to_num::<u32>() as usize;
235 for i in 1..=max_iterations {
236 kstate = kalman_update_fixed(&kstate, TestType::from_num(i));
237 }
238
239 println!("est: {} uncert: {}", kstate.estimate, kstate.uncertainty);
241 assert_near_eq_fixed(
242 kstate.estimate,
243 TestType::from_num(max_iterations),
244 TestType::from_num(0.75),
245 );
246 assert_near_eq_fixed(
247 kstate.uncertainty,
248 TestType::from_num(0.003),
249 TestType::from_num(1E-3),
250 );
251 }
252
253 #[test]
254 fn test_with_monotonic_increasing_u32f32() {
255 type TestType = U32F32;
256 let step_size: usize = 1000;
257
258 let mut kstate = KalmanState::new_fixed (
259 TestType::from_num(0),
260 TestType::from_num(1),
261 TestType::from_num(1E-3),
262 TestType::from_num(1E-3),
263 );
264
265 let max_iterations: usize = TestType::MAX.to_num::<u32>() as usize;
266 for i in (1..=max_iterations).step_by(step_size) {
267 kstate = kalman_update_fixed(&kstate, TestType::from_num(i));
268 }
269
270 println!("est: {} uncert: {}", kstate.estimate, kstate.uncertainty);
272 assert_near_eq_fixed(
273 kstate.estimate,
274 TestType::from_num(max_iterations),
275 TestType::from_num(step_size),
276 );
277 assert_near_eq_fixed(
278 kstate.uncertainty,
279 TestType::from_num(1),
280 TestType::from_num(1E-2),
281 );
282 }
283}