滤波器设计

Tips:

matlab信号处理工具规定单位频率为奈圭斯特频率(采样频率的一半),所以基本的滤波器设计函数的截止频率参数均以奈圭斯特频率为基准做归一化。例如,对于一个采样频率为1000Hz的系统,300Hz则对应300/500=0.6。若要将归一化频率转换为单位圆上的弧度,则将归一化值乘以π(pi)即可。
所以:这个fvtool()求得的幅频特性的横坐标是归一化的。若要求Hz为单位的截止频率,只需乘以fs/2即可。
当然也可以用 freqz()或者freqs()求取横坐标以Hz为单位的幅频特性。
而且调用fvtool()是不需要知道采样频率的,而freqz()或者freqs()是有fs采样频率这个参数的。

IIR滤波器简介

ARM官方提供的直接I型IIR库支持Q7,Q15,Q31和浮点四种数据类型。其中Q15和Q31提供了基于Cortex-M3和Cortex-M4的快速版本。 直接I型IIR滤波器是基于二阶Biquad级联的方式来实现的。每个Biquad由一个二阶的滤波器组成:

y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2] 

直接I型算法每个阶段需要5个系数和4个状态变量。

这里有一点要特别的注意,有些滤波器系数生成工具是采用的下面公式实现:

y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]

比如matlab就是使用上面的公式实现的,所以在使用fdatool工具箱生成的a系数需要取反才能用于直接I型IIR滤波器的函数中。
高阶IIR滤波器的实现是采用二阶Biquad级联的方式来实现的。其中参数numStages就是用来做指定二阶Biquad的个数。比如8阶IIR滤波器就可以采用numStages=4个二阶Biquad来实现。

如果要实现9阶IIR滤波器就需要将numStages=5,这时就需要其中一个Biquad配置成一阶滤波器(也就是b2=0,a2=0)。

1. 使用matlab fdatool设计滤波器

打开matlab 输入:

fdatool

选择滤波器响应类型和设计方法,选择滤波器阶数,选择Fs:采样频率 Fc:中心频率,点击设计即可

转换结构类型为Direct Form I,SOCK_STREAM,如图选择并保存Coefficent File(*.fcf).

*.fcf

% Generated by MATLAB(R) 8.4 and the Signal Processing Toolbox 6.22.
% Generated on: 04-Jan-2022 11:10:28

% Coefficient Format: Decimal

% Discrete-Time IIR Filter (real)                           
% -------------------------------                           
% Filter Structure    : Direct-Form I, Second-Order Sections
% Number of Sections  : 2                                   
% Stable              : Yes                                 
% Linear Phase        : No                                  

                                                           
SOS Matrix:                                                 
1  2  1  1  -0.22705028708083497  0.4514083390923061        
1  2  1  1  -0.16359116611362662  0.045748876831938463      
                                                            
Scale Values:                                               
0.30608951300286774                                         
0.22053942767957796    

SOS Matrix:

b0 b1 b2 a0 a1 a2
1 2 1 1 -0.22705028708083497 0.4514083390923061
1 2 1 1 -0.16359116611362662 0.045748876831938463
ARM 使用直接I型IIR滤波器是基于二阶Biquad级联的方式来实现的。
每个Biquad由一个二阶的滤波器组成:
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] + a1 * y[n-1] + a2 * y[n-2]
直接I型算法每个阶段需要5个系数和4个状态变量。

matlab工具生成系数对应如下公式:
y[n] = b0 * x[n] + b1 * x[n-1] + b2 * x[n-2] - a1 * y[n-1] - a2 * y[n-2]

注意:a1 a2 系数实际在ARM中需要取反

2.通过fvtool验证结果(通过滤波器系数绘制曲线)

打开matlab 输入:

a=[
1  2  1  1  -0.22705028708083497  0.4514083390923061        
1  2  1  1  -0.16359116611362662  0.045748876831938463  ];%已知的系数

fvtool(a);

右击选择采样频率后,可见曲线得到还原.

3.ARM中如何使用滤波器


#define numStages  2                /* 2阶IIR滤波的个数 */
#define TEST_LENGTH_SAMPLES  400    /* 采样点数 */

static float32_t data_input[TEST_LENGTH_SAMPLES]; /* 采样点 */
static float32_t data_output[TEST_LENGTH_SAMPLES];/* 滤波后的输出 */
static float32_t IIRStateF32[4*numStages];        /* 状态缓存,大小numTaps+blockSize-1 */
                                                                                               
const float32_t IIRCoeffs32[5*numStages] = { /*实际使用时,去除a0 系数*/
1.0,  -2.0,  1.0,  -0.22705028708083497,  0.4514083390923061,   
1.0,  -2.0,  1.0,  -0.16359116611362662,  0.045748876831938463,
};

static void arm_iir_f32_hp(void)
{
    arm_biquad_casd_df1_inst_f32 S;
    float32_t ScaleValue;

    /* 初始化 */
    arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32[0], 
                                   (float32_t*)&IIRStateF32[0]);
    /* IIR滤波 */
    arm_biquad_cascade_df1_f32(&S, data_input, data_output, TEST_LENGTH_SAMPLES);
    /* 缩放系数 */   
    ScaleValue = 0.30608951300286774 * 0.22053942767957796; 
    /* 打印滤波后结果 */
    for(uint32_t i = 0; i < TEST_LENGTH_SAMPLES; i++)
    {
        printf("%f\r\n", data_output[i] * ScaleValue);
    }
}

#include "iir.h"
float B[3] = {1,2,1};
float A[3] = {1,-0.753537,0.406307};
float Gain = 0.163192;
float w_x[3] = {0,0,0};
float w_y[3] = {0,0,0};
float y[32] = {0};
// IIR滤波函数
// x[i]:输入信号
// y[i]:滤波信号
// len:输入数据长度
void IIR_Filter(float x[],int len)
{
        unsigned char i;
        w_x[0]=w_x[1]=w_x[2]=0;
        w_y[0]=w_y[1]=w_y[2]=0;
        for(i=0;i<len;i++)
        {
                w_x[0]=x[i];
                w_y[0]=(B[0]*w_x[0]+B[1]*w_x[1]+B[2]*w_x[2])*Gain-w_y[1]*A[1]-w_y[2]*A[2];
                y[i]=w_y[0]/A[0];
                w_x[2]=w_x[1];w_x[1]=w_x[0];
                w_y[2]=w_y[1];w_y[1]=w_y[0];
        }
}


B[3] = {1,2,1};
A[3] = {1,-0.753537,0.406307};
Gain = 0.163192;
w_x[3] = {0,0,0};
w_y[3] = {0,0,0};
y[32] = {0};
// IIR滤波函数
// x[i]:输入信号
// y[i]:滤波信号
// len:输入数据长度
void IIR_Filter(float x[],int len)
{
        unsigned char i;
        w_x[0]=w_x[1]=w_x[2]=0;
        w_y[0]=w_y[1]=w_y[2]=0;
        for(i=0;i<len;i++)
        {
                w_x[0]=x[i];
                w_y[0]=(B[0]*w_x[0]+B[1]*w_x[1]+B[2]*w_x[2])*Gain-w_y[1]*A[1]-w_y[2]*A[2];
                y[i]=w_y[0]/A[0];
                w_x[2]=w_x[1];w_x[1]=w_x[0];
                w_y[2]=w_y[1];w_y[1]=w_y[0];
        }
}

作者:EnzoSun
微信关注:勿忘初兴
本文出处:http://sunduoze.github.io/post/%E6%BB%A4%E6%B3%A2%E5%99%A8%E8%AE%BE%E8%AE%A1/
文章版权归本人所有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。