Matlab中fdatool结合STM32F4设计滤波器

数字滤波器的原理

1.从功能上分;低通、带通、高通、带阻。滤波器口诀:低通滤高频;高通滤低频;带通滤两边;带阻阻中间;

2.从实现方法上分:FIR、IIR

3.从设计方法上来分:Chebyshev(切比雪夫),Butterworth(巴特沃斯)

4.从处理信号分:经典滤波器、现代滤波器

经典滤波器从功能上分又可分为:

低通滤波器(LPAF/LPDF):Low pass analog filter

带通滤波器(BPAF/BPDF):Bandpass analog filter

高通滤波器(HPAF/HPDF):High pass analog filter

带阻滤波器(BSAF/BSDF):Bandstop analog filter

IIR滤波器和FIR滤波器

数字信号处理里面的滤波器分两种:一种是IIR滤波器,另一种是FIR滤波器,本质区别就是IIR滤波器的当前输出与以前的输出和输入有关,FIR滤波器只与输入有关,看一下差分方程就一目了然了。

更多对比参考:

细说IIR滤波器和FIR滤波器的区别_iir和fir的区别_Gordennizaicunzai的博客-CSDN博客

Matlab用指令实现滤波器

以下以IIR巴特沃斯带通滤波器设计为例。

fs=1000; %设置采样频率 1k

N=1024; %采样点数

n=0:N-1;

t=0:1/fs:1-1/fs; %时间序列

f=n*fs/N; %频率序列

x1=sin(2*pi*50*t); %噪声

x2=sin(2*pi*200*t); %信号

x=x1+x2; %信号混合

subplot(311);

plot(t,x); %绘制原始信号

xlabel('时间');

ylabel('幅值');

title('原始信号');

subplot(312);

y=fft(x,N); %绘制原始信号的幅频响应

plot(f,abs(y));

xlabel('频率/Hz');

ylabel('振幅');

title('原始信号 FFT');

subplot(313);

Wn=[125*2 300*2]/fs; %设置通带 125Hz 到 300Hz

[b,a]=butter(1,Wn); %注意第一个参数虽然是 1,但生成的却是 2 阶 IIR 滤波器系数

y2=filtfilt(b,a,x); %计算滤波后的波形 y2

y3=fft(y2,N); %滤波后波形的幅频响应

plot(f,abs(y3));

xlabel('频率/Hz');

ylabel('振幅');

title('滤波后信号 FFT');

Fdatool工具的使用

如果要对数据进行滤波,可以使用matlab提供的工具fdatool来进行滤波器的设计,我们可以设计出一系列的滤波器,并且可以实时看到滤波器的效果图,滤波器设计好之后,我们还可以对目标数据进行滤波,然后根据滤波的效果去调整滤波器的参数。

我们可以在matlab的命令行处输入fdatool命令来调出fdatool工具。

该界面内容较多,我们这里仅对较常使用的地方进行说明。

响应类型和设计方式

这里是滤波器的选择,从上到下依次是:

低通、高通、带通、带阻 ,接着是其他的一些特殊滤波器,这里面有个Notching陷波滤波器,常常用来滤除特定频率的信号比如工频干扰及其谐波。

再下方的就是IIR和FIR滤波器选择,这个根据需要去选择即可,具体滤波器的应用场景可以查阅相关资料。IIR里常用的就是巴特沃斯滤波器,FIR里常用的就是加窗方式window

后面还有一些参数,我们就分别在滤波器的类型设计中去讲解吧。

这里先说一下几个问题:

第一个就是,FIR的阶数和IIR的阶数选择,基于FIR和IIR滤波器的特点,同样的效果,FIR需要比IIR有更多的阶数。通常,FIR的阶数都是几十几十的,甚至几百的,比如50阶、60阶、100阶、150阶等等,具体根据滤波效果来设定,总之,不能小,一小就效果差;相反,IIR设定的阶数不能大,一般不会超过6阶,常用的就是2阶或者4阶,如果大了,反而会溢出产生漂移等问题,初学者很容易看到IIR低阶效果不好,就加大阶数,这会适得其反。

第二个就是,我们可以通过参数图看下各参数是啥意思,通过幅频图直观地看到滤波器的效果,就是这个:

参数图

幅频图

可以直观地看到滤波器的效果。

接下来,依次介绍几个有代表性的滤波器,其他滤波器都是类似的。

IIR巴特沃斯低通滤波器

都比较好理解。

这里展示了当前滤波器的信息

有个地方需要注意,那就是Minimum order,虽然说是最小的阶数,但选中之后其实阶数很大,不知道是不是bug。

一般,我们手动指定阶数即可。

FIR加窗window低通滤波器

高通滤波器同理,不再赘述。

IIR巴特沃斯带通滤波器

带阻滤波器同理

单频率陷波滤波器

多频率陷波滤波器

这种滤波器被称作梳状滤波器,像一把梳子,可以滤去某个频率及其谐波成分,也就是某频率的所有整数倍频率,最常见的就是滤掉50Hz的工频干扰及其谐波。

这里需要注意的是,这里的阶数不能随便设,是有固定的数值的,=Fs/目标频率,比如,要滤掉50Hz及其谐波部分,采样率2000,那么这里的阶数就要填2000/50=40。

其他滤波器的参数补充

另外,还有一些其他滤波器,可能有一些不一样的参数,比如FIR默认的低通滤波器,截止频率填入时就不只是填入截止频率,而是填入一个范围

这里表示从Fpass开始截止,然后到Fstop时衰减到最低,看上面的幅频图就很明白了。

Wpass/Wstop/Apass/Astop这些意思都是差不多,分别调节衰减开始处和衰减结束出的频率范围精度,比如目标频率是50,如果这些值比较小,可能从49.5才开始衰减,但是值太大了,可能从45就开始衰减,这样的话,本来只想滤掉50Hz的频率,结果把45---55的频率都滤掉了。

再通俗点,就跟带阻滤波器两侧的范围误差差不多。

以上,就是设计滤波器时需要知道的一些参数设置。

这里总结一下,如何调节滤波器的效果?一般可以通过调节以下这些参数达到最适合的效果:

1、调节阶数,fir增大阶数,iir适当增加阶数;

2、陷波滤波器时提高品质;

3、调节Wpass/Wstop/Apass/Astop这些参数;

4、如果以上调节没什么改进的话,那就直接更换滤波器类型,比如,如果用IIR滤波器做带通,怎么调节效果都不好,那就直接换成FIR滤波器,再比如,如果陷波滤波器效果不好的话,就直接换成带阻滤波器。

......

总之,虽然需要一些经验,但也需要多多调试。

注意:设计滤波器时,所使用的阶数 n 应为偶数。

matlab验证滤波器效果

我们使用fdatool设置好滤波器参数之后,点击最下方的按钮Design Filter

此时,滤波器就设计好了。

接着,可以将设计好的滤波器导出成一个matlab对象。

fdatool工具界面上面,点击File------Export

这里的意思就是,将当前滤波器导出到matlab的变量空间Workspace,导出为对象,并且命名为Hd_bp,如果变量名已存在则覆盖,然后确定导出。

此时,在matlab的工作空间就会出现这个滤波器对象

接下来,我们准备好原始数据,然后对原始数据进行滤波

Fs = 2000;

%带通滤波器,Fir滤波

sig1 = filter(Hd_bp, VarName1);

%带阻滤波器,iir滤波

sig2 = filter(Hd_bs_50, sig1);

sig3 = filter(Hd_bs_100, sig2);

sig4 = filter(Hd_bs_150, sig3);%奇次谐波

sig5 = filter(Hd_bs_200, sig4);

sig6 = filter(Hd_bs_250, sig5);%奇次谐波

sig7 = filter(Hd_bs_300, sig6);

sig8 = filter(Hd_bs_350, sig7);%奇次谐波

sig9 = filter(Hd_bs_400, sig8);

sig10 = filter(Hd_bs_450, sig9);%奇次谐波

sig11 = filter(Hd_bs_500, sig10);

%频谱图

Y = fft(sig11);

L = length(Y);

P2 = abs(Y/L);

P1 = P2(1:L/2+1);

P1(2:end-1) = 2*P1(2:end-1);

f = Fs*(0:(L/2))/L;

plot(f,P1);

%axis([0,Fs/2,0,2000]);

title('frequency-domain');

xlabel('f(Hz)');

ylabel('频率成分的幅值');

以上代码中,filter就是滤波函数,这里面放入两个参数,第一个就是刚才设计并导出的滤波器对象,第二个就是原始数据。

我们可以对滤波前后的数据分别绘制幅频图,以此来验证滤波效果。

上面的代码做了20~500的带通和工频干扰的带阻滤波,效果如下:

效果还是可以的。

STM32F4实现滤波器

我们在matlab设计好滤波器之后,如果把这个滤波器用到STM32里呢?因为F4有FPU,所以最好在F4上使用,要不速度会是个大问题。

其实也比较简单

如果是FIR滤波器,在滤波器设计好之后,导出头文件

Targets------Generate C header

生成并保存后,我们可以到目标路径去找到头文件并打开查看

这里面关键的就是个系数,系数的个数是设定的阶数+1,这是算法要求,不用管太多,直接拿到C里面使用即可。

如果是IIR滤波器

默认生成的IIR滤波器是II型

导出之前,我们先将滤波器转换成直接1型

Edit------Convert Struct

选择第一项并确定

然后File------Export导出为系数

系数中的关键信息就是系数和缩放系数

因为是4阶,由两个二阶滤波器组成,所以二阶滤波器系数有两组。

这里,系数分别为b0 b1 b2 a0 a1 a2,其中a0这个系数是固定的,所以不必使用。

同时,要注意的是,在STM32F4中用DSP调用时,需要将每组的a1和a2取反,即正的改成负的,负的改成正的。

这个看公式就知道了。


比如 matlab 就是使用上面的公式实现的,所以在使用 fdatool 工具箱生成的 a 系数需要取反才能用于直接 I 型 IIR 滤波器的函数中。
其实,各类滤波器本质上就是计算公式不同,各有各的系数,各有各的算法。
我们得到系数之后,在F4中初始化,写滤波函数,然后调用即可。
附上代码:

Kotlin 复制代码
#include "IIR.h"
#include "arm_const_structs.h"
#include "stm32f4xx.h"

#define NUM_PER_CALL                1               //调用一次滤波函数所处理的采样点个数

//FIR带通滤波器
#define FIR_EFFICIENT_NUM           151             //fir滤波器系数个数

arm_fir_instance_f32 S_BP;                          //fir滤波器实例
static float32_t firStateF32[NUM_PER_CALL + FIR_EFFICIENT_NUM - 1]; //FIR状态缓存,大小FIR_EFFICIENT_NUM + NUM_PER_CALL - 1
const float32_t firCoeffs32BP[FIR_EFFICIENT_NUM] =  //fir滤波器系数数组
{
    0,6.783468507e-07,5.500670341e-06,6.206928447e-06,-3.594570046e-07,
    1.734129728e-05,5.174893886e-05,3.377356188e-05,-6.174600458e-06,5.468466406e-05,
    0.0001484536479,7.860602636e-05,-3.384135198e-05,0.0001032602231,0.0002951264905,
    0.0001253946684,-0.0001162498447,0.0001406262745,0.0004820130707,0.0001433174912,
    -0.0003082125622,0.0001265054452,0.0006859251298,8.190450171e-05,-0.0006903739995,
    -5.077828102e-19,0.0008687517256,-0.0001297538547,-0.001369225443,-0.0003186257964,
    0.000981297344,-0.000578189909, -0.00247148145,-0.0009198086918,0.0009743300034,
    -0.001354034874,-0.004132688046,-0.001889958396,0.0008173419628, -0.00253453129,
    -0.006482330617,-0.003291910049,0.0005241415929,-0.004162855446,-0.009630653076,
    -0.005144232418,0.0001840474579,-0.006228647195, -0.01366603095, -0.00740425894,
    -1.092867096e-18,-0.008654787205,  -0.0186777208,-0.009959736839,0.0003446365299,
    -0.01129483711, -0.02483416907, -0.01263269503,  0.00187640998,   -0.013943634,
    -0.03260042891, -0.01519669406, 0.005871396046, -0.01636073925, -0.04341268912,
    -0.01740563288,  0.01548426691, -0.01830341667, -0.06258355826, -0.01902942732,
    0.04320411757, -0.01956332289,  -0.1251707077, -0.01988991722,   0.2981061041,
    0.4799961746,   0.2981061041, -0.01988991722,  -0.1251707077, -0.01956332289,
    0.04320411757, -0.01902942732, -0.06258355826, -0.01830341667,  0.01548426691,
    -0.01740563288, -0.04341268912, -0.01636073925, 0.005871396046, -0.01519669406,
    -0.03260042891,   -0.013943634,  0.00187640998, -0.01263269503, -0.02483416907,
    -0.01129483711,0.0003446365299,-0.009959736839,  -0.0186777208,-0.008654787205,
    -1.092867096e-18, -0.00740425894, -0.01366603095,-0.006228647195,0.0001840474579,
    -0.005144232418,-0.009630653076,-0.004162855446,0.0005241415929,-0.003291910049,
    -0.006482330617, -0.00253453129,0.0008173419628,-0.001889958396,-0.004132688046,
    -0.001354034874,0.0009743300034,-0.0009198086918, -0.00247148145,-0.000578189909,
    0.000981297344,-0.0003186257964,-0.001369225443,-0.0001297538547,0.0008687517256,
    -5.077828102e-19,-0.0006903739995,8.190450171e-05,0.0006859251298,0.0001265054452,
    -0.0003082125622,0.0001433174912,0.0004820130707,0.0001406262745,-0.0001162498447,
    0.0001253946684,0.0002951264905,0.0001032602231,-3.384135198e-05,7.860602636e-05,
    0.0001484536479,5.468466406e-05,-6.174600458e-06,3.377356188e-05,5.174893886e-05,
    1.734129728e-05,-3.594570046e-07,6.206928447e-06,5.500670341e-06,6.783468507e-07,
    0
};

//IIR带阻滤波器-50Hz
#define numStages_50Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_50Hz;
static float32_t IIRStateF32_50Hz[4*numStages_50Hz];
static float32_t ScaleValue_50Hz = 0.99335783101529118 * 0.99335783101529118;//放缩系数

const float32_t IIRCoeffs32BP_50Hz[5*numStages_50Hz] =
{
    1,-1.9754644172762135,1,1.9596811054397389,-0.98620549853243988,
    1,-1.9754644172762135,1,1.9649189860762641,-0.98731438166310681
};

//IIR带阻滤波器-100Hz
#define numStages_100Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_100Hz;
static float32_t IIRStateF32_100Hz[4*numStages_100Hz];
static float32_t ScaleValue_100Hz = 0.99335783101529107 * 0.99335783101529107;//放缩系数

const float32_t IIRCoeffs32BP_100Hz[5*numStages_100Hz] =
{
    1,-1.9021975146812826,1,1.8851730633310202,-0.98648991967768052,
    1,-1.9021975146812826,1,1.8938697151225545,-0.98702972281202106
};

//IIR带阻滤波器-150Hz
#define numStages_150Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_150Hz;
static float32_t IIRStateF32_150Hz[4*numStages_150Hz];
static float32_t ScaleValue_150Hz = 0.99335783101529107 * 0.99335783101529107;//放缩系数

const float32_t IIRCoeffs32BP_150Hz[5*numStages_150Hz] =
{
    1,-1.782092196243289,1,1.7640519295652939,-0.98658772855718069,
    1,-1.782092196243289,1,1.7763809606964005,-0.98693187011384975
};

//IIR带阻滤波器-200Hz
#define numStages_200Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_200Hz;
static float32_t IIRStateF32_200Hz[4*numStages_200Hz];
static float32_t ScaleValue_200Hz = 0.99335783101529118 * 0.99335783101529118;//放缩系数

const float32_t IIRCoeffs32BP_200Hz[5*numStages_200Hz] =
{
    1,-1.6181058535088741,1,1.5994425294189876,-0.98663912868667558,
    1,-1.6181058535088741,1,1.6152032648694865,-0.98688045473364316
};

//IIR带阻滤波器-250Hz
#define numStages_250Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_250Hz;
static float32_t IIRStateF32_250Hz[4*numStages_250Hz];
static float32_t ScaleValue_250Hz = 0.99335783101529118 * 0.99335783101529118;//放缩系数

const float32_t IIRCoeffs32BP_250Hz[5*numStages_250Hz] =
{
    1,-1.4142763744756295,1,1.3954270755132026,-0.98667212489138056,
    1,-1.4142763744756295,1,1.4142763745489406,-0.98684745156199472
};

//IIR带阻滤波器-300Hz
#define numStages_300Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_300Hz;
static float32_t IIRStateF32_300Hz[4*numStages_300Hz];
static float32_t ScaleValue_300Hz = 0.99335783101529096 * 0.99335783101529096;//放缩系数

const float32_t IIRCoeffs32BP_300Hz[5*numStages_300Hz] =
{
    1,-1.17562271738861,1,1.1570389697979899,-0.98669609658241275,
    1,-1.17562271738861,1,1.1785379122261563,-0.98682347619380328
};

//IIR带阻滤波器-350Hz
#define numStages_350Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_350Hz;
static float32_t IIRStateF32_350Hz[4*numStages_350Hz];
static float32_t ScaleValue_350Hz = 0.99335783101529118 * 0.99335783101529118;//放缩系数

const float32_t IIRCoeffs32BP_350Hz[5*numStages_350Hz] =
{
    1,-0.90802132733137575,1,0.91378825004392716,-0.98680445057512212,
    1,-0.90802132733137575,1,0.8901524097715261,-0.98671512011202733
};

//IIR带阻滤波器-400Hz
#define numStages_400Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_400Hz;
static float32_t IIRStateF32_400Hz[4*numStages_400Hz];
static float32_t ScaleValue_400Hz = 0.99335783101529096 * 0.99335783101529096;//放缩系数

const float32_t IIRCoeffs32BP_400Hz[5*numStages_400Hz] =
{
    1,-0.61806143864523178,1,0.62654427006115254,-0.98678826715653045,
    1,-0.61806143864523178,1,0.60134116156514272,-0.98673130233100281
};

//IIR带阻滤波器-450Hz
#define numStages_450Hz          2    //2阶IIR滤波的个数

static arm_biquad_casd_df1_inst_f32 S_450Hz;
static float32_t IIRStateF32_450Hz[4*numStages_450Hz];
static float32_t ScaleValue_450Hz = 0.99335783101529096 * 0.99335783101529096;//放缩系数

const float32_t IIRCoeffs32BP_450Hz[5*numStages_450Hz] =
{
    1,-0.31288282611132939,1,0.32387775390876944,-0.98677366833749702,
    1,-0.31288282611132939,1,0.29771783508361671,-0.98674590052325395
};

//滤波后剩余的直流分量
#define DC_AFTER_FILTER     3088

//所有滤波器的初始化
void arm_emg_f32_filter_init()
{
    //带通滤波器初始化
    arm_fir_init_f32(&S_BP, FIR_EFFICIENT_NUM, (float32_t *)&firCoeffs32BP[0], &firStateF32[0], NUM_PER_CALL);
    
    //IIR带阻滤波器-50Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_50Hz, numStages_50Hz, (float32_t *)&IIRCoeffs32BP_50Hz[0], (float32_t *)&IIRStateF32_50Hz[0]);

    //IIR带阻滤波器-100Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_100Hz, numStages_100Hz, (float32_t *)&IIRCoeffs32BP_100Hz[0], (float32_t *)&IIRStateF32_100Hz[0]);

    //IIR带阻滤波器-150Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_150Hz, numStages_150Hz, (float32_t *)&IIRCoeffs32BP_150Hz[0], (float32_t *)&IIRStateF32_150Hz[0]);

    //IIR带阻滤波器-200Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_200Hz, numStages_200Hz, (float32_t *)&IIRCoeffs32BP_200Hz[0], (float32_t *)&IIRStateF32_200Hz[0]);

    //IIR带阻滤波器-250Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_250Hz, numStages_250Hz, (float32_t *)&IIRCoeffs32BP_250Hz[0], (float32_t *)&IIRStateF32_250Hz[0]);

    //IIR带阻滤波器-300Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_300Hz, numStages_300Hz, (float32_t *)&IIRCoeffs32BP_300Hz[0], (float32_t *)&IIRStateF32_300Hz[0]);

    //IIR带阻滤波器-350Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_350Hz, numStages_350Hz, (float32_t *)&IIRCoeffs32BP_350Hz[0], (float32_t *)&IIRStateF32_350Hz[0]);

    //IIR带阻滤波器-400Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_400Hz, numStages_400Hz, (float32_t *)&IIRCoeffs32BP_400Hz[0], (float32_t *)&IIRStateF32_400Hz[0]);

    //IIR带阻滤波器-450Hz初始化
    arm_biquad_cascade_df1_init_f32(&S_450Hz, numStages_450Hz, (float32_t *)&IIRCoeffs32BP_450Hz[0], (float32_t *)&IIRStateF32_450Hz[0]);
}

//带通滤波和带阻滤波
void arm_emg_f32_filter(float32_t *dataInput, float32_t *dataOutput)
{
    float32_t dataOutputAfterFirbp = 0;
    float32_t dataOutputAfterIIRbs_50Hz = 0;
    float32_t dataOutputAfterIIRbs_100Hz = 0;
    float32_t dataOutputAfterIIRbs_150Hz = 0;
    float32_t dataOutputAfterIIRbs_200Hz = 0;
    float32_t dataOutputAfterIIRbs_250Hz = 0;
    float32_t dataOutputAfterIIRbs_300Hz = 0;
    float32_t dataOutputAfterIIRbs_350Hz = 0;
    float32_t dataOutputAfterIIRbs_400Hz = 0;
    float32_t dataOutputAfterIIRbs_450Hz = 0;
    
    //带通滤波
    arm_fir_f32(&S_BP, dataInput, &dataOutputAfterFirbp, NUM_PER_CALL);
    
    //50Hz带阻
    arm_biquad_cascade_df1_f32(&S_50Hz, &dataOutputAfterFirbp, &dataOutputAfterIIRbs_50Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_50Hz *= ScaleValue_50Hz;
    
    //100Hz带阻
    arm_biquad_cascade_df1_f32(&S_100Hz, &dataOutputAfterIIRbs_50Hz, &dataOutputAfterIIRbs_100Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_100Hz *= ScaleValue_100Hz;
    
    //150Hz带阻
    arm_biquad_cascade_df1_f32(&S_150Hz, &dataOutputAfterIIRbs_100Hz, &dataOutputAfterIIRbs_150Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_150Hz *= ScaleValue_150Hz;
    
    //200Hz带阻
    arm_biquad_cascade_df1_f32(&S_200Hz, &dataOutputAfterIIRbs_150Hz, &dataOutputAfterIIRbs_200Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_200Hz *= ScaleValue_200Hz;
    
    //250Hz带阻
    arm_biquad_cascade_df1_f32(&S_250Hz, &dataOutputAfterIIRbs_200Hz, &dataOutputAfterIIRbs_250Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_250Hz *= ScaleValue_250Hz;
    
    //300Hz带阻
    arm_biquad_cascade_df1_f32(&S_300Hz, &dataOutputAfterIIRbs_250Hz, &dataOutputAfterIIRbs_300Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_300Hz *= ScaleValue_300Hz;
    
    //350Hz带阻
    arm_biquad_cascade_df1_f32(&S_350Hz, &dataOutputAfterIIRbs_300Hz, &dataOutputAfterIIRbs_350Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_350Hz *= ScaleValue_350Hz;

    //400Hz带阻
    arm_biquad_cascade_df1_f32(&S_400Hz, &dataOutputAfterIIRbs_350Hz, &dataOutputAfterIIRbs_400Hz, NUM_PER_CALL);
    dataOutputAfterIIRbs_400Hz *= ScaleValue_400Hz;
    
    //450Hz带阻
    arm_biquad_cascade_df1_f32(&S_450Hz, &dataOutputAfterIIRbs_400Hz, &dataOutputAfterIIRbs_450Hz, NUM_PER_CALL);  
    dataOutputAfterIIRbs_450Hz *= ScaleValue_450Hz;

    //返回正数值以计算均方根
    if(dataOutputAfterIIRbs_450Hz >= DC_AFTER_FILTER)
    {
        *dataOutput = dataOutputAfterIIRbs_450Hz - DC_AFTER_FILTER;
    }
    else
    {
        *dataOutput = DC_AFTER_FILTER - dataOutputAfterIIRbs_450Hz;
    }
}

这里有个需要注意的问题,就是每次调用函数处理的数据个数,可以一个一个地处理,也可以一次处理多个,我这里是一个一个地处理的。其实,各滤波器就是个算法,也就是有个对应的公式,将数据输入进去,再输出即可,具体设计到傅里叶变换的知识,可自行查阅资料。

另外,这个FIR系数里有些是用科学计数法来表示的,不用特别处理,C能识别。在C语言中,我们可以使用科学计数法来表示数字。具体方法是在数字后面加上一个大写或小写的字母E,再加上一个指数。

我的一点想法:时域数据通过fft转成频域,删除特定频率的数据,再ifft转成时域,不就可以删除特定频率的数据了?

这样的话:

低通:就相当于我把高频率的数据删除,只留低频率的数据;

高通:就相当于我把低频率的数据删除,只留高频率的数据;

带通:就相当于我把两侧的数据都删了;

带阻:就相当于我把中间的数据删掉了

补充

直流分量信号的频率是0,高通,带通都会被过滤掉,只有低通可以通过。
更多内容可参考以下系列课程:NO.1 基于matlab中的fdatool进行电生理信号预处理实战演练,以肌电信号为例去除噪声_哔哩哔哩_bilibili

相关推荐
InfiSight智睿视界1 小时前
AI 技术,让洗护行业焕然「衣」新
人工智能·算法
程序员一诺1 小时前
【机器学习】嘿马机器学习(算法篇)第11篇:决策树算法,学习目标【附代码文档】
人工智能·python·算法·机器学习
Evand J1 小时前
平方根无迹卡尔曼滤波(SR-UKF)算法,用于处理三维非线性状态估计问题
算法
taoyong0011 小时前
代码随想录算法训练营第十五天-二叉树-110.平衡二叉树
数据结构·算法
-芒果酱-2 小时前
k-Means聚类算法 HNUST【数据分析技术】(2025)
算法·kmeans·聚类
渣渣威的仿真秀2 小时前
Jensen-Shannon Divergence:定义、性质与应用
人工智能·算法·概率论
柒月的猫2 小时前
求和(2022蓝桥杯A组试题C)
c语言·算法·蓝桥杯
simple_ssn2 小时前
【蓝桥杯】压缩字符串
java·算法
c1assy3 小时前
DP动态规划+贪心题目汇总
数据结构·算法·leetcode·贪心算法·动态规划
jjjxxxhhh1233 小时前
C++ 模板是为了解决啥问题
开发语言·c++·算法