精华内容
下载资源
问答
  • 利用高通、低通滤波器级联可以实现宽带带通滤波器,利用此方法设计了一个工作频段在100~400 MHz 的LC宽带带通滤波器。将所设计的截止频率为100 MHz的高通滤波器HPF以及截止频率为400 MHz的低通滤波器 LPF级联实现...
  • 看到一个带通滤波器的设计如下,开始研究是如何设计的 代码: band_low = 0.3; band_high = 1.2; fs_origin = 25; hd_band = design(fdesign.bandpass('N,F3dB1,F3dB2',4,band_low,band_high,fs_origin),'...

    写在前面的话:

    由滤波器系数得到传输函数:

    使用matlab fdatool设计滤波器,得到幅频响应,得到滤波器系数,由系数如何得到滤波器的参数?

    我的方法是 使用:点击Filt-Export to simulink Model, simulink打开后,出现了简单的滤波器或者在 simulink中设计滤波器,双击设计好的滤波器,可以参看其框图,根据框图可以将传输函数写出,即可得到滤波器的参数。

    看到一个带通滤波器的设计如下,开始研究是如何设计的

    带通滤波器设计matlab代码:

    band_low = 0.3;       
    band_high = 1.2;       
    fs_origin = 25; 
    hd_band = design(fdesign.bandpass('N,F3dB1,F3dB2',4,band_low,band_high,fs_origin),'butter'); %带通滤波器
    %fvtool(hd_band); % view
    measure(hd_band) %Measure the frequency response characteristics of the filter 
    %filtered = filter(hd_band,x);  % 滤波器的使用,输入数组x,输出数组filtered

    查看官网MathWorks,找到关于滤波器的设计design,带通滤波器的设计fdesign.bandpass

    The fdesign.bandpass function returns a bandpass filter design specification object that contains specifications for a filter such as passband frequency, stopband frequency, passband ripple, and filter order. Use the design function to design the filter from the filter design specifications object.

    本处只解析此处滤波器的设计参数,若查看更多,移至官网MathWorks

    • N:Filter order for FIR filters. Or both the numerator and denominator orders for IIR filters when Na and Nb are not provided. Specified using FilterOrder. 关于滤波其的阶数
    • F3dB1:Frequency of the 3 dB point below the passband value for the first cutoff, specified in normalized frequency units. Applies to IIR filters.
    • F3dB2:Frequency of the 3 dB point below the passband value for the second cutoff, specified in normalized frequency units. Applies to IIR filters.
    • Fs bandpassSpecs = fdesign.bandpass(___,Fs) provides the sample rate in Hz of the signal to be filtered. Fs must be specified as a scalar trailing the other numerical values provided. In this case, all frequencies in the specifications are in Hz as well. 

    上面这句话解释了传入采样频率的必要性。

    'N,F3dB1,F3dB2'butter

    以上参数的设置使用与IIR butter

    fdesign.bandpass('N,F3dB1,F3dB2',4,band_low,band_high,fs_origin)
    show:  
    bandpass (具有属性):
    
                   Response: 'Bandpass'
              Specification: 'N,F3dB1,F3dB2'
                Description: {3×1 cell}
        NormalizedFrequency: 0
                         Fs: 25
                FilterOrder: 4
                      F3dB1: 0.3000
                      F3dB2: 1.2000

    fvtool(hd_band)% 查看幅频特性

    measure(hd_band) %Measure the frequency response characteristics of the filter 

    Sample Rate             : 25 Hz       
    First Stopband Edge     : Unknown     
    First 6-dB Point        : 250.7041 mHz
    First 3-dB Point        : 300 mHz     
    First Passband Edge     : Unknown     
    Second Passband Edge    : Unknown     
    Second 3-dB Point       : 1.2 Hz      
    Second 6-dB Point       : 1.4315 Hz   
    Second Stopband Edge    : Unknown     
    First Stopband Atten.   : Unknown     
    Passband Ripple         : Unknown     
    Second Stopband Atten.  : Unknown     
    First Transition Width  : Unknown     
    Second Transition Width : Unknown  

    使用fdatool同样实现此滤波器的设计

    设计的滤波器通过File-Export导出到工作区;

    也可以在analysis中查看器信息,比如系数、幅频、相频特性。比如查看analysis中点击Filter Information中可以看到fdesign使用的内容:'N,F3dB1,F3dB2'

    完成了带通滤波器的设计,就在考虑如何转化为C语言代码,这里有个网站可以进行转化,设计滤波器转为C语言实现,但是结果并没有达到我想要的要求,我的目的是怎样将fdatool中设计的滤波器系数中得到其对应的传递函数H(Z),有了传递函数,就可以自己写C语言实现了

    在上面fdatool设计的滤波器中,两种方法查看设计的滤波器,任意一种都可以;

    1. 点击Filt-Export to simulink Model, simulink打开后,出现了简单的滤波器,
    2. 或者采用如下图操作,从左到右三个按键

       

    双击可以看到滤波器的内部结构,如图显示为两个二阶滤波器级联:

    放大其中一个滤波器如下

    简单作了标记如下

    并给出其对应的C语言实现,此代码无法直接运行只是提取了一部分带通滤波器实现部分

    /* IIR fourth-order filter coefficients */
    typedef struct 
    {
    	float(*a)[3];
    	float(*b)[3];
    	float* gain;
    } IIR_ORDER4_COEFF_T;
    
    /* Save the in-process' data of the second-order filter */
    typedef struct 
    {
    	float m1;
    	float m2;
    } FILTER_ORDER2_T;
    
    /*三轴信号处理前的滤波:四阶带通(0.3-1.2)Hz)滤波,由两个二阶滤波级联起来*/
    float a_raw[2][3] = {
    	{ 1.00, (float)-1.9175958145710057, (float)0.9246554650412394 },    //第一级二阶滤波,分母
    	{ 1.00, (float)-1.7227109782351659, (float)0.7854234338937474 }    //第二级二阶滤波,分母
    };//分母
    float b_raw[2][3] = {
    	{ 1.00, (float)0.00, (float)-1.00 },    //第一级二阶滤波,分子
    	{ 1.00, (float)0.00, (float)-1.00 }    //第二级二阶滤波,分子
    };//分子
    float gain_raw[2] = { (float)0.1048485643154691/*第一级增益*/, (float)0.1048485643154691/*第二级增益*/ };
    
    /******************************************************************************/
    /** Start, initialize the parameters
    * @param[in]
    *
    * @return
    *
    *//*
    * History        :
    * 1.Date         : 2020/8/28
    *   Author       : 
    *   Modification : Created function
    
    *******************************************************************************/
    void StartSwim(void) 
    {
    	/* signal filter parameter initialization */
    	IIR_Raw.a = a_raw;
    	IIR_Raw.b = b_raw;
    	IIR_Raw.gain = gain_raw;
    }
    
    /*
    x: input
    m1:保存中间滤波器数据
    m2:保存中间滤波器数据
    a:滤波器系数
    b:滤波器系数
    gain:增益,对于只支持定点小数运算的,需要把增益分配到每个二阶IIR滤波器的系数中,使得每次中间的结果都不溢出,即使其频率响应的最大值最接近0dB
    */
    float filterOrder2(float* x, float* m_1, float* m_2, float* a, float* b, float* gain){
    	float y, m;
    	//计算没有增益的滤波输出,存于y_
    	m = *x - a[1] * *m_1 - a[2] * *m_2;    //求当前m,同时作为求y_的中间步骤
    	y = m + b[1] * *m_1 + b[2] * *m_2;
    	//更新*m_1和*m_2
    	*m_2 = *m_1;
    	*m_1 = m;
    	//返回带增益的滤波输出
    	return y* *gain;
    }
    
    /******************************************************************************/
    /** filter: Fourth-order filter, direct type II
    * @param[in]
    * filter_state	:Store the middle state of the filter
    * @return
    *
    *//*
    * History        :
    * 1.Date         : 2020/8/28
    *   Author       : 
    *   Modification : Created function
    
    *******************************************************************************/
    float FilterOrder4(float data, FILTER_ORDER4_T* filter_state, IIR_ORDER4_COEFF_T* IIR_coeffs)
    {
    	float data_filtered;
    
    	filter_state->first_order2_out = filterOrder2(&data, &filter_state->first_order2.m1, &filter_state->first_order2.m2, IIR_coeffs->a[0], IIR_coeffs->b[0], IIR_coeffs->gain);  //第一级二阶滤波
    	data_filtered = filterOrder2(&filter_state->first_order2_out, &filter_state->second_order2.m1, &filter_state->second_order2.m2, IIR_coeffs->a[1], IIR_coeffs->b[1], &IIR_coeffs->gain[1]);  //第二级二阶滤波
    	
    	return data_filtered;
    }
    
    /******************************************************************************/
    /** Band-pass filtering for the norm data: 0.25-2Hz
    * @param[in] x:norm data
    *
    * @return filtered data
    *
    *//*
    * History        :
    * 1.Date         : 2020/8/28
    *   Author       : 
    *   Modification : Created function
    
    *******************************************************************************/
    float BandFilter(float x)
    {
    	float y = FilterOrder4(x, &xyz_filter, &IIR_vec);
    
    	return y;
    }

    关于fdatool设计的带通滤波器的系数使用

    使用Matlab的FDAtool工具可以很方便地设计IIR滤波器。使用File菜单中的export选项可以把滤波器的参数输出到Matlab的工作空间中。若滤波器为IIR型,则输出的变量名为G和SOS。它把高阶的IIR滤波器转换为一系列二阶IIR滤波器的级联。SOS为二阶IIR滤波器的系数(b,a),G为各级的增益系数,可用来调节各级通带的衰减。计算IIR滤波器的输出的时候,先将输入数据乘以G, 然后一一通过SOS中的每个IIR滤波器,就得到最终的结果了。

    SOS的每一行表示一级二阶IIR滤波器系[b0,b1,b2,a0,a1,a2],G的每个元素表示相应级的增益系数。也即将G乘上SOS的b0,b1,b2。得到一组新的滤波器系数SOS',可调用MATLAB滤波函数sosfilt对输入信号进行滤波。

    但是如果二阶IIR滤波器的程序只支持定点小数运算的话,那么就需要调整一下系数了。因为设计出来的G有时候很小(不知道会不会很大),这样一旦把输入数据乘以G后,就会使得二阶IIR滤波器的输入过小,造成很大的误差。我们需要把G分配到每个二阶IIR滤波器的系数中,使得每次得到的中间结果都刚好不会溢出。若以IIRi表示第i个二阶IIR滤波器的话,则我们需要保证IIR1, IIR1 * IIR2, IIR1 * IIR2 * IIR3, … 的频率响应都不超过0dB,*号表示级联。为了使得输出的精度最好,我们还需要让上面这些滤波器的频率响应中的最大值最接近0dB。

    级联型:将系统传递函数H(z)因式分解为多个二阶子系统,系统函数就可以表示为这些二阶子系统传递函数的乘积。实现时将每个二阶子系统用直接型实现,整个系统函数用二阶环节的级联实现。

    高阶IIR滤波器的实现是采用二阶滤波器级联的方式来实现的。默认情况下,Filter Coefficients把结果分成多个2阶Section显示,其中还有增益。增益的目的是为了保证计算的精度和系统的稳定性。

     

    简单介绍低通滤波器的使用,其函数参考fdesign官网

    如下

    简单设计了低通滤波

    %% 低通滤波
    function filtered = LowFilter(x)
    fs_origin=1;
    fc=0.03;
    N=4;
    hd_low = design(fdesign.lowpass('N,F3dB',N,fc, fs_origin),'butter');
    filtered = filter(hd_low,x); 
    end

    ..

     

    展开全文
  • 窄带滤波器—般用带通滤波器电路实现,宽带滤波器通常用低通滤波器和高通滤波器级联实现。带通滤波器的中心频率几和带宽BW之间的关系为 式中,Q为品质因数,fH为带通滤波器的上限频率,fL为带通滤波器的下限频率,...
  • 带通滤波器可用于隔离或滤除位于特定频带或频率范围内的某些频率。简单的RC无源滤波器中的截止频率或ƒc点可以通过仅使用一个与无极性电容器串联的电阻器来精确控制,并且根据连接它们的方式,我们可以看到低通或...

    带通滤波器可用于隔离或滤除位于特定频带或频率范围内的某些频率。简单的RC无源滤波器中的截止频率或ƒc点可以通过仅使用一个与无极性电容器串联的电阻器来精确控制,并且根据连接它们的方式,我们可以看到低通或获得高通滤波器。

    这些类型的无源滤波器的一种简单用法是在音频放大器应用或电路中,例如在扬声器分频滤波器或前置放大器音调控制中。有时,仅需要通过特定的频率范围,该频率范围不是从0Hz(DC)开始,也不是在某个较高的高频点结束,而是在某个范围或频率范围内(窄或宽)。

          通过将单个低通滤波器电路与高通滤波器电路连接或“级联” ,我们可以生产另一种无源RC滤波器,该滤波器通过选定的范围或“频带”,该频带可以窄或宽,同时衰减所有超出此范围的人。这种新型的无源滤波器装置可产生一个频率选择滤波器,通常称为带通滤波器或简称BPF。

    带通滤波电路

    与仅使低频范围的信号通过的低通滤波器或使高频范围的信号通过的高通滤波器不同,带通滤波器使特定的“频带”或“扩展”频率内的信号通过而不会使输入失真信号或引入额外的噪声。该频带可以是任何宽度,通常称为滤波器Bandwidth。

    带宽通常定义为存在于两个指定频率截止点(ƒc )之间的频率范围,该频率范围 比最大中心或共振峰值低3dB,同时衰减或削弱这两个点之外的其他频率。

    然后,对于广泛的传播频率中,我们可以简单地定义术语“带宽”,BW为下截止频率(之间的差 ƒc LOWER )和更高的截止频率( ƒc 高等 )点。换句话说,BW =ƒ ħ - ƒ 大号。显然,要使通带滤波器正常工作,低通滤波器的截止频率必须高于高通滤波器的截止频率。

    “理想” 带通滤波器还可用于隔离或滤除位于特定频带内的某些频率,例如,消除噪声。带通滤波器通常被称为二阶滤波器(两极),因为它们在电路设计中具有“两个”电抗成分,即电容器。低通电路中的一个电容器,高通电路中的另一个电容器。

    二阶带通滤波器的频率响应

    上方的波特图或频率响应曲线显示了带通滤波器的特性。在这里,信号在低频带,直至频率达到“下限截止”点处的输出在+20分贝/十年(6分贝/倍频程)的斜率增加衰减ƒ 大号。在此频率下,输出电压再次为输入信号值的1 /√2= 70.7%或输入的-3dB(20 * log(V OUT / V IN))。

    输出继续到直到它到达“上限截止”点最大增益ƒ ħ,其中在-20dB /十倍频(6分贝/倍频程)的速率下的输出降低衰减的任何高频信号。最大输出增益的点通常是上下限之间的两个-3dB值的几何平均值,称为“中心频率”或“谐振峰值”值ƒr。这种几何平均值计算为ƒr 2 =ƒ (UPPER) Xƒ (LOWER) 。

    带通滤波器被认为是二阶(两极)型滤波器,因为它的电路结构中具有“两个”电抗分量,因此相角将是先前看到的一阶滤波器的相角的两倍。180 Ò。输出信号的相位角LEADS通过使输入的90 ø到中心或谐振频率,ƒr点分别成为“零”度(0 Ò)或“同相”,然后改变到LAG输入由-90 ø作为输出频率的增加。

    例如,可以使用与低通和高通滤波器相同的公式找到带通滤波器的上限和下限截止频率点。

    那么显然,可以通过两个滤波器的两个截止频率点的位置来控制滤波器的通带宽度。

    带通滤波器示例No.1。

    将使用RC组件构建一个二阶带通滤波器,该滤波器将仅允许一定范围的频率通过高于1kHz(1,000Hz)和低于30kHz(30,000Hz)的频率。假设两个电阻的阻值为10kΩ,则计算所需的两个电容的阻值。

    高通滤波器阶段

    电容器的值C1需要,得到的截止频率ƒ 大号 1kHz时的与电阻值10kΩ的计算公式为:

    然后,高通级给出截止频率为1.0kHz所需的R1和C1的值为:R1 =10kΩ并最接近的首选值C1 = 15nF。

    低通滤波器阶段

    电容器的值C2需要,得到的截止频率ƒ ħ用的电阻器值的30kHz的10kΩ的计算公式为:

    然后,低通级给出截止频率为30kHz所需的R2和C2的值为R =10kΩ和C = 530pF。但是,计算得出的530pF电容器值的最接近首选值是560pF,因此将其替代。

    假设电阻R1和R2的值均为10kΩ,高通和低通滤波器的电容C1和C2的值分别为15nF和560pF,那么我们的简单无源带通滤波器的电路给出为。

    完成的带通滤波器电路

    带通滤波器谐振频率

    我们还可以计算输出增益达到最大值或峰值时带通滤波器的“谐振”或“中心频率”(ƒr)点。该峰值不是您可能期望的-3dB上下截止点的算术平均值,而是实际上的“几何”或平均值。这种几何平均值计算为ƒr 2 =ƒc (UPPER) Xƒc (LOWER)例如:

    中心频率方程

    其中,ƒ - [R是谐振或中心频率

    ƒ 大号是下-3dB截止频率点

    ƒ ħ是上部-3db截止频率点

    在我们的上述简单例子中,所计算出的截止频率被发现是ƒ 大号 = 1060赫兹和ƒ ħ = 28420赫兹使用该滤波器值。

    然后通过将这些值代入上式得出中心谐振频率为:

    带通滤波器摘要

    通过将单个低通滤波器与高通滤波器级联在一起,可以制成一个简单的无源带通滤波器。RC组合的上下-3dB截止点之间的频率范围(以赫兹为单位)被称为滤波器“带宽”。

    滤波器带宽的宽度或频率范围可以非常小和选择性,或者非常宽且非选择性,具体取决于所使用的R和C的值。

    中心或共振频率点是上下截止点的几何平均值。在此中心频率下,输出信号达到最大值,并且输出信号的相移与输入信号相同。

    对于这种情况,来自带通滤波器或任何无源RC滤波器的输出信号的幅度将始终小于输入信号的幅度。换句话说,无源滤波器也是衰减器,其电压增益小于1(单位)。为了提供具有大于一的电压增益的输出信号,在电路设计中需要某种形式的放大。

    甲无源带通滤波器被归类为一个二阶滤波器,因为它具有它的设计中的两个反应性组分,该电容器。它由两个单个RC滤波器电路组成,每个电路本身都是一阶滤波器。

    如果多个过滤器串联在一起所产生的电路将被称为“N 个阶”过滤器,其中的“n”代表个体反应性组分,并且因此过滤器电路内的极数。例如,过滤器可以是一个2 次阶,4 个阶,10 个阶等

    滤波器阶数越高,n倍-20dB / decade的斜率就越大。但是,将两个或多个单独的电容器组合在一起而获得的单个电容器值仍然是一个电容器。

    上面的示例显示了“理想”带通滤波器的输出频率响应曲线,通带具有恒定增益,阻带具有零增益。实际上,该带通滤波器电路的频率响应与高通电路的输入电抗会影响低通电路(串联或并联连接的组件)的频率响应不同,反之亦然。解决该问题的一种方法是在两个滤波器电路之间提供某种形式的电隔离,如下所示。

    缓冲单个滤波器级

    将放大和滤波组合到同一电路中的一种方法是使用运算放大器或运算放大器,运算放大器部分提供了这些示例。在下一个教程中,我们将介绍在设计中使用运算放大器的滤波器电路,这些滤波器不仅会引入增益,而且会在各级之间提供隔离。这些类型的过滤器布置通常称为有源过滤器。

    声明:本站内容及配图由作者撰写或者网站转载。文章及其配图仅供学习参考分享之用,如有内容图片侵权或者其他问题,请联系本站及时删除。

    ☆ END ☆

    精彩回顾

    • 腔体滤波器技术提升解决方案
    • 腔体滤波器设计之----自动单腔频率温飘
    • 秒仿糖葫芦串形低通
    • 秒仿糖葫芦型低通后续之----低通优化
    • TE01模介质滤波器滤波器
    • 无源互调浅析
    • 如何选择谐振杆的尺寸使功率容量达到最佳
    • 金属介质混合+零腔案例
    • 三模并联耦合介质波导滤波器仿真实例
    • 同轴高低阻抗型低通的公差影响几何?
    • Coupfil对高阶强零点生成的结果偶会出错
    • 陶瓷滤波器的各项制备工序讲解_简介篇
    • (干货)陶瓷滤波器讲解----材料篇
    • (干货)陶瓷滤波器讲解----材料制备篇
    • 细而全的5G产业链详解
    • 陶瓷滤波器讲解----陶瓷材料检测篇
    • BAW,SAW和FBAR滤波器剖析
    • LTCC、IPD、SAW、BAW、FBAR滤波器入门以及应用场景分析

    欢迎加入滤波器、多工器、天线、环形隔离器、功分耦合器、连接器、线缆负载等无源器件的大家庭,关注后可加群

    长按扫左侧二维码可关注

    本团队提供可信可靠的滤波器相关产品各种定制化服务,响应快,专业强,敬请咨询微信号18681587206

    点"在看"为本文点个赞,才算真的看完呦

    展开全文
  • 该滤波器是一个四阶的由LMF100中两节工作模式1的二阶带通滤波器级联构成,使用MC14046锁相环和双BCD同步加计数器MCl4518对输入信号产生100或50倍频脉冲作为LMF100的时钟,实现带通滤波器中心频率的自动跟踪....
  • 提出了一种基于LTCC级联技术的边带陡峭高阻带抑制多级带通滤波器的实现方法。该滤波器电路由两个谐振部分级联而成,每个部分均由电感耦合的四阶谐振腔组成。在一般抽头式梳状线滤波器设计的基础上,引入了交叉耦合,...
  • 现代通信系统经常用双频带带通滤波器来隔离同一网络中的不同工作频带。这种滤波器的传统设计尺寸都比较大,而且需要对两个滤波器应用额外的组合网络。但本文将要详细讨论的双频带带通滤波器设计方法可以做得非常小。...
  • 摘要:本文通过具体调试实例验证了反射系数相位与群时延混合法调谐耦合级联带通滤波器的可行性。文章对比了反射系数群时延法和耦合带宽法,综合其优点提出相位与时延混合的方法,定性地分析了该方法减少读数次数,...
  • 提出了一种基于多波长光纤激光器和色散器件级联的微波光子带通滤波器。该滤波器利用双折射光纤环镜对多波长激光器的输出信号进行整形,整形后的信号作为滤波器的抽头,实现滤波器的可重构性。将标准单模光纤(SSMF)...
  • 当上截止频率与下截止频率之比近似超过2时,则可认为带通滤波器是宽带型的。于是,设计指标可划分为单独的低通和高通技术指标,并通过级联有源高通和低通滤波器来满足设计指标。  窄带LC带通滤波器通常通过直接把...
  • 现代通信系统经常用双频带带通滤波器来隔离同一网络中的不同工作频带。这种滤波器的传统设计尺寸都比较大,而且需要对两个滤波器应用额外的组合网络。但本文将要详细讨论的双频带带通滤波器设计方法可以做得非常小。...
  • 要求 有源带通滤波器,在3000~9000 Hz范围内,衰减的最大变化值为1dB,低于1000 Hz和高于18 000Hz范围内,最小衰减为35dB,增益为+20dB。  解 ①由于上截止频率和下截止频率之比远大于一个倍频程,因此该设计可以...
  • 设计一个范围很宽且连续可变的带通滤波器,从实际调试的角度来看,希望所设计的滤波器具有良好的滤波响应和陡峭的通带一阻带过渡,而单个带通滤波器是无法实现这个目标的,通过级联多个基本单元就可以得到高性能的...
  •  带通滤波器,在500Hz和1OOOHz处衰减3dB,在2OO Hz和2000Hz处最小衰减为40dB。  解 ①确定上截止频率与下截止频率的比:  此滤波器为宽带型带通滤波器。  ②把设计指标分解为两个单独的设计指标:  高通...
  • 提出了一种小型化超宽带(UWB)带通滤波器的设计方案。带通滤波器由一个环形槽线谐振器和两对嵌入式的圆形槽线结构组成,环形槽线谐振器用来获得良好UWB通带特性,圆形槽线结构可抑制阻带内的谐波。相对于利用级联低...
  • 此外,通过将两个谐振器与SCLS级联,设计了用于WLAN应用的中心频率为5.2 GHz的四极超导带通滤波器。 另外,添加非谐振节点谐振器以实现谐振器的简并模式之间的耦合。 最后,通过在厚度为0.5毫米的MgO衬底上沉积YBCO...
  • 因此,通过将高通和低通滤波器级联在一起,我获得了带通滤波器带通滤波器的范围 = [fc1 , fc2]。 fc1:高通滤波器的截止频率。 fc2:低通滤波器的截止频率。 fc1 = 1/(2*pi*R1*C1) fc2 = 1/(2*pi*R2*C2) 放大 :=...
  • 提出的“基于带通滤波器的参差滤波实现高增益宽带有源滤波的方法”是利用多个带通滤波器将一个宽带的输入信号分成几个频段,将每一个频段的信号作为一个分信手。然后,由对应每个分信号的相应支路对分信号进行加权...
  • 这时滤波器的设计指标可以被分为独立的低通和高通指标,并简单地看作低通滤波器和高通滤波器级联。  窄带滤波器的设计更困难一些,必须恰当地选择电路结构,丽且要运用合适的变换,以避免元件值不符合实际。此外...
  • 该演示包含通过简单的双二阶滤波器级联可高达96db bp滚降的代码,这可能会显着提高质量,但是由于滤波器设计的原因,它并不完美,因此随着阶数增加(频谱可能看起来延迟/平滑),它可能会引起振铃问题,一个可以仅...
  • 提出一种新型的基于平行带线的带通滤波器,在不增加电路尺寸的基础上增强了滤波器的阻带抑制.该滤波器以平行带线进行馈电,包含顶层和底层2个完全相同的电路,两层电路中电流反相,可以认为这2个电路是级联工作的.与传统...
  • 第46章 STM32F407的IIR带通滤波器实现(支持逐个数据的实时滤波) 本章节讲解IIR带通滤波器实现。 目录 46.1 初学者重要提示 46.2 带通滤波器介绍 46.3 IIR滤波器介绍 46.4 Matlab工具箱filterDesigner生成IIR...

    完整版教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

    第46章       STM32F407的IIR带通滤波器实现(支持逐个数据的实时滤波)

    本章节讲解IIR带通滤波器实现。

    目录

    46.1 初学者重要提示

    46.2 带通滤波器介绍

    46.3 IIR滤波器介绍

    46.4 Matlab工具箱filterDesigner生成IIR带通滤波器系数

    46.5 IIR带通滤波器设计

    46.5.1        函数arm_biquad_cascade_df1_init_f32

    46.5.2 函数arm_biquad_cascade_df1_f32

    46.5.3 filterDesigner获取带通滤波器系数

    46.5.4 带通滤波器实现

    46.6 实验例程说明(MDK)

    46.7 实验例程说明(IAR)

    46.8 总结


    46.1 初学者重要提示

     1、 本章节提供的带通滤波器支持实时滤波,每次可以滤波一个数据,也可以多个数据,不限制大小。但要注意以下两点:

    •   所有数据是在同一个采样率下依次采集的数据。
    •   每次过滤数据个数一旦固定下来,运行中不可再修改。

     2、 FIR滤波器的群延迟是一个重要的知识点,详情在本教程第41章有详细说明。IIR和FIR一样,也有群延迟问题。

    46.2 带通滤波器介绍

    允许一个范围内的频率信号通过,而减弱范围之外频率的信号通过。比如混合信号含有50Hz + 200Hz 信号,我们可通过带通滤波器,仅让200Hz信号通过。

    46.3 IIR滤波器介绍

    ARM官方提供的直接I型IIR库支持Q7,Q15,Q31和浮点四种数据类型。其中Q15和Q31提供了快速版本。

    直接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)。

    46.4 Matlab工具箱filterDesigner生成IIR带通滤波器系数

    前面介绍FIR滤波器的时候,我们讲解了如何使用filterDesigner生成C头文件,从而获得滤波器系数。这里不能再使用这种方法了,主要是因为通过C头文件获取的滤波器系数需要通过ARM官方的IIR函数调用多次才能获得滤波结果,所以我们这里换另外一种方法。

    下面我们讲解如何通过filterDesigner工具箱生成滤波器系数。首先在matlab的命令窗口输入filterDesigner就能打开这个工具箱:

     

    filterDesigner界面打开效果如下:

    IIR滤波器的低通,高通,带通,带阻滤波的设置会在下面一 一讲解,这里说一下设置后相应参数后如何生成滤波器系数。参数设置好以后点击如下按钮:

    点击Design Filter之后,注意左上角生成的滤波器结构:

    默认生成的IIR滤波器类型是Direct-Form II, Second-Order Sections(直接II型,每个Section是一个二阶滤波器)。这里我们需要将其转换成Direct-Form I, Second-Order Sections,因为本章使用的IIR滤波器函数是Direct-Form I的结构。

    转换方法,点击Edit->Convert Structure,界面如下,这里我们选择第一项,并点击OK:

    转换好以后再点击File-Export,第一项选择Coefficient File(ASCII):

    第一项选择好以后,第二项选择Decimal:

    两个选项都选择好以后,点击Export进行导出,导出后保存即可:

    保存后Matlab会自动打开untitled.fcf文件,可以看到生成的系数:

    % Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0.
    % Generated on: 15-Aug-2021 22:20:26
    
    % 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  0  -1  1   1.127651872054164616798743736580945551395  0.470013145087532668853214090631809085608
    1  0  -1  1  -0.774953058046049081397654845204669982195  0.367077500556684199750634434167295694351
                                                                                                      
    Scale Values:                                                                                     
    0.558156585760773649163013487850548699498                                                         
    0.558156585760773649163013487850548699498                                                         
    

    由于前面选择的是4阶IIR滤波,生成的结果就是由两组二阶IIR滤波系数组成,系数的对应顺序如下:

    SOS Matrix:                                                  
    1   2   1   1   1.127651872054164616798743736580945551395  0.470013145087532668853214090631809085608        
    b0  b1  b2  a0          a1                                                   a2
    1    2   1   1   -0.774953058046049081397654845204669982195  0.367077500556684199750634434167295694351        
    b0  b1  b2  a0        a1                                                     a2

    注意,实际使用ARM官方的IIR函数调用的时候要将a1和a2取反。另外下面两组是每个二阶滤波器的增益,滤波后的结果要乘以这两个增益数值才是实际结果:

    0.558156585760773649163013487850548699498                                                         
    0.558156585760773649163013487850548699498    

    实际的滤波系数调用方法,看下面的例子即可。

    46.5 IIR带通滤波器设计

    本章使用的IIR滤波器函数是arm_biquad_cascade_df1_f32。使用此函数可以设计IIR低通,高通,带通和带阻滤波器

    46.5.1        函数arm_biquad_cascade_df1_init_f32

    函数原型:

    void arm_biquad_cascade_df1_init_f32(
            arm_biquad_casd_df1_inst_f32 * S,
            uint8_t numStages,
      const float32_t * pCoeffs,
            float32_t * pState)

    函数描述:

    这个函数用于IIR初始化。

    函数参数:

    •   第1个参数是arm_biquad_casd_df1_inst_f32类型结构体变量。
    •   第2个参数是2阶滤波器的个数。
    •   第3个参数是滤波器系数地址。
    •   第4个参数是缓冲状态地址。

    注意事项:

    结构体arm_biquad_casd_df1_inst_f32的定义如下(在文件filtering_functions.h文件):

    typedef struct
    {
      uint32_t numStages;      /**< number of 2nd order stages in the filter.  Overall order is 2*numStages. */
     float32_t *pState; /**< Points to the array of state coefficients.  The array is of length 4*numStages. */
     const float32_t *pCoeffs; /**< Points to the array of coefficients.  The array is of length 5*numStages */
    } arm_biquad_casd_df1_inst_f32;
    1. numStages表示二阶滤波器的个数,总阶数是2*numStages。
    2. pState指向状态变量数组,这个数组用于函数内部计算数据的缓存,总大小4*numStages。
    3. 参数pCoeffs指向滤波因数,滤波因数数组长度为5*numStages。但要注意pCoeffs指向的滤波因数应该按照如下的逆序进行排列:

    {b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}

    先放第一个二阶Biquad系数,然后放第二个,以此类推。

    46.5.2 函数arm_biquad_cascade_df1_f32

    函数定义如下:

    void arm_biquad_cascade_df1_f32(
          const arm_biquad_casd_df1_inst_f32 * S,
          float32_t * pSrc,
          float32_t * pDst,
          uint32_t blockSize)

    函数描述:

    这个函数用于IIR滤波。

    函数参数:

    •   第1个参数是arm_biquad_casd_df1_inst_f32类型结构体变量。
    •   第2个参数是源数据地址。
    •   第3个参数是滤波后的数据地址。
    •   第4个参数是每次调用处理的数据个数,最小可以每次处理1个数据,最大可以每次全部处理完。

    46.5.3 filterDesigner获取带通滤波器系数

    设计一个如下的例子:

    信号由50Hz正弦波和200Hz正弦波组成,采样率1Kbps,现设计一个巴特沃斯滤波器带通滤波器,采用直接I型,截止频率140Hz和400,采样400个数据,滤波器阶数设置为4。filterDesigner的配置如下:

    配置好带通滤波器后,具体滤波器系数的生成大家参考本章第4小节的方法即可。

    46.5.4 带通滤波器实现

    通过工具箱filterDesigner获得带通滤波器系数后在开发板上运行函数arm_biquad_cascade_df1_f32来测试低通滤波器的效果。

    #define numStages  2                /* 2阶IIR滤波的个数 */
    #define TEST_LENGTH_SAMPLES  400    /* 采样点数 */
    #define BLOCK_SIZE           1      /* 调用一次arm_biquad_cascade_df1_f32处理的采样点个数 */
    
    
    uint32_t blockSize = BLOCK_SIZE;
    uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE;       /* 需要调用arm_biquad_cascade_df1_f32的次数 */
    
    
    static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; /* 采样点 */
    static float32_t testOutput[TEST_LENGTH_SAMPLES];               /* 滤波后的输出 */
    static float32_t IIRStateF32[4*numStages];                      /* 状态缓存 */
          
    /* 巴特沃斯带通滤波器系数140Hz 400Hz*/                                                                                                                                         
    const float32_t IIRCoeffs32BP[5*numStages] = {
        1.0f,  0.0f,  -1.0f,     -1.127651872054164616798743736580945551395f,  
    -0.470013145087532668853214090631809085608f,      
        1.0f,  0.0f,  -1.0f,     0.774953058046049081397654845204669982195f,  
    -0.367077500556684199750634434167295694351f                               
    };                                              
    
    /*
    *********************************************************************************************************
    *    函 数 名: arm_iir_f32_bp
    *    功能说明: 调用函数arm_iir_f32_bp实现带通滤波器
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void arm_iir_f32_bp(void)
    {
        uint32_t i;
        arm_biquad_casd_df1_inst_f32 S;
        float32_t ScaleValue;
        float32_t  *inputF32, *outputF32;
        
        /* 初始化输入输出缓存指针 */
        inputF32 = &testInput_f32_50Hz_200Hz[0];
        outputF32 = &testOutput[0];
        
        
        /* 初始化 */
        arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32BP[0], 
    (float32_t *)&IIRStateF32[0]);
        
        
        /* 实现IIR滤波,这里每次处理1个点 */
        for(i=0; i < numBlocks; i++)
        {
            arm_biquad_cascade_df1_f32(&S, inputF32 + (i * blockSize),  outputF32 + (i * blockSize), 
     blockSize);
        }
                
        /*放缩系数 */
        ScaleValue = 0.558156585760773649163013487850548699498f * 0.558156585760773649163013487850548699498f; 
        
        /* 打印滤波后结果 */
        for(i=0; i<TEST_LENGTH_SAMPLES; i++)
        {
            printf("%f, %f\r\n", testInput_f32_50Hz_200Hz[i], testOutput[i]*ScaleValue);
        }
    }

    运行如上函数可以通过串口打印出函数arm_biquad_cascade_df1_f32滤波后的波形数据,下面通过Matlab绘制波形来对比Matlab计算的结果和ARM官方库计算的结果。

    对比前需要先将串口打印出的一组数据加载到Matlab中, arm_biquad_cascade_df1_f32的计算结果起名sampledata,加载方法在第13章13.6小结已经讲解,这里不做赘述了。Matlab中运行的代码如下:

    fs=1000;            %设置采样频率 1K
    N=400;               %采样点数      
    n=0:N-1;
    t=n/fs;                %时间序列
    f=n*fs/N;              %频率序列
    
    x1=sin(2*pi*50*t);
    x2=sin(2*pi*200*t);     %50Hz和200Hz正弦波
    subplot(211);
    plot(t, x1);
    title('滤波后的理想波形');
    grid on;
    
    subplot(212);
    plot(t, sampledata);
    title('ARM官方库滤波后的波形');
    grid on;

    Matlab计算结果如下:

    从上面的波形对比来看,matlab和函数arm_biquad_cascade_df1_f32计算的结果基本是一致的。为了更好的说明滤波效果,下面从频域的角度来说明这个问题,Matlab上面运行如下代码:

    fs=1000;                %设置采样频率 1K
    N=400;                 %采样点数      
    n=0:N-1;
    t=n/fs;                  %时间序列
    f=n*fs/N;                %频率序列
    
    x = sin(2*pi*50*t) + sin(2*pi*200*t);      %50Hz和200Hz正弦波合成
      
    subplot(211);
    y=fft(x, N);                %对信号x做FFT   
    plot(f,abs(y));
    xlabel('频率/Hz');
    ylabel('振幅');
    title('原始信号FFT');
    grid on;
    
    y3=fft(sampledata, N);    %经过IIR滤波器后得到的信号做FFT
    subplot(212);                               
    plot(f,abs(y3));
    xlabel('频率/Hz');
    ylabel('振幅');
    title('IIR滤波后信号FFT');
    grid on;

    Matlab计算结果如下:

    上面波形变换前的FFT和变换后FFT可以看出,50Hz的正弦波基本被滤除。

    46.6 实验例程说明(MDK)

    配套例子:

    V5-231_IIR带通滤波器(支持逐点实时滤波)

    实验目的:

    1. 学习IIR带通滤波器的实现,支持实时滤波

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
    2. 按下按键K1,打印原始波形数据和滤波后的波形数据。

    使用AC6注意事项

    特别注意附件章节C的问题

    上电后串口打印的信息:

    波特率 115200,数据位 8,奇偶校验位无,停止位 1。

    RTT方式打印信息:

    程序设计:

      系统栈大小分配:

      硬件外设初始化

    硬件外设的初始化是在 bsp.c 文件实现:

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 
           STM32F407 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIC优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到168MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitLed();        /* 初始化LED */        
    }

      主功能:

    主程序实现如下操作:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   按下按键K1,打印原始波形数据和滤波后的波形数据。
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;        /* 按键代码 */
        uint16_t i;
    
        
        bsp_Init();        /* 硬件初始化 */
        PrintfLogo();    /* 打印例程信息到串口1 */
    
        PrintfHelp();    /* 打印操作提示信息 */
        
        for(i=0; i<TEST_LENGTH_SAMPLES; i++)
        {
            /* 50Hz正弦波+200Hz正弦波,采样率1KHz */
            testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) + 
    arm_sin_f32(2*3.1415926f*200*i/1000);
        }
        
    
        bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */
    
        /* 进入主程序循环体 */
        while (1)
        {
            bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
            
    
            if (bsp_CheckTimer(0))    /* 判断定时器超时时间 */
            {
                /* 每隔100ms 进来一次 */
                bsp_LedToggle(2);    /* 翻转LED的状态 */
            }
            
            ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
            if (ucKeyCode != KEY_NONE)
            {
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:            /* K1键按下 */
                        arm_iir_f32_bp();
                        break;
                    
        
                    default:
                        /* 其它的键值不处理 */
                        break;
                }
            }
    
        }
    }

    46.7 实验例程说明(IAR)

    配套例子:

    V5-231_IIR带通滤波器(支持逐点实时滤波)

    实验目的:

    1. 学习IIR带通滤波器的实现,支持实时滤波

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
    2. 按下按键K1,打印原始波形数据和滤波后的波形数据。

    上电后串口打印的信息:

    波特率 115200,数据位 8,奇偶校验位无,停止位 1。

    RTT方式打印信息:

    程序设计:

      系统栈大小分配:

      硬件外设初始化

    硬件外设的初始化是在 bsp.c 文件实现:

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 
           STM32F407 HAL 库初始化,此时系统用的还是F407自带的16MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIC优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到168MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V5开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitLed();        /* 初始化LED */        
    }

      主功能:

    主程序实现如下操作:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   按下按键K1,打印原始波形数据和滤波后的波形数据。
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;        /* 按键代码 */
        uint16_t i;
    
        
        bsp_Init();        /* 硬件初始化 */
        PrintfLogo();    /* 打印例程信息到串口1 */
    
        PrintfHelp();    /* 打印操作提示信息 */
        
        for(i=0; i<TEST_LENGTH_SAMPLES; i++)
        {
            /* 50Hz正弦波+200Hz正弦波,采样率1KHz */
            testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) + 
    arm_sin_f32(2*3.1415926f*200*i/1000);
        }
        
    
        bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */
    
        /* 进入主程序循环体 */
        while (1)
        {
            bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
            
    
            if (bsp_CheckTimer(0))    /* 判断定时器超时时间 */
            {
                /* 每隔100ms 进来一次 */
                bsp_LedToggle(2);    /* 翻转LED的状态 */
            }
            
            ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
            if (ucKeyCode != KEY_NONE)
            {
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:            /* K1键按下 */
                        arm_iir_f32_bp();
                        break;
                    
        
                    default:
                        /* 其它的键值不处理 */
                        break;
                }
            }
    
        }
    }

    46.8 总结

    本章节主要讲解了IIR滤波器的带通实现,同时一定要注意IIR滤波器的群延迟问题,详见本教程的第41章。

    展开全文
  • 级联法设计全等宽祸合微带线带通滤波器时,要多次对参量进行调整、验证,尺度不好把握,难以得到最佳值。针对此问题,将改进的遗传算法与级联法结合使用,不需对参量反复调整,这不仅节省了设计时间,且能一次得到...
  • 本文提出了一种低成本的紧凑型超宽带(UWB)带通滤波器(BPF),该滤波器由缺陷接地结构(DGS)和短路的T形短截线组成。 带通电路的实现是通过级联基于DGS的LPF和使用短截线设计的HPF来实现的。 BPF的分数带宽(FBW...
  • 本文提出了利用基片集成波导(SIW)的毫米波(mmW)带通滤波器(BPF)。 讨论了两种不同类型的电磁带隙(EBG)单元的传播常数,并比较了它们的通带和阻带性能。 其中,开槽式SIW单元显示出非常好的上下阻带性能。 ...
  • Coder兼容的滤波器功能,能够实现二阶高,低和带通滤波器及其组合。 执照 即做你想要的! 动机 我经常使用MATLAB编码器来加快仿真速度。 通用过滤函数在这些仿真中可能很有用,但是MATLAB的过滤器设计函数(特别是...
  • 第46章 STM32H7的IIR带通滤波器实现(支持逐个数据的实时滤波) 本章节讲解IIR带通滤波器实现。 目录 46.1 初学者重要提示 46.2 带通滤波器介绍 46.3 IIR滤波器介绍 46.4 Matlab工具箱filterDesigner生成IIR...

    完整版教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=94547

    第46章       STM32H7的IIR带通滤波器实现(支持逐个数据的实时滤波)

    本章节讲解IIR带通滤波器实现。

    目录

    46.1 初学者重要提示

    46.2 带通滤波器介绍

    46.3 IIR滤波器介绍

    46.4 Matlab工具箱filterDesigner生成IIR带通滤波器系数

    46.5 IIR带通滤波器设计

    46.5.1 函数arm_biquad_cascade_df1_init_f32

    46.5.2 函数arm_biquad_cascade_df1_f32

    46.5.3 filterDesigner获取带通滤波器系数

    46.5.4 带通滤波器实现

    46.6 实验例程说明(MDK)

    46.7 实验例程说明(IAR)

    46.8 总结


    46.1 初学者重要提示

      1、本章节提供的带通滤波器支持实时滤波,每次可以滤波一个数据,也可以多个数据,不限制大小。但要注意以下两点:

    •   所有数据是在同一个采样率下依次采集的数据。
    •   每次过滤数据个数一旦固定下来,运行中不可再修改。

      2、FIR滤波器的群延迟是一个重要的知识点,详情在本教程第41章有详细说明。IIR和FIR一样,也有群延迟问题。

    46.2 带通滤波器介绍

    允许一个范围内的频率信号通过,而减弱范围之外频率的信号通过。比如混合信号含有50Hz + 200Hz 信号,我们可通过带通滤波器,仅让200Hz信号通过。

    46.3 IIR滤波器介绍

    ARM官方提供的直接I型IIR库支持Q7,Q15,Q31和浮点四种数据类型。其中Q15和Q31提供了快速版本。

    直接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)。

    46.4 Matlab工具箱filterDesigner生成IIR带通滤波器系数

    前面介绍FIR滤波器的时候,我们讲解了如何使用filterDesigner生成C头文件,从而获得滤波器系数。这里不能再使用这种方法了,主要是因为通过C头文件获取的滤波器系数需要通过ARM官方的IIR函数调用多次才能获得滤波结果,所以我们这里换另外一种方法。

    下面我们讲解如何通过filterDesigner工具箱生成滤波器系数。首先在matlab的命令窗口输入filterDesigner就能打开这个工具箱:

     

    filterDesigner界面打开效果如下:

    IIR滤波器的低通,高通,带通,带阻滤波的设置会在下面一 一讲解,这里说一下设置后相应参数后如何生成滤波器系数。参数设置好以后点击如下按钮:

    点击Design Filter之后,注意左上角生成的滤波器结构:

    默认生成的IIR滤波器类型是Direct-Form II, Second-Order Sections(直接II型,每个Section是一个二阶滤波器)。这里我们需要将其转换成Direct-Form I, Second-Order Sections,因为本章使用的IIR滤波器函数是Direct-Form I的结构。

    转换方法,点击Edit->Convert Structure,界面如下,这里我们选择第一项,并点击OK:

    转换好以后再点击File-Export,第一项选择Coefficient File(ASCII):

    第一项选择好以后,第二项选择Decimal:

    两个选项都选择好以后,点击Export进行导出,导出后保存即可:

    保存后Matlab会自动打开untitled.fcf文件,可以看到生成的系数:

    % Generated by MATLAB(R) 9.4 and Signal Processing Toolbox 8.0.
    % Generated on: 15-Aug-2021 22:20:26
    
    % 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  0  -1  1   1.127651872054164616798743736580945551395  0.470013145087532668853214090631809085608
    1  0  -1  1  -0.774953058046049081397654845204669982195  0.367077500556684199750634434167295694351
                                                                                                      
    Scale Values:                                                                                     
    0.558156585760773649163013487850548699498                                                         
    0.558156585760773649163013487850548699498     
    

    由于前面选择的是4阶IIR滤波,生成的结果就是由两组二阶IIR滤波系数组成,系数的对应顺序如下:

    SOS Matrix:                                                  
    1   2   1   1   1.127651872054164616798743736580945551395  0.470013145087532668853214090631809085608        
    b0  b1  b2  a0          a1                                                   a2
    1    2   1   1   -0.774953058046049081397654845204669982195  0.367077500556684199750634434167295694351        
    b0  b1  b2  a0        a1                                                     a2

    注意,实际使用ARM官方的IIR函数调用的时候要将a1和a2取反。另外下面两组是每个二阶滤波器的增益,滤波后的结果要乘以这两个增益数值才是实际结果:

    0.558156585760773649163013487850548699498                                                         
    0.558156585760773649163013487850548699498    

    实际的滤波系数调用方法,看下面的例子即可。

    46.5 IIR带通滤波器设计

    本章使用的IIR滤波器函数是arm_biquad_cascade_df1_f32。使用此函数可以设计IIR低通,高通,带通和带阻滤波器

    46.5.1 函数arm_biquad_cascade_df1_init_f32

    函数原型:

    void arm_biquad_cascade_df1_init_f32(
            arm_biquad_casd_df1_inst_f32 * S,
            uint8_t numStages,
      const float32_t * pCoeffs,
            float32_t * pState)

    函数描述:

    这个函数用于IIR初始化。

    函数参数:

    •   第1个参数是arm_biquad_casd_df1_inst_f32类型结构体变量。
    •   第2个参数是2阶滤波器的个数。
    •   第3个参数是滤波器系数地址。
    •   第4个参数是缓冲状态地址。

    注意事项:

    结构体arm_biquad_casd_df1_inst_f32的定义如下(在文件filtering_functions.h文件):

    typedef struct
    {
      uint32_t numStages;      /**< number of 2nd order stages in the filter.  Overall order is 2*numStages. */
     float32_t *pState; /**< Points to the array of state coefficients.  The array is of length 4*numStages. */
     const float32_t *pCoeffs; /**< Points to the array of coefficients.  The array is of length 5*numStages */
    } arm_biquad_casd_df1_inst_f32;
    1. numStages表示二阶滤波器的个数,总阶数是2*numStages。
    2. pState指向状态变量数组,这个数组用于函数内部计算数据的缓存,总大小4*numStages。
    3. 参数pCoeffs指向滤波因数,滤波因数数组长度为5*numStages。但要注意pCoeffs指向的滤波因数应该按照如下的逆序进行排列:

    {b10, b11, b12, a11, a12, b20, b21, b22, a21, a22, ...}

    先放第一个二阶Biquad系数,然后放第二个,以此类推。

    46.5.2 函数arm_biquad_cascade_df1_f32

    函数定义如下:

    void arm_biquad_cascade_df1_f32(
          const arm_biquad_casd_df1_inst_f32 * S,
          float32_t * pSrc,
          float32_t * pDst,
          uint32_t blockSize)

    函数描述:

    这个函数用于IIR滤波。

    函数参数:

    •   第1个参数是arm_biquad_casd_df1_inst_f32类型结构体变量。
    •   第2个参数是源数据地址。
    •   第3个参数是滤波后的数据地址。
    •   第4个参数是每次调用处理的数据个数,最小可以每次处理1个数据,最大可以每次全部处理完。

    46.5.3 filterDesigner获取带通滤波器系数

    设计一个如下的例子:

    信号由50Hz正弦波和200Hz正弦波组成,采样率1Kbps,现设计一个巴特沃斯滤波器带通滤波器,采用直接I型,截止频率140Hz和400,采样400个数据,滤波器阶数设置为4。filterDesigner的配置如下:

    配置好带通滤波器后,具体滤波器系数的生成大家参考本章第4小节的方法即可。

    46.5.4 带通滤波器实现

    通过工具箱filterDesigner获得带通滤波器系数后在开发板上运行函数arm_biquad_cascade_df1_f32来测试低通滤波器的效果。

    #define numStages  2                /* 2阶IIR滤波的个数 */
    #define TEST_LENGTH_SAMPLES  400    /* 采样点数 */
    #define BLOCK_SIZE           1      /* 调用一次arm_biquad_cascade_df1_f32处理的采样点个数 */
    
    
    uint32_t blockSize = BLOCK_SIZE;
    uint32_t numBlocks = TEST_LENGTH_SAMPLES/BLOCK_SIZE;       /* 需要调用arm_biquad_cascade_df1_f32的次数 */
    
    
    static float32_t testInput_f32_50Hz_200Hz[TEST_LENGTH_SAMPLES]; /* 采样点 */
    static float32_t testOutput[TEST_LENGTH_SAMPLES];               /* 滤波后的输出 */
    static float32_t IIRStateF32[4*numStages];                      /* 状态缓存 */
          
    /* 巴特沃斯带通滤波器系数140Hz 400Hz*/                                                                                                                                         
    const float32_t IIRCoeffs32BP[5*numStages] = {
        1.0f,  0.0f,  -1.0f,     -1.127651872054164616798743736580945551395f,  
    -0.470013145087532668853214090631809085608f,      
        1.0f,  0.0f,  -1.0f,     0.774953058046049081397654845204669982195f,  
    -0.367077500556684199750634434167295694351f                               
    };                                              
    
    /*
    *********************************************************************************************************
    *    函 数 名: arm_iir_f32_bp
    *    功能说明: 调用函数arm_iir_f32_bp实现带通滤波器
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void arm_iir_f32_bp(void)
    {
        uint32_t i;
        arm_biquad_casd_df1_inst_f32 S;
        float32_t ScaleValue;
        float32_t  *inputF32, *outputF32;
        
        /* 初始化输入输出缓存指针 */
        inputF32 = &testInput_f32_50Hz_200Hz[0];
        outputF32 = &testOutput[0];
        
        
        /* 初始化 */
        arm_biquad_cascade_df1_init_f32(&S, numStages, (float32_t *)&IIRCoeffs32BP[0], 
    (float32_t *)&IIRStateF32[0]);
        
        
        /* 实现IIR滤波,这里每次处理1个点 */
        for(i=0; i < numBlocks; i++)
        {
            arm_biquad_cascade_df1_f32(&S, inputF32 + (i * blockSize),  outputF32 + (i * blockSize), 
     blockSize);
        }
                
        /*放缩系数 */
        ScaleValue = 0.558156585760773649163013487850548699498f * 0.558156585760773649163013487850548699498f; 
        
        /* 打印滤波后结果 */
        for(i=0; i<TEST_LENGTH_SAMPLES; i++)
        {
            printf("%f, %f\r\n", testInput_f32_50Hz_200Hz[i], testOutput[i]*ScaleValue);
        }
    }

    运行如上函数可以通过串口打印出函数arm_biquad_cascade_df1_f32滤波后的波形数据,下面通过Matlab绘制波形来对比Matlab计算的结果和ARM官方库计算的结果。

    对比前需要先将串口打印出的一组数据加载到Matlab中, arm_biquad_cascade_df1_f32的计算结果起名sampledata,加载方法在第13章13.6小结已经讲解,这里不做赘述了。Matlab中运行的代码如下:

    fs=1000;            %设置采样频率 1K
    N=400;               %采样点数      
    n=0:N-1;
    t=n/fs;                %时间序列
    f=n*fs/N;              %频率序列
    
    x1=sin(2*pi*50*t);
    x2=sin(2*pi*200*t);     %50Hz和200Hz正弦波
    subplot(211);
    plot(t, x1);
    title('滤波后的理想波形');
    grid on;
    
    subplot(212);
    plot(t, sampledata);
    title('ARM官方库滤波后的波形');
    grid on;

    Matlab计算结果如下:

    从上面的波形对比来看,matlab和函数arm_biquad_cascade_df1_f32计算的结果基本是一致的。为了更好的说明滤波效果,下面从频域的角度来说明这个问题,Matlab上面运行如下代码:

    fs=1000;                %设置采样频率 1K
    N=400;                 %采样点数      
    n=0:N-1;
    t=n/fs;                  %时间序列
    f=n*fs/N;                %频率序列
    
    x = sin(2*pi*50*t) + sin(2*pi*200*t);      %50Hz和200Hz正弦波合成
      
    subplot(211);
    y=fft(x, N);                %对信号x做FFT   
    plot(f,abs(y));
    xlabel('频率/Hz');
    ylabel('振幅');
    title('原始信号FFT');
    grid on;
    
    y3=fft(sampledata, N);    %经过IIR滤波器后得到的信号做FFT
    subplot(212);                               
    plot(f,abs(y3));
    xlabel('频率/Hz');
    ylabel('振幅');
    title('IIR滤波后信号FFT');
    grid on;

    Matlab计算结果如下:

    上面波形变换前的FFT和变换后FFT可以看出,50Hz的正弦波基本被滤除。

    46.6 实验例程说明(MDK)

    配套例子:

    V7-231_IIR带通滤波器(支持逐点实时滤波)

    实验目的:

    1. 学习IIR带通滤波器的实现,支持实时滤波

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
    2. 按下按键K1,打印原始波形数据和滤波后的波形数据。

    使用AC6注意事项

    特别注意附件章节C的问题

    上电后串口打印的信息:

    波特率 115200,数据位 8,奇偶校验位无,停止位 1。

    RTT方式打印信息:

    程序设计:

      系统栈大小分配:

      RAM空间用的DTCM:

      硬件外设初始化

    硬件外设的初始化是在 bsp.c 文件实现:

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 配置MPU */
        MPU_Config();
        
        /* 使能L1 Cache */
        CPU_CACHE_Enable();
    
        /* 
           STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIC优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到400MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
        bsp_InitLed();        /* 初始化LED */    
    }

      MPU配置和Cache配置:

    数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区。

    /*
    *********************************************************************************************************
    *    函 数 名: MPU_Config
    *    功能说明: 配置MPU
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void MPU_Config( void )
    {
        MPU_Region_InitTypeDef MPU_InitStruct;
    
        /* 禁止 MPU */
        HAL_MPU_Disable();
    
        /* 配置AXI SRAM的MPU属性为关闭读Cache和写Cache */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x24000000;
        MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT _BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT _CACHEABLE;
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
        
        
        /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x60000000;
        MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
        
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
        /*使能 MPU */
        HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: CPU_CACHE_Enable
    *    功能说明: 使能L1 Cache
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void CPU_CACHE_Enable(void)
    {
        /* 使能 I-Cache */
        SCB_EnableICache();
    
        /* 使能 D-Cache */
        SCB_EnableDCache();
    }

      主功能:

    主程序实现如下操作:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   按下按键K1,打印原始波形数据和滤波后的波形数据。
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;        /* 按键代码 */
        uint16_t i;
    
        
        bsp_Init();        /* 硬件初始化 */
        PrintfLogo();    /* 打印例程信息到串口1 */
    
        PrintfHelp();    /* 打印操作提示信息 */
        
        for(i=0; i<TEST_LENGTH_SAMPLES; i++)
        {
            /* 50Hz正弦波+200Hz正弦波,采样率1KHz */
            testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) + 
    arm_sin_f32(2*3.1415926f*200*i/1000);
        }
        
    
        bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */
    
        /* 进入主程序循环体 */
        while (1)
        {
            bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
            
    
            if (bsp_CheckTimer(0))    /* 判断定时器超时时间 */
            {
                /* 每隔100ms 进来一次 */
                bsp_LedToggle(2);    /* 翻转LED的状态 */
            }
            
            ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
            if (ucKeyCode != KEY_NONE)
            {
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:            /* K1键按下 */
                        arm_iir_f32_bp();
                        break;
                    
        
                    default:
                        /* 其它的键值不处理 */
                        break;
                }
            }
    
        }
    }

    46.7 实验例程说明(IAR)

    配套例子:

    V7-231_IIR带通滤波器(支持逐点实时滤波)

    实验目的:

    1. 学习IIR带通滤波器的实现,支持实时滤波

    实验内容:

    1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
    2. 按下按键K1,打印原始波形数据和滤波后的波形数据。

    上电后串口打印的信息:

    波特率 115200,数据位 8,奇偶校验位无,停止位 1。

    RTT方式打印信息:

    程序设计:

      系统栈大小分配:

      RAM空间用的DTCM:

      硬件外设初始化

    硬件外设的初始化是在 bsp.c 文件实现:

    /*
    *********************************************************************************************************
    *    函 数 名: bsp_Init
    *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
    *    形    参:无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    void bsp_Init(void)
    {
        /* 配置MPU */
        MPU_Config();
        
        /* 使能L1 Cache */
        CPU_CACHE_Enable();
    
        /* 
           STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
           - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
           - 设置NVIC优先级分组为4。
         */
        HAL_Init();
    
        /* 
           配置系统时钟到400MHz
           - 切换使用HSE。
           - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
        */
        SystemClock_Config();
    
        /* 
           Event Recorder:
           - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
           - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
        */    
    #if Enable_EventRecorder == 1  
        /* 初始化EventRecorder并开启 */
        EventRecorderInitialize(EventRecordAll, 1U);
        EventRecorderStart();
    #endif
        
        bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
        bsp_InitTimer();      /* 初始化滴答定时器 */
        bsp_InitUart();    /* 初始化串口 */
        bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
        bsp_InitLed();        /* 初始化LED */    
    }

      MPU配置和Cache配置:

    数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区。

    /*
    *********************************************************************************************************
    *    函 数 名: MPU_Config
    *    功能说明: 配置MPU
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void MPU_Config( void )
    {
        MPU_Region_InitTypeDef MPU_InitStruct;
    
        /* 禁止 MPU */
        HAL_MPU_Disable();
    
        /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x24000000;
        MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
    
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
        
        
        /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
        MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
        MPU_InitStruct.BaseAddress      = 0x60000000;
        MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;    
        MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
        MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
        MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;    
        MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
        MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
        MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
        MPU_InitStruct.SubRegionDisable = 0x00;
        MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
        
        HAL_MPU_ConfigRegion(&MPU_InitStruct);
    
        /*使能 MPU */
        HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
    }
    
    /*
    *********************************************************************************************************
    *    函 数 名: CPU_CACHE_Enable
    *    功能说明: 使能L1 Cache
    *    形    参: 无
    *    返 回 值: 无
    *********************************************************************************************************
    */
    static void CPU_CACHE_Enable(void)
    {
        /* 使能 I-Cache */
        SCB_EnableICache();
    
        /* 使能 D-Cache */
        SCB_EnableDCache();
    }

      主功能:

    主程序实现如下操作:

    •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
    •   按下按键K1,打印原始波形数据和滤波后的波形数据。
    /*
    *********************************************************************************************************
    *    函 数 名: main
    *    功能说明: c程序入口
    *    形    参: 无
    *    返 回 值: 错误代码(无需处理)
    *********************************************************************************************************
    */
    int main(void)
    {
        uint8_t ucKeyCode;        /* 按键代码 */
        uint16_t i;
    
        
        bsp_Init();        /* 硬件初始化 */
        PrintfLogo();    /* 打印例程信息到串口1 */
    
        PrintfHelp();    /* 打印操作提示信息 */
        
        for(i=0; i<TEST_LENGTH_SAMPLES; i++)
        {
            /* 50Hz正弦波+200Hz正弦波,采样率1KHz */
            testInput_f32_50Hz_200Hz[i] = arm_sin_f32(2*3.1415926f*50*i/1000) + 
    arm_sin_f32(2*3.1415926f*200*i/1000);
        }
        
    
        bsp_StartAutoTimer(0, 100);    /* 启动1个100ms的自动重装的定时器 */
    
        /* 进入主程序循环体 */
        while (1)
        {
            bsp_Idle();        /* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
            
    
            if (bsp_CheckTimer(0))    /* 判断定时器超时时间 */
            {
                /* 每隔100ms 进来一次 */
                bsp_LedToggle(2);    /* 翻转LED的状态 */
            }
            
            ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
            if (ucKeyCode != KEY_NONE)
            {
                switch (ucKeyCode)
                {
                    case KEY_DOWN_K1:            /* K1键按下 */
                        arm_iir_f32_bp();
                        break;
                    
        
                    default:
                        /* 其它的键值不处理 */
                        break;
                }
            }
    
        }
    }

    46.8 总结

    本章节主要讲解了IIR滤波器的带通实现,同时一定要注意IIR滤波器的群延迟问题,详见本教程的第41章。

    展开全文
  • 第46章 STM32F429的IIR带通滤波器实现(支持逐个数据的实时滤波) 本章节讲解IIR带通滤波器实现。 目录 46.1 初学者重要提示 46.2 带通滤波器介绍 46.3 IIR滤波器介绍 46.4 Matlab工具箱filterDesigner生成IIR...
  • 6. IIR滤波器主要是设计规格化的、频率特性为分段常数的标准低通、高通、带通、带阻、全通滤波器,而FIR滤波器则要灵活得多,例如频率抽样设计法,可适应各种幅度特性的要求,因而FIR滤波器则要灵活得多,例如频率器...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 444
精华内容 177
关键字:

带通滤波器级联