0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Verilog并行FIR滤波器设计

冬至子 来源:数字IC与好好生活的两居室 作者:除夕之夜啊 2023-06-01 11:11 次阅读

FIR(Finite Impulse Response)滤波器是一种有限长单位冲激响应滤波器,又称为非递归型滤波器。FIR 滤波器具有严格的线性相频特性,同时其单位响应是有限长的,因而是稳定的系统,在数字通信、图像处理等领域都有着广泛的应用。

FIR 滤波器原理

FIR 滤波器是有限长单位冲击响应滤波器。直接型结构如下:

图片

FIR 滤波器本质上就是输入信号与单位冲击响应函数的卷积,表达式如下:

图片

FIR 滤波器有如下几个特性:

(1) 响应是有限长序列。

(2) 系统函数在 |z| > 0 处收敛,极点全部在 z=0 处,属于因果系统。

(3) 结构上是非递归的,没有输出到输入的反馈。

(4) 输入信号相位响应是线性的,因为响应函数 h(n) 系数是对称的。

(5) 输入信号的各频率之间,相对相位差也是固定不变的。

(6) 时域卷积等于频域相乘,因此该卷积相当于筛选频谱中各频率分量的增益倍数。某些频率分量保留,某些频率分量衰减,从而实现滤波的效果。

并行 FIR 滤波器设计

◆设计说明

输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号,经过 FIR 滤波器后,高频信号 7.5MHz 被滤除,只保留 250KHz 的信号。设计参数如下:

输入频率: 7.5MHz 和 250KHz

采样频率: 50MHz

阻带: 1MHz ~ 6MHz

阶数: 15(N-1=15)

由 FIR 滤波器结构可知,阶数为 15 时,FIR 的实现需要 16 个乘法器,15 个加法器和 15 组延时寄存器。为了稳定第一拍的数据,可以再多用一组延时寄存器,即共用 16 组延时寄存器。由于 FIR 滤波器系数的对称性,乘法器可以少用一半,即共使用 8 个乘法器。

并行设计,就是在一个时钟周期内对 16 个延时数据同时进行乘法、加法运算,然后在时钟驱动下输出滤波值。这种方法的优点是滤波延时短,但是对时序要求比较高。

◆并行设计

设计中使用到的乘法器模块代码,可参考之前流水线式设计的乘法器。

为方便快速仿真,也可以直接使用乘号 “*” 完成乘法运算,设计中加入宏定义 SAFE_DESIGN 来选择使用哪种乘法器。

FIR 滤波器系数可由 matlab 生成,具体见附录。

/***********************************************************
> > V201001 : Fs50Mhz, fstop:1Mhz-6Mhz, order: 15
************************************************************/
`define SAFE_DESIGN

module fir_guide    (
    input                rstn,  //复位,低有效
    input                clk,   //工作频率,即采样频率
    input                en,    //输入数据有效信号
    input        [11:0]  xin,   //输入混合频率的信号数据
    output               valid, //输出数据有效信号
    output       [28:0]  yout   //输出数据,低频信号,即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) 系数对称,16个移位寄存器数据进行首位相加
    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个乘法器
    // 滤波器系数,已经过一定倍数的放大
    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 ;
    wire        [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
    //如果对时序要求不高,可以直接用乘号
    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) 积分累加,825bit数据 - > 129bit 数据
    //数据有效延时
    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
    //加法运算时,分多个周期进行流水,优化时序
    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 
    //一步计算累加结果,但是实际中时序非常危险
    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 编写如下,主要功能就是不间断连续的输入 250KHz 与 7.5MHz 的正弦波混合信号数据。输入的混合信号数据也可由 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  //周期送入数据控制
                    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

◆仿真结果

由下图仿真结果可知,经过 FIR 滤波器后的信号只有一种低频率信号(250KHz),高频信号(7.5MHz)被滤除了。而且输出波形是连续的,能够持续输出。

但是,如红圈所示,波形起始部分呈不规则状态,对此进行放大。

图片

波形起始端放大后如下图所示,可见不规则波形的时间段,即两根竖线之间的时间间隔是16 个时钟周期。

因为数据是串行输入,设计中使用了 16 组延时寄存器,所以滤波后的第一个正常点应该较第一个滤波数据输出时刻延迟 16 个时钟周期。即数据输出有效信号 valid 应该再延迟 16 个时钟周期,则会使输出波形更加完美。

图片

附录:matlab 使用

◆生成 FIR 滤波器系数

打开 matlab,在命令窗口输入命令: fdatool。

然后会打开如下窗口,按照 FIR 滤波器参数进行设置。

这里选择的 FIR 实现方法是最小二乘法(Least-squares),不同的实现方式滤波效果也不同。

图片

点击 File -> Export

将滤波器参数输出,存到变量 coef 中,如下图所示。

图片

此时 coef 变量应该是浮点型数据。对其进行一定倍数的相乘扩大,然后取其近似的定点型数据作为设计中的 FIR 滤波器参数。这里取扩大倍数为 2048,结果如下所示。

图片

◆生成输入的混合信号

利用 matlab 生成混合的输入信号参考代码如下。

信号为无符号定点型数据,位宽宽度为 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 ;        % 信号周期
Num         = Fs * T ;      % 周期内信号采样点数
t           = (0:Num-1)/Fs ;      % 离散时间
cosx        = cos(2*pi*fc*t) ;    % 中心频率正弦信号
cosn        = cos(2*pi*fn*t) ;    % 杂波信号
cosy        = mapminmax(cosx + cosn) ;     %幅值扩展到(-1,1) 之间
cosy_dig    = floor((2^11-1) * cosy + 2^11) ;     %幅值扩展到 0~4095
fid         = fopen('cosx0p25m7p5m12bit.txt', 'wt') ;  %写数据文件
fprintf(fid, '%x\\n', cosy_dig) ;
fclose(fid) ;

%时域波形
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)) ;
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 滤波器
    +关注

    关注

    160

    文章

    7703

    浏览量

    177421
  • 寄存器
    +关注

    关注

    31

    文章

    5292

    浏览量

    119796
  • FIR
    FIR
    +关注

    关注

    4

    文章

    146

    浏览量

    33061
收藏 人收藏

    评论

    相关推荐

    DSP in FPGA:FIR滤波器(一)

    FIR 滤波器广泛应用于数字信号处理中,主要功能就是将不感兴趣的信号滤除,留下有用信号。##全并行FIR滤波器结构
    发表于 06-27 10:02 9291次阅读

    matlab与FPGA数字信号处理系列 Verilog 实现并行 FIR 滤波器

    在 FPGA 实现 FIR 滤波器时,最常用的是直接型结构,简单方便,在实现直接型结构时,可以选择串行结构/并行结构/分布式结构。 并行结构即并行
    发表于 05-24 07:48

    并行FIR滤波器Verilog设计

    本文将简单介绍FIR滤波器的原理,详细介绍使用Verilog HDL设计并行FIR滤波器的流程和
    发表于 09-25 17:44

    FIR并行滤波器设计

    FIR并行滤波器设计 数字滤波器可以滤除多余的噪声,扩展信号频带,完成信号预调,改变信号的特定频谱分量,从而得到预期的结果。数字滤波器在D
    发表于 01-16 09:47 1414次阅读
    <b class='flag-5'>FIR</b><b class='flag-5'>并行</b><b class='flag-5'>滤波器</b>设计

    基于流水线技术的并行高效FIR滤波器设计

    基于流水线技术的并行高效FIR滤波器设计 基于流水线技术,利用FPGA进行并行可重复配置高精度的FIR
    发表于 03-28 15:12 804次阅读
    基于流水线技术的<b class='flag-5'>并行</b>高效<b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>设计

    基于流水线的并行FIR滤波器设计

    基于流水线技术,利用FPGA进行并行可重复配置高精度的 FIR滤波器 设计。使用VHDL可以很方便地改变滤波器的系数和阶数。在DSP中采用这种FIR
    发表于 07-18 17:09 63次下载
    基于流水线的<b class='flag-5'>并行</b><b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>设计

    基于位并行DA结构的高速FIR滤波器

    基于位并行DA结构的高速FIR滤波器_周云
    发表于 01-07 21:39 4次下载

    基于FPGA的横向FIR滤波器设计详解

    在理论的基础上详细阐述了如何基于Verilog HDL搭建的数字电路,来完成来完成FIR横向滤波器的设计。
    的头像 发表于 07-08 08:33 5852次阅读

    如何使用FPGA实现实现高速并行FIR滤波器

    提出了一种基于多相滤波器并行有限脉冲响应(finite impulse response,FIR滤波器结构,可以有效提高滤波器运算的吞吐
    发表于 01-28 17:22 15次下载
    如何使用FPGA实现实现高速<b class='flag-5'>并行</b><b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>

    如何使用FPGA实现实现高速并行FIR滤波器

    提出了一种基于多相滤波器并行有限脉冲响应(finite impulse response,FIR滤波器结构,可以有效提高滤波器运算的吞吐
    发表于 01-28 17:22 7次下载
    如何使用FPGA实现实现高速<b class='flag-5'>并行</b><b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>

    Verilog并行FIR滤波器设计

    FIR(Finite Impulse Response)滤波器是一种有限长单位冲激响应滤波器,又称为非递归型滤波器FIR
    的头像 发表于 03-27 11:33 902次阅读
    <b class='flag-5'>Verilog</b><b class='flag-5'>并行</b><b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>设计

    Verilog串行FIR滤波器设计

    设计参数不变,与并行 FIR 滤波器参数一致。即,输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号,经过 FIR 滤波器后,
    的头像 发表于 03-27 11:36 803次阅读
    <b class='flag-5'>Verilog</b>串行<b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>设计

    并行FIR滤波器MATLAB与FPGA实现

    本文介绍了设计滤波器的FPGA实现步骤,并结合杜勇老师的书籍中的并行FIR滤波器部分进行一步步实现硬件设计,对书中的架构做了复现以及解读,并进行了仿真验证。
    的头像 发表于 05-24 10:57 1018次阅读
    <b class='flag-5'>并行</b><b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>MATLAB与FPGA实现

    Verilog串行FIR滤波器设计

    设计参数不变,与并行 FIR 滤波器参数一致。即,输入频率为 7.5 MHz 和 250 KHz 的正弦波混合信号,经过 FIR 滤波器后,
    的头像 发表于 06-01 11:08 775次阅读
    <b class='flag-5'>Verilog</b>串行<b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>设计

    FPGA的数字信号处理:Verilog实现简单的FIR滤波器

    该项目介绍了如何使用 Verilog 实现具有预生成系数的简单 FIR 滤波器
    的头像 发表于 06-07 14:51 3515次阅读
    FPGA的数字信号处理:<b class='flag-5'>Verilog</b>实现简单的<b class='flag-5'>FIR</b><b class='flag-5'>滤波器</b>