Verilog 并行FIR濾波器設(shè)計(jì)

2022-05-18 10:47 更新

FIR(Finite Impulse Response)濾波器是一種有限長單位沖激響應(yīng)濾波器,又稱為非遞歸型濾波器。

FIR 濾波器具有嚴(yán)格的線性相頻特性,同時(shí)其單位響應(yīng)是有限長的,因而是穩(wěn)定的系統(tǒng),在數(shù)字通信、圖像處理等領(lǐng)域都有著廣泛的應(yīng)用。

FIR 濾波器原理

FIR 濾波器是有限長單位沖擊響應(yīng)濾波器。直接型結(jié)構(gòu)如下:


FIR 濾波器本質(zhì)上就是輸入信號(hào)與單位沖擊響應(yīng)函數(shù)的卷積,表達(dá)式如下:


FIR 濾波器有如下幾個(gè)特性:

  • 響應(yīng)是有限長序列。
  • 系統(tǒng)函數(shù)在 |z| > 0 處收斂,極點(diǎn)全部在 z=0 處,屬于因果系統(tǒng)。
  • 結(jié)構(gòu)上是非遞歸的,沒有輸出到輸入的反饋。
  • 輸入信號(hào)相位響應(yīng)是線性的,因?yàn)轫憫?yīng)函數(shù) h(n) 系數(shù)是對(duì)稱的。
  • 輸入信號(hào)的各頻率之間,相對(duì)相位差也是固定不變的。
  • 時(shí)域卷積等于頻域相乘,因此該卷積相當(dāng)于篩選頻譜中各頻率分量的增益倍數(shù)。某些頻率分量保留,某些頻率分量衰減,從而實(shí)現(xiàn)濾波的效果。

并行 FIR 濾波器設(shè)計(jì)

設(shè)計(jì)說明

輸入頻率為 7.5 MHz 和 250 KHz 的正弦波混合信號(hào),經(jīng)過 FIR 濾波器后,高頻信號(hào) 7.5MHz 被濾除,只保留 250KHz 的信號(hào)。設(shè)計(jì)參數(shù)如下:

輸入頻率:    7.5MHz 和 250KHz
采樣頻率:    50MHz
阻帶:           1MHz ~ 6MHz
階數(shù):           15(N-1=15)

由 FIR 濾波器結(jié)構(gòu)可知,階數(shù)為 15 時(shí),F(xiàn)IR 的實(shí)現(xiàn)需要 16 個(gè)乘法器,15 個(gè)加法器和 15 組延時(shí)寄存器。為了穩(wěn)定第一拍的數(shù)據(jù),可以再多用一組延時(shí)寄存器,即共用 16 組延時(shí)寄存器。由于 FIR 濾波器系數(shù)的對(duì)稱性,乘法器可以少用一半,即共使用 8 個(gè)乘法器。

并行設(shè)計(jì),就是在一個(gè)時(shí)鐘周期內(nèi)對(duì) 16 個(gè)延時(shí)數(shù)據(jù)同時(shí)進(jìn)行乘法、加法運(yùn)算,然后在時(shí)鐘驅(qū)動(dòng)下輸出濾波值。這種方法的優(yōu)點(diǎn)是濾波延時(shí)短,但是對(duì)時(shí)序要求比較高。

并行設(shè)計(jì)

設(shè)計(jì)中使用到的乘法器模塊代碼,可參考之前流水線式設(shè)計(jì)的乘法器。

為方便快速仿真,也可以直接使用乘號(hào) * 完成乘法運(yùn)算,設(shè)計(jì)中加入宏定義 ?SAFE_DESIGN ?來選擇使用哪種乘法器。

FIR 濾波器系數(shù)可由 matlab 生成,具體見附錄。

/***********************************************************
>> V201001 : Fs:50Mhz, fstop:1Mhz-6Mhz, order: 15
************************************************************/
`define SAFE_DESIGN
 
module fir_guide    (
    input                rstn,  //復(fù)位,低有效
    input                clk,   //工作頻率,即采樣頻率
    input                en,    //輸入數(shù)據(jù)有效信號(hào)
    input        [11:0]  xin,   //輸入混合頻率的信號(hào)數(shù)據(jù)
    output               valid, //輸出數(shù)據(jù)有效信號(hào)
    output       [28:0]  yout   //輸出數(shù)據(jù),低頻信號(hào),即250KHz
    );
 
    //data en delay
    reg [3:0]            en_r ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            en_r[3:0]      <= 'b0 ;
        end
        else begin
            en_r[3:0]      <= {en_r[2:0], en} ;
        end
    end
 
   //(1) 16 組移位寄存器
    reg        [11:0]    xin_reg[15:0];
    reg [3:0]            i, j ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            for (i=0; i<15; i=i+1) begin
                xin_reg[i]  <= 12'b0;
            end
        end
        else if (en) begin
            xin_reg[0] <= xin ;
            for (j=0; j<15; j=j+1) begin
                xin_reg[j+1] <= xin_reg[j] ; //周期性移位操作
            end
        end
    end
 
   //Only 8 multipliers needed because of the symmetry of FIR filter coefficient
   //(2) 系數(shù)對(duì)稱,16個(gè)移位寄存器數(shù)據(jù)進(jìn)行首位相加
    reg        [12:0]    add_reg[7:0];
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            for (i=0; i<8; i=i+1) begin
                add_reg[i] <= 13'd0 ;
            end
        end
        else if (en_r[0]) begin
            for (i=0; i<8; i=i+1) begin
                add_reg[i] <= xin_reg[i] + xin_reg[15-i] ;
            end
        end
    end
 
    //(3) 8個(gè)乘法器
    // 濾波器系數(shù),已經(jīng)過一定倍數(shù)的放大
    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 ;
    reg        [24:0]   mout[7:0];
 
`ifdef SAFE_DESIGN
    //流水線式乘法器
    wire [7:0]          valid_mult ;
    genvar              k ;
    generate
        for (k=0; k<8; k=k+1) begin
            mult_man #(13, 12)
            u_mult_paral          (
              .clk        (clk),
              .rstn       (rstn),
              .data_rdy   (en_r[1]),
              .mult1      (add_reg[k]),
              .mult2      (coe[k]),
              .res_rdy    (valid_mult[k]), //所有輸出使能完全一致  
              .res        (mout[k])
            );
        end
    endgenerate
    wire valid_mult7     = valid_mult[7] ;
 
`else
    //如果對(duì)時(shí)序要求不高,可以直接用乘號(hào)
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            for (i=0 ; i<8; i=i+1) begin
                mout[i]     <= 25'b0 ;
            end
        end
        else if (en_r[1]) begin
            for (i=0 ; i<8; i=i+1) begin
                mout[i]     <= coe[i] * add_reg[i] ;
            end
        end
    end
    wire valid_mult7 = en_r[2];
`endif
 
    //(4) 積分累加,8組25bit數(shù)據(jù) -> 1組 29bit 數(shù)據(jù)
    //數(shù)據(jù)有效延時(shí)
    reg [3:0]            valid_mult_r ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            valid_mult_r[3:0]  <= 'b0 ;
        end
        else begin
            valid_mult_r[3:0]  <= {valid_mult_r[2:0], valid_mult7} ;
        end
    end

`ifdef SAFE_DESIGN
    //加法運(yùn)算時(shí),分多個(gè)周期進(jìn)行流水,優(yōu)化時(shí)序
    reg        [28:0]    sum1 ;
    reg        [28:0]    sum2 ;
    reg        [28:0]    yout_t ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            sum1   <= 29'd0 ;
            sum2   <= 29'd0 ;
            yout_t <= 29'd0 ;
        end
        else if(valid_mult7) begin
            sum1   <= mout[0] + mout[1] + mout[2] + mout[3] ;
            sum2   <= mout[4] + mout[5] + mout[6] + mout[7] ;
            yout_t <= sum1 + sum2 ;
        end
    end
 
`else
    //一步計(jì)算累加結(jié)果,但是實(shí)際中時(shí)序非常危險(xiǎn)
    reg signed [28:0]    sum ;
    reg signed [28:0]    yout_t ;
    always @(posedge clk or negedge rstn) begin
        if (!rstn) begin
            sum    <= 29'd0 ;
            yout_t <= 29'd0 ;
        end
        else if (valid_mult7) begin
            sum    <= mout[0] + mout[1] + mout[2] + mout[3] + mout[4] + mout[5] + mout[6] + mout[7];
            yout_t <= sum ;
        end
    end
`endif
    assign yout  = yout_t ;
    assign valid = valid_mult_r[0];

endmodule

testbench

testbench 編寫如下,主要功能就是不間斷連續(xù)的輸入 250KHz 與 7.5MHz 的正弦波混合信號(hào)數(shù)據(jù)。輸入的混合信號(hào)數(shù)據(jù)也可由 matlab 生成,具體見附錄。

`timescale 1ps/1ps
 
module test ;
   //input
    reg          clk ;
    reg          rst_n ;
    reg          en ;
    reg [11:0]   xin ;
    //output
    wire         valid ;
    wire [28:0]  yout ;
 
    parameter    SIMU_CYCLE   = 64'd2000 ;  //50MHz 采樣頻率
    parameter    SIN_DATA_NUM = 200 ;      //仿真周期

//=====================================
// 50MHz clk generating
    localparam   TCLK_HALF     = 10_000;
    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 * SIMU_CYCLE) ;
        $finish ;
    end
 
//=======================================
// read signal data into register
    reg          [11:0] stimulus [0: SIN_DATA_NUM-1] ;
    integer      i ;
    initial begin
        $readmemh("../tb/cosx0p25m7p5m12bit.txt", stimulus) ;
        i = 0 ;
        en = 0 ;
        xin = 0 ;
        # 200 ;
        forever begin
            @(negedge clk) begin
                en          = 1'b1 ;
                xin         = stimulus[i] ;
                if (i == SIN_DATA_NUM-1) begin  //周期送入數(shù)據(jù)控制
                    i = 0 ;
                end
                else begin
                    i = i + 1 ;
                end
            end
        end
    end
 
    fir_guide u_fir_paral (
      .xin         (xin),
      .clk         (clk),
      .en          (en),
      .rstn        (rst_n),
      .valid       (valid),
      .yout        (yout));
 
endmodule

仿真結(jié)果

由下圖仿真結(jié)果可知,經(jīng)過 FIR 濾波器后的信號(hào)只有一種低頻率信號(hào)(250KHz),高頻信號(hào)(7.5MHz)被濾除了。而且輸出波形是連續(xù)的,能夠持續(xù)輸出。

但是,如紅圈所示,波形起始部分呈不規(guī)則狀態(tài),對(duì)此進(jìn)行放大。


波形起始端放大后如下圖所示,可見不規(guī)則波形的時(shí)間段,即兩根豎線之間的時(shí)間間隔是 16 個(gè)時(shí)鐘周期。

因?yàn)閿?shù)據(jù)是串行輸入,設(shè)計(jì)中使用了 16 組延時(shí)寄存器,所以濾波后的第一個(gè)正常點(diǎn)應(yīng)該較第一個(gè)濾波數(shù)據(jù)輸出時(shí)刻延遲 16 個(gè)時(shí)鐘周期。即數(shù)據(jù)輸出有效信號(hào) valid 應(yīng)該再延遲 16 個(gè)時(shí)鐘周期,則會(huì)使輸出波形更加完美。


附錄:matlab 使用

生成 FIR 濾波器系數(shù)

打開 matlab,在命令窗口輸入命令: fdatool。

然后會(huì)打開如下窗口,按照 FIR 濾波器參數(shù)進(jìn)行設(shè)置。

這里選擇的 FIR 實(shí)現(xiàn)方法是最小二乘法(Least-squares),不同的實(shí)現(xiàn)方式濾波效果也不同。


點(diǎn)擊 File -> Export

將濾波器參數(shù)輸出,存到變量 coef 中,如下圖所示。


此時(shí) coef 變量應(yīng)該是浮點(diǎn)型數(shù)據(jù)。對(duì)其進(jìn)行一定倍數(shù)的相乘擴(kuò)大,然后取其近似的定點(diǎn)型數(shù)據(jù)作為設(shè)計(jì)中的 FIR 濾波器參數(shù)。這里取擴(kuò)大倍數(shù)為 2048,結(jié)果如下所示。


生成輸入的混合信號(hào)

利用 matlab 生成混合的輸入信號(hào)參考代碼如下。

信號(hào)為無符號(hào)定點(diǎn)型數(shù)據(jù),位寬寬度為 12bit,存于文件 cosx0p25m7p5m12bit.txt。

clear all;close all;clc;
%=======================================================
% generating a cos wave data with txt hex format
%=======================================================

fc          = 0.25e6 ;      % 中心頻率
fn          = 7.5e6 ;       % 雜波頻率
Fs          = 50e6 ;        % 采樣頻率
T           = 1/fc ;        % 信號(hào)周期
Num         = Fs * T ;      % 周期內(nèi)信號(hào)采樣點(diǎn)數(shù)
t           = (0:Num-1)/Fs ;      % 離散時(shí)間
cosx        = cos(2*pi*fc*t) ;    % 中心頻率正弦信號(hào)
cosn        = cos(2*pi*fn*t) ;    % 雜波信號(hào)
cosy        = mapminmax(cosx + cosn) ;     %幅值擴(kuò)展到(-1,1) 之間
cosy_dig    = floor((2^11-1) * cosy + 2^11) ;     %幅值擴(kuò)展到 0~4095
fid         = fopen('cosx0p25m7p5m12bit.txt', 'wt') ;  %寫數(shù)據(jù)文件
fprintf(fid, '%x\n', cosy_dig) ;
fclose(fid) ;
 
%時(shí)域波形
figure(1);
subplot(121);plot(t,cosx);hold on ;
plot(t,cosn) ;
subplot(122);plot(t,cosy_dig) ;
 
%頻域波形
fft_cosy    = fftshift(fft(cosy, Num)) ;
f_axis      = (-Num/2 : Num/2 - 1) * (Fs/Num) ;
figure(5) ;
plot(f_axis, abs(fft_cosy)) ;

點(diǎn)擊這里下載源碼


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)