原创 fir低通滤波器的编写(串行)

2011-8-3 20:10 2010 19 20 分类: FPGA/CPLD
这几天编写了一个FIR低通滤波器,也算一波三折啊。主要是对FPGA内部的数据运算不熟,在FPGA中是没有负数的说法的,确切的说应该是硬件没有负数的概念,FPGA是硬件的编程。所以在FPGA中负数一般是用补码来表示,这样的话加法就没有什么差错了。
此次,FIR滤波器是19阶的低通滤波器。fs=60M,fpass=15M,fstop=20M。
FIR的计算原理是:y(n)=∑h(m)x(n-m) , 其中h(m)的值可以用MATLAB的FDAtool 来完成设计。由于FIR滤波器系数是对称的,所以每次的计算可以减半。
在此程序中,我调用了一个乘法器(他必须计算的是有符号数的乘法)。且输入数据量化为11位,系数量化为10位。在这里,补码的计算需要一点小注意,就是数据的最高位为符号位,不占用数据的绝对值大小,因此,如果要量化为10位的数据,则数据要乘以2^9后再对负数进行2^10的相加以变成补码的值。事实上,对于10位的数据,他的补码所对应的十进制数变化范围是(-512,511)。而正数的补码,反码和原码是一样的,所以要处理的是负数的补码表示。计算也简单,在十进制上,比如量化-0.3为10位的补码,则结果应为2^10 + (-0.3)* 2^9 = 870。可以看到十进制上的计算就是这样的,只要大于511,就是表示负数。所以最后仿真结果只要选择显示符号数,就可以通过补码的反应来显示出正数和负数。
以下是我编写的程序,大家可以多多交流,本人也是初学者。
module fir_test(clk,rst,
                datain,
                dataout
                );
               
input clk,rst;
input[10:0] datain;
output[22:0] dataout;

reg[10:0] datain_r; 
reg[4:0] mult_state;
reg[11:0] data_ad_buf[19:1]; //处理的数据,加上符号位需要12位,输入数据为11位
reg[11:0] data_add[10:1]; //对称相加后的数据
reg[11:0] dataa_r; //乘法器的输入---输入数据
reg[9:0] datab_r;  //乘法器的输入---FIR系数
reg[22:0] sum;
reg[22:0] dataout;

wire[11:0] dataa;
wire[9:0] datab;
wire[21:0] result;

assign dataa = dataa_r;
assign datab = datab_r;

parameter
h0=10'd1022,
h1=10'd1014,
h2=10'd1013,
h3=10'd6,
h4=10'd21,
h5=10'd1016,
h6=10'd978,
h7=10'd8,
h8=10'd160,
h9=10'd246;
/*----------------------------------------------------------------------------*/

always@(posedge clk or negedge rst) begin
       if(!rst) datain_r <= 0;
       else if(mult_state==5'd10) datain_r <= datain;
       else datain_r <= datain_r;
end

/*----------------------------------------------------------------------------*/
//数据移位
always@(posedge clk or negedge rst) begin
       if(!rst) begin data_ad_buf[1] <= 12'd0; data_ad_buf[2] <= 12'd0;
                      data_ad_buf[3] <= 12'd0; data_ad_buf[4] <= 12'd0;
                      data_ad_buf[5] <= 12'd0; data_ad_buf[6] <= 12'd0;
                      data_ad_buf[7] <= 12'd0; data_ad_buf[8] <= 12'd0;
                      data_ad_buf[9] <= 12'd0; data_ad_buf[10] <= 12'd0;
                      data_ad_buf[11] <= 12'd0; data_ad_buf[12] <= 12'd0;
                      data_ad_buf[13] <= 12'd0; data_ad_buf[14] <= 12'd0;
                      data_ad_buf[15] <= 12'd0; data_ad_buf[16] <= 12'd0;
                      data_ad_buf[17] <= 12'd0; data_ad_buf[18] <= 12'd0;
                      data_ad_buf[19] <= 12'd0;
                end
       else if(mult_state==5'd10)begin
             data_ad_buf[19] <= data_ad_buf[18];
             data_ad_buf[18] <= data_ad_buf[17];
             data_ad_buf[17] <= data_ad_buf[16];
             data_ad_buf[16] <= data_ad_buf[15];
             data_ad_buf[15] <= data_ad_buf[14];
             data_ad_buf[14] <= data_ad_buf[13];
             data_ad_buf[13] <= data_ad_buf[12];
             data_ad_buf[12] <= data_ad_buf[11];
             data_ad_buf[11] <= data_ad_buf[10];
             data_ad_buf[10] <= data_ad_buf[9];
             data_ad_buf[9] <= data_ad_buf[8];
             data_ad_buf[8] <= data_ad_buf[7];
             data_ad_buf[7] <= data_ad_buf[6];
             data_ad_buf[6] <= data_ad_buf[5];
             data_ad_buf[5] <= data_ad_buf[4];
             data_ad_buf[4] <= data_ad_buf[3];
             data_ad_buf[3] <= data_ad_buf[2];
             data_ad_buf[2] <= data_ad_buf[1];
             data_ad_buf[1] <= {datain_r[10],datain_r};
         end
end

//数据对称位相加,方便计算
always@(posedge clk or negedge rst) begin
       if(!rst) begin data_add[1] <= 0; data_add[2] <= 0;
                      data_add[3] <= 0; data_add[4] <= 0;
                      data_add[5] <= 0; data_add[6] <= 0;
                      data_add[7] <= 0; data_add[8] <= 0;
                      data_add[9] <= 0; data_add[10] <= 0;
                end
       else if(mult_state==5'd10) begin
                 data_add[1] <= data_ad_buf[1] + data_ad_buf[19];
                 data_add[2] <= data_ad_buf[2] + data_ad_buf[18];
                 data_add[3] <= data_ad_buf[3] + data_ad_buf[17];
                 data_add[4] <= data_ad_buf[4] + data_ad_buf[16];
                 data_add[5] <= data_ad_buf[5] + data_ad_buf[15];
                 data_add[6] <= data_ad_buf[6] + data_ad_buf[14];
                 data_add[7] <= data_ad_buf[7] + data_ad_buf[13];
                 data_add[8] <= data_ad_buf[8] + data_ad_buf[12];
                 data_add[9] <= data_ad_buf[9] + data_ad_buf[11];
                 data_add[10] <= data_ad_buf[10];
            end
end

//每个输出值的计算
always@(posedge clk or negedge rst) begin
       if(!rst) begin mult_state <= 5'd0; dataa_r <= 0; datab_r <= 0; sum <= 0;end
       else begin
               case(mult_state)
                 5'd0: begin dataa_r <= data_add[1]; datab_r <= h0; 
                             dataout <= sum;
                             sum <= 0; mult_state <= 5'd1;
                       end
                 5'd1: begin dataa_r <= data_add[2]; datab_r <= h1;
                             sum <= sum + {result[21],result}; mult_state <= 5'd2;
                       end
                 5'd2: begin dataa_r <= data_add[3]; datab_r <= h2;
                             sum <= sum + {result[21],result}; mult_state <= 5'd3;
                       end
                 5'd3: begin dataa_r <= data_add[4]; datab_r <= h3;
                             sum <= sum + {result[21],result}; mult_state <= 5'd4;
                       end
                 5'd4: begin dataa_r <= data_add[5]; datab_r <= h4;
                             sum <= sum + {result[21],result}; mult_state <= 5'd5;
                       end
                 5'd5: begin dataa_r <= data_add[6]; datab_r <= h5;
                             sum <= sum + {result[21],result}; mult_state <= 5'd6;
                       end
                 5'd6: begin dataa_r <= data_add[7]; datab_r <= h6;
                             sum <= sum + {result[21],result}; mult_state <= 5'd7;
                       end
                 5'd7: begin dataa_r <= data_add[8]; datab_r <= h7;
                             sum <= sum + {result[21],result}; mult_state <= 5'd8;
                       end
                 5'd8: begin dataa_r <= data_add[9]; datab_r <= h8;
                             sum <= sum + {result[21],result}; mult_state <= 5'd9;
                       end
                 5'd9: begin dataa_r <= data_add[10]; datab_r <= h9;
                             sum <= sum + {result[21],result}; mult_state <= 5'd10; 
                       end
                 5'd10: begin mult_state <= 5'd0;
                              sum <= sum + {result[21],result};
                        end
                 default: begin dataa_r <= 0; datab_r <= 0; sum <= 0; end
               endcase
            end
end

/*----------------------------------------------------------------------------*/
mult_smp mult_smp_inst (
.dataa ( dataa ),
.datab ( datab ),
.result ( result )
);


endmodule

接着是对滤波器的验证。我这里用的是modelsim,输入数据是有MATLAB产生的。如下所示:
f1=10e6;
f2=25e6;
fs=60e6;
N=61;
t=0:N-1;
x1=cos(2*pi*f1/fs*t)
x2=cos(2*pi*f2/fs*t);
x=x1+x2;
然后再对数据进行量化,最后通过编写testebench 来在modelsim中进行功能仿真验证。对于testbench 大家可以自己掂量下,数据是各自可以产生自己需要的数据,这里我只给出思路和大家交流。有所不妥,还请指教。以下是我仿真后的波形,但是大家可以从图中看到有很多的毛刺,而且产生的比较均匀,但是结果的数值是正确的,我不明白是为什么,因为我进行的是功能仿真,以前编写DDS也出现过类似的情况,一直不明白为什么,我用的modelsim是6.6版本,不知是我哪里设置有问题,还请各位赐教。

20110803201028498.png

文章评论1条评论)

登录后参与讨论

40763529_613887482 2011-12-23 16:52

相关推荐阅读
用户1600457 2012-04-13 15:53
BOA WEB服务器移植
BOA WEB服务器的移植: 下载源码:最新的为0.94.13,之后再没有更新过 解压后进入文件夹的src/下 ./configure产生Makefile 修改Makefil...
用户1600457 2012-04-09 10:52
【博客大赛】(原创) linux进程间通信之有名管道(FIFO)的简单应用
之前写了无名管道方式的通信,这里就验证下有名管道的通信方式。 有名管道他和普通文件一样可以被读写,而且实际存在于存储设备中,一般也即磁盘,但是有名管道在进程结束后通信的信息就自动消失了,而一般...
用户1600457 2012-04-09 10:51
【博客大赛】(原创)linux进程间通信之无名管道(pipe)的简单应用
最近开始学了linux应用编程,懂了点多进程的基础知识,便跃跃欲试,想立即应用起来,以加深印象,学任何东西重在实践,技术尤为如此。 在linux中创建新的进程的函数为fork(),如果成功返回...
用户1600457 2012-04-08 11:02
【博客大赛】(原创)OK6410按键中断实现
这里本人使用中断形式实现按键的驱动,首先还是先呈上源程序: #include <linux/kernel.h> #include <linux/module.h> ...
用户1600457 2012-04-02 15:55
【博客大赛】(原创)OK6410的第一个驱动程序--点灯
开始自己的嵌入式之旅了。一切神秘的面纱均可以由闪亮的LED揭开。 贴上自己的驱动程序: #include<linux/kernel.h> #include<linux/...
用户1600457 2012-03-23 14:03
nor flash 与 nand flash的比较(转)
NOR和NAND是现在市场上两种主要的非易失闪存技术。Intel于1988年首先开发出NOR Flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面。紧接着,19***,东芝公司发...
我要评论
1
19
关闭 站长推荐上一条 /2 下一条