一直想找一个简单、清晰、明了的fir滤波器的设计,终于找到了一个可以应用的,和大家分享一下,有助于FPGA新手入门。

1.说道fir滤波器,滤波系数肯定是最重要的,因为后面程序中涉及到滤波系数问题,所以先来介绍,此处使用matlab来辅助求出。

①打开matlab中的start,toolbox,filter design,filter design & Analysis Tool,具体位置见下图。

②选择想要涉及的滤波器类型,本次以8阶fir滤波器为例。

设计参数:低通fir滤波器,采样精度是根据自己的输入数据来的,本例为25MHz,通过频率2MHz,截止频率8MHz,可以在specify order处选择几阶滤波器。


③把滤波器数据导出,选择export,在随后弹出的框中再次点击Export(本步骤可以改变数据的变量名),就可以看到命名为Num的滤波器系数出现在目录里。

④在matlab框中输入指令Num=Num'

可以看到如下结果,这个就是滤波器的系数了,新建一个txt文件,命名如图,把滤波器系数复制进去。

⑤编写matlab程序,进行系数量化。

运行下面一段程序,生成的COF就是最后的量化数据,记录这组数据。

clc;
clear all ;
load COFFICIENT.dat;%加载系数
a1=COFFICIENT(1:1:length(COFFICIENT));
width = 16;%数据宽度8位
% 量化滤波器系数
COF  = round(a1 .* (2^(width-1) - 1));%量化正弦波形数据并取整

2.在quartusII中建立一个工程,新建一个fir_filter模块,把我们计算出来的滤波器系数写在程序里面


整体程序如下:

`timescale 1 ns / 1 ns

module fir_filter
               (
                i_fpga_clk ,
                i_rst_n    ,
                i_filter_in,
                o_filter_out
                );

input                   i_fpga_clk  ; //25MHz
  input                   i_rst_n     ;
  input   signed      [7:0] i_filter_in ; //数据速率25Mh
  output  signed      [7:0] o_filter_out; //滤波输出

//==============================================================
//8阶滤波器系数,共9个系数,系数对称
//==============================================================
  wire signed[15:0] coeff1 = 16'd239 ;
  wire signed[15:0] coeff2 = 16'd1507;
  wire signed[15:0] coeff3 = 16'd4397;
  wire signed[15:0] coeff4 = 16'd7880;
  wire signed[15:0] coeff5 = 16'd9493;

//===============================================================
//    延时链
//===============================================================
reg signed [7:0] delay_pipeline1 ;
reg signed [7:0] delay_pipeline2 ;
reg signed [7:0] delay_pipeline3 ;
reg signed [7:0] delay_pipeline4 ;
reg signed [7:0] delay_pipeline5 ;
reg signed [7:0] delay_pipeline6 ;
reg signed [7:0] delay_pipeline7 ;
reg signed [7:0] delay_pipeline8 ;

always@(posedge i_fpga_clk or negedge i_rst_n)
       if(!i_rst_n)
                begin
                    delay_pipeline1 <= 8'b0 ;
                     delay_pipeline2 <= 8'b0 ;
                     delay_pipeline3 <= 8'b0 ;
                     delay_pipeline4 <= 8'b0 ;
                     delay_pipeline5 <= 8'b0 ;
                     delay_pipeline6 <= 8'b0 ;
                     delay_pipeline7 <= 8'b0 ;
                     delay_pipeline8 <= 8'b0 ;
                end
       else
                begin
                    delay_pipeline1 <= i_filter_in     ;
                     delay_pipeline2 <= delay_pipeline1 ;
                     delay_pipeline3 <= delay_pipeline2 ;
                     delay_pipeline4 <= delay_pipeline3 ;
                     delay_pipeline5 <= delay_pipeline4 ;
                     delay_pipeline6 <= delay_pipeline5 ;
                     delay_pipeline7 <= delay_pipeline6 ;
                     delay_pipeline8 <= delay_pipeline7 ;
                end
     
//================================================================
//加法,对称结构,减少乘法器的数目
//================================================================
reg signed [8:0] add_data1 ;
reg signed [8:0] add_data2 ;
reg signed [8:0] add_data3 ;
reg signed [8:0] add_data4 ;
reg signed [8:0] add_data5 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(0)+x(8)
       if(!i_rst_n)                                   
           add_data1 <= 9'b0 ;
       else
           add_data1 <= i_filter_in + delay_pipeline8 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(1)+x(7) 
       if(!i_rst_n)                                        
           add_data2 <= 9'b0 ;                             
       else                                                
           add_data2 <= delay_pipeline1 + delay_pipeline7 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(2)+x(6) 
       if(!i_rst_n)                                        
           add_data3 <= 9'b0 ;                             
       else                                                
           add_data3 <= delay_pipeline2 + delay_pipeline6 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(3)+x(5) 
       if(!i_rst_n)                                        
           add_data4 <= 9'b0 ;                             
       else                                                
           add_data4 <= delay_pipeline3 + delay_pipeline5 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(4) 
       if(!i_rst_n)                                        
           add_data5 <= 9'b0 ;                             
       else                                                
           add_data5 <= {delay_pipeline4[7],delay_pipeline4} ;

//===================================================================
//乘法器
//====================================================================
reg signed [24:0] multi_data1 ;
reg signed [24:0] multi_data2 ;
reg signed [24:0] multi_data3 ;
reg signed [24:0] multi_data4 ;
reg signed [24:0] multi_data5 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //(x(0)+x(8))*h(0)
       if(!i_rst_n)                                   
           multi_data1 <= 24'b0 ;
       else
           multi_data1 <= add_data1*coeff1 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //(x(1)+x(7))*h(1)
       if(!i_rst_n)                                   
           multi_data2 <= 24'b0 ;
       else
           multi_data2 <= add_data2*coeff2 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //(x(2)+x(6))*h(2)
       if(!i_rst_n)                                   
           multi_data3 <= 24'b0 ;
       else
           multi_data3 <= add_data3*coeff3 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //(x(0)+x(8))*h(3)
       if(!i_rst_n)                                   
           multi_data4 <= 24'b0 ;
       else
           multi_data4 <= add_data4*coeff4 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(4)*h(4)
       if(!i_rst_n)                                   
           multi_data5 <= 24'b0 ;
       else
           multi_data5 <= add_data5*coeff5 ;

//========================================================================
//流水线累加
//========================================================================
reg signed[25:0] add_level1_1;//1级
reg signed[25:0] add_level1_2;//1级
reg signed[25:0] add_level1_3;//1级

always@(posedge i_fpga_clk or negedge i_rst_n) //(x(0)+x(8))*h(0)+(x(1)+x(7))*h(1)
       if(!i_rst_n)                                   
           add_level1_1 <= 26'b0 ;
       else
           add_level1_1 <= multi_data1+multi_data2 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //(x(2)+x(6))*h(2)+(x(3)+x(5))*h(3)
       if(!i_rst_n)                                   
           add_level1_2 <= 26'b0 ;
       else
           add_level1_2 <= multi_data3+multi_data4 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(4)*h(4)
       if(!i_rst_n)                                   
           add_level1_3 <= 26'b0 ;
       else
           add_level1_3 <= {multi_data5[24],multi_data5}   ;

//==2级加法
reg signed [26:0] add_level2_1 ;
reg signed [26:0] add_level2_2 ;
always@(posedge i_fpga_clk or negedge i_rst_n) //(x(0)+x(8))*h(0)+(x(1)+x(7))*h(1)+(x(2)+x(6))*h(2)+(x(3)+x(5))*h(3)
       if(!i_rst_n)                                   
           add_level2_1 <= 27'b0 ;
       else
           add_level2_1 <= add_level1_1+add_level1_2 ;

always@(posedge i_fpga_clk or negedge i_rst_n) //x(4)*h(4)
       if(!i_rst_n)                                   
           add_level2_2 <= 27'b0 ;
       else
           add_level2_2 <= {add_level1_3[25],add_level1_3} ;

//-===3级
reg signed [27:0] add_level3_1 ;
always@(posedge i_fpga_clk or negedge i_rst_n)
       if(!i_rst_n)                                   
           add_level3_1 <= 27'b0 ;
       else
           add_level3_1 <= add_level2_1+add_level2_2 ;

//================================================================================
// 5、output                                                                 
//================================================================================
 reg signed  [22:0]  r_filter_out ;
always@(posedge i_fpga_clk or negedge i_rst_n)
 if(!i_rst_n)                                   
  r_filter_out <= 23'b0 ;
 else
  r_filter_out <= (add_level3_1[22:0]+{!add_level3_1[22],{14{add_level3_1[22]}}})>>15 ;//四舍五入输出

//================================================================================
// 6、output   取低8位                                                              
//================================================================================
 assign o_filter_out  = r_filter_out[7:0] ;

endmodule

**************************************总结************************************************
因为输入的数据是AD芯片采样的结果,该AD的采样精度是8位,所以本例使用8阶滤波器,设计的延时链、加法、乘法的程序都是根据8位来的。所以,如果数据输入是16位,或32位等等,需要改变的有设计滤波器的系数等等。

相应的延时链要多添加至reg signed [7:0] delay_pipeline16 ;

加法和乘法也要有相应的改变,举个例子,大家自行修改

always@(posedge i_fpga_clk or negedge i_rst_n) //x(0)+x(16)
       if(!i_rst_n)                                   
           add_data1 <= 9'b0 ;
       else
           add_data1 <= i_filter_in + delay_pipeline16 ;

转载自:http://blog.sina.com.cn/s/blog_13b436b340102xfpw.html

关于截位问题:http://bbs.eccn.com/viewthread.php?tid=22773

[求助]使用过FIR滤波器IP_CORE的过来看一下,急呀!!

我使用XILINX的MAC_FIR和DA_FIR过程中,设定

COE_WIDTH = 12;
DATA_IN_WIDTH = 12;

MAC_FIR中统计输出是30位数据,

请问,我怎么截取数据,即,从哪儿开始是符号位?符号位有几位?哪儿开始是数据位?

谢谢帮帮忙呀,提示提示 

 
 
   

论坛元老

UID
81104 
性别
男 
2#

 
 vincent发表于 2006-6-7 09:55 | 只看该作者
你这个问题,原来就有人问过的,当时的一位大虾给解答的非常的好,你看一下

首先,我要告诉你的是Xilinx是如何给出的输出位宽。
OutputWidth=coefwidth+inputwidth+ceil(log2(Tap)) (*)
比如,这里coefwidth=12, inputwidth=12, Tap是滤波器的阶数,ceil是向上取整。如果阶数为48,最接近48的2^n为64,那么,(*)式最后一项即为6,那么输出位宽即为30。

如何截位?首先,应该求出输出的最大值,
Max(output)=Max(input)*sum(abs(coef)) (a)
这样保证不溢出,求得输出的最大值,化为二进制当然是补码了,即可确定输出最大位宽,系数和输入都是有符号二进制补码表示,那么高两位都是符号位,从次高位向下截取
(a)式所确定的位宽,但这时所得位宽仍较大,实际上由于ad量化噪声引起的部分还可以去除,使得最终位宽仍可进一步减小。但目标是大信号不溢出,小信号不损失。

 
我不是高手
 
   

新手上路

UID
15892 
性别
男 
3#

 
 Roger Lin发表于 2006-6-7 09:57 | 只看该作者
太谢谢了!!我都弄了很久了,现在一下子明白了!!
非常的感谢!!
 
 
   

注册会员

UID
104679 
性别
男 
4#

 
 deguiqin发表于 2006-6-7 10:00 | 只看该作者
首先应保证小信号不损失,然后实验得出截取位数,向后截取一位输出信号减小6dB 。
这个问题我也曾经遇到过,二楼的解答真的很精彩,谢谢了!
 
 
   

版主

UID
123438 
性别
男 
5#

 
 pengyoubieku发表于 2006-6-7 19:25 | 只看该作者
讲的不错,清楚且合理.谢谢了
 
 
   

注册会员

UID
142119 
性别
男 
6#

 
 xueym发表于 2006-6-8 11:03 | 只看该作者
very good!!!
 
 
   

超级版主

UID
149046 
性别
男 
7#

 
 silverwolf7516发表于 2006-6-8 11:48 | 只看该作者
确实不错,加为精华
 
 
 
   

注册会员

UID
142896 
性别
男 
8#

 
 agilite发表于 2006-6-16 11:00 | 只看该作者
长见识了!
 
 
   

新手上路

UID
814719 
9#

 
 cjm15983646014发表于 2010-6-29 22:15 | 只看该作者
二楼回答的太好了,不过OutputWidth=coefwidth+inputwidth+ceil(log2(Tap)) 这个式子有问题,用不到那么多位。根据做2加法树计算的流水线设计方法,每一级流水线位数加一位,同时参与加法运算的数据减少一半,所以会得出log2(Tap)这个式子,实际上,因为系数不是取coefwidth所能取到的最大数,所以一定会有冗余位出现,具体取多少位,应该根据仿真或者自己编写一个测试程序来计算。Matlab里的fdatool就做好了这一点,考虑到了冗余位这个问题。
 
 
   

新手上路

UID
814719 
10#

 
 cjm15983646014发表于 2010-6-29 22:20 | 只看该作者
在这里,我想请问一下:输出数据如何截取一定的位数?比如和一楼一样,输入数据12位,系数12位,48阶,假如输出是28位(在这里肯定不会是30位,那么做太失水准了),如何将28位数据截取为12位或16位?如何截取才是最佳方案?
 
 
   

禁止发言

UID
814332 
11#

 
 猫弟虎弟发表于 2010-6-30 20:40 | 只看该作者
加载符号表了吗?#3 0x0912c590in?()这种情况一般都是内存越界
 
 
   

新手上路

UID
814745 
12#

 
 丫头不哭哦发表于 2010-7-2 05:49 | 只看该作者
在IDC环境,很多人使用,不能gdb r,该怎么办呢?而且也不是时时core,一天core一两次差不多。
 
 

基于Verilog语言的FIR滤波【程序和理解】的更多相关文章

  1. 【iCore、iCore2 双核心板】EPCS 实验(SPI Flash)(基于Verilog语言)

    _____________________________________ 深入交流QQ群: A: 204255896(1000人超级群,可加入) B: 165201798(500人超级群,满员) C ...

  2. 基于go语言结合微信小程序开发的微商城系统

    最近在慕课网上录制了一门<Golang微信小程序微商城系统原型>,这门免费课程特别适合在校大学生或者刚毕业的大学生,go语言初学者以及想要从事微商城开发项目入门的小伙伴们来学习.在课程当中 ...

  3. 基于Verilog语言的可维护性设计技术

    [注]本文内容主体部分直接翻译参考文献[1]较多内容,因此本文不用于任何商业目的,也不会发表在任何学术刊物上,仅供实验室内部交流和IC设计爱好者交流之用. “曲意而使人喜,不若直节而使人忌:无善而致人 ...

  4. 【iCore2双核心板】SRAM 读写实验(基于Verilog语言)

    _____________________________________ 深入交流QQ群: A: 204255896(1000人超级群,可加入) B: 165201798(500人超级群,满员) C ...

  5. 基于Verilog的奇数偶数小数分频器设计

    今天呢,由泡泡鱼工作室发布的微信公共号“硬件为王”(微信号:king_hardware)正式上线啦,关注有惊喜哦.在这个普天同庆的美好日子里,小编脑洞大开,决定写一首诗赞美一下我们背后伟大的团队,虽然 ...

  6. 基于FPGA的音频信号的FIR滤波(Matlab+Modelsim验证)

    1 设计内容 本设计是基于FPGA的音频信号FIR低通滤波,根据要求,采用Matlab对WAV音频文件进行读取和添加噪声信号.FFT分析.FIR滤波处理,并分析滤波的效果.通过Matlab的分析验证滤 ...

  7. 基于php基础语言编写的小程序之计算器

    基于php基础语言编写的小程序之计算器 需求:在输入框中输入数字进行加.减.乘.除运算(html+php) 思路: 1首先要创建输入数字和运算符的输入框,数字用input的text属性,运算符用sel ...

  8. 基于MATLAB2016b图形化设计自动生成Verilog语言的积分模块及其应用

    在电力电子变流器设备中,常常需要计算发电量,由于电力电子变流器设备一般是高频变流设备,所以发电量的计算几乎时实时功率的积分,此时就会用到一个积分模块.发电量计算的公式如下:Q=∫P. FPGA由于其并 ...

  9. 概率图模型 基于R语言 这本书中的第一个R语言程序

    概率图模型 基于R语言 这本书中的第一个R语言程序 prior <- c(working =0.99,broken =0.01) likelihood <- rbind(working = ...

随机推荐

  1. 使用Facebook的create-react-app脚手架快速构建React开发环境(ant.design,redux......)

    编程领域中的“脚手架(Scaffolding)”指的是能够快速搭建项目“骨架”的一类工具.例如大多数的React项目都有src,public,webpack配置文件等等,而src目录中又包含compo ...

  2. 网络管理命令list

    网络管理 axel 多线程下载工具 tcpreplay 将PCAP包重新发送,用于性能或者功能测试 hping3 测试网络及主机的安全 ssh-copy-id 把本地的ssh公钥文件安装到远程主机对应 ...

  3. ylbtech-LanguageSamples-OfficeSample(COM 互操作)

    ylbtech-Microsoft-CSharpSamples:ylbtech-LanguageSamples-OfficeSample(COM 互操作) 1.A,示例(Sample) 返回顶部 本示 ...

  4. 流畅的python第十七章使用期物处理并发

    从 Python 3.4 起,标准库中有两个名为 Future 的类:concurrent.futures.Future 和asyncio.Future.这两个类的作用相同:两个 Future 类的实 ...

  5. 解决NoClassDefFoundError: javax/servlet/jsp/jstl/core/Config

    使用spring3.05 mvc进行开发,使用tomcat容器,通过url映射寻找view的时候,会报错NoClassDefFoundError: javax/servlet/jsp/jstl/cor ...

  6. Java笔记13:统计文件中每个字符出现的次数

    一.代码实现 import java.io.*; import java.util.*; /** 功能:统计文件中每个字符出现的次数 思路: 1.定义字符读取(缓冲)流 2.循环读取文件里的字符,用一 ...

  7. Azkaban配置

    1,新建azkaban目录,用于安置azkaban程序 2,azkaban web服务器安装  解压 azkaban-web-server-2.5.0.tar.gz tar -zvxf azkaban ...

  8. java程序计算数独游戏

    兴趣来了,写了个简单的数独游戏计算程序,未做算法优化. 通过文件来输入一个二维数组,9行,每行9个数组,数独游戏中需要填空的地方用0来表示.结果也是打印二维数组. import java.io.Fil ...

  9. java 过滤器(理解二)

    request.setCharacterEncoding("utf-8"); response.setContentType("text/html;charset=utf ...

  10. 在Eclipse中点击ctrl+h打开搜索界面,范围指定的项目中搜索包含person的文件

    ctrl+h ===>File Search Tab ===>在containing text里输入person,scope ==>selected resources,搜索就可以了