1nnocent 发表于 2024-11-18 11:13

FPGA设计一个FIR数字滤波器(vivado+MATLAB)

<div class='showpostmsg'> 本帖最后由 1nnocent 于 2024-11-23 11:24 编辑

<p><span style="font-size:16px;"><span style="color:#1abc9c;"><strong>要求</strong></span></span></p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;设计一个带通滤波器,并验证其功能。</p>

<p><span style="font-size:16px;"><span style="color:#1abc9c;"><strong>1、使用MATLAB设计滤波器系数</strong></span></span></p>

<p>&nbsp; &nbsp; MATLAB首页找到APP后找到滤波器设计工具并打开,使用该工具可以生成数字滤波器的系数后续用于FPGA配置FIR IP核。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 打开滤波器设计工具后即可输入相关参数并设计需要的滤波器,本次设计一个带通滤波器,所以滤波器响应类型选择带通;设计方案选择FIR(有限冲激响应);滤波器阶数这里选择最小阶,也可以自己指定阶数,阶数越大滤波器的滤波效果越好但越耗费FPGA资源,阶数可以根据实际情况进行取舍;密度因子默认20;频率设定,本次设计的采样率设置为10MHz,滤波器的频率特性设置可以按照图示进行填写,图片指示的意义很清楚,Fstop1为下限阻带截止频率,这里设置为50kHz,Fpass1为下限通带截止频率,这里设置为100kHz,Fpass2为上限通道截止频率,这里设置为400kHz,Fstop2为上限阻带截止频率,这里设置为450kHz(Fpass1-Fstop1和Fstop2-Fpass2为过渡带宽度,本次设计的过渡带宽度为50kHz;Fpass2-Fpass1为通带宽度,本次设计的通带宽度为400kHz;其余为阻带);幅值设定,其中Astop为阻带衰减的幅度值,本次设计阻带衰减50dB,Apass为通带的纹波,这里限制通带纹波不超过0.1dB。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 设置好以上参数后点击滤波器设计,等待片刻即可设计好所需滤波器,从左侧窗口当前滤波器信息中可以发现符合本次设计需求的最小阶数为483阶。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 点击工具栏&nbsp;&nbsp;可以查看滤波器幅值响应、相位响应、零极点等。</p>

<p>&nbsp; &nbsp; 点击工具栏文件--导出,即可导出设计的滤波器系数。导出后可以在工作区中看到滤波器系数的变量Num。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 以下为本次导出的系数,一共484个。</p>

<p>&nbsp; &nbsp; &nbsp; 滤波器系数在FPGA中导入时每个系数之间需要逗号隔开,所以这里将系数保存到txt并使用逗号隔开,注意最后一个数的逗号需要删除。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 生成后的系数删除最后的逗号。</p>

<p> &nbsp;</p>

<p><strong><span style="color:#1abc9c;"><span style="font-size:16px;">2、FPGA中FIR的实现</span></span></strong></p>

<p>&nbsp; 这里省略FPGA工程建立过程,新建工程后点击Create Block Design。</p>

<p> &nbsp;</p>

<p>&nbsp;&nbsp;&nbsp;&nbsp;添加FIR IP核。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 配置FIR IP核,Filter Option中Select Source选择Vector,Coefficient Vector中粘贴之前MATLAB生成的系数,其余保持默认。左边Freq.Response窗口中可以查看频率响应曲线。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; Channel Specification中主要配置采样率和工作时钟,input Sampling Frequency(MHz)配置10MHz采样率,后续DDS工作时钟需要和采样率保持一致;Clock Frequency(MHz)配置200MHz后续FIR IP核的工作时钟给200MHz。</p>

<p>&nbsp; &nbsp; &nbsp; Implement配置,Coefficient With可以根据需要进行配置,本次设计时配置成24,配置成24时通过查看左边Freq.Response窗口可以发现两条红色和蓝色曲线重合较接近理想曲线Ideal,所以这里配置成24,也可以根据需要进行配置。</p>

<p>&nbsp; &nbsp; &nbsp; Interface这里配置如下:</p>

<p>&nbsp; &nbsp; &nbsp;FIR配置完后再增加一个fifo,配置如下:</p>

<p></p>

<p>&nbsp; &nbsp; 配置完后将FIR和fifo相连并引出接口:</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 最后右击block design先generate Output ...再Create HDL...。</p>

<p></p>

<p>&nbsp;</p>

<p><strong><span style="font-size:16px;"><span style="color:#1abc9c;">3、FPGA中DDS的实现</span></span></strong></p>

<p>&nbsp; &nbsp; 这里DDS用于产生FIR的输入信号。同样点击Create Block Design,添加DDS IP核。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; Configuration配置System Clock(MHz)为10MHz即可,其余保持默认配置。</p>

<p>&nbsp; &nbsp; &nbsp; Detailed Implementation配置如下:</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 最后输出频率配置成0.15MHz即150kHz,也可以根据需要进行配置。</p>

<p>&nbsp; &nbsp; &nbsp; 按照上述配置再生成50kHz、350kHz、450kHz频率的DDS。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 生成完DDS后再生成一个fifo。该fifo用于跨时钟域,将DDS产生的10MHz时钟域的信号转到200MHz时钟域输入FIR进行滤波。fifo配置如下,深度16,数据位宽16bit。</p>

<p> &nbsp;</p>

<p>&nbsp; &nbsp; 最后将生成的IP核按下图连线,该dds用于测试fir滤波器。可以外部可以将DDS生成的350kHz和150kHz进行叠加后再输入到fifo中,最后经过跨时钟域后从Multi_wave_M_AXIS输出到FIR进行滤波,叠加后的波形存在和频(500kHz)、差频(200kHz),经过滤波器后只剩下差频200kHz,如果滤波器输出200kHz正弦波则说明设计符合预期。也可以将单频信号(50kHz/150kHz/350kHz/450kHz)输入滤波器查看滤波器输出幅度情况。</p>

<p> &nbsp;</p>

<p><strong><span style="font-size:16px;"><span style="color:#1abc9c;">4、top模块编写</span></span></strong></p>

<p>&nbsp; &nbsp; &nbsp;顶层模块例化两个block_design&nbsp;,dds产生50kHz、150kHz、350kHz和450kHz的正弦信号,外部将dds生成的其中两个信号做乘法后输入到dds的fifo接口中,使相乘的信号从10Mhz时钟域到200Mhz时钟域,最后输入到FIR中进行滤波。如果需要测试FIR单频信号的滤波器则可以将DDS输出的其中一个信号与常数相乘后再输入到FIR中进行测试。另外top模块中还需例化一个pll产生10MHz时钟用于DDS产生信号,以及200MHz时钟用于FIR。</p>

<pre>
<code>
module fir_top(
    input       pl_ref_clk_100m_p,
    input       pl_ref_clk_100m_n
);
    reg          cnt;
    wire                clk_10m,clk_200m;
    wire signed    M_AXIS_50k_tdata;
    wire                M_AXIS_50k_tvalid,M_AXIS_50k_tready;
    wire signed    M_AXIS_150k_tdata;
    wire                M_AXIS_150k_tvalid,M_AXIS_150k_tready;
    wire signed    M_AXIS_350k_tdata;
    wire                M_AXIS_350k_tvalid,M_AXIS_350k_tready;
    wire signed    M_AXIS_450k_tdata;
    wire                M_AXIS_450k_tvalid,M_AXIS_450k_tready;
    wire signed Multi_wave_S_AXIS_tdata;
    wire                Multi_wave_S_AXIS_tvalid,Multi_wave_S_AXIS_tready;
    wire signed Multi_wave_M_AXIS_tdata;
    wire                Multi_wave_M_AXIS_tvalid,Multi_wave_M_AXIS_tready;
    wire signed FIR_S_AXIS_tdata;
    wire                FIR_S_AXIS_tvalid,FIR_S_AXIS_tready;
    wire signed FIR_M_AXIS_tdata;
    wire                FIR_M_AXIS_tvalid,FIR_M_AXIS_tready;
    assign rst_n = locked;
    // Multi_wave_S_AXIS
    assign Multi_wave_S_AXIS_tdata= M_AXIS_450k_tdata   *   8'hff/*M_AXIS_350k_tdata    */;
    assign Multi_wave_S_AXIS_tvalid = M_AXIS_450k_tvalid&amp;   1/*M_AXIS_350k_tvalid   */;
    assign M_AXIS_50k_tready      = Multi_wave_S_AXIS_tready;
    assign M_AXIS_150k_tready       = Multi_wave_S_AXIS_tready;
    assign M_AXIS_350k_tready       = Multi_wave_S_AXIS_tready;
    assign M_AXIS_450k_tready       = Multi_wave_S_AXIS_tready;
    // Multi_wave_M_AXIS
    assign FIR_S_AXIS_tvalid      = Multi_wave_M_AXIS_tvalid;
    assign FIR_S_AXIS_tdata         = Multi_wave_M_AXIS_tdata;
    assign Multi_wave_M_AXIS_tready= FIR_S_AXIS_tready;
   
    assign FIR_M_AXIS_tready      = (cnt == 'd19) &amp;&amp; Multi_wave_M_AXIS_tvalid;
dds_design_wrapper dds_design(
    .M_AXIS_150k_tdata      (M_AXIS_150k_tdata      ),
    .M_AXIS_150k_tready   (M_AXIS_150k_tready   ),
    .M_AXIS_150k_tvalid   (M_AXIS_150k_tvalid   ),
    .M_AXIS_350k_tdata      (M_AXIS_350k_tdata      ),
    .M_AXIS_350k_tready   (M_AXIS_350k_tready   ),
    .M_AXIS_350k_tvalid   (M_AXIS_350k_tvalid   ),
    .M_AXIS_450k_tdata      (M_AXIS_450k_tdata      ),
    .M_AXIS_450k_tready   (M_AXIS_450k_tready   ),
    .M_AXIS_450k_tvalid   (M_AXIS_450k_tvalid   ),
    .M_AXIS_50k_tdata       (M_AXIS_50k_tdata       ),
    .M_AXIS_50k_tready      (M_AXIS_50k_tready      ),
    .M_AXIS_50k_tvalid      (M_AXIS_50k_tvalid      ),
    .Multi_wave_M_AXIS_tdata (Multi_wave_M_AXIS_tdata ),
    .Multi_wave_M_AXIS_tready(Multi_wave_M_AXIS_tready),
    .Multi_wave_M_AXIS_tvalid(Multi_wave_M_AXIS_tvalid),
    .Multi_wave_S_AXIS_tdata (Multi_wave_S_AXIS_tdata ),
    .Multi_wave_S_AXIS_tready(Multi_wave_S_AXIS_tready),
    .Multi_wave_S_AXIS_tvalid(Multi_wave_S_AXIS_tvalid),
    .aresetn                (rst_n                  ),
    .clk_10m                (clk_10m                ),
    .clk_200m               (clk_200m               )
);
    always@(posedge clk_200m or negedge rst_n)begin
      if(!rst_n)begin
            cnt &lt;= 'd0;
      end
      else begin
            cnt &lt;= (cnt == 'd19)? 'd0 : (cnt + 1'b1);
      end
    end
bandpass_fir_wrapper bandpass_fir(
    .FIR_M_AXIS_tdata   (FIR_M_AXIS_tdata   ),
    .FIR_M_AXIS_tready(FIR_M_AXIS_tready),
    .FIR_M_AXIS_tvalid(FIR_M_AXIS_tvalid),
    .FIR_S_AXIS_tdata   (FIR_S_AXIS_tdata   ),
    .FIR_S_AXIS_tready(FIR_S_AXIS_tready),
    .FIR_S_AXIS_tvalid(FIR_S_AXIS_tvalid),
    .aresetn            (rst_n            ),
    .clk_200m         (clk_200m         )
);
clk_wiz_0 pll(
    .clk_10m(clk_10m),
    .clk_200m(clk_200m),   // output clk_200m
    .reset(1'b0), // input reset
    .locked(locked),       // output locked
    .clk_100m_in(clk_100m)      // input clk_100m_in
);
IBUFDS clk_100m_ibufds(
    .O        (clk_100m),
    .I        (pl_ref_clk_100m_p),
    .IB        (pl_ref_clk_100m_n)
);
endmodule
</code></pre>

<p><strong><span style="font-size:16px;"><span style="color:#1abc9c;">5、功能仿真</span></span></strong></p>

<p>&nbsp;</p>

<p>&nbsp; &nbsp; &nbsp;DDS产生的四个信号如下:</p>

<p id="20241114165641-6daeq9s" updated="20241114165954">50kHz信号,一个时钟周期的时间为102.31-82.31=20us,刚好为50kHz。</p>

<p id="20241114165638-fps5sb1" updated="20241114165638"> &nbsp;150kHz,一个时钟周期的时间为82.51-75.91=6.6us,频率约为151515Hz。</p>

<p updated="20241114165638"> &nbsp;350kHz,一个是时钟周期的时间为71.21-68.31=2.9us,频率约为344827Hz。</p>

<p updated="20241114165638"> &nbsp;450kHz,一个时钟周期的时间为91.51-89.31=2.2us,频率约为454545Hz。</p>

<p updated="20241114165638">&nbsp; &nbsp; &nbsp; 将150kHz正弦和350kHz正弦叠加后输入到FIR,输入信号代码修改如下(配图中的频率写错了,实际是150kHz和350kHz相叠加,图片的是450kHz和350kHz,图片上的组合也不影响测试FIR,因为两个信号的和频以及差频为800kHz和100kHz,经过滤波器后100kHz信号正常输出而800kHz信号则被滤除):</p>

<p updated="20241114165638"> &nbsp;</p>

<p id="20241116115530-6t1ao6s" updated="20241116115530">&nbsp;&nbsp;&nbsp;&nbsp;两个光标之间的间隔为112.975-102.975=10us,每个时钟周期为5us,所以滤波器输出的频率为200kHz。由于输入的信号为150kHz正弦波叠加350kHz的正弦波,叠加后的波形存在和频500kHz和差频200kHz,由于500kHz在滤波器通频带外,所以500kHz的信号会被滤除,经过滤波器后只剩下200kHz的正弦波。所以仿真结果符合滤波器特性。仿真波形如下图,其中FIR_M_AXIS_tdata信号为FIR滤波输出信号。</p>

<p updated="20241116115530">&nbsp; &nbsp; &nbsp; 将50kHz正弦信号输入FIR,输入信号代码修改如下:50kHz信号与常数8&lsquo;hff叠加后输入到FIR。</p>

<p updated="20241116115530"> &nbsp;</p>

<p updated="20241116115530">&nbsp; &nbsp; 由于50kHz在滤波器带外,所以经过滤波器后幅度应该被衰减。仿真波形如下图,FIR输出信号FIR_M_AXIS_tdata被衰减,符合预期。</p>

<p updated="20241116115530"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将150kHz正弦信号输入FIR,输入信号代码修改如下:150kHz信号与常数8&lsquo;hff叠加后输入到FIR。</p>

<p updated="20241116115530"> &nbsp;</p>

<p updated="20241116115530">&nbsp;&nbsp;&nbsp;&nbsp;由于150kHz在滤波器带内,所以经过滤波器后幅度不变。仿真波形如下图,FIR输出信号FIR_M_AXIS_tdata幅度正常,符合预期。</p>

<p updated="20241116115530"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将350kHz正弦信号输入FIR,输入信号代码修改如下:350kHz信号与常数8&lsquo;hff叠加后输入到FIR。</p>

<p updated="20241116115530"> &nbsp;</p>

<p updated="20241116115530">&nbsp;&nbsp;&nbsp;&nbsp;由于350kHz在滤波器带内,所以经过滤波器后幅度不变。仿真波形如下图,FIR输出信号FIR_M_AXIS_tdata幅度正常,符合预期。</p>

<p updated="20241116115530"> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;将450kHz正弦信号输入FIR,输入信号代码修改如下:450kHz信号与常数8&lsquo;hff叠加后输入到FIR。</p>

<p updated="20241116115530"> &nbsp;</p>

<p updated="20241116115530">&nbsp;&nbsp;&nbsp;&nbsp;由于450kHz在滤波器带外,所以经过滤波器后幅度应该被衰减。仿真波形如下图,FIR输出信号FIR_M_AXIS_tdata被衰减,符合预期。</p>

<p updated="20241116115530">&nbsp;</p>

<p><strong><span style="font-size:16px;"><span style="color:#1abc9c;">6、结论</span></span></strong></p>

<p><strong><span style="font-size:16px;"><span style="color:#1abc9c;">&nbsp;&nbsp;&nbsp;&nbsp;</span></span></strong>&nbsp;从仿真结果可知输入信号不管是单频信号还是叠加后的双频信号,结果都符合预期。</p>

<p>工程源码下载地址:</p>

<div><a href="https://download.eeworld.com.cn/detail/1nnocent/634988" target="_self">FPGA实现FIR滤波器</a></div>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>

okhxyyo 发表于 2024-11-18 11:42

<p>酷!!!!!给你一个超大的赞!!</p>

1nnocent 发表于 2024-11-18 14:24

okhxyyo 发表于 2024-11-18 11:42
酷!!!!!给你一个超大的赞!!

<p><img height="48" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/congra.gif" width="48" /></p>

jpwu10 发表于 2024-11-19 06:14

<p>赞,讲清楚了FIR的设计。</p>

uestc_fpgaer 发表于 2024-11-19 19:57

<p>配置和仿真给的比较充分,空闲了自己搭建一个,感谢分享</p>

1nnocent 发表于 2024-11-20 11:00

uestc_fpgaer 发表于 2024-11-19 19:57
配置和仿真给的比较充分,空闲了自己搭建一个,感谢分享

<p>搭一个也挺快的</p>

<p>。</p>
页: [1]
查看完整版本: FPGA设计一个FIR数字滤波器(vivado+MATLAB)