Skip to content

Commit ac5e973

Browse files
committed
✨ feat(Kalman): 增加卡尔曼滤波算法
1 parent addd8bf commit ac5e973

File tree

5 files changed

+126
-2
lines changed

5 files changed

+126
-2
lines changed

readme.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030

3131
移动平均滤波通过计算窗口内数据的移动平均值来平滑数据,适用于时间序列数据的平滑处理。
3232

33+
### 1.4 卡尔曼滤波
34+
35+
卡尔曼滤波器是一种用于估计动态系统状态的递归算法,广泛应用于目标跟踪、导航、控制系统等领域
36+
3337
## 2. 多项式拟合算法
3438

3539
多项式拟合算法用于拟合数据点,找到一个多项式函数来近似表示数据。

src/algorithm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,5 @@
77
#include "algorithms/sort.h"
88
#include "algorithms/search.h"
99
#include "algorithms/array_utils.h"
10+
#include "algorithms/kalman_filter.h"
1011
#endif // ALGORITHM_MODULE_H

src/algorithms/kalman_filter.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include "kalman_filter.h"
2+
3+
// 初始化卡尔曼滤波器
4+
void KalmanFilter_Init(KalmanFilter *kf, float Q, float R, float P, float initial_value)
5+
{
6+
kf->Q = Q;
7+
kf->R = R;
8+
kf->P = P;
9+
kf->x = initial_value;
10+
kf->K = 0;
11+
}
12+
13+
// 更新卡尔曼滤波器状态
14+
float KalmanFilter_Update(KalmanFilter *kf, float measurement)
15+
{
16+
// 预测步骤
17+
kf->P = kf->P + kf->Q; // 更新估计误差协方差
18+
19+
// 更新步骤
20+
kf->K = kf->P / (kf->P + kf->R); // 计算卡尔曼增益
21+
kf->x = kf->x + kf->K * (measurement - kf->x); // 更新状态估计值
22+
kf->P = (1 - kf->K) * kf->P; // 更新估计误差协方差
23+
24+
return kf->x; // 返回滤波后的状态估计值
25+
}

src/algorithms/kalman_filter.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#ifndef KALMAN_FILTER_H
2+
#define KALMAN_FILTER_H
3+
4+
typedef struct {
5+
float Q; // 过程噪声协方差
6+
float R; // 观测噪声协方差
7+
float P; // 估计误差协方差
8+
float K; // 卡尔曼增益
9+
float x; // 状态估计值
10+
} KalmanFilter;
11+
12+
// 初始化卡尔曼滤波器
13+
void KalmanFilter_Init(KalmanFilter *kf, float Q, float R, float P, float initial_value);
14+
15+
// 更新卡尔曼滤波器状态
16+
float KalmanFilter_Update(KalmanFilter *kf, float measurement);
17+
18+
#endif // KALMAN_FILTER_H

test/test_algorithms.c

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,79 @@ START_TEST(test_medianFilter)
2727
}
2828
END_TEST
2929

30+
// 测试初始化函数
31+
START_TEST(test_kalman_filter_init)
32+
{
33+
KalmanFilter kf;
34+
KalmanFilter_Init(&kf, 0.01, 0.1, 1, 0);
35+
36+
ck_assert_float_eq(kf.Q, 0.01);
37+
ck_assert_float_eq(kf.R, 0.1);
38+
ck_assert_float_eq(kf.P, 1);
39+
ck_assert_float_eq(kf.x, 0);
40+
ck_assert_float_eq(kf.K, 0);
41+
}
42+
END_TEST
43+
44+
// 测试更新函数
45+
START_TEST(test_kalman_filter_update)
46+
{
47+
KalmanFilter kf;
48+
KalmanFilter_Init(&kf, 0.01, 0.1, 1, 0);
49+
50+
float measurement = 1.2;
51+
float filtered_value = KalmanFilter_Update(&kf, measurement);
52+
53+
// 检查卡尔曼增益和状态估计值是否合理
54+
ck_assert(kf.K > 0 && kf.K < 1);
55+
ck_assert(filtered_value > 0 && filtered_value < measurement);
56+
}
57+
END_TEST
58+
59+
// 测试多次更新
60+
START_TEST(test_kalman_filter_multiple_updates)
61+
{
62+
KalmanFilter kf;
63+
KalmanFilter_Init(&kf, 0.01, 0.1, 1, 0);
64+
65+
// 模拟含噪声的测量数据(真实值为 1.0)
66+
float measurements[] = {1.2, 0.9, 1.1, 0.8, 1.3, 1.1, 0.7, 1.4, 0.6, 1.5};
67+
int num_measurements = sizeof(measurements) / sizeof(measurements[0]);
68+
69+
// 记录滤波后的值
70+
float filtered_values[num_measurements];
71+
72+
// 更新卡尔曼滤波器
73+
for (int i = 0; i < num_measurements; i++)
74+
{
75+
filtered_values[i] = KalmanFilter_Update(&kf, measurements[i]);
76+
// printf("measurement: %f, filtered: %f\n", measurements[i], filtered_values[i]);
77+
}
78+
79+
// 检查滤波后的值是否逐渐收敛到真实值(1.0)
80+
for (int i = 1; i < num_measurements; i++)
81+
{
82+
// 检查滤波后的值是否比原始测量值更接近真实值
83+
float measurement_error = fabs(measurements[i] - 1.0);
84+
float filtered_error = fabs(filtered_values[i] - 1.0);
85+
// printf("measurement_error: %f, filtered_error: %f\n", measurement_error, filtered_error);
86+
ck_assert(filtered_error <= measurement_error);
87+
88+
// 检查滤波后的值是否逐渐稳定
89+
if (i > 1)
90+
{
91+
float delta = fabs(filtered_values[i] - filtered_values[i - 1]);
92+
// printf("delta: %f\n", delta);
93+
ck_assert(delta < 0.2); // 确保滤波后的值变化不大
94+
}
95+
}
96+
97+
// 检查最终滤波后的值是否接近真实值
98+
float final_error = fabs(filtered_values[num_measurements - 1] - 1.0);
99+
ck_assert(final_error < 0.2);
100+
}
101+
END_TEST
102+
30103
// 辅助函数:比较浮点数是否相等(允许一定的误差)
31104
int float_equal(float a, float b, float epsilon)
32105
{
@@ -131,11 +204,11 @@ START_TEST(test_cubic_fit)
131204

132205
polyfit(x, y, n, 3, coef);
133206

134-
printf("拟合的三次多项式为: y = %.12fx^3 + %.12fx^2 + %.12fx + %.12f\n", coef[3], coef[2], coef[1], coef[0]);
207+
// printf("拟合的三次多项式为: y = %.12fx^3 + %.12fx^2 + %.12fx + %.12f\n", coef[3], coef[2], coef[1], coef[0]);
135208

136209
double x_max_y, max_y;
137210
find_max_y_x(coef, 105, 113, &x_max_y, &max_y);
138-
printf("在范围 [105,113] 内, 最大 y 值为 %.5f 对应 x = %.5f\n", max_y, x_max_y);
211+
// printf("在范围 [105,113] 内, 最大 y 值为 %.5f 对应 x = %.5f\n", max_y, x_max_y);
139212
ck_assert_int_le(max_y, 0.00063);
140213
ck_assert_int_ge(max_y, 0.00057);
141214
ck_assert_int_le(x_max_y, 113);
@@ -331,6 +404,9 @@ Suite *algorithms_suite(void)
331404
tcase_add_test(tc_mean, test_meanFilterint32);
332405
tcase_add_test(tc_mean, test_meanFilterFloat);
333406
tcase_add_test(tc_mean, test_medianFilter);
407+
tcase_add_test(tc_mean, test_kalman_filter_init);
408+
tcase_add_test(tc_mean, test_kalman_filter_update);
409+
tcase_add_test(tc_mean, test_kalman_filter_multiple_updates);
334410
suite_add_tcase(s, tc_mean);
335411
/* Core test case */
336412
TCase *tc_cubic_fit = tcase_create("cubic_fit");

0 commit comments

Comments
 (0)