wenbo2005.online

学习记录 / STM32

滤波

STM322025-07-06
//==========================================================中间值滤波===============================================

优点:能有效克服因偶然因素引起的波动干扰;对温度、液位等变化缓慢的被测参数有良好的滤波效果

缺点:对流量,速度等快速变化的参数不宜

/*中间值滤波
* input:传入的数
* N:采集总次数
* BAN:从小到大排列后,左右两端各舍去的数量
* 注意:N > 2 * BAN
*
*/
#define N 300
#define BAN 100
uint32_t  Get_MedianFiltering(uint16_t input)
{
    uint16_t ValueBuff[N]={0},Valuetemp=0;
    uint32_t count = 0, i=0, j=0;
    uint32_t sum=0;
    for(count=0;count<N;count++)
        ValueBuff[count] = input;
    for( j = 0 ;j< N-1 ;j ++)
    {
        for( i = 0 ;i< N-j ;i ++)
        {
            if(ValueBuff[i] > ValueBuff[i+1])
            {
                Valuetemp = ValueBuff[i];
                ValueBuff[i] = ValueBuff[i+1];
                ValueBuff[i+1] = Valuetemp;
            }
        }
    }
    for(count = BAN;count <N - BAN;count++)
        sum+=ValueBuff[count];
    return ((uint32_t) ((float)sum / (N - BAN * 2)));
}

//=========================================================卡尔曼滤波================================================
typedef struct
{
    float LastP;    //前序协方差
    float Now_P;    //当前方差
    float Out;        //滤波结果
    float Kg;            //卡尔曼增益
    float Q;            //背景白噪声
    float R;            //器件方差
}Kalman_Filter;

Kalman_Filter MY_Kalman_Filter = {0.02,0,0,0,0.001,0.543};
float Kalman(Kalman_Filter * efk, float input)//一维卡尔曼
{
    efk->Now_P = efk->LastP + efk->Q ;
    efk->Kg = efk->Now_P / (efk->Now_P + efk->R );
    efk->Out = efk->Out + efk->Kg * (input - efk->Out);
    efk->LastP = (1 - efk->Kg) * efk->Now_P ;

    return efk->Out;
}
//=====================================================低配版卡尔曼滤波
int KalmanFilter(int inData)
{
        static float prevData = 0;                                 //先前数值
        static float p = 10, q = 0.001, r = 0.001, kGain = 0;      // q控制误差  r控制响应速度

        p = p + q;
        kGain = p / ( p + r );                                     //计算卡尔曼增益
        inData = prevData + ( kGain * ( inData - prevData ) );     //计算本次滤波估计值
        p = ( 1 - kGain ) * p;                                     //更新测量方差
        prevData = inData;
        return inData;                                             //返回滤波值
}

//=========================================================算术平均值滤波================================================

N值较大时:信号平滑度较高,但灵敏度较低

N值较小时:信号平滑度较低,但灵敏度较高

N值的选取:一般流量,N=12;压力:N=4

优点:试用于对一般具有随机干扰的信号进行滤波。这种信号的特点是有一个平均值,信号在某一数值范围附近上下波动。

缺点:测量速度较慢或要求数据计算较快的实时控制不适用。

float averageFilter(int N)
{
   float sum = 0;
   int i;
   for(i = 0; i < N; ++i)
   {
        sum += HAL_ADC_GetValue(&hadc1);    //数据来源
   }
   return sum/N;
}

//=========================================================平滑均值滤波================================================

把连续取N个采样值看成一个队列,队列的长度固定为N。每次采样到一个新数据放入队尾,并扔掉原来队首的一次数据(先进先出原则)。把队列中的N个数据进行算术平均运算,就可获得新的滤波结果。

N值的选取:流量,N=12;压力:N=4;液面,N=4~12;温度,N=1~4

优点:对周期性干扰有良好的抑制作用,平滑度高;试用于高频振荡的系统

缺点:灵敏度低;对偶然出现的脉冲性干扰的抑制作用较差,不适于脉冲干扰较严重的场合比较浪费RAM(改进方法,减去的不是队首的值,而是上一次得到的平均值)

#define AVGNMU 5
uint8_t avg_num=0;
float MoveAvg(float newadc)
{
    static float sum;
    if(avg_num<AVGNMU)
    {
        sum+=newadc;
        avg_num++;
        return sum/avg_num;
    }
    else
    {
        sum -= sum/AVGNMU;
        sum+=newadc;
        return sum/AVGNMU;
    }
}

//加速度使用低通滤波(噪声在高频),角速度使用高通滤波(噪声在低频)

低通滤波器:通常选择较小的 α,使得滤波器对低频信号响应较好。

高通滤波器:通常选择较大的 α,使得滤波器对高频信号响应较好。

float LowPassFilter(volatile short newInput,volatile short *output);
float HighPassFilter(volatile short newInput,volatile short *output);

//低通
static float Lalpha = 0.2;
//高通
static float Halpha = 0.9;

//一阶低通滤波函数
float LowPassFilter(volatile short newInput,volatile short *output)
{
    *output = (*output) + Lalpha * (newInput - (*output));
    return *output;
}

//一阶高通滤波函数
float HighPassFilter(volatile short newInput,volatile short *output)
{
    *output = (*output) + Halpha * (newInput - (*output));
    return *output;
}