GD32F103卡尔曼滤波实现及效果

[复制链接]
2759|9
 楼主| zeshoufx 发表于 2022-11-25 20:53 | 显示全部楼层 |阅读模式
卡尔曼滤波在数据去噪,获得真实值的运用中广泛使用,在采集一些信号时,很实用。
测试方法:通过将DAC输出与ADC连接,,DAC输出一固定值
通过ADC采集数据,由于ADC精度受限以及一些干扰,ADC采集到
的数据在固定值附近波动,通过卡尔曼滤波估计一下ADC采集的真实值。

这个与之前的PID测试有点区别,PID是设定目标,自动调节DAC,使
ADC采集数据接近目标。
PID演示连接:
专栏:ARM DSP库 PID控制测试 - 哔哩哔哩 (bilibili.com)
视频:【ARM单片机PID控制测试——基于DSP库】 https://www.bilibili.com/video/BV1sd4y1w755/?share_source=copy_web&vd_source=7f0cb9c0f09b768583faf157910eb515
视频
1、卡尔曼滤波结构体:type_KalmanFilter
  1. //卡尔曼滤波结构体
  2. typedef struct KalmanFilter
  3. {
  4.         float x_mea;         // 测量值
  5.         float x_est;         // 估计值
  6.         float e_mea;         // 测量偏差
  7.         float e_est;         // 估计偏差
  8.         float Kk;                  // Karlman 增益
  9. }type_KalmanFilter;
2、初始化,为结构体成员赋值
  1. //Kalman初始化
  2. void Kalman_Init(type_KalmanFilter* kalmanFilter, float FirstMeaValue, float E_mea, float FirstEstValue, float E_est)
  3. {
  4.         kalmanFilter->x_est = FirstEstValue;
  5.         kalmanFilter->x_mea = FirstMeaValue;
  6.         kalmanFilter->e_est = E_est;
  7.         kalmanFilter->e_mea = E_mea;
  8.         kalmanFilter->Kk = Kk_calc(kalmanFilter->e_est, kalmanFilter->e_mea);
  9. }
3、更新,将采集到的数据作为测量输入
  1. //Kalman更新
  2. void Kalman_Update(type_KalmanFilter* kalmanFilter, float newMeaValue)
  3. {
  4.         float temp = kalmanFilter->e_est;
  5.         kalmanFilter->x_est = kalmanFilter->x_est + kalmanFilter->Kk * (newMeaValue - kalmanFilter->x_est);
  6.         kalmanFilter->x_mea = newMeaValue;
  7.         kalmanFilter->Kk = Kk_calc(kalmanFilter->e_est, kalmanFilter->e_mea);
  8.         kalmanFilter->e_est = (1 - kalmanFilter->Kk) * temp;
  9. }
4、端口设置
  1. void ad_da_init(void)
  2. {
  3.         //时钟配置
  4.         rcu_periph_clock_enable(RCU_GPIOA);
  5.         rcu_periph_clock_enable(RCU_AF);
  6.         rcu_periph_clock_enable(RCU_ADC0);
  7.         rcu_periph_clock_enable(RCU_DAC);
  8.        
  9.         rcu_adc_clock_config(RCU_CKADC_CKAPB2_DIV12);
  10.        
  11.         //接口配置
  12.         gpio_init(GPIOA,GPIO_MODE_AIN,GPIO_OSPEED_50MHZ,GPIO_PIN_4);
  13.         gpio_init(GPIOA,GPIO_MODE_AIN,GPIO_OSPEED_50MHZ,GPIO_PIN_6);
  14.        
  15.         //ADC输入配置
  16.         adc_special_function_config(ADC0,ADC_CONTINUOUS_MODE,ENABLE);
  17.         adc_data_alignment_config(ADC0,ADC_DATAALIGN_RIGHT);
  18.         adc_channel_length_config(ADC0,ADC_REGULAR_CHANNEL,1);
  19.         adc_regular_channel_config(ADC0,0,ADC_CHANNEL_6,ADC_SAMPLETIME_55POINT5);
  20.         adc_external_trigger_config(ADC0,ADC_REGULAR_CHANNEL,DISABLE);
  21.        
  22.         adc_enable(ADC0);
  23.         delay_ms(1);
  24.         adc_calibration_enable(ADC0);
  25.        
  26.         //DAC输出配置
  27.         dac_trigger_source_config(DAC0,DAC_TRIGGER_SOFTWARE);
  28.         dac_trigger_enable(DAC0);
  29.         dac_wave_mode_config(DAC0,DAC_WAVE_DISABLE);
  30.         dac_output_buffer_enable(DAC0);
  31.        
  32.         dac_enable(DAC0);
  33.         dac_data_set(DAC0, DAC_ALIGN_12B_R, (u16)1024);
  34.     dac_software_trigger_enable(DAC0);
  35.        
  36.         //Kalman初始化
  37.         Kalman_Init(&k, 1024, 2, 1024, 2);
  38. }
5、滤波处理
  1. void dsp_test(void)
  2. {
  3.         u16 adc_get=0;
  4.        
  5.         adc_software_trigger_enable(ADC0,ADC_REGULAR_CHANNEL);
  6.         if(adc_flag_get(ADC0,ADC_FLAG_EOC))
  7.         {
  8.                 adc_flag_clear(ADC0,ADC_FLAG_EOC);
  9.                 adc_get = adc_regular_data_read(ADC0);
  10.                 Kalman_Update(&k,adc_get);
  11.         }
  12.        
  13.         printf("%d        %f        %f\r\n",adc_get,k.x_mea,k.x_est);
  14. }
6、主函数
  1. #include "bitband.h"
  2. #include "led.h"
  3. #include "systick.h"
  4. #include "print.h"
  5. #include "dsp_test.h"

  6. u16 mem_infor[2]={0};
  7. u32 uid[3]={0};


  8. int main(void)
  9. {
  10.     systick_set(96);
  11.         led_init();
  12.        
  13.         print_config(9600);
  14.        
  15.         get_mem_infor(&mem_infor[0],&mem_infor[1]);
  16.         printf("GD32F103VKT6 Flash Size=%dKB,Sram Size=%dKB...\r\n",mem_infor[1],mem_infor[0]);
  17.         get_uid(uid);
  18.         printf("GD32F103VKT6 UID=%d%d%d...\r\n",uid[0],uid[1],uid[2]);
  19.        
  20.         ad_da_init();
  21.        
  22.     while(1)
  23.         {
  24.                 dsp_test();
  25.                 delay_ms(100);
  26.     }
  27. }
演示视频:
GD32F103卡尔曼滤波实现
【GD32F103卡尔曼滤波测试】 https://www.bilibili.com/video/BV1bR4y1o7TQ/?share_source=copy_web&vd_source=7f0cb9c0f09b768583faf157910eb515
GD32F103卡尔曼滤波测试效果
【GD32F103卡尔曼滤波测试效果】 https://www.bilibili.com/video/BV1u14y1n7KD/?share_source=copy_web&vd_source=7f0cb9c0f09b768583faf157910eb515
7、将数据打印输出,导入MATLAB,结果如图所示:
可以看到整体上实际的采集值在波动,而卡尔曼滤波估计的真实值却基本很平稳

结果2

结果2

结果1

结果1
呐咯密密 发表于 2022-11-26 16:58 | 显示全部楼层
这个卡尔曼滤波执行一次时间多久,会不会影响系统的时效性
 楼主| zeshoufx 发表于 2022-11-26 20:00 | 显示全部楼层
呐咯密密 发表于 2022-11-26 16:58
这个卡尔曼滤波执行一次时间多久,会不会影响系统的时效性

还没具体测试过,,,我觉得跟多采集几次然后取平均这种暴力滤波方式差不多,,明天测试后补充,,,
OKAKAKO 发表于 2022-12-2 17:08 | 显示全部楼层
zeshoufx 发表于 2022-11-26 20:00
还没具体测试过,,,我觉得跟多采集几次然后取平均这种暴力滤波方式差不多,,明天测试后补充 ...

估计跟直接取平均还是有区别的,大概误差应该在0.2左右
 楼主| zeshoufx 发表于 2022-12-2 20:08 | 显示全部楼层
OKAKAKO 发表于 2022-12-2 17:08
估计跟直接取平均还是有区别的,大概误差应该在0.2左右

0.2秒吗
Jacquetry 发表于 2022-12-21 17:35 | 显示全部楼层
这个应该会有一点误差的
星辰大海不退缩 发表于 2022-12-22 16:25 | 显示全部楼层
卡尔曼滤波确实通过MATLAB分析后的结果很稳定,果然滤波能消除干扰
jf101 发表于 2022-12-24 13:26 | 显示全部楼层
zeshoufx 发表于 2022-11-26 20:00
还没具体测试过,,,我觉得跟多采集几次然后取平均这种暴力滤波方式差不多,,明天测试后补充 ...

楼主,平均算法滤波测试了嘛?结果跟卡尔曼滤波差距怎么样?
dspmana 发表于 2023-1-9 17:42 | 显示全部楼层
这个卡尔曼可以做数据融合的吗?              
pentruman 发表于 2023-1-9 17:51 | 显示全部楼层
这个的计算量应该不会很小了。              
您需要登录后才可以回帖 登录 | 注册

本版积分规则

67

主题

1991

帖子

15

粉丝
快速回复 在线客服 返回列表 返回顶部