Matlab中fdatool结合STM32F4设计滤波器

news2024/12/23 14:34:52

数字滤波器的原理

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中初始化,写滤波函数,然后调用即可。
附上代码:
#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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/970900.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

哪家证券公司能做股票的量化交易?

一般证券公司都是能做股票的量化交易的,证券公司主流使用的量化软件一般是P-trade或QMT。其中P-trade普通版更适合没有太多编程经验的投资者使用,可以直接应用软件中现成的程序进行交易,QMT适合专业的投资者,有一定学编程语言基础…

34k*16 薪,3年自动化测试历经3轮面试成功拿下字节Offer....

前言 转眼过去,距离读书的时候已经这么久了吗?,从18年5月本科毕业入职了一家小公司,到现在快4年了,前段时间社招想着找一个新的工作,前前后后花了一个多月的时间复习以及面试,前几天拿到了字节…

国产信创替代迫在眉睫,如何选择合适的信创文件传输系统?

当今世界正经历着百年未有之大变局,随着时代发展进步,党的二十大也对于加快建设数字中国做出了重要部署。只有牵制住自主创新这么一个关键点,以关键核心技术突破推动实现高水平科技自立自强,才能牢牢掌握数字经济发展的主动权。自…

手写Mybatis:第11章-流程解耦,封装结果集处理器

文章目录 一、目标:结果集处理器二、设计:结果集处理器三、实现:结果集处理器3.1 工程结构3.2 结果集处理器关系图3.3 出参参数处理3.3.1 结果映射Map3.3.2 结果映射封装3.3.3 修改映射器语句类3.3.4 映射构建器助手3.3.5 语句构建器调用助手…

Java“牵手”京东商品评论数据接口方法,京东商品评论接口,京东商品评价接口,行业数据监测,京东API实现批量商品评论内容数据抓取示例

京东平台商品评论数据接口是开放平台提供的一种API接口,通过调用API接口,开发者可以获取京东商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片、评论内容、评论日期、评论图片、追评内容等详细信息 。 获取商品评论接口API是一种用于获取…

无涯教程-JavaScript - DCOUNTA函数

描述 DCOUNTA函数返回列表或数据库中符合您指定条件的列中非空白单元格的计数。 此函数与DCOUNT函数相似,不同之处在于DCOUNTA函数对所有非空白单元进行计数。 DCOUNT函数仅计算包含数值的单元格。 语法 DCOUNTA (database, field, criteria)争论 Argument描述Required/Op…

参编三大金融国标,奇富科技以技术促行业规范化演进

近期,由中国互联网金融协会领导制定的《互联网金融智能风险防控技术要求》《互联网金融个人网络消费信贷信息披露》《互联网金融个人身份识别技术要求》三项国家标准颁布,由国家市场监督管理总局、国家标准化管理委员会发布,奇富科技作为核心…

sqli-labs例题复现

less-1.1 在源码中$id$_GET[id];之后加入如下代码: if(preg_match(/select\b[\s\S]*\bfrom/is,$id)){die(SQL Injection); }; 1.分析正则 第一个\b匹配select单词边界,\s\S匹配到所有字符,最后一个\b匹配到from单词边界。 select...from…

超详细!80个Python入门实例,代码清晰拿来即用,学习提升必备

对于大部分Python学习者来说,核心知识基本已经掌握了,但"纸上得来终觉浅,绝知此事要躬行",要想完全掌握Python,还得靠实践应用。 今天给大家分享80个Python入门实例,都是基础实例,经典实用&…

问道管理:什么是大盘?大盘股又是什么?

聊到股市就免不了聊到大盘,有些新进场的投资者对此或许带有疑问,什么是大盘?我们所说的大盘股又是什么?关于这些,问道管理为我们准备了以下参考内容。 什么是大盘? 大盘,主要是指股市的整体行情…

最新secureCRT成功安装教程含资源链接

下载压缩包解压,如下双击安装: 打开按步骤导入就可以了 secureCRT 正常打开连上ubuntu的效果: 界面还没配置,还需根据个人爱好配置一下。 时间就是金钱,按下面链接操作完会自动弹出下载窗口,下载大概要三四…

算法leetcode|76. 最小覆盖子串(rust重拳出击)

文章目录 76. 最小覆盖子串:样例 1:样例 2:样例 3:提示:进阶: 分析:在这里插入图片描述 题解:rust:go:c:python:java: 76.…

动态贴纸、美颜SDK与AR:创造独特的互动体验

目前,动态贴纸、美颜SDK、增强现实(AR)等技术是比较热门的话题,它们所结合的新兴玩法更是收到大家推崇,正潜移默化的改变我们与数字世界互动的方式。 一、动态贴纸:个性化互动的开始 动态贴纸&#xff0c…

智能聊天机器人,帮你排解烦恼!

在繁忙的生活中,你是否曾经感到压力和烦恼无处宣泄?现在,我们为你带来了一款全新的智能聊天机器人,它能够倾听你的心声,理解你的情绪,为你提供安慰和支持,让你告别烦恼,重拾快乐生活…

ToBeWritten之基于ATTCK的运营流程与实践

也许每个人出生的时候都以为这世界都是为他一个人而存在的,当他发现自己错的时候,他便开始长大 少走了弯路,也就错过了风景,无论如何,感谢经历 转移发布平台通知:将不再在CSDN博客发布新文章,敬…

Mysql底层数据结构为什么选择B+树

索引底层采用什么数据结构,为什么使用B树而不是其他数据结构: (1)如果采用二叉树:使用递增字段作为索引时,二叉树会退化成链表,查找效率太低 (2)如果采用红黑树&#xf…

2023年新风口,Kwai快手海外公会入驻详细指南!

Kwai快手海外公会发展前景作为中国短视频市场的领头羊,Kwai快手在海外市场也取得了一定的成绩。但是,海外市场的发展前景还存在一些不确定因素,需要快手进一步探索和努力。首先,海外市场对于内容的申请找cmxyci要求与国内市场有所…

系统学习Linux-zabbix监控平台

一、zabbix的基本概述 zabbix是一个监控软件,其可以监控各种网络参数,保证企业服务架构安全运营,同时支持灵活的告警机制,可以使得运维人员快速定位故障、解决问题。zabbix支持分布式功能,支持复杂架构下的监控解决方…

ZLMeidaKit在Windows上启动时:计算机中丢失MSVCR110.dll,以及rtmp推流后无法转换为flv视频流解决

场景 ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放: ZLMediaKit在Windows上实现Rtmp流媒体服务器以及模拟rtmp推流和http-flv拉流播放_zlm流媒体服务器_霸道流氓气质的博客-CSDN博客 按照以上教程启动MediaServer.exe时提示&am…

新上线:爱校对的PDF校对工具,专为专业人士设计

在这个信息爆炸的时代,准确和专业的信息交流比以往任何时候都更为重要。专业人士,无论是律师、医生、研究人员还是企业高管,都依赖于高质量的PDF文档来进行准确无误的沟通。但是,校对这些文档常常是一个既耗时又容易出错的任务。这…