您现在的位置是:首页 > 正文

串行FIR滤波器

2024-04-01 04:35:04阅读 3

串行 FIR 滤波器设计

串行设计,就是在 16 个时钟周期内对 16 个延时数据分时依次进行乘法、加法运算,然后在时钟驱动下输出滤波值。考虑到 FIR 滤波器系数的对称性,计算一个滤波输出值的周期可以减少到 8 个。串行设计时每个周期只进行一次乘法运算,所以设计中只需一个乘法器即可。此时数据需要每 8 个时钟周期有效输入一次,但是为了保证输出信号频率的正确性,工作时钟需要为采样频率的 8 倍,即 400MHz。这种方法的优点是资源耗费少,但是工作频率要求高,数据不能持续输出。

串行设计

/**********************************************************
>> Description : fir study with serial tech
>>             : Fs:50Mhz, fstop:1-6Mhz, order:16, sys clk:400MHz
***********************************************************/
`define SAFE_DESIGN
 
module fir_serial(
    input                rstn,
    input                clk,   // 系统工作时钟,400MHz
    input                en ,   // 输入数据有效信号
    input        [11:0]  xin,   // 输入混合频率的信号数据
    output               valid, // 输出数据有效信号
    output       [28:0]  yout   // 输出数据
    );
 
   //delay of input data enable
    reg [11:0]            en_r ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            en_r[11:0]      <= 'b0 ;
        end
        else begin
            en_r[11:0]      <= {en_r[10:0], en} ;
        end
    end
 
    //fir coeficient
    wire        [11:0]   coe[7:0] ;
    assign coe[0]        = 12'd11 ;
    assign coe[1]        = 12'd31 ;
    assign coe[2]        = 12'd63 ;
    assign coe[3]        = 12'd104 ;
    assign coe[4]        = 12'd152 ;
    assign coe[5]        = 12'd198 ;
    assign coe[6]        = 12'd235 ;
    assign coe[7]        = 12'd255 ;
 
    //(1) 输入数据移位部分
    reg [2:0]            cnt ;
    integer              i, j ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            cnt <= 3'b0 ;
        end
        else if (en || cnt != 0) begin
            cnt <= cnt + 1'b1 ;    //8个周期计数
        end
    end
 
    reg [11:0]           xin_reg[15:0];
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            for (i=0; i<16; i=i+1) begin
                xin_reg[i]  <= 12'b0;
            end
        end
        else if (cnt == 3'd0 && en) begin    //每8个周期读入一次有效数据
            xin_reg[0] <= xin ;
            for (j=0; j<15; j=j+1) begin
                xin_reg[j+1] <= xin_reg[j] ; // 数据移位
            end
        end
    end
 
    //(2) 系数对称,16个移位寄存器数据进行首位相加
    reg  [11:0]          add_a, add_b ;
    reg  [11:0]          coe_s ;
    wire [12:0]          add_s ;
    wire [2:0]           xin_index = cnt>=1 ? cnt-1 : 3'd7 ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            add_a  <= 13'b0 ;
            add_b  <= 13'b0 ;
            coe_s  <= 12'b0 ;
        end
        else if (en_r[xin_index]) begin //from en_r[1]
            add_a  <= xin_reg[xin_index] ;
            add_b  <= xin_reg[15-xin_index] ;
            coe_s  <= coe[xin_index] ;
        end
    end
    assign add_s = {add_a} + {add_b} ;  
 
    //(3) 乘法运算,只用一个乘法
    wire        [24:0]    mout ;
`ifdef SAFE_DESIGN
    wire                 en_mult ;
    wire [3:0]           index_mult = cnt>=2 ? cnt-1 : 4'd7 + cnt[0] ;
    mult_man #(13, 12)   u_mult_single    //例化自己设计的流水线乘法器
        (.clk        (clk),
         .rstn       (rstn),
         .data_rdy   (en_r[index_mult]),  //注意数据时序对应
         .mult1      (add_s),
         .mult2      (coe_s),
         .res_rdy    (en_mult),  
         .res        (mout)
        );
 
`else
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            mout   <= 25'b0 ;
        end
        else if (|en_r[8:1]) begin
            mout   <= coe_s * add_s ;  //直接乘
        end
    end
    wire                 en_mult = en_r[2];
`endif
 
    //(4) 积分累加,8组25bit数据 -> 1组 29bit 数据
    reg        [28:0]    sum ;
    reg                  valid_r ;
    //mult output en counter
    reg [4:0]            cnt_acc_r ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            cnt_acc_r <= 'b0 ;
        end
        else if (cnt_acc_r == 5'd7) begin  //计时8个周期
            cnt_acc_r <= 'b0 ;
        end
        else if (en_mult || cnt_acc_r != 0) begin //只要en有效,计时不停
            cnt_acc_r <= cnt_acc_r + 1'b1 ;
        end
    end
 
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            sum      <= 29'd0 ;
            valid_r  <= 1'b0 ;
        end
        else if (cnt_acc_r == 5'd7) begin //在第8个累加周期输出滤波值
            sum      <= sum + mout;
            valid_r  <= 1'b1 ;
        end
        else if (en_mult && cnt_acc_r == 0) begin //初始化
            sum      <= mout ;
            valid_r  <= 1'b0 ;
        end
        else if (cnt_acc_r != 0) begin //acculating between cycles
            sum      <= sum + mout ;
            valid_r  <= 1'b0 ;
        end
    end
 
    //时钟锁存有效的输出数据,为了让输出信号不是那么频繁的变化
    reg [28:0]           yout_r ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            yout_r <= 'b0 ;
        end
        else if (valid_r) begin
            yout_r <= sum ;
        end
    end
    assign yout = yout_r ;
 
    //(5) 输出数据有效延迟,即滤波数据丢掉前15个滤波值
    reg [4:0]    cnt_valid ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            cnt_valid      <= 'b0 ;
        end
        else if (valid_r && cnt_valid != 5'd16) begin
            cnt_valid      <= cnt_valid + 1'b1 ;
        end
    end
    assign valid = (cnt_valid == 5'd16) & valid_r ;

endmodule

testbench

module test ;
    //input
    reg          clk ;
    reg          rst_n ;
    reg          en ;
    reg  [11:0]  xin ;
    //output
    wire [28:0]  yout ;
    wire         valid ;

    parameter    SIMU_CYCLE   = 64'd1000 ;
    parameter    SIN_DATA_NUM = 200 ;

//=====================================
// 8*50MHz clk generating
    localparam   TCLK_HALF     = (10_000 >>3);
    initial begin
        clk = 1'b0 ;
        forever begin
            # TCLK_HALF clk = ~clk ;
        end
     end
 
//============================
//  reset and finish
    initial begin
        rst_n = 1'b0 ;
        # 30        rst_n = 1'b1 ;
        # (TCLK_HALF * 2 * 8  * SIMU_CYCLE) ;
        $finish ;
    end
 
//=======================================
// read cos data into register
    reg          [11:0] stimulus [0: SIN_DATA_NUM-1] ;
    integer      i ;
    initial begin
        $readmemh("E:/appdata/SimulationTools/modelsim/demo/filter/FIR_filter/tb/cosx0p25m7p5m12bit.txt", stimulus) ;
        en = 0 ;
        i = 0 ;
        xin = 0 ;
        # 200 ;
        forever begin
            repeat(7)  @(negedge clk) ; //空置7个周期,第8个周期给数据
            en          = 1 ;
            xin         = stimulus[i] ;
            @(negedge clk) ;
            en          = 0 ;         //输入数据有效信号只持续一个周期即可
            if (i == SIN_DATA_NUM-1)  i = 0 ;
            else  i = i + 1 ;
        end
    end
 
    fir_serial       u_fir_serial (
        .clk         (clk),
        .rstn        (rst_n),
        .en          (en),
        .xin         (xin),
        .valid       (valid),
        .yout        (yout));

endmodule

仿真结果

在这里插入图片描述

网站文章

  • Visual Studio 秘钥

    Visual Studio 2015

    2024-04-01 04:34:23
  • win10小工具

    win10小工具

    clover给资源管理器加上标签页spacesniff图形化展示磁盘文件大小NDM下载工具

    2024-04-01 04:34:16
  • 常用正则表达式,持续更新

    常用正则表达式,手机号,身份证号,邮编

    2024-04-01 04:34:09
  • 使用swagger上传文件时,报错 Content type &#39;multipart/form-data;boundary=----WebKitFormBoundaryRAYPKeHKTYSNdzc1

    使用swagger上传文件时,传参包括一个文件类型的数据,和一个对象实体,上传时报错: &quot;timestamp&quot;: 1473349676109, &quot;status&quot;...

    2024-04-01 04:33:30
  • 一文搞懂操作系统虚拟内存管理

    一文搞懂操作系统虚拟内存管理

    早期的计算机系统中,主存容量很小,虽然主存中仅存放一道用户程序,但是存储空间放不下用户进程的现象也经常发生。比如 IBM 推出的第一台PC机最大只支持 1MB 大小的内存。因此经常会出现内存大小不够的...

    2024-04-01 04:33:24
  • 完成二十道编程题,就有机会获得作者赠书

    完成二十道C#编程入门题(任务),就有机会获得价值89元的赠书《31天学会CRM项目开发(C#编程入门及项目实战)》,面向编程新手,仅限十本,送完为止。搜索书名,加入读者群,领取任务。...

    2024-04-01 04:33:17
  • Github一周狂飙到50.5Kstars的Java 八股文汇总,到底有多强?

    Github一周狂飙到50.5Kstars的Java 八股文汇总,到底有多强?

    很多 Java 工程师的技术不错,但是一面试就头疼,10 次面试 9 次都是被刷,过的那次还是去了家不知名的小公司。问题就在于:面试有技巧,而。:你该如何准备简历,面试项目和面试说辞?Spring 底...

    2024-04-01 04:32:37
  • C++面经大全 热门推荐

    作者:一个offer都没有的菜鸡 链接:https://www.nowcoder.com/discuss/125248 来源:牛客网 楼主菜鸡一只,是真的菜,我是转软件的,所以学的很浅,面试根本经不起深挖,研一荒废了半年,春节之后才意识到要开始找工作,然后就开始疯狂的学习数据结构算法,计网,OS啥的,学的很水,前后投了20多家,最终就拿了4个小厂的offer,大厂真的一个都没过,是真的应证了...

    2024-04-01 04:32:30
  • 【专项学习】 —— Webpack5从入门到精通课程学习(六)

    【专项学习】 —— Webpack5从入门到精通课程学习(六)

    这篇主要介绍《webpack优化环境配置(下)》。 知识点包括: 懒加载和预加载 懒加载 预加载 PWA(离线可访问) 多进程打包 externals DLL(动态链接库) 一、懒加载和预加载 懒加载 懒加载就是,在实际项目中,某个.js文件,还没有用到,此时不进行加载,当网页中进行某个功能,有需要时在加载。 1、复制代码分割工程文件,修改其中的webpack.config.js,...

    2024-04-01 04:32:22
  • element plus table表格复选框实现单选效果

    element plus table表格复选框实现单选效果

    框架vue3 + vite4.4.2 + element plus;需求背景:数据列表展示内容-复选框支持单选;我们都知道element的table ui组件type = selection,是一个复...

    2024-04-01 04:32:15