|
|
非常好用的adc滤波算法,滑动窗口滤波+自适应一阶低通,实际效果很好的压制了噪声
- #include "bsp.h"
- #include <math.h>
- /* ˲ */
- Kalman kfp;
- #define ADC_CHANNEL_NUM 4
- static AdaptiveFilterState adc_filter_states[ADC_CHANNEL_NUM] = {
- {0, 0.0f}, // 通道0
- {0, 0.0f}, // 通道1
- {0, 0.0f}, // 通道2
- {0, 0.0f} // 通道3
- };
- // 连续自适应滤波器(沿用原函数名以保持系统兼容)
- float adc_kalman_filter(int channel, float ADC_Value) {
- // 限制通道有效性,防止越界
- if (channel < 0 || channel >= ADC_CHANNEL_NUM) {
- return ADC_Value; // 无效通道返回原始值
- }
- // 获取当前通道状态
- AdaptiveFilterState *state = &adc_filter_states[channel];
- // 初始化判定:使用标志位,避免传感器真实值为 0 时反复重置
- if (!state->initialized) {
- state->filtered_old = ADC_Value;
- state->initialized = 1;
- return ADC_Value;
- }
- // 1. 计算当前测量值与上一次滤波值的绝对差值
- float diff = fabs(ADC_Value - state->filtered_old);
- // 2. 使用差值的平方进行自适应计算,以获得更陡峭的过渡曲线
- // 突变时极速收敛,静态时超级稳定
- float diff2 = diff * diff;
- float k2 = ADAPTIVE_K_SENSITIVITY * ADAPTIVE_K_SENSITIVITY;
- float alpha = ADAPTIVE_ALPHA_MIN + (ADAPTIVE_ALPHA_MAX - ADAPTIVE_ALPHA_MIN) * (diff2 / (diff2 + k2));
- // 3. 一阶低通滤波迭代
- float filtered_value = alpha * ADC_Value + (1.0f - alpha) * state->filtered_old;
- // 4. 更新历史滤波状态
- state->filtered_old = filtered_value;
- return filtered_value; // 返回滤波结果
- }
- /*˲*/
- // λͷָ飨ÿάǰдλã
- static int window_heads[MAX_SENSOR_NUM] = {0}; // ʼΪ0
- // ݲб
- int32_t m_dataList[MAX_SENSOR_NUM][MAX_DATA_NUM] = {0};
- void InsertionSort(int32_t array[], int len) {
- int32_t key;
- int i, j;
- for (i = 1; i < len; i++) {
- key = array[i];
- j = i - 1;
-
- while (j >= 0 && array[j] > key) {
- array[j + 1] = array[j];
- j--;
- }
- array[j + 1] = key;
- }
- }
- // ھֵ˲ȥֵ
- // index - Ӧͬݣdata - ǰ
- // ֵ˲Ľֵ
- float Filter_SlidingWindowAvg(int index, int32_t data) {
- // 静态数组:记录每个通道当前已采集的数据个数,初始为0
- static int dataNum[MAX_SENSOR_NUM] = {0};
- int i;
- int64_t sum = 0; // 累加和,使用int64防止溢出
- float out = 0.0f; // 滤波输出
- int32_t array[MAX_DATA_NUM] = {0}; // 临时排序数组
- int current_head = window_heads[index]; // 获取当前通道的环形缓冲区写指针
- // 将新数据写入当前写指针位置
- m_dataList[index][current_head] = data; // 写入数据
- window_heads[index] = (current_head + 1) % MAX_DATA_NUM; // 写指针前移
- // 1. 如果当前数据还未填满滑动窗口
- if (dataNum[index] < MAX_DATA_NUM) {
- dataNum[index]++;
- if (dataNum[index] < 3) {
- // 数据点太少(<3),直接简单平均
- for (i = 0; i < dataNum[index]; i++) {
- int pos = current_head - i;
- if (pos < 0) {
- pos += MAX_DATA_NUM;
- }
- sum += m_dataList[index][pos];
- }
- out = (float)sum / dataNum[index];
- } else {
- // 数据点 >= 3,拷贝到临时数组排序后去极值
- int32_t tmpArr[MAX_DATA_NUM] = {0};
- for (i = 0; i < dataNum[index]; i++) {
- int pos = current_head - i;
- if (pos < 0) {
- pos += MAX_DATA_NUM;
- }
- tmpArr[i] = m_dataList[index][pos];
- }
- InsertionSort(tmpArr, dataNum[index]);
- // 去掉首尾各 1 个极值,对中间部分求平均
- for (i = 1; i < dataNum[index] - 1; i++) {
- sum += tmpArr[i];
- }
- out = (float)sum / (dataNum[index] - 2);
- }
- }
- // 2. 滑动窗口已填满
- else {
- // 按照时间顺序拷贝数据到临时数组(最新写入的数据在 current_head 处)
- for (i = 0; i < MAX_DATA_NUM; i++) {
- int pos = current_head - i;
- if (pos < 0) {
- pos += MAX_DATA_NUM;
- }
- array[i] = m_dataList[index][pos];
- }
- // 插入排序
- InsertionSort(array, MAX_DATA_NUM);
- // 去掉两端极值,对中间 WINDOW_DATA_NUM 个点求平均
- int start = (MAX_DATA_NUM - WINDOW_DATA_NUM) / 2;
- for (i = start; i < start + WINDOW_DATA_NUM; i++) {
- sum += array[i];
- }
- out = (float)sum / WINDOW_DATA_NUM; // 使用浮点数除法保留精度
- }
- return out;
- }
复制代码
|
-
-
filter.rar
2.89 KB, 下载次数: 0, 下载积分: 黑币 -5
自适应滤波+滑动平均
评分
-
查看全部评分
|