一阶RC低通滤波算法原理与实现

文章目录

  • 1. 一阶低通滤波算法原理
  • 2. 一阶滤波算法的特点
  • 3. 基本算法的例程
  • 4. 优化:减少乘、除的运算次数以提高运算速度
  • 5. 改进:动态调整滤波系数
      • 动态调整滤波例程

本文整理自网络,参考文献附在文末,侵权请联系!


1. 一阶低通滤波算法原理

一阶滤波,又叫一阶惯性滤波,或一阶低通滤波,软件实现RC低通滤波器的功能。

Y ( n ) = α X ( n ) + ( 1 − α ) Y ( n − 1 ) Y(n)=αX(n) + (1-α)Y(n-1) Y(n)=αX(n)+(1α)Y(n1)

式中: α α α为滤波系数, X ( n ) X(n) X(n)为本次采样值, Y ( n − 1 ) Y(n-1) Y(n1)为上次滤波输出值, Y ( n ) Y(n) Y(n)为本次滤波输出值
一阶RC低通滤波算法原理与实现_第1张图片

2. 一阶滤波算法的特点

  • 对于周期干扰有良好的抑制作用(优)

  • 带来了相位滞后,导致灵敏度低(缺)

  • 不能滤除频率高于采样频率的二分之一(称为奈奎斯特频率)的干扰(例如采样频率为100Hz,则它不能滤除50Hz以上的干扰信号)(缺)

  • 滤波系数越小,滤波结果越平稳,灵敏度越低

  • 滤波系数越大,灵敏度越高,但滤波结果越不稳定

一阶滤波无法完美地兼顾灵敏度和平稳度。有时,我们只能寻找一个平衡,在可接受的灵敏度范围内取得尽可能好的平稳度。而在一些场合,我们希望拥有这样一种接近理想状态的滤波算法。即:当数据快速变化时,滤波结果能及时跟进(灵敏度优先);当数据趋于稳定,在一个固定的点上下振荡时,滤波结果能趋于平稳(平稳度优先)。

3. 基本算法的例程

案例1:油门数据滤波

// 油门滤波
thr_lpf+=(1/(1+1/(2.0f*3.14f*T)))*(height_thr-thr_lpf)

案例2:

#define a   0.01                // 滤波系数a(0-1) 

static float oldOutData = 0;

char filter(void)
{
    nowData  = get_Data(); 
    nowOutData = a * nowData  + (1.0f - a) * oldOutData;
    oldOutData = nowOutData;
    return nowOutData;  
}


/*
程序中整数运算比小数运算快,为加快程序的处理速度,
为计算方便,a取一整数,1-a用256-a来代替,
a则取0~255,代表新采样值在滤波结果中的权重
(也可将1-a的基数改为100-a,计算结果做相应处理,这里不做说明)
*/

#define a 128 

char value; //上次滤波值
char filter()
{
    char new_value;
    new_value=get_ad();//本次采样值
    return(256-a)*value/256+a*new_value/256}

案例3:MATLAB测试

% 一阶低通滤波器测试
close all;
t = 0.003;
A = 1/(1+(1/(2*pi*t)));
tt = 0:t:25;
y = sin(0.5*tt);
y_noise = awgn(y,35);
y_proce = y_noise;
for i = 2:length(y)
    y_proce(i) = (1-A) * y_proce(i-1) + A * y_noise(i);
end

plot(tt,y,'r');
figure(2)
plot(tt,y_noise,'g');hold on;
plot(tt,y_proce,'b');
hold off;

4. 优化:减少乘、除的运算次数以提高运算速度

思路:先将新采样值与上次滤波结果进行比较,然后根据比较采用不同的公式计算,这样程序的运算效率提高了一倍

一阶RC低通滤波算法原理与实现_第2张图片
一阶RC低通滤波算法原理与实现_第3张图片

/*入口:NEW_DATA 新采样值
       OLD_DATA 上次滤波结果
       k        滤波系数(0~255)(代表在滤波结果中的权重)
  出口:         本次滤波结果
 */
 char filter_1(char NEW_DATA,char OLD_DATA,char k)
{
    int result;
    if(NEW_DATA<OLD_DATA)
    {
        result=OLD_DATA-NEW_DATA;
        result=result*k;
        result=result+128;//+128是为了四色五入
        result=result/256;
        result=OLD_DATA-result;
    }
    else if(NEW_DATA>OLD_DATA)
    {
        result=NEW_DATA-OLD_DATA;
        result=result*k;
        result=result+128;//+128是为了四色五入
        result=result/256;
        result=OLD_DATA-result;
    }
    else result=OLD_DATA;
    return((char)result);
}

分析:

  • 仍然存在灵敏度与平温度之间的矛盾
  • 小数舍弃带来的误差(单片机很少采用浮点数,小数位要么舍弃要么四舍五入)

5. 改进:动态调整滤波系数

实现功能:

  • 当数据快速变化时,滤波结果能及时跟进,并且数据的变化越快,灵敏度应该越高(灵敏度优先原则)
  • 当数据趋于稳定,并在一个范围内振荡时,滤波结果能趋于平稳(平稳度优先原则)
  • 当数据稳定后,滤波结果能逼近并最终等于采样数据(消除因计算中小数带来的误差)
    调整前判断:
  • 数据变化方向是否为同一个方向(如当连续两次的采样值都比其上次滤波结果大时,视为变化方向一致,否则视为不一致)
  • 数据变化是否较快(主要是判断采样值和上一次滤波结果之间的差值)
    调整原则:
  • 当两次数据变化不一致时,说明有抖动,将滤波系数清零,忽略本次新采样值
  • 当数据持续向一个方向变化时,逐渐提高滤波系数,提供本次采样值得权;
  • 当数据变化较快(差值>消抖计数加速反应阈值)时,要加速提高滤波系数

一阶RC低通滤波算法原理与实现_第4张图片
几个常量参数及其取值范围(不同的取值会影响滤波的灵敏度和稳定度):

  1. 消抖计数加速反应阈值,取值根据数据情况确定
  2. 消抖计数最大值,一般取值10;
  3. 滤波系数增量,一般取值范围为10~30
  4. 滤波系数最大值,一般取值255;

一阶RC低通滤波算法原理与实现_第5张图片

在调用一阶滤波程序前,先调用调整滤波系数程序,对系数进行即时调整。滤波效果:

  1. 当采样数据偶然受到干扰,滤波结果中的干扰完全被滤除
  2. 当数据在一个范围内振荡时,滤波结果曲线非常平滑,几乎是一根直线
  3. 当采样数据发生真实的变化时,滤波结果也能比较及时地跟进
  4. 当采样数据趋于稳定时,滤波结果逐渐逼近并最终等于采样数据
  • 最终改进算法,兼顾了灵敏度和平稳度的要求;同时又不太消耗系统的RAM;
  • 只要合理调整几个常量,以使得算法更合适实际应用;

动态调整滤波例程

//用MPU6050测得数据;对x轴滤波处理

#define Threshold_1     8       //阈值1用于一阶带参滤波器,变化角度大于此值时,计数增加
#define Threshold_2     30      //阈值2用于一阶带参滤波器,计数值大于此值时,增大参数,增强滤波跟随

float K_x=0; //滤波系数
u8 new_flag_x=0;//本次数据变化方向
u8 num_x=0;//滤波计数器


/*****带系数修改的一阶滤波函数

入口: NEW_DATA    新采样的角度值
      OLD_DATA    上次滤波获得的角度结果
      k           滤波系数(代表在滤波结果中的权重)
      flag        上次数据变化方向
出口: result      本次滤波角度结果
 */
float filter_1_x(float NEW_DATA,float OLD_DATA,float k,u8 flag)
{


    //角度变化方向,new_flag=1表示角度增加,=0表示角度正在减小
    if((NEW_DATA-OLD_DATA)>0)
        new_flag_x=1;
    else if((NEW_DATA-OLD_DATA)<0)
        new_flag_x=0;


    if(new_flag_x==flag)  //此次变化与前一次变化方向是否一致,相等表示角度变化方向一致
        {
            num_x++;
            if(fabs((NEW_DATA-OLD_DATA))>Threshold_1)
        //当变化角度大于Threshold_1度的时候,进行计数器num快速增加,以达到快速增大K值,提高跟随性
                num_x+=5;                           

            if(num_x>Threshold_2)   //计数阈值设置,当角度递增或递减速度达到一定速率时,增大K值
            {
                K_x=k+0.2;          //0.2为K_x的增长值,看实际需要修改
                num_x=0;
            }
        }
    else 
        {
            num_x=0;
            K_x=0.01;     //角度变化稳定时K_x值,看实际修改
        }

    OLD_DATA=(1-K_x)*OLD_DATA+K_x*NEW_DATA;
    return OLD_DATA;
}


参考文献:

  • 飞控中的一阶RC低通滤波算法
  • 一阶低通滤波算法 - 不会飞的小肥鱼
  • 【滤波器学习笔记】一阶RC低通滤波

你可能感兴趣的:(▶,运动控制,▶,Linux/嵌入式,低通滤波器,RC滤波器)