FPGA实战(01):基于对称系数的7阶FIR滤波器设计与仿真- 完整代码

发布时间:2026/6/12 13:39:11

FPGA实战(01):基于对称系数的7阶FIR滤波器设计与仿真- 完整代码 一、前言在数字信号处理中FIR有限长单位冲激响应滤波器因其线性相位、稳定易实现等优点被广泛使用。本文基于Verilog HDL设计了一个7阶对称系数FIR滤波器输入为2位有符号数输出为16位有符号数并通过ModelSim/Vivado进行仿真验证。文章将详细分析代码的功能点与创新点帮助读者快速掌握FPGA实现FIR滤波器的核心技巧。二、整体架构与模块说明设计包含两个文件fir_tops.v顶层滤波器模块test_fir.v仿真测试激励顶层模块主要包含移位寄存器链r_x0~r_x67个乘法器IP核multer累加器与输出寄存器状态机IDLE/RUN三、功能点详解3.1 对称系数与参数化设计parameter P_B0 14d82 ; parameter P_B1 14d317 ; parameter P_B2 14d788 ; parameter P_B3 14d1023 ; parameter P_B4 14d788 ; parameter P_B5 14d317 ; parameter P_B6 14d82 ;系数呈中心对称B0B6, B1B5, B2B4这是FIR线性相位滤波器的典型特征。使用parameter定义系数便于后期修改和移植。3.2 移位寄存器链always (posedge i_clk or posedge i_rst) begin if (i_rst) r_x0 2d0; else r_x0 i_din; end always (posedge i_clk) r_x1 r_x0; ... // r_x2 ~ r_x6 类似每个时钟周期输入数据依次向右移动形成7个抽头tap。复位时仅复位第一级后级寄存器无复位数据会自然被新输入覆盖符合常规流水线设计。3.3 乘法器IP实例化multer multer_u0 ( .CLK (i_clk), .A (r_x0), .B (P_B0), .SCLR(i_rst), .P (w_r0) ); ... // 共7个乘法器使用IP核实现有符号乘法。输入A为2位B为14位输出P为16位。SCLR同步清零端在复位时清零输出确保复位后累加初始状态正确。3.4 全流水线累加always (posedge i_clk) begin r_sum w_r0 w_r1 w_r2 w_r3 w_r4 w_r5 w_r6; end直接将7个乘法结果相加利用FPGA内部加法器资源形成加法树。整个计算路径为纯流水线结构每个时钟周期完成一次完整的乘累加运算。3.5 输出寄存器always (posedge i_clk or posedge i_rst) begin if (i_rst) ro_dout 16d0; else ro_dout r_sum; end assign o_dout ro_dout;最后一级寄存器输出消除累加组合逻辑的毛刺同时实现一个时钟周期的输出延迟便于与下游模块接口。3.6 状态机框架parameter P_ST_IDLE 2b01, P_ST_RUN 2b10; assign p_st_idle2p_st_run_start state_cP_ST_IDLE (1); assign p_st_run2p_st_idle_start state_cP_ST_RUN (1);设计中预留了经典的两状态状态机框架。当前转换条件恒为1表示滤波器上电后立即持续运行。该框架可方便地扩展为外部信号控制的启动/停止模式例如接入数据有效标志或使能信号体现了模块的可扩展性。四、创新点提炼极低位宽输入2位输入仅为2位有符号数取值范围-2~1大幅降低乘法器资源消耗适用于语音、简单控制等低精度场景。对称系数与参数化系数以parameter形式集中定义且具备中心对称性。这一方面便于系数调优和重用另一方面为后续采用“对称抽头先加后乘”的优化方法减少乘法器数量提供了结构基础。测试激励的“脉冲簇”模式test_fir.v中持续交替输入01、00、11等模拟随机脉冲序列便于观察滤波器的瞬态响应和对称系数带来的波形平滑效果。结构清晰的模块化编程将移位、乘法、累加、输出分离每个always块职责单一符合FPGA设计规范利于综合与调试。同时例化统一的乘法器IP代码整洁且易于IP复用。五、仿真测试策略测试代码test_fir.v要点初始复位1000ns确保内部寄存器清零。数据每隔10ns或30ns变化一次形成不规则的输入流。使用#5周期反转时钟产生100MHz时钟周期10ns。预期结果读者可自行仿真验证当输入为0时输出应为0。当输入单个脉冲01即十进制1时输出应为系数序列的累加和。由于系数对称输出波形应对称。六、总结本文详细解析了一个7阶对称系数FIR滤波器的Verilog实现涵盖移位寄存器、乘法器IP、累加输出及状态机框架。该设计包含了数字信号处理与FPGA开发的典型元素参数化系数、流水线结构、有符号运算、模块化代码组织。读者可以此为基础轻松掌握FIR滤波器的FPGA实现方法并进一步拓展至更高阶数或系数可重载的灵活设计。工程源码与仿真文件已附于文中欢迎下载试用。如有疑问或改进想法欢迎评论区交流my_fir_top.vtimescale 1ns / 1ps module fir_tops( input i_clk , input i_rst , input signed [1:0] i_din , output signed [15:0] o_dout ); // // 参数P_ 前缀状态机用 P_ST_ 前缀 // parameter P_B0 14d82 ; parameter P_B1 14d317 ; parameter P_B2 14d788 ; parameter P_B3 14d1023 ; parameter P_B4 14d788 ; parameter P_B5 14d317 ; parameter P_B6 14d82 ; // // 寄存器声明 (Reg) // reg signed [1:0] r_x0; reg signed [1:0] r_x1; reg signed [1:0] r_x2; reg signed [1:0] r_x3; reg signed [1:0] r_x4; reg signed [1:0] r_x5; reg signed [1:0] r_x6; reg signed [15:0] r_sum; // 乘累加和 reg signed [15:0] ro_dout; // 输出寄存器 reg [ 1: 0] state_c ; reg [ 1: 0] state_n ; // // 线网声明 (Wire) // wire signed [15:0] w_r0; wire signed [15:0] w_r1; wire signed [15:0] w_r2; wire signed [15:0] w_r3; wire signed [15:0] w_r4; wire signed [15:0] w_r5; wire signed [15:0] w_r6; wire p_st_idle2p_st_run_start ; wire p_st_run2p_st_idle_start ; // // 连续赋值 (Assign) // assign o_dout ro_dout; // // 乘累加和 // parameter P_ST_IDLE 2b01 ; parameter P_ST_RUN 2b10 ; always (posedge i_clk or posedge i_rst) begin if (i_rst) begin state_c P_ST_IDLE ; end else begin state_c state_n; end end always (*) begin case(state_c) P_ST_IDLE :begin if(p_st_idle2p_st_run_start) state_n P_ST_RUN ; else state_n state_c ; end P_ST_RUN :begin if(p_st_run2p_st_idle_start) state_n P_ST_IDLE ; else state_n state_c ; end default : state_n P_ST_IDLE ; endcase end assign p_st_idle2p_st_run_start state_cP_ST_IDLE (1); assign p_st_run2p_st_idle_start state_cP_ST_RUN (1); // // 时序逻辑 always 块移位寄存器 x0 ~ x6 // always (posedge i_clk or posedge i_rst) begin if (i_rst) r_x0 2d0; else r_x0 i_din; end always (posedge i_clk) begin r_x1 r_x0; end always (posedge i_clk) begin r_x2 r_x1; end always (posedge i_clk) begin r_x3 r_x2; end always (posedge i_clk) begin r_x4 r_x3; end always (posedge i_clk) begin r_x5 r_x4; end always (posedge i_clk) begin r_x6 r_x5; end always (posedge i_clk )begin r_sum w_r0 w_r1 w_r2 w_r3 w_r4 w_r5 w_r6 ; end // // 时序逻辑 always 块输出寄存器 // always (posedge i_clk or posedge i_rst) begin if (i_rst) ro_dout 16d0; else ro_dout r_sum; end // // 乘法器 IP 实例化保持不变 // multer multer_u0 ( .CLK (i_clk), .A (r_x0), .B (P_B0), .SCLR(i_rst), .P (w_r0) ); multer multer_u1 ( .CLK (i_clk), .A (r_x1), .B (P_B1), .SCLR(i_rst), .P (w_r1) ); multer multer_u2 ( .CLK (i_clk), .A (r_x2), .B (P_B2), .SCLR(i_rst), .P (w_r2) ); multer multer_u3 ( .CLK (i_clk), .A (r_x3), .B (P_B3), .SCLR(i_rst), .P (w_r3) ); multer multer_u4 ( .CLK (i_clk), .A (r_x4), .B (P_B4), .SCLR(i_rst), .P (w_r4) ); multer multer_u5 ( .CLK (i_clk), .A (r_x5), .B (P_B5), .SCLR(i_rst), .P (w_r5) ); multer multer_u6 ( .CLK (i_clk), .A (r_x6), .B (P_B6), .SCLR(i_rst), .P (w_r6) ); endmoduletb_my_fir_top.vtimescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 2022/03/26 23:21:32 // Design Name: // Module Name: test_fir // Project Name: // Target Devices: // Tool Versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module test_fir; reg i_clk; reg i_rst; reg signed[1:0]i_din; wire signed[15:0]o_dout; fir_tops fir_tops_u( .i_clk (i_clk), .i_rst (i_rst), .i_din (i_din), .o_dout (o_dout) ); initial begin i_clk1b1; i_rst1b1; i_din2b00; #1000 i_rst1b0; i_din2b01; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b11; #10 i_din2b00; #30 i_din2b01; #10 i_din2b00; end always #5 i_clk~i_clk; endmodule

相关新闻