1#[allow(unused_imports)]
17use crate::math::FloatMath;
18use crate::matrix::{MatrixInstance, MatrixInstanceMut, mat_inverse_f32};
19use crate::types::Status;
20
21#[derive(Debug, Clone, Copy)]
23pub struct KalmanFilter1D {
24 pub x: f32,
26 pub p: f32,
28 pub q: f32,
30 pub r: f32,
32}
33
34impl KalmanFilter1D {
35 pub fn new(x0: f32, p0: f32, q: f32, r: f32) -> Self {
37 Self { x: x0, p: p0, q, r }
38 }
39
40 pub fn predict(&mut self, u: f32) {
42 self.x += u;
43 self.p += self.q;
44 }
45
46 pub fn update(&mut self, z: f32) -> f32 {
48 let k = self.p / (self.p + self.r);
49 self.x += k * (z - self.x);
50 self.p = (1.0 - k) * self.p;
51 self.x
52 }
53}
54
55#[derive(Debug, Clone, Copy)]
57pub struct KalmanFilter2D {
58 pub x: [f32; 2],
60 pub p: [f32; 4],
62 pub q_var: f32,
64 pub r_var: f32,
66}
67
68impl KalmanFilter2D {
69 pub fn new(initial_pos: f32, initial_vel: f32, q_var: f32, r_var: f32) -> Self {
71 Self {
72 x: [initial_pos, initial_vel],
73 p: [1.0, 0.0, 0.0, 1.0],
74 q_var,
75 r_var,
76 }
77 }
78
79 pub fn predict(&mut self, dt: f32) {
81 self.x[0] += dt * self.x[1];
83
84 let dt2 = dt * dt;
86 let dt3 = dt2 * dt;
87 let dt4 = dt3 * dt;
88
89 let p00 =
90 self.p[0] + dt * (self.p[2] + self.p[1]) + dt2 * self.p[3] + 0.25 * dt4 * self.q_var;
91 let p01 = self.p[1] + dt * self.p[3] + 0.5 * dt3 * self.q_var;
92 let p10 = self.p[2] + dt * self.p[3] + 0.5 * dt3 * self.q_var;
93 let p11 = self.p[3] + dt2 * self.q_var;
94
95 self.p = [p00, p01, p10, p11];
96 }
97
98 pub fn update(&mut self, z_pos: f32) -> [f32; 2] {
100 let y = z_pos - self.x[0];
102 let s = self.p[0] + self.r_var;
103
104 let k0 = self.p[0] / s;
106 let k1 = self.p[2] / s;
107
108 self.x[0] += k0 * y;
110 self.x[1] += k1 * y;
111
112 let p00 = (1.0 - k0) * self.p[0];
114 let p01 = (1.0 - k0) * self.p[1];
115 let p10 = self.p[2] - k1 * self.p[0];
116 let p11 = self.p[3] - k1 * self.p[1];
117
118 self.p = [p00, p01, p10, p11];
119 self.x
120 }
121}
122
123#[inline]
126fn mat_vec_mul<const R: usize, const C: usize>(
127 a: &[[f32; C]; R],
128 x: &[f32; C],
129 out: &mut [f32; R],
130) {
131 for r in 0..R {
132 let mut sum = 0.0f32;
133 for c in 0..C {
134 sum += a[r][c] * x[c];
135 }
136 out[r] = sum;
137 }
138}
139
140#[inline]
141fn mat_mul<const R: usize, const K: usize, const C: usize>(
142 a: &[[f32; K]; R],
143 b: &[[f32; C]; K],
144 out: &mut [[f32; C]; R],
145) {
146 for r in 0..R {
147 for c in 0..C {
148 let mut sum = 0.0f32;
149 for k in 0..K {
150 sum += a[r][k] * b[k][c];
151 }
152 out[r][c] = sum;
153 }
154 }
155}
156
157#[inline]
159fn mat_mul_bt<const R: usize, const K: usize, const C: usize>(
160 a: &[[f32; K]; R],
161 b: &[[f32; K]; C],
162 out: &mut [[f32; C]; R],
163) {
164 for r in 0..R {
165 for c in 0..C {
166 let mut sum = 0.0f32;
167 for k in 0..K {
168 sum += a[r][k] * b[c][k];
169 }
170 out[r][c] = sum;
171 }
172 }
173}
174
175#[inline]
176fn mat_add_inplace_nn<const N: usize>(a: &mut [[f32; N]; N], b: &[[f32; N]; N]) {
177 for r in 0..N {
178 for c in 0..N {
179 a[r][c] += b[r][c];
180 }
181 }
182}
183
184#[inline]
185fn mat_add_inplace_mm<const M: usize>(a: &mut [[f32; M]; M], b: &[[f32; M]; M]) {
186 for r in 0..M {
187 for c in 0..M {
188 a[r][c] += b[r][c];
189 }
190 }
191}
192
193#[inline]
194fn identity_n<const N: usize>() -> [[f32; N]; N] {
195 let mut i = [[0.0f32; N]; N];
196 for n in 0..N {
197 i[n][n] = 1.0;
198 }
199 i
200}
201
202fn invert_mxm<const M: usize>(s: &[[f32; M]; M], s_inv: &mut [[f32; M]; M]) -> Status {
204 if M == 0 {
205 return Status::SizeMismatch;
206 }
207 if M > 16 {
208 return Status::ArgumentError;
209 }
210
211 let mut flat_src = [0.0f32; 16 * 16];
212 let mut flat_dst = [0.0f32; 16 * 16];
213 for r in 0..M {
214 for c in 0..M {
215 flat_src[r * M + c] = s[r][c];
216 }
217 }
218
219 let src = MatrixInstance::new(M as u16, M as u16, &flat_src[..M * M]);
220 let mut dst = MatrixInstanceMut::new(M as u16, M as u16, &mut flat_dst[..M * M]);
221 let status = mat_inverse_f32(&src, &mut dst);
222 if status != Status::Success {
223 return status;
224 }
225
226 for r in 0..M {
227 for c in 0..M {
228 s_inv[r][c] = flat_dst[r * M + c];
229 }
230 }
231 Status::Success
232}
233
234fn kf_predict_core<const N: usize>(
236 x: &mut [f32; N],
237 p: &mut [[f32; N]; N],
238 q: &[[f32; N]; N],
239 f: &[[f32; N]; N],
240) {
241 let mut x_new = [0.0f32; N];
242 mat_vec_mul(f, x, &mut x_new);
243 *x = x_new;
244
245 let mut fp = [[0.0f32; N]; N];
246 mat_mul(f, p, &mut fp);
247 let mut p_new = [[0.0f32; N]; N];
248 mat_mul_bt(&fp, f, &mut p_new);
249 mat_add_inplace_nn(&mut p_new, q);
250 *p = p_new;
251}
252
253fn kf_predict_control_core<const N: usize, const U: usize>(
255 x: &mut [f32; N],
256 p: &mut [[f32; N]; N],
257 q: &[[f32; N]; N],
258 f: &[[f32; N]; N],
259 b: &[[f32; U]; N],
260 u: &[f32; U],
261) {
262 let mut x_new = [0.0f32; N];
263 mat_vec_mul(f, x, &mut x_new);
264 let mut bu = [0.0f32; N];
265 mat_vec_mul(b, u, &mut bu);
266 for i in 0..N {
267 x_new[i] += bu[i];
268 }
269 *x = x_new;
270
271 let mut fp = [[0.0f32; N]; N];
272 mat_mul(f, p, &mut fp);
273 let mut p_new = [[0.0f32; N]; N];
274 mat_mul_bt(&fp, f, &mut p_new);
275 mat_add_inplace_nn(&mut p_new, q);
276 *p = p_new;
277}
278
279fn kf_update_core<const N: usize, const M: usize>(
281 x: &mut [f32; N],
282 p: &mut [[f32; N]; N],
283 r: &[[f32; M]; M],
284 h: &[[f32; N]; M],
285 z: &[f32; M],
286) -> Status {
287 if M > 16 {
288 return Status::ArgumentError;
289 }
290 if M == 0 {
291 return Status::SizeMismatch;
292 }
293
294 let mut hx = [0.0f32; M];
296 mat_vec_mul(h, x, &mut hx);
297 let mut y = [0.0f32; M];
298 for i in 0..M {
299 y[i] = z[i] - hx[i];
300 }
301
302 let mut hp = [[0.0f32; N]; M];
304 mat_mul(h, p, &mut hp);
305 let mut s = [[0.0f32; M]; M];
306 mat_mul_bt(&hp, h, &mut s);
307 mat_add_inplace_mm(&mut s, r);
308
309 let mut s_inv = [[0.0f32; M]; M];
310 let inv_status = invert_mxm(&s, &mut s_inv);
311 if inv_status != Status::Success {
312 return inv_status;
313 }
314
315 let mut pht = [[0.0f32; M]; N];
317 for i in 0..N {
318 for j in 0..M {
319 let mut sum = 0.0f32;
320 for k in 0..N {
321 sum += p[i][k] * h[j][k];
322 }
323 pht[i][j] = sum;
324 }
325 }
326
327 let mut k = [[0.0f32; M]; N];
329 mat_mul(&pht, &s_inv, &mut k);
330
331 let mut ky = [0.0f32; N];
333 mat_vec_mul(&k, &y, &mut ky);
334 let mut x_new = *x;
335 for i in 0..N {
336 x_new[i] += ky[i];
337 }
338
339 let mut kh = [[0.0f32; N]; N];
341 mat_mul(&k, h, &mut kh);
342 let mut i_kh = identity_n::<N>();
343 for r in 0..N {
344 for c in 0..N {
345 i_kh[r][c] -= kh[r][c];
346 }
347 }
348 let mut p_new = [[0.0f32; N]; N];
349 mat_mul(&i_kh, p, &mut p_new);
350
351 *x = x_new;
352 *p = p_new;
353 Status::Success
354}
355
356#[derive(Debug, Clone, Copy, PartialEq)]
361pub struct KalmanFilter<const N: usize, const M: usize> {
362 pub x: [f32; N],
364 pub p: [[f32; N]; N],
366 pub q: [[f32; N]; N],
368 pub r: [[f32; M]; M],
370}
371
372impl<const N: usize, const M: usize> KalmanFilter<N, M> {
373 pub fn new(x0: [f32; N], p0: [[f32; N]; N], q: [[f32; N]; N], r: [[f32; M]; M]) -> Self {
375 Self { x: x0, p: p0, q, r }
376 }
377
378 pub fn from_variances(x0: [f32; N], p_var: f32, q_var: f32, r_var: f32) -> Self {
380 let mut p = [[0.0f32; N]; N];
381 let mut q = [[0.0f32; N]; N];
382 let mut r = [[0.0f32; M]; M];
383 for i in 0..N {
384 p[i][i] = p_var;
385 q[i][i] = q_var;
386 }
387 for i in 0..M {
388 r[i][i] = r_var;
389 }
390 Self::new(x0, p, q, r)
391 }
392
393 pub fn predict(&mut self, f: &[[f32; N]; N]) {
395 kf_predict_core(&mut self.x, &mut self.p, &self.q, f);
396 }
397
398 pub fn predict_with_control<const U: usize>(
400 &mut self,
401 f: &[[f32; N]; N],
402 b: &[[f32; U]; N],
403 u: &[f32; U],
404 ) {
405 kf_predict_control_core(&mut self.x, &mut self.p, &self.q, f, b, u);
406 }
407
408 pub fn update(&mut self, h: &[[f32; N]; M], z: &[f32; M]) -> Status {
413 kf_update_core(&mut self.x, &mut self.p, &self.r, h, z)
414 }
415}
416
417pub trait EkfModel<const N: usize, const M: usize> {
419 fn f(&self, x: &[f32; N], dt: f32, out: &mut [f32; N]);
421
422 fn h(&self, x: &[f32; N], out: &mut [f32; M]);
424
425 fn jacobian_f(&self, x: &[f32; N], dt: f32, out: &mut [[f32; N]; N]);
427
428 fn jacobian_h(&self, x: &[f32; N], out: &mut [[f32; N]; M]);
430
431 fn f_with_input<const U: usize>(
438 &self,
439 x: &[f32; N],
440 u: &[f32; U],
441 dt: f32,
442 out: &mut [f32; N],
443 ) {
444 let _ = u;
445 self.f(x, dt, out)
446 }
447
448 fn jacobian_f_with_input<const U: usize>(
453 &self,
454 x: &[f32; N],
455 u: &[f32; U],
456 dt: f32,
457 out: &mut [[f32; N]; N],
458 ) {
459 let _ = u;
460 self.jacobian_f(x, dt, out)
461 }
462
463 fn h_with_input<const U: usize>(&self, x: &[f32; N], u: &[f32; U], out: &mut [f32; M]) {
468 let _ = u;
469 self.h(x, out)
470 }
471
472 fn jacobian_h_with_input<const U: usize>(
477 &self,
478 x: &[f32; N],
479 u: &[f32; U],
480 out: &mut [[f32; N]; M],
481 ) {
482 let _ = u;
483 self.jacobian_h(x, out)
484 }
485}
486
487#[derive(Debug, Clone, Copy, PartialEq)]
491pub struct ExtendedKalmanFilter<const N: usize, const M: usize, Model> {
492 pub x: [f32; N],
494 pub p: [[f32; N]; N],
496 pub q: [[f32; N]; N],
498 pub r: [[f32; M]; M],
500 pub model: Model,
502}
503
504impl<const N: usize, const M: usize, Model: EkfModel<N, M>> ExtendedKalmanFilter<N, M, Model> {
505 pub fn new(
507 x0: [f32; N],
508 p0: [[f32; N]; N],
509 q: [[f32; N]; N],
510 r: [[f32; M]; M],
511 model: Model,
512 ) -> Self {
513 Self {
514 x: x0,
515 p: p0,
516 q,
517 r,
518 model,
519 }
520 }
521
522 pub fn from_variances(x0: [f32; N], p_var: f32, q_var: f32, r_var: f32, model: Model) -> Self {
524 let mut p = [[0.0f32; N]; N];
525 let mut q = [[0.0f32; N]; N];
526 let mut r = [[0.0f32; M]; M];
527 for i in 0..N {
528 p[i][i] = p_var;
529 q[i][i] = q_var;
530 }
531 for i in 0..M {
532 r[i][i] = r_var;
533 }
534 Self::new(x0, p, q, r, model)
535 }
536
537 pub fn predict(&mut self, dt: f32) {
539 let mut f_jac = [[0.0f32; N]; N];
540 self.model.jacobian_f(&self.x, dt, &mut f_jac);
541
542 let mut x_new = [0.0f32; N];
543 self.model.f(&self.x, dt, &mut x_new);
544
545 ekf_predict_apply(&mut self.x, &mut self.p, &self.q, &f_jac, x_new);
546 }
547
548 pub fn predict_with_input<const U: usize>(&mut self, dt: f32, u: &[f32; U]) {
552 let mut f_jac = [[0.0f32; N]; N];
553 self.model.jacobian_f_with_input(&self.x, u, dt, &mut f_jac);
554
555 let mut x_new = [0.0f32; N];
556 self.model.f_with_input(&self.x, u, dt, &mut x_new);
557
558 ekf_predict_apply(&mut self.x, &mut self.p, &self.q, &f_jac, x_new);
559 }
560
561 pub fn update(&mut self, z: &[f32; M]) -> Status {
565 let mut h_jac = [[0.0f32; N]; M];
566 self.model.jacobian_h(&self.x, &mut h_jac);
567
568 let mut hx = [0.0f32; M];
569 self.model.h(&self.x, &mut hx);
570
571 ekf_update_apply(&mut self.x, &mut self.p, &self.r, &h_jac, &hx, z)
572 }
573
574 pub fn update_with_input<const U: usize>(&mut self, z: &[f32; M], u: &[f32; U]) -> Status {
580 let mut h_jac = [[0.0f32; N]; M];
581 self.model.jacobian_h_with_input(&self.x, u, &mut h_jac);
582
583 let mut hx = [0.0f32; M];
584 self.model.h_with_input(&self.x, u, &mut hx);
585
586 ekf_update_apply(&mut self.x, &mut self.p, &self.r, &h_jac, &hx, z)
587 }
588}
589
590fn ekf_predict_apply<const N: usize>(
594 x: &mut [f32; N],
595 p: &mut [[f32; N]; N],
596 q: &[[f32; N]; N],
597 f_jac: &[[f32; N]; N],
598 x_new: [f32; N],
599) {
600 *x = x_new;
601
602 let mut fp = [[0.0f32; N]; N];
603 mat_mul(f_jac, p, &mut fp);
604 let mut p_new = [[0.0f32; N]; N];
605 mat_mul_bt(&fp, f_jac, &mut p_new);
606 mat_add_inplace_nn(&mut p_new, q);
607 *p = p_new;
608}
609
610fn ekf_update_apply<const N: usize, const M: usize>(
615 x: &mut [f32; N],
616 p: &mut [[f32; N]; N],
617 r: &[[f32; M]; M],
618 h_jac: &[[f32; N]; M],
619 hx: &[f32; M],
620 z: &[f32; M],
621) -> Status {
622 if M > 16 {
623 return Status::ArgumentError;
624 }
625 if M == 0 {
626 return Status::SizeMismatch;
627 }
628
629 let mut z_equiv = [0.0f32; M];
632 let mut hx_lin = [0.0f32; M];
633 mat_vec_mul(h_jac, x, &mut hx_lin);
634 for i in 0..M {
635 z_equiv[i] = z[i] - hx[i] + hx_lin[i];
636 }
637
638 kf_update_core(x, p, r, h_jac, &z_equiv)
639}
640
641#[derive(Debug, Clone)]
651pub struct SquareRootKalmanFilter<const N: usize, const M: usize> {
652 pub x: [f32; N],
654 pub s: [[f32; N]; N],
656 pub f: [[f32; N]; N],
658 pub s_q: [[f32; N]; N],
660 pub h: [[f32; N]; M],
662 pub s_r: [[f32; M]; M],
664}
665
666impl<const N: usize, const M: usize> SquareRootKalmanFilter<N, M> {
667 pub fn new(
669 x0: [f32; N],
670 s0: [[f32; N]; N],
671 f: [[f32; N]; N],
672 s_q: [[f32; N]; N],
673 h: [[f32; N]; M],
674 s_r: [[f32; M]; M],
675 ) -> Self {
676 Self {
677 x: x0,
678 s: s0,
679 f,
680 s_q,
681 h,
682 s_r,
683 }
684 }
685
686 pub fn predict(&mut self) {
688 let mut x_new = [0.0f32; N];
690 mat_vec_mul(&self.f, &self.x, &mut x_new);
691 self.x = x_new;
692
693 let mut fs = [[0.0f32; N]; N];
695 mat_mul(&self.f, &self.s, &mut fs);
696
697 let mut s_new = [[0.0f32; N]; N];
698 for i in 0..N {
699 for j in 0..=i {
700 let mut sum = 0.0f32;
701 for k in 0..N {
702 sum += fs[i][k] * fs[j][k] + self.s_q[i][k] * self.s_q[j][k];
703 }
704 s_new[i][j] = sum;
705 }
706 }
707 cholesky_inplace_lower(&mut s_new);
708 self.s = s_new;
709 }
710
711 pub fn update(&mut self, z: &[f32; M]) -> Status {
713 if M == 0 || M > 16 {
714 return Status::ArgumentError;
715 }
716
717 let mut hx = [0.0f32; M];
719 mat_vec_mul(&self.h, &self.x, &mut hx);
720 let mut y = [0.0f32; M];
721 for i in 0..M {
722 y[i] = z[i] - hx[i];
723 }
724
725 let mut hs = [[0.0f32; N]; M];
727 mat_mul(&self.h, &self.s, &mut hs);
728
729 let mut s_yy = [[0.0f32; M]; M];
730 for r in 0..M {
731 for c in 0..M {
732 let mut sum = 0.0f32;
733 for k in 0..N {
734 sum += hs[r][k] * hs[c][k];
735 }
736 for k in 0..M {
737 sum += self.s_r[r][k] * self.s_r[c][k];
738 }
739 s_yy[r][c] = sum;
740 }
741 }
742
743 let mut s_yy_inv = [[0.0f32; M]; M];
745 let status = invert_mxm(&s_yy, &mut s_yy_inv);
746 if status != Status::Success {
747 return status;
748 }
749
750 let mut p = [[0.0f32; N]; N];
752 mat_mul_bt(&self.s, &self.s, &mut p);
753
754 let mut pht = [[0.0f32; M]; N];
755 mat_mul_bt(&p, &self.h, &mut pht);
756
757 let mut k_gain = [[0.0f32; M]; N];
758 mat_mul(&pht, &s_yy_inv, &mut k_gain);
759
760 let mut ky = [0.0f32; N];
762 mat_vec_mul(&k_gain, &y, &mut ky);
763 for i in 0..N {
764 self.x[i] += ky[i];
765 }
766
767 let mut i_kh = identity_n::<N>();
769 let mut kh = [[0.0f32; N]; N];
770 mat_mul(&k_gain, &self.h, &mut kh);
771 for r in 0..N {
772 for c in 0..N {
773 i_kh[r][c] -= kh[r][c];
774 }
775 }
776
777 let mut i_kh_p = [[0.0f32; N]; N];
778 mat_mul(&i_kh, &p, &mut i_kh_p);
779 let mut p_plus = [[0.0f32; N]; N];
780 mat_mul_bt(&i_kh_p, &i_kh, &mut p_plus);
781
782 let mut r_mat = [[0.0f32; M]; M];
783 mat_mul_bt(&self.s_r, &self.s_r, &mut r_mat);
784 let mut kr = [[0.0f32; M]; N];
785 mat_mul(&k_gain, &r_mat, &mut kr);
786 let mut krkt = [[0.0f32; N]; N];
787 mat_mul_bt(&kr, &k_gain, &mut krkt);
788 mat_add_inplace_nn(&mut p_plus, &krkt);
789
790 cholesky_inplace_lower(&mut p_plus);
792 self.s = p_plus;
793
794 Status::Success
795 }
796
797 pub fn covariance(&self) -> [[f32; N]; N] {
799 let mut p = [[0.0f32; N]; N];
800 mat_mul_bt(&self.s, &self.s, &mut p);
801 p
802 }
803}
804
805fn cholesky_inplace_lower<const N: usize>(a: &mut [[f32; N]; N]) {
807 for i in 0..N {
808 for j in 0..=i {
809 let mut sum = a[i][j];
810 for k in 0..j {
811 sum -= a[i][k] * a[j][k];
812 }
813 if i == j {
814 a[i][j] = sum.max(1e-12).sqrt();
815 } else {
816 let diag = a[j][j].max(1e-12);
817 a[i][j] = sum / diag;
818 }
819 }
820 for j in (i + 1)..N {
821 a[i][j] = 0.0;
822 }
823 }
824}