问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 42 人浏览分享

开启左侧

第七章FIR 滤波器实验

[复制链接]
42 0
       本章将带您完成第一个真正意义上的“标准”滤波器设计。我们将面对一个经典的信号处理问题:如何从包含多个频率成分的混合信号中,精确地提取出我们需要的部分?为此,我们将设计并实现一个有限长冲激响应(FIR)带通滤波器。项目首先使用DDS生成5MHz、10MHz和20MHz的三种正弦波并将其叠加,形成一个复杂的“噪音”信号。我们的目标,是让滤波器像一个精准的频率“筛子”,仅让10MHz的成分通过,而滤除其他所有无关频率。
       通过本章,您将系统地学习FIR滤波器的核心原理、如何在MATLAB中利用专业工具(如fdatool/filterDesigner)设计并导出满足指标的滤波器系数,以及如何在FPGA中高效地调用Xilinx官方IP核来实现它。最后,我们将同时从时域和频域两个维度,严谨地验证滤波器的性能,亲眼见证其“去伪存真”的强大能力。
1 项目目标
       用DDS产生三个采样率为100MHz,频率分别为5MHz、10MHz和20MHz的正弦波,然后将它们叠加混合,形成一个混乱的噪音。对于这个噪音,我们需要提取出频率为10MHz的成分,过滤掉其他我们不关注的成分。于是,我们通过一个FIR带通滤波器来实现这个功能,仅保留频率为10MHz左右的成分。


2 FIR 滤波器简介
FIR滤波器,全称为有限长单位冲激响应滤波器,是数字信号处理中最基本、最常见的滤波器之一。
       数字滤波器:它的输入和输出信号都是离散的数字信号。
       有限长:这是它的核心特征。当您给FIR滤波器一个非常短暂且强烈的输入信号(称为“单位脉冲”)时,它产生的响应(输出)只会在有限的时间内存在,而不是无限持续。
       线性、非递归:FIR滤波器的当前输出仅由当前的输入和过去的输入决定,不会将过去的输出反馈回来用于计算当前输出。这使得它在行为上非常稳定和可预测。
       FIR滤波器的工作原理可以概括为 “加权滑动平均”。
       想象一个长度为 N 的窗口(也称为滤波器的阶数),里面存放着 N 个预先设定好的系数(h[0], h[1], ..., h[N-1]),这些系数决定了滤波器的特性(如低通、高通等)。
       计算过程如下:
              输入信号 x[n] 依次进入这个窗口。
              在每一个时刻 n,将窗口内的 N 个最新的输入样本(从 x[n] 到 x[n-(N-1)])分别与对应的 N 个滤波器系数相乘。
              将所有乘积结果相加,就得到了当前时刻的输出 y[n]。
       这个过程可以用一个关键的数学运算来描述:卷积。
              差分方程(核心公式):
                     y[n] = h[0]*x[n] + h[1]*x[n-1] + h[2]*x[n-2] + ... + h[N-1]*x[n-(N-1)]
                     其中:
                     y[n] 是当前输出。
                     x[n] 是当前输入。
                     x[n-1], x[n-2] ... 是过去的输入。
                     h[0], h[1] ... h[N-1] 是滤波器系数(也称为抽头权重),它们是滤波器的“灵魂”。

3 MATLAB 设计滤波器系数
打开MATLAB在命令行窗口输入的FDATOOL(新版改用filterDesigner),打开滤波器设计工具。如图:
image.jpg
由于我们需要过滤的信号是有三种5M、10M及20M频率混合的,现在只保留10M,故可以设计一个带通滤波器仅保留10M的部分,以下为参考设计。
image.jpg
按照这个配置好后,要导出.coe文件用于配置FIR IP,步骤如下:
image.jpg
image.jpg

4 FPGA实现
这里实现FIR滤波器使用了官方IP,这里简要说明下如何配置这个IP,步骤如下:
image.jpg
Select source 选择COE File,然后在Coefficient File中导入MATLAB生成的.coe文件。
image.jpg
然后时钟和输出信号的采样率按实际情况配置,这个实验是100M故设置100.
image.jpg
这个界面默认就行。
image.jpg
默认即可。
image.jpg
默认即可。
image.jpg
配置完这个IP之后,其他的如DDS等简单的IP就不过多的赘述,我们这边放上源码:
Top.v
`timescale 1ns / 1ps

module top (
    input                               I_sysclk_p                 ,
    input                               I_sysclk_n                 ,
    input                               I_rst_n                    ,
    output                              O_led                       
);
/*******************************************************************\
                            变量定义
\*******************************************************************/
//clock
    wire                                clk_100m                    ;
    wire                                locked                      ;//后续用于高复位,待优化

//dds
    wire    signed     [  15: 0]        dds_data_5m                 ;
    wire                                dds_data_5m_valid           ;
    wire                                phase_tvalid_5m             ;
    wire               [  31: 0]        phase_tdata_5m              ;
   
    wire    signed     [  15: 0]        dds_data_10m                ;
    wire                                dds_data_10m_valid          ;
    wire                                phase_tvalid_10m            ;
    wire               [  31: 0]        phase_tdata_10m             ;

    wire    signed     [  15: 0]        dds_data_20m                ;
    wire                                dds_data_20m_valid          ;
    wire                                phase_tvalid_20m            ;
    wire               [  31: 0]        phase_tdata_20m             ;

//信号叠加
    reg     signed     [  16: 0]        mix_data_add1               ;
    reg     signed     [  16: 0]        mix_data_add                ;
    wire    signed     [  15: 0]        mix_data                    ;
    wire                                mix_data_add_valid          ;
    reg                                 mix_data_add_valid_reg      ;
    reg                                 mix_data_valid              ;

//fir
    wire                                s_axis_data_tready          ;
    wire                                fir_data_out_valid          ;
    wire    signed     [  15: 0]        fir_data_out                ;

/*******************************************************************\
                            时钟管理模块
\*******************************************************************/
  clk_wiz_1 clock_and_reset
   (
    .clk_out1(clk_100m),   
    .locked(locked),
    .clk_in1_p(I_sysclk_p),   
    .clk_in1_n(I_sysclk_n)
    );   

/*******************************************************************\
                            DDS模块
\*******************************************************************/
    //采样频率为100MHz,频率为5MHz的单音信号
    dds_16_16_5m dds_16_5m (
      .aclk(clk_100m),                                // input wire aclk
      .m_axis_data_tvalid(dds_data_5m_valid),    // output wire m_axis_data_tvalid
      .m_axis_data_tdata(dds_data_5m),      // output wire [15 : 0] m_axis_data_tdata
      .m_axis_phase_tvalid(phase_tvalid_5m),  // output wire m_axis_phase_tvalid
      .m_axis_phase_tdata(phase_tdata_5m)    // output wire [31 : 0] m_axis_phase_tdata
    );

    //采样频率为100MHz,频率为10MHz的单音信号
    dds_16_16_10m dds_16_10m (
      .aclk(clk_100m),                                // input wire aclk
      .m_axis_data_tvalid(dds_data_10m_valid),    // output wire m_axis_data_tvalid
      .m_axis_data_tdata(dds_data_10m),      // output wire [15 : 0] m_axis_data_tdata
      .m_axis_phase_tvalid(phase_tvalid_10m),  // output wire m_axis_phase_tvalid
      .m_axis_phase_tdata(phase_tdata_10m)    // output wire [31 : 0] m_axis_phase_tdata
    );

    //采样频率为100MHz,频率为20MHz的单音信号
    dds_16_16_20m dds_16_20m (
      .aclk(clk_100m),                                // input wire aclk
      .m_axis_data_tvalid(dds_data_20m_valid),    // output wire m_axis_data_tvalid
      .m_axis_data_tdata(dds_data_20m),      // output wire [15 : 0] m_axis_data_tdata
      .m_axis_phase_tvalid(phase_tvalid_20m),  // output wire m_axis_phase_tvalid
      .m_axis_phase_tdata(phase_tdata_20m)    // output wire [31 : 0] m_axis_phase_tdata
    );

/*******************************************************************\
                            信号叠加模块
\*******************************************************************/
    //叠加信号,由三种单音信号叠加而成
    always @(posedge clk_100m or negedge I_rst_n)  begin                                       
        if(!I_rst_n) begin
            mix_data_add1 <= 'b0;
            mix_data_add  <= 'b0;      
        end else begin                                                         
            mix_data_add1 <= dds_data_5m + dds_data_10m;
            mix_data_add  <= mix_data_add1[16:1] + dds_data_20m;                     
        end                     
    end                                          

    assign  mix_data = mix_data_add[16:1];

    //叠加信号有效
    assign mix_data_add_valid = dds_data_5m_valid & dds_data_10m_valid & dds_data_20m_valid;

    always @(posedge clk_100m or negedge I_rst_n)  begin                                       
        if(!I_rst_n) begin
            mix_data_add_valid_reg <= 'b0;
            mix_data_valid <= 'b0;      
        end else begin                                                         
            mix_data_add_valid_reg <= mix_data_add_valid;  
            mix_data_valid <= mix_data_add_valid_reg;                  
        end                     
    end

/*******************************************************************\
                            FIR滤波模块
\*******************************************************************/
    assign O_led = fir_data_out_valid;

    //带通滤波器,保留频率为10MHz的单音信号
    fir_compiler_0 fir_bpf (
      .aclk(clk_100m),                              // input wire aclk
      .s_axis_data_tvalid(mix_data_valid),  // input wire s_axis_data_tvalid
      .s_axis_data_tready(s_axis_data_tready),  // output wire s_axis_data_tready
      .s_axis_data_tdata(mix_data),    // input wire [15 : 0] s_axis_data_tdata
      .m_axis_data_tvalid(fir_data_out_valid),  // output wire m_axis_data_tvalid
      .m_axis_data_tdata(fir_data_out)    // output wire [39 : 0] m_axis_data_tdata
    );

/*******************************************************************\
                            ILA调试模块
\*******************************************************************/

    ila_0 debug(
        .clk(clk_100m), // input wire clk

        .probe0(mix_data), // input wire [15:0]  probe0  
        .probe1(fir_data_out) // input wire [15:0]  probe1
    );



endmodule

仿真代码如下:
Tb_top.v

`timescale 1ns / 1ps

module tb_top();

  reg I_sysclk_p;
  reg I_rst_n;
  wire  O_led;

  initial begin
    I_sysclk_p = 1;
    I_rst_n = 0;
    #1000 I_rst_n = 1;

  end

always #5  I_sysclk_p = ! I_sysclk_p ;

  top  top_inst (
    .I_sysclk_p(I_sysclk_p),
    .I_sysclk_n(~I_sysclk_p),
    .I_rst_n(I_rst_n),
    .O_led(O_led)
  );

endmodule



5 实验结果分析
5.1仿真结果
       如下所示,可以看到红色部分的波形(mix_data)为叠加混合的噪音,经过滤波后输出粉红色的波形,与DDS生成的频率为10MHz的正弦波(橙色波形)基本一致。也就是说,从时域上看,我们的实验成功了。
image.jpg
5.2 WaveVision5分析
       为了严谨,我们还需要频域上验证我们的实验结果是否正确,于是我们上板,通过ila导出mix_data和fir_data_out这两个数据进行分析。
ILA抓取波形如下,可以看到与仿真结果一致。
image.jpg
通过TI公司的频谱分析软件WaveVision5分析如下:
mix_data时域分析,时域波形与仿真结果和ILA一致。
image.jpg
mix_data频域分析,频域上看有频率分别为5MHz、10MHz和20MHz的成分以及它们的谐波。
image.jpg
fir_data_out时域分析,时域波形与仿真结果和ILA一致。
image.jpg
fir_data_out频域分析,频域上看基本仅有频率为10MHz的成分以及它的谐波。
image.jpg
从上面的结果来看,我们的工程成功的实现了目标。

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

10

粉丝

150

主题
精彩推荐
热门资讯
    网友晒图
      图文推荐
        
        • 微信公众平台

        • 扫描访问手机版