1 /** @file range_kalman.c
2  *
3  * @brief This file contains Kalman filter for WLS range measurements
4  *
5  * Copyright 2023-2024 NXP
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  *
9  */
10 
11 #include <osa.h>
12 #if CONFIG_WLS_CSI_PROC
13 #include "range_kalman.h"
14 #include <stdio.h>
15 #include <math.h>
16 
17 #ifdef RANGE_RUN_FLT
range_kalman(range_kalman_state * in)18 int range_kalman(range_kalman_state *in)
19 {
20     float range_hat, range_rate_hat;
21     float nu, S1;
22     float R1_11, R1_12, R1_22, W1_1, W1_2;
23     float delta_T  = (float)(in->time - in->last_time) / 1000; // now seconds
24     float delta_T2 = delta_T * delta_T;
25     float delta_T3 = delta_T2 * delta_T;
26 
27     // state propagation
28     // A = | 1 T |
29     //     | 0 1 |
30     range_hat      = in->last_range + delta_T * in->last_range_rate;
31     range_rate_hat = in->last_range_rate;
32     // residual
33     nu = in->range_measurement - range_hat; // H = [1; 0]
34 
35     // propagated cov = A*R11*A' + Q
36     R1_11 = in->R0_11 + delta_T * 2 * in->R0_12 + delta_T2 * in->R0_22;
37     R1_12 = in->R0_12 + delta_T * in->R0_22;
38     R1_22 = in->R0_22;
39     // Q = | T^3/3 T^2/2 | *  drive_var
40     //     | T^2/2 T     |
41     R1_11 += in->drive_var * delta_T3 / 3;
42     R1_12 += in->drive_var * delta_T2 / 2;
43     R1_22 += in->drive_var * delta_T;
44 
45     // inovation cov S1 = y_err + H*R1*H'
46     S1 = in->measurement_var + R1_11;
47     // filter gain W1 = (R1*H')/S1
48     W1_1 = R1_11 / S1;
49     W1_2 = R1_12 / S1;
50 
51     // updated covariance R11 = R1 - W1*S1*W1'
52     R1_11 -= W1_1 * S1 * W1_1;
53     in->R0_11 = (R1_11 > 0) ? R1_11 : 0;
54     R1_12 -= W1_1 * S1 * W1_2;
55     in->R0_12 = R1_12;
56     R1_22 -= W1_2 * S1 * W1_2;
57     in->R0_22 = (R1_22 > 0) ? R1_22 : 0;
58     // updated state
59     range_hat += W1_1 * nu;
60     in->last_range = (range_hat > 0) ? range_hat : 0;
61     range_rate_hat += W1_2 * nu;
62     in->last_range_rate = range_rate_hat;
63     in->last_time       = in->time;
64 
65     PRINTF("Kalman update R mat: %f m, %f m/s; d-time: %d ms; range rate %f m/s\r\n", (double)sqrtf(in->R0_11),
66            (double)sqrtf(in->R0_22), (int)(delta_T * 1000), (double)in->last_range_rate);
67     return 0; // no errors
68 }
69 
range_kalman_init(range_kalman_state * in,float range,unsigned long long time,float range_drive_var,float range_measurement_var,float range_rate_init)70 void range_kalman_init(range_kalman_state *in,
71                        float range,
72                        unsigned long long time,
73                        float range_drive_var,
74                        float range_measurement_var,
75                        float range_rate_init)
76 {
77     // initialize state
78     in->last_range      = range;
79     in->last_range_rate = 0;
80     in->last_time       = time;
81 
82     in->R0_11 = range_measurement_var;
83     in->R0_12 = 0;
84     in->R0_22 = range_rate_init;
85 
86     // initialize parameters
87     in->drive_var       = range_drive_var;
88     in->measurement_var = range_measurement_var;
89 }
90 
91 #else
range_kalman(range_kalman_state * in)92 int range_kalman(range_kalman_state *in)
93 {
94     int range_hat, range_rate_hat;
95     int nu, S1;
96     int R1_11, R1_12, R1_22, W1_1, W1_2;
97     unsigned int delta_T  = in->time - in->last_time; // format ??
98     unsigned int delta_T2 = delta_T * delta_T;
99     unsigned int delta_T3 = delta_T2 * delta_T;
100 
101     // state propagation
102     // A = | 1 T |
103     //     | 0 1 |
104     range_hat      = in->last_range + delta_T * in->last_range_rate;
105     range_rate_hat = in->last_range_rate;
106     // residual
107     nu = in->range_measurement - range_hat; // H = [1; 0]
108 
109     // propagated cov = A*R11*A' + Q
110     R1_11 = in->R0_11 + delta_T * 2 * in->R0_12 + delta_T2 * in->R0_22;
111     R1_12 = in->R0_12 + delta_T * in->R0_22;
112     R1_22 = in->R0_22;
113     // Q = | T^3/3 T^2/2 | *  drive_var
114     //     | T^2/2 T     |
115     R1_11 += in->drive_var * delta_T3 / 3;
116     R1_12 += in->drive_var * delta_T2 / 2;
117     R1_22 += in->drive_var * delta_T;
118 
119     // inovation cov S1 = y_err + H*R1*H'
120     S1 = in->measurement_var + R1_11;
121     // filter gain W1 = (R1*H')/S1
122     W1_1 = R1_11 / S1;
123     W1_2 = R1_12 / S1;
124 
125     // updated covariance R11 = R1 - W1*S1*W1'
126     R1_11 -= W1_1 * S1 * W1_1;
127     in->R0_11 = (R1_11 > 0) ? (unsigned short)R1_11 : 0;
128     R1_12 -= W1_1 * S1 * W1_2;
129     in->R0_12 = R1_12;
130     R1_22 -= W1_2 * S1 * W1_2;
131     in->R0_22 = (R1_22 > 0) ? (unsigned short)R1_22 : 0;
132     // updated state
133     range_hat += W1_1 * nu;
134     in->last_range = (range_hat > 0) ? (unsigned short)range_hat : 0;
135     range_rate_hat += W1_2 * nu;
136     in->last_range_rate = (signed short)range_rate_hat;
137     in->last_time       = in->time;
138 
139     return 0; // no errors
140 }
141 #endif
142 
143 #endif /* CONFIG_WLS_CSI_PROC */
144