找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4|回复: 0
打印 上一主题 下一主题
收起左侧

stm32单片机适用的adc采样滤波算法

[复制链接]
跳转到指定楼层
楼主
ID:13307 发表于 2026-7-17 19:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
非常好用的adc滤波算法,滑动窗口滤波+自适应一阶低通,实际效果很好的压制了噪声

  1. #include "bsp.h"

  2. #include <math.h>

  3. /* ˲ */
  4. Kalman kfp;

  5. #define ADC_CHANNEL_NUM 4
  6. static AdaptiveFilterState adc_filter_states[ADC_CHANNEL_NUM] = {
  7.     {0, 0.0f}, // 通道0
  8.     {0, 0.0f}, // 通道1
  9.     {0, 0.0f}, // 通道2
  10.     {0, 0.0f}  // 通道3
  11. };

  12. // 连续自适应滤波器(沿用原函数名以保持系统兼容)
  13. float adc_kalman_filter(int channel, float ADC_Value) {
  14.   // 限制通道有效性,防止越界
  15.   if (channel < 0 || channel >= ADC_CHANNEL_NUM) {
  16.     return ADC_Value; // 无效通道返回原始值
  17.   }

  18.   // 获取当前通道状态
  19.   AdaptiveFilterState *state = &adc_filter_states[channel];

  20.   // 初始化判定:使用标志位,避免传感器真实值为 0 时反复重置
  21.   if (!state->initialized) {
  22.     state->filtered_old = ADC_Value;
  23.     state->initialized = 1;
  24.     return ADC_Value;
  25.   }

  26.   // 1. 计算当前测量值与上一次滤波值的绝对差值
  27.   float diff = fabs(ADC_Value - state->filtered_old);

  28.   // 2. 使用差值的平方进行自适应计算,以获得更陡峭的过渡曲线
  29.   //    突变时极速收敛,静态时超级稳定
  30.   float diff2 = diff * diff;
  31.   float k2 = ADAPTIVE_K_SENSITIVITY * ADAPTIVE_K_SENSITIVITY;
  32.   float alpha = ADAPTIVE_ALPHA_MIN + (ADAPTIVE_ALPHA_MAX - ADAPTIVE_ALPHA_MIN) * (diff2 / (diff2 + k2));

  33.   // 3. 一阶低通滤波迭代
  34.   float filtered_value = alpha * ADC_Value + (1.0f - alpha) * state->filtered_old;

  35.   // 4. 更新历史滤波状态
  36.   state->filtered_old = filtered_value;

  37.   return filtered_value; // 返回滤波结果
  38. }

  39. /*˲*/
  40. // λͷָ飨ÿάǰдλã
  41. static int window_heads[MAX_SENSOR_NUM] = {0}; // ʼΪ0
  42. // ݲб
  43. int32_t m_dataList[MAX_SENSOR_NUM][MAX_DATA_NUM] = {0};


  44. void InsertionSort(int32_t array[], int len) {
  45.   int32_t key;
  46.   int i, j;
  47.   for (i = 1; i < len; i++) {
  48.     key = array[i];
  49.     j = i - 1;
  50.    
  51.     while (j >= 0 && array[j] > key) {
  52.       array[j + 1] = array[j];
  53.       j--;
  54.     }
  55.     array[j + 1] = key;
  56.   }
  57. }

  58. // ھֵ˲ȥֵ
  59. // index - Ӧͬݣdata - ǰ
  60. // ֵ˲Ľֵ
  61. float Filter_SlidingWindowAvg(int index, int32_t data) {
  62.   // 静态数组:记录每个通道当前已采集的数据个数,初始为0
  63.   static int dataNum[MAX_SENSOR_NUM] = {0};
  64.   int i;
  65.   int64_t sum = 0;                        // 累加和,使用int64防止溢出
  66.   float out = 0.0f;                       // 滤波输出
  67.   int32_t array[MAX_DATA_NUM] = {0};      // 临时排序数组
  68.   int current_head = window_heads[index]; // 获取当前通道的环形缓冲区写指针

  69.   // 将新数据写入当前写指针位置
  70.   m_dataList[index][current_head] = data;                  // 写入数据
  71.   window_heads[index] = (current_head + 1) % MAX_DATA_NUM; // 写指针前移

  72.   // 1. 如果当前数据还未填满滑动窗口
  73.   if (dataNum[index] < MAX_DATA_NUM) {
  74.     dataNum[index]++;

  75.     if (dataNum[index] < 3) {
  76.       // 数据点太少(<3),直接简单平均
  77.       for (i = 0; i < dataNum[index]; i++) {
  78.         int pos = current_head - i;
  79.         if (pos < 0) {
  80.           pos += MAX_DATA_NUM;
  81.         }
  82.         sum += m_dataList[index][pos];
  83.       }
  84.       out = (float)sum / dataNum[index];
  85.     } else {
  86.       // 数据点 >= 3,拷贝到临时数组排序后去极值
  87.       int32_t tmpArr[MAX_DATA_NUM] = {0};
  88.       for (i = 0; i < dataNum[index]; i++) {
  89.         int pos = current_head - i;
  90.         if (pos < 0) {
  91.           pos += MAX_DATA_NUM;
  92.         }
  93.         tmpArr[i] = m_dataList[index][pos];
  94.       }
  95.       InsertionSort(tmpArr, dataNum[index]);
  96.       // 去掉首尾各 1 个极值,对中间部分求平均
  97.       for (i = 1; i < dataNum[index] - 1; i++) {
  98.         sum += tmpArr[i];
  99.       }
  100.       out = (float)sum / (dataNum[index] - 2);
  101.     }
  102.   }
  103.   // 2. 滑动窗口已填满
  104.   else {
  105.     // 按照时间顺序拷贝数据到临时数组(最新写入的数据在 current_head 处)
  106.     for (i = 0; i < MAX_DATA_NUM; i++) {
  107.       int pos = current_head - i;
  108.       if (pos < 0) {
  109.         pos += MAX_DATA_NUM;
  110.       }
  111.       array[i] = m_dataList[index][pos];
  112.     }
  113.     // 插入排序
  114.     InsertionSort(array, MAX_DATA_NUM);

  115.     // 去掉两端极值,对中间 WINDOW_DATA_NUM 个点求平均
  116.     int start = (MAX_DATA_NUM - WINDOW_DATA_NUM) / 2;
  117.     for (i = start; i < start + WINDOW_DATA_NUM; i++) {
  118.       sum += array[i];
  119.     }
  120.     out = (float)sum / WINDOW_DATA_NUM; // 使用浮点数除法保留精度
  121.   }
  122.   return out;
  123. }
复制代码


filter.rar

2.89 KB, 下载次数: 0, 下载积分: 黑币 -5

自适应滤波+滑动平均

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表