单片机数字滤波算法如何实现?(附代码)

关注、星标公众号,直达精彩内容

ID:技术让梦想更伟大

整理:李肖遥

单片机主要作用是控制外围的器件,并实现一定的通信和数据处理。

但在某些特定场合,不可避免地要用到数学运算,尽管单片机并不擅长实现算法和进行复杂的运算。

下面主要是介绍如何用单片机实现数字滤波。

在单片机进行数据采集时,会遇到数据的随机误差,随机误差是由随机干扰引起的,其特点是在相同条件下测量同一量时,其大小和符号会现无规则的变化而无法预测,但多次测量的结果符合统计规律。

为克服随机干扰引起的误差,硬件上可采用滤波技术,软件上可采用软件算法实现数字滤波。滤波算法往往是系统测控算法的一个重要组成部分,实时性很强。

采用数字滤波算法克服随机干扰的误差具有以下优点:

  1. 数字滤波无需其他的硬件成本,只用一个计算过程,可靠性高,不存在阻抗匹配问题。尤其是数字滤波可以对频率很低的信号进行滤波,这是模拟滤波器做不到的。

  2. 数字滤波使用软件算法实现,多输入通道可共用一个滤波程序,降低系统开支。

  3. 只要适当改变滤波器的滤波程序或运算,就能方便地改变其滤波特性,这对于滤除低频干扰和随机信号会有较大的效果。

  4. 在单片机系统中常用的滤波算法有限幅滤波法、中值滤波法、算术平均滤波法、加权平均滤波法、滑动平均滤波等。

限幅滤波算法

该运算的过程中将两次相邻的采样相减,求出其增量,然后将增量的绝对值,与两次采样允许的最大差值A进行比较。

A的大小由被测对象的具体情况而定,如果小于或等于允许的最大差值,则本次采样有效;否则取上次采样值作为本次数据的样本。

算法的程序代码如下:

 1#define A //允许的最大差值
 2
 3char data; //上一次的数据
 4
 5char filter()
 6
 7{
 8
 9    char datanew; //新数据变量
10
11    datanew=get_data(); //获得新数据变量
12
13    if((datanew-data)>A||(data-datanew>A))
14
15        return data;
16
17    else
18
19        return datanew;
20
21}

说明:

限幅滤波法主要用于处理变化较为缓慢的数据,如温度、物体的位置等。使用时,关键要选取合适的门限制A。通常这可由经验数据获得,必要时可通过实验得到。

中值滤波算法

该运算的过程是对某一参数连续采样N次(N一般为奇数),然后把N次采样的值按从小到大排列,再取中间值作为本次采样值,整个过程实际上是一个序列排序的过程。

算法的程序代码如下:

 1#define N 11 //定义获得的数据个数 2 3char filter()
 4
 5{
 6 7    char value_buff[N]; //定义存储数据的数组 8 9    char count,i,j,temp;
1011    for(count=0;count<N;count++)
1213    {
1415        value_buf[count]=get_data();
1617        delay(); //如果采集数据比较慢,那么就需要延时或中断1819    }
2021    for(j=0;j<N;j++)
2223    {
2425        if(value_buff[i]>value_buff[i+1])
2627        {
2829            temp=value_buff[i];
3031            value_buff[i]=value_buff[i+1];
3233            value_buff[i+1]=temp;
3435        }
3637    }
3839return value_buff[(N-1)/2];
4041}

说明:中值滤波比较适用于去掉由偶然因素引起的波动和采样器不稳定而引起的脉动干扰。若被测量值变化比较慢,采用中值滤波法效果会比较好,但如果数据变化比较快,则不宜采用此方法。

算术平均滤波算法

该算法的基本原理很简单,就是连续取N次采样值后进行算术平均。

算法的程序代码如下:

 1char filter()
 2
 3{
 4
 5    int sum=0;
 6
 7    for(count=0;count<N;count++)
 8
 9    {
10
11        sum+=get_data();
12
13        delay():
14
15    }
16
17    return (char)(sum/N);
18
19}

说明:算术平均滤波算法适用于对具有随机干扰的信号进行滤波。这种信号的特点是有一个平均值,信号在某一数值附近上下波动。

信号的平均平滑程度完全到决于N值。当N较大时,平滑度高,灵敏度低;当N较小时,平滑度低,但灵敏度高。为了方便求平均值,N一般取4、8、16、32之类的2的整数幂,以便在程序中用移位操作来代替除法。

加权平均滤波算法

由于前面所说的“算术平均滤波算法”存在平滑度和灵敏度之间的矛盾。为了协调平滑度和灵敏度之间的关系,可采用加权平均滤波。

它的原理是对连续N次采样值分别乘上不同的加权系数之后再求累加,加权系数一般先小后大,以突出后面若干采样的效果,加强系统对参数变化趋势的认识。

各个加权系数均小于1的小数,且满足总和等于1的结束条件。这样加权运算之后的累加和即为有效采样值。其中加权平均数字滤波的数学模型是:

式中:D为N个采样值的加权平均值:XN-i为第N-i次采样值;N为采样次数;Ci为加权系数。加权系数Ci体现了各种采样值在平均值中所占的比例。

一般来说采样次数越靠后,取的比例越大,这样可增加新采样在平均值中所占的比重。

加权平均值滤波法可突出一部分信号抵制另一部分信号,以提高采样值变化的灵敏度。

样例程序代码如下:

 1char codejq[N]={1,2,3,4,5,6,7,8,9,10,11,12}; //code数组为加权系数表,存在程序存储区
 2
 3char codesum_jq=1+2+3+4+5+6+7+8+9+10+11+12;
 4
 5char filter()
 6
 7{
 8
 9    char count;
10
11    char value_buff[N];
12
13    int sum=0;
14
15    for(count=0;count<N;count++)
16
17    {
18
19        value_buff[count]=get_data();
20
21        delay();
22
23    }
24
25    for(count=0;count<N;count++)
26
27        sum+=value_buff[count]*jq[count];
28
29    return (char)(sum/sum_jq);
30
31}

滑动平均滤波算法

以上介绍和各种平均滤波算法有一个共同点,即每获取一个有效采样值必须连续进行若干次采样,当采速度慢时,系统的实时得不到保证。

这里介绍的滑动平均滤波算法只采样一次,将一次采样值和过去的若干次采样值一起求平均,得到的有效采样值即可投入使用。

如果取N个采样值求平均,存储区中必须开辟N个数据的暂存区。

每新采集一个数据便存入暂存区中,同时去掉一个最老数据,保存这N个数据始终是最新更新的数据。采用环型队列结构可以方便地实现这种数据存放方式。

程序代码如下:

 1char value_buff[N];
 2
 3char i=0;
 4
 5char filter()
 6
 7{
 8
 9    char count;
10
11    int sum=0;
12
13    value_buff[i++]=get_data();
14
15    if(i==N)
16
17        i=0;
18
19    for(count=0;count<N;count++)
20
21        sum=value_buff[count];
22
23    return (char)(sum/N);
24
25}


低通滤波

将普通硬件RC低通滤波器的微分方程用差分方程来表求,变可以采用软件算法来模拟硬件滤波的功能,经推导,低通滤波算法如下:

1Yn=a* Xn+(1-a) *Yn-1
2
3式中 Xn——本次采样值
4
5Yn-1——上次的滤波输出值;
6
7a——滤波系数,其值通常远小于1;
8
9Yn——本次滤波的输出值。

由上式可以看出,本次滤波的输出值主要取决于上次滤波的输出值(注意不是上次的采样值,这和加权平均滤波是有本质区别的),本次采样值对滤波输出的贡献是比较小的,但多少有些修正作用,这种算法便模拟了具体有教大惯性的低通滤波器功能。滤波算法的截止频率可用以下式计算:

1fL=a/2Pit pi为圆周率3.14…
2
3式中 a——滤波系数;
4
5t——采样间隔时间;
6
7例如:当t=0.5s(即每秒2次),a=1/32时;
8
9fL=(1/32)/(2*3.14*0.5)=0.01Hz

当目标参数为变化很慢的物理量时,这是很有效的。另外一方面,它不能滤除高于1/2采样频率的干搅信号,本例中采样频率为2Hz,故对1Hz以上的干搅信号应采用其他方式滤除,

低通滤波算法程序于加权平均滤波相似,但加权系数只有两个:a和1-a。为计算方便,a取一整数,1-a用256-a,来代替,计算结果舍去最低字节即可,因为只有两项,a和1-a,均以立即数的形式编入程序中,不另外设表格。

虽然采样值为单元字节(8位A/D)。为保证运算精度,滤波输出值用双字节表示,其中一个字节整数,一字节小数,否则有可能因为每次舍去尾数而使输出不会变化。

设Yn-1存放在30H(整数)和31H(小数)两单元中,Yn存放在32H(整数)和33H(小数)中。

-END-

整理文章为传播相关技术,版权归原作者所有 |

| 如有侵权,请联系删除 |

往期好文合集

研究生,该学单片机还是PLC?

"单片机解密"是什么?

如何才能学好单片机?

  最 后  

 

若觉得文章不错,转发分享,也是我们继续更新的动力。

5T资源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,PCB、FPGA、DSP、labview、单片机、等等

在公众号内回复「更多资源」,即可免费获取,期待你的关注~

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 贝塞尔滤波是一种数字滤波器,可用于信号处理和图像处理中。在单片机中使用C语言编写贝塞尔滤波器可以通过以下步骤实现: 步骤1:了解贝塞尔滤波原理。贝塞尔滤波是一种低通滤波器,通过计算输入信号的加权平均值来减少高频噪音的影响。它通常使用递归方法实现。 步骤2:定义好所需的参数。贝塞尔滤波需要确定滤波器的阶数(order)和截止频率(cut off frequency)。这些参数将决定滤波器的性能。 步骤3:在C语言中编写贝塞尔滤波器的函数。该函数应该接受输入的数据和滤波器的参数,并返回滤波后的输出数据。 步骤4:在主程序中调用贝塞尔滤波器的函数。将输入数据传递给滤波器函数,并接收滤波后的输出数据。 步骤5:根据需要进行进一步的处理。滤波器可以作为预处理步骤来删除噪音,然后对滤波后的数据进行进一步的分析或操作。 需要注意的是,贝塞尔滤波器的性能和效果与滤波器的阶数和截止频率有关。较高的阶数和较低的截止频率可以提供更好的滤波效果,但也会增加计算负担和延迟。因此,在实际应用中需要根据需求做出权衡。 总之,单片机中使用C语言实现贝塞尔滤波可以通过理解贝塞尔滤波原理,定义参数,编写滤波器函数,并在主程序中调用函数来完成。 ### 回答2: 贝塞尔滤波是一种常用的数字滤波算法,可以通过降低噪声和平滑信号。在单片机实现贝塞尔滤波可以通过以下步骤: 1. 首先,在单片机中定义一个数组作为输入信号的缓冲区,并初始化一些必要的变量,如滤波器的阶数、采样率、截止频率等。 2. 确定贝塞尔滤波器的系数。贝塞尔滤波器的系数是根据所选的阶数和截止频率计算得到的。一般可通过公式或在线计算器得到。 3. 设置一个循环,不断读取输入信号。可以使用单片机的计时器或外部中断来定时采样输入信号。 4. 在循环中,将输入信号保存到缓冲区中,并按照贝塞尔滤波器的差分方程进行滤波计算。差分方程可以写成一个递推式,通过前面输入信号和滤波系数的加权系数计算当前输出信号。 5. 对输出信号进行处理,如显示、存储或发送到其他设备。 需要注意的是,在单片机实现贝塞尔滤波需要考虑输入信号的采样率、缓冲区的大小和处理能力,以保证滤波效果和实时性。此外,还需要根据具体的单片机型号和编程环境,合理选择相关的库函数和指令集。 总结来说,通过定义输入信号的缓冲区,确定滤波器系数,循环采样输入信号,并按照差分方程计算输出信号,可以在单片机实现贝塞尔滤波算法。这样可以减少信号中的噪声和实现信号的平滑。 ### 回答3: 贝塞尔滤波是一种数字滤波器,可以用于信号平滑处理和数据去噪。在单片机实现贝塞尔滤波,可以使用C语言编写相应的算法。 首先,需要了解贝塞尔滤波的原理。贝塞尔滤波是基于贝塞尔曲线的,其核心思想是通过计算滤波数据点的平均值,并将其位置移动到贝塞尔曲线上。具体来说,可以通过采样一组输入数据,然后计算出每个数据点在曲线上的位置,最后将这些位置的平均值作为输出。 在C语言中,可以通过定义一维数组来存储输入数据和输出数据。使用循环结构,遍历输入数据数组,计算每个数据点在曲线上的位置,并将其存储到输出数据数组中。最后,对输出数据进行平均处理,得到最终的滤波结果。 以下是一个简单的C语言代码示例: ```c #define NUM_SAMPLES 10 // 输入数据点的数量 #define FILTER_ORDER 3 // 贝塞尔滤波器的阶数 // 输入数据和输出数据数组定义,长度为NUM_SAMPLES float input_data[NUM_SAMPLES]; float output_data[NUM_SAMPLES]; // 贝塞尔滤波函数 float bezier_filter(float x[], float y[], int n, float t) { float result = 0; for (int i = 0; i < n; i++) { float coefficient = 1; for (int j = 0; j < n; j++) { if (j != i) { coefficient *= (t - x[j]) / (x[i] - x[j]); } } result += coefficient * y[i]; } return result; } // 贝塞尔滤波过程 void bezier_filtering() { for (int i = 0; i < NUM_SAMPLES; i++) { // 计算贝塞尔滤波曲线上的位置 float t = (float)i / (NUM_SAMPLES - 1); output_data[i] = bezier_filter(x, input_data, FILTER_ORDER, t); } } int main() { // 初始化输入数据数组 for (int i = 0; i < NUM_SAMPLES; i++) { input_data[i] = ...; // 根据需要填入实际输入数据 } // 进行贝塞尔滤波 bezier_filtering(); // 输出结果 for (int i = 0; i < NUM_SAMPLES; i++) { printf("Output[%d]: %f\n", i, output_data[i]); } return 0; } ``` 以上是一个简单的单片机实现贝塞尔滤波的C语言示例。根据具体的需求,可以调整输入数据的采样数量和滤波器的阶数。在实际应用中,可以根据实际情况进行优化和改进,以满足特定的滤波需求。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值