C语言实现滑动平均滤波器

前言

使用电机速度做闭环控制时,发现传感器的数据受到了高频噪声的影响,于是想先对其进行滤波处理。

原理

滑动平均滤波器本质是一个低通滤波器,可以看成FIR滤波器的一个特例。其时域表达为

y ( k ) = 1 N ∑ i = 0 N − 1 x ( k + i ) y(k)=\frac{1}{N} \sum_{i=0}^{N-1} x(k+i) y(k)=N1i=0N1x(k+i)
,其中N为滤波器长度。

代码

代码比较简单,我就没有注释。大概思想就是设置一个滤波器长度的数组,然后不断更新数组内容,再求平均就可以了。写的时候发现其实用队列写应该会更快,但是我懒了一把,因为单片机性能够用所以就算了,如果有写出来的,欢迎一起讨论哈。

/*滑动平均滤波器长度*/
#define MVF_LENGTH 8
float moving_average_filtre(float xn)
{
  static int index = -1;
  static float buffer[MVF_LENGTH];
  static float sum = 0;
  float yn = 0;
  int i = 0;
  if(index == -1)
  {
	//初始化
    for(i = 0; i <MVF_LENGTH; i++)
    {
      buffer[i] = xn;
    }
    sum = xn*MVF_LENGTH;
    index = 0;
  }
  else
  {
    sum -= buffer[index];
    buffer[index] = xn;
    sum += xn;
    index++;
    if(index >= MVF_LENGTH)
    {
      index = 0;
    }
  }
  yn = sum/MVF_LENGTH;
  return yn;
}

讨论

滑动平均滤波器的长度选择也是个值得讨论的问题。太短的话消除了不了高频噪声,太长的话延迟比较严重。
参考文章里给出了滤波器长度与系统截止频率的经验公式:
N = 0.443 ∗ f s / f c o \mathrm{N}=0.443* \mathrm{f}_{\mathrm{s}} / \mathrm{fco} N=0.443fs/fco

其中,fs为采样频率,fco为截至频率。推导的过程简单讲就是假设输入信号为正弦信号,且将离散信号变为连续信号之后,对输出信号进行傅里叶变换,进而得到他们的关系。
在这里插入图片描述
滑动平均滤波器频率响应

图片来源:https://www.cnblogs.com/pingwen/p/6670675.html

改进

最近又看到一个改进的计算公式,可以节省计算时间,原理很简单,学而不思则罔啊。

改进后的公式为:

y ( k ) = y ( k − 1 ) + 1 N ( x ( k ) − x ( k − N ) ) y(k)=y(k-1)+\frac{1}{N} (x(k)-x(k-N)) y(k)=y(k1)+N1x(k)x(kN)

参考文章

截止频率和MAF滤波器长度关系

  • 16
    点赞
  • 94
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
下面是用 C 语言实现滑动平均滤波器的示例代码: ```c #include <stdio.h> #define FILTER_SIZE 5 // 滤波器大小 float filter[FILTER_SIZE]; // 滤波器数组 int filter_index = 0; // 滤波器当前下标 float sum = 0; // 滤波器当前和 // 滑动平均滤波函数 float moving_average(float input) { sum -= filter[filter_index]; // 减去最早的数据 filter[filter_index] = input; // 加入最新的数据 sum += input; // 计算新的和 filter_index++; // 下标加 1 if(filter_index >= FILTER_SIZE) // 下标超过滤波器大小时,重置 { filter_index = 0; } return sum / FILTER_SIZE; // 返回平均值 } int main() { float input[] = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; // 输入数据 int input_size = sizeof(input) / sizeof(float); // 输入数据大小 for(int i = 0; i < input_size; i++) { printf("Input: %f\tOutput: %f\n", input[i], moving_average(input[i])); // 输出每次滤波的结果 } return 0; } ``` 该代码中,首先定义了一个常量 `FILTER_SIZE` 表示滤波器的大小,又定义了一个长度为 `FILTER_SIZE` 的数组 `filter` 来存储滤波器的数据,定义了一个变量 `filter_index` 表示当前滤波器的下标,定义了一个变量 `sum` 表示当前滤波器的和。 在 `moving_average` 函数中,每次输入一个数据 `input`,先将最早的数据从和中减去,再将最新的数据加入和中,计算得到新的平均值,并将最新的数据存入滤波器数组中。如果当前下标超过了滤波器大小,就将下标重置为 0。 在 `main` 函数中,输入一组数据并进行滤波,输出每次滤波的结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值