1. 滑动平均值滤波算法

  • 实现思想:滑动平均值滤波的基本原理是在内存中建立一个数据缓冲区,顺序存放 N 个采样数据。每当采进一个新数据时,最早采集的数据会被丢弃,然后计算包括新数据在内的 N 个数据的算术平均值或加权平均值。这样,每次采样时都能计算出一个新的平均值,从而加快了数据处理的速度。无论是算术平均值滤波还是加权平均值滤波,都需要连续采样 N 个数据,然后求算术平均值或加权平均值。
  • 优点:
    1. 平滑度高:能有效去除数据中的高频噪声,使得数据曲线更加平滑,适用于需要降噪的应用场景。
    2. 对周期性干扰有良好的抑制作用:这种方法通过计算一系列数据的平均值来减少随机波动,特别适用于处理周期性或重复性的数据模式。
  • 缺点:
    1. 灵敏度低:由于滑动平均值滤波主要关注数据的平均变化,因此对于快速或突然的变化响应较慢,可能导致对某些重要事件或数据的忽略。
    2. 对脉冲性干扰抑制作用较差:在数据中存在突发的脉冲或尖峰时,滑动平均值滤波可能无法有效消除这些由脉冲干扰引起的采样值偏差,尤其是在干扰较为频繁或严重的情况下。
    3. 资源消耗较大:实现滑动平均值滤波通常需要较大的数据缓冲区来存储连续的数据样本,这可能会占用较多的 RAM 资源,特别是在处理大量数据时。
    4. 存在滞后性:由于是新数据替换旧数据并重新计算平均值,这可能导致滤波结果对输入信号的变化有一定的延迟。
/* Moving Average Filter Struct - float */
typedef struct
{
    float *p_avg_buf;
    uint32_t buf_max_deep;
    uint32_t index;
    uint32_t buf_is_full;
} move_avg_filter_st;
 
extern float move_avg_filter_clean(move_avg_filter_st *move_avg_filter);
extern float move_avg_filter_run(move_avg_filter_st *move_avg_filter, float val);
 
/* Moving Average Filter - Initialization and Run functions */
#define REG_MOVE_AVG_FILTER(name, deep)                                      \
    float mov_avg_buf_##name[deep] = {0.0F};                                 \
    move_avg_filter_st move_avg_filter_##name =                              \
    {                                                                        \
        .p_avg_buf = mov_avg_buf_##name,                                     \
        .buf_max_deep = deep,                                                \
        .index = 0,                                                          \
        .buf_is_full = 0                                                     \
    };
#define MOVE_AVG_FILTER_NAME(name) &move_avg_filter_##name
#define RUN_MOVE_AVG_FILTER(name, val) move_avg_filter_run(&move_avg_filter_##name, val)
 
/**
 * @brief       清除滑动平均值滤波过程变量
 * @param [in]  move_avg_filter     滑动平均值滤波结构体指针
 * @param [out] none
 * @retval      返回结果            1-清除完成
 * @details     相当于重新初始化, 下标和满标志清零, 缓冲区全部写0.
 */
float move_avg_filter_clean(move_avg_filter_st *move_avg_filter)
{
    uint32_t i;
    move_avg_filter->index = 0;
    move_avg_filter->buf_is_full = 0;
    for (i = 0; i < move_avg_filter->buf_max_deep; i++)
    {
        move_avg_filter->p_avg_buf[i] = 0.0F;
    }
    return 1;
}
 
/**
 * @brief       滑动平均值滤波
 * @param [in]  move_avg_filter     滑动平均值滤波结构体指针
 * @param [in]  val                 本次采样值
 * @param [out] none
 * @retval      返回结果            滤波后的平均值; 缓冲区无效或深度为0时返回0
 * @details     float类型数据滤波;
 *              deep = 0时, 直接返回0;
 *              deep < 3时, 直接取平均值;
 *              deep >= 3时, 滤除最大最小值后取平均值.
 */
float move_avg_filter_run(move_avg_filter_st *move_avg_filter, float val)
{
    float sum_val = 0.0F;
    float min_val = 0.0F;
    float max_val = 0.0F;
    float ret_val = 0.0F;
    uint32_t i;
    uint32_t deep;
 
    if ((move_avg_filter->p_avg_buf == NULL) || (move_avg_filter->buf_max_deep == 0))
    {
        return ret_val;
    }
 
    move_avg_filter->p_avg_buf[move_avg_filter->index] = val;
    move_avg_filter->index += 1;
    if (move_avg_filter->index >= move_avg_filter->buf_max_deep)
    {
        move_avg_filter->index = 0;
        move_avg_filter->buf_is_full = 1;
    }
 
    if (move_avg_filter->buf_is_full)
    {
        deep = move_avg_filter->buf_max_deep;
    }
    else
    {
        deep = move_avg_filter->index;
    }
 
    if (deep == 0)
    {
        return ret_val;
    }
    min_val = move_avg_filter->p_avg_buf[0];
    max_val = min_val;
    for (i = 0; i < deep; i++)
    {
        if (move_avg_filter->p_avg_buf[i] < min_val)
        {
            min_val = move_avg_filter->p_avg_buf[i];
        }
        if (move_avg_filter->p_avg_buf[i] > max_val)
        {
            max_val = move_avg_filter->p_avg_buf[i];
        }
        sum_val += move_avg_filter->p_avg_buf[i];
    }
 
    if (deep >= 3)
    {
        sum_val = sum_val - max_val - min_val;
        ret_val = (float)(sum_val / (deep - 2));
    }
    else
    {
        ret_val = (float)(sum_val / deep);
    }
 
    return ret_val;
}
 
// 使用例子:
REG_MOVE_AVG_FILTER(vol, 10);
int main(void)
{
    static float test_val = 3300.0F;
    static float output = 0.0F;
 
    while (1)
    {
        // output = RUN_MOVE_AVG_FILTER(vol, test_val);
        output = move_avg_filter_run(MOVE_AVG_FILTER_NAME(vol), test_val);
 
        printf("output = %f\n", output);
 
        if (++test_val == 3400.0F)
        {
            move_avg_filter_clean(MOVE_AVG_FILTER_NAME(vol));
            test_val = 3400.0F;
            break;
        }
    }
 
    return 0;
}