FPGA 基于累加器的 FIR 滤波器原理与工程实例

发布时间:2026/6/25 16:18:13
FPGA 基于累加器的 FIR 滤波器原理与工程实例 一、FIR 滤波器基础理论1. FIR 数学公式有限长单位冲激响应滤波器FIR差分方程y[n]∑k0N−1​h[k]⋅x[n−k]N滤波器阶数抽头数h[k]滤波器系数固定对称线性相位x[n−k]当前与过去 N 个输入采样y[n]滤波输出。核心运算乘累加 MAC (Multiply-Accumulate)每输出 1 个采样需要 N 次乘法 N 次加法。2. 传统结构痛点直接并行 MACN 个乘法器阶数高时消耗大量 DSP48 资源 串行分时 MAC只用 1 个乘法器分时复用但需要时钟提速。基于累加器的 FIR是串行分时 MAC 的最简实现架构核心只用一组乘法器 累加寄存器适合资源受限 FPGA。二、基于累加器的 FIR 核心原理1. 架构核心思想将求和运算拆分为逐次乘累加sum0​sum1​sum2​y[n]​h[0]⋅x[n]sum0​h[1]⋅x[n−1]sum1​h[2]⋅x[n−2]…sumN−1​​流程拆解输入移位寄存器缓存 N 个历史采样 x[n],x[n−1],...,x[n−N1]计数器遍历 0~N-1依次取出系数h[k]和对应采样x[n−k]乘法器算出单路乘积送入累加器持续叠加一轮 N 次循环结束累加器输出滤波结果随后清零准备下一组采样。2. 硬件模块划分整体分 5 个子模块输入移位寄存器组Shift Register缓存连续 N 个输入采样每次新采样到来右移 1 位保存历史数据系数 ROM预存 FIR 抽头系数h[0]∼h[N−1]FPGA 用 Block ROM 实现系数可定点量化循环计数器Cnt0~N-1 循环计数同时作为 ROM 读地址、移位寄存器选择地址单路乘法器DSP48E1分时复用同一时刻只计算一组h[k]×x[n−k]累加器Accumulator带同步清零每次乘积输入持续相加计数到 N-1 时输出结果。3. 时序工作逻辑关键设滤波器阶数N8系统时钟远高于采样时钟过采样分时运算采样时钟上升沿采集新输入xnew​移位寄存器整体右移复位计数器、累加器系统时钟连续 8 拍拍 0cnt0 → 读 h [0]、取 x [n] → 乘积存入累加器拍 1cnt1 → 读 h [1]、取 x [n-1] → 累加器 原值 新乘积……拍 7cnt7 → 最后一组乘加累加器输出有效滤波值 y等待下一次采样触发重复循环。约束条件系统时钟频率 ≥ N × 采样频率保证在两次采样间隔内完成 N 次乘累加。4. 定点量化说明FPGA 必做浮点数系数无法直接硬件实现定点化处理MATLAB 生成浮点 h [k]放大2Q倍取整Q 为小数位宽常用 Q15、Q16输出累加后右移 Q 位还原幅值。例Q15 量化系数范围 [-1,1] → 乘以 32768 取 16 位整数存入 ROM。三、线性相位 FIR 优化节省资源绝大多数 FIR 采用对称系数 h[k]h[N−1−k]基于累加器架构可减半运算次数y[n]∑k0(N/2)−1​h[k]⋅(x[n−k]x[n−(N−1−k)])硬件改动先将对称位置两个采样相加再与系数相乘循环次数从 N 次变为 N/2 次大幅降低运算时钟要求累加器架构同样兼容。四、Verilog 工程实例8 阶低通 FIR基于累加器串行 MAC1. 参数定义阶数 N8输入位宽12bit 采样数据系数 Q15 定点 16bit累加器位宽32bit防止溢出系统时钟 50MHz采样频率 5MHz50M ≥ 8×5M满足时序。2. 完整代码verilogmodule fir_accumulator #( parameter TAP_NUM 8, // 滤波器阶数 parameter DATA_WIDTH 12, // 输入采样位宽 parameter COE_WIDTH 16, // 系数Q15位宽 parameter ACC_WIDTH 32, // 累加器位宽防溢出 parameter Q_BIT 15 // 定点小数位 ) ( input wire clk, // 50MHz系统时钟 input wire rst_n, // 低电平复位 input wire sample_en, // 采样使能5MHz input wire [DATA_WIDTH-1:0] x_in, // 输入采样 output reg y_valid, // 输出有效标志 output reg [DATA_WIDTH-1:0] y_out // 滤波输出 ); // 1. 移位寄存器缓存采样 reg [DATA_WIDTH-1:0] shift_reg [0:TAP_NUM-1]; integer i; always (posedge clk or negedge rst_n) begin if(!rst_n) begin for(i0; iTAP_NUM; ii1) shift_reg[i] d0; end else if(sample_en) begin shift_reg[0] x_in; for(i1; iTAP_NUM; ii1) shift_reg[i] shift_reg[i-1]; end end // 2. 系数ROM 8阶低通FIR Q15定点 reg [COE_WIDTH-1:0] coe_rom [0:TAP_NUM-1]; initial begin // MATLAB生成8阶低通系数 Q15量化 coe_rom[0] 16h0240; coe_rom[1] 16h0780; coe_rom[2] 16h0C80; coe_rom[3] 16h1000; coe_rom[4] 16h1000; coe_rom[5] 16h0C80; coe_rom[6] 16h0780; coe_rom[7] 16h0240; end // 3. 循环计数器 0~7 reg [3:0] cnt; always (posedge clk or negedge rst_n) begin if(!rst_n) begin cnt d0; end else if(sample_en) begin cnt d0; end else if(cnt TAP_NUM - 1) begin cnt cnt 1b1; end end // 4. 分时乘法器 wire [DATA_WIDTH-1:0] x_sel; wire [COE_WIDTH-1:0] h_sel; wire [ACC_WIDTH-1:0] mult_prod; assign x_sel shift_reg[cnt]; assign h_sel coe_rom[cnt]; // 乘法器有符号乘自动调用DSP48 assign mult_prod $signed(x_sel) * $signed(h_sel); // 5. 累加器核心 reg signed [ACC_WIDTH-1:0] accum; always (posedge clk or negedge rst_n) begin if(!rst_n) begin accum d0; end else if(sample_en) begin accum d0; // 新采样到来清空累加器 end else begin accum accum mult_prod; // 逐次累加乘积 end end // 6. 输出锁存与有效标志 always (posedge clk or negedge rst_n) begin if(!rst_n) begin y_valid 1b0; y_out d0; end else if(cnt TAP_NUM - 1) begin y_valid 1b1; // 右移Q_BIT位截断至输入位宽 y_out accum[ACC_WIDTH-1 : Q_BIT]; end else begin y_valid 1b0; end end endmodule五、代码关键逻辑解读移位寄存器sample_en采样时钟到来时存入新采样所有历史数据右移shift_reg[k]对应x[n−k]系数 ROMinitial块预存定点系数高阶滤波器可改用 IP 核 Block ROM 节省逻辑计数器时序采样使能时 cnt 清零之后每个系统时钟 1依次读取每一组采样与系数累加器工作每次采样刷新自动清零每个时钟叠加一次乘积完成全部 8 次乘加后输出定点缩放累加结果右移 15 位抵消 Q15 放大截取高位得到与输入同位宽输出。六、仿真验证思路ModelSim/MATLAB 联合MATLAB 生成正弦叠加带噪输入波形导出 txt 采样数据仿真激励读取采样驱动sample_en抓取y_out输出波形与 MATLAB 浮点 FIR 滤波结果对比观察y_valid仅在每轮 8 次运算结束时拉高输出平滑滤波波形高频噪声被抑制。七、架构优缺点分析优点资源占用极低仅使用 1 个硬件乘法器1 个 DSP48阶数提升不增加乘法器结构简单易实现无复杂并行布线时序收敛容易系数修改方便系数存在 ROM可动态更新实现可调滤波。缺点吞吐率受限完成一次输出需要 N 个系统时钟采样频率受系统时钟约束高阶滤波器时钟压力大N 很大时必须大幅提升系统时钟无法满足高速采样场景适用场景低速采集系统温感、音频、低频传感器、FPGA 逻辑资源紧张、滤波器阶数中等N128。八、拓展改进方案对称系数减半运算增加加法器先合并对称采样循环次数减半降低时钟频率要求多周期流水线累加在乘法器后插入寄存器切割关键路径提升最高系统时钟多通道时分复用多组输入共用同一套累加器 FIR进一步节省 DSP分布式 RAM 存采样高阶 FIR 时用 Block RAM 代替移位寄存器减少大量寄存器消耗。九、与并行 FIR 对比总结表格架构乘法器数量时钟要求资源消耗最高采样速率并行直接型 FIRN 个采样时钟即可极高最高基于累加器串行 FIR1 个N× 采样时钟极低低速基于累加器的 FIR 是面积换取速度的典型串行架构是 FPGA 入门 FIR 最经典、最容易理解的实现方式。for(i1; iTAP_NUM; ii1) shift_reg[i] shift_reg[i-1];什么意思逐行拆解这条移位寄存器代码verilogfor(i1; iTAP_NUM; ii1) shift_reg[i] shift_reg[i-1];1. 先看懂变量定义shift_reg是一个寄存器数组用来存 FIR 滤波器连续 N 个采样点verilogreg [DATA_WIDTH-1:0] shift_reg [0:TAP_NUM-1];TAP_NUMFIR 抽头总数例子里是 8数组下标shift_reg[0]、shift_reg[1] ... shift_reg[7]shift_reg[0]最新进来的采样x[n]shift_reg[1]上一拍采样x[n-1]shift_reg[2]前两拍采样x[n-2]……shift_reg[7]最早的旧采样x[n-7]2. for 循环执行逻辑硬件综合后等效移位链循环条件初始i1只要i TAP_NUM就执行一次赋值然后ii1以TAP_NUM8举例循环会依次执行这 7 条并行赋值verilogshift_reg[1] shift_reg[0]; shift_reg[2] shift_reg[1]; shift_reg[3] shift_reg[2]; shift_reg[4] shift_reg[3]; shift_reg[5] shift_reg[4]; shift_reg[6] shift_reg[5]; shift_reg[7] shift_reg[6];3. 整体移位流程配合前面一句完整移位逻辑是两段合在一起verilogshift_reg[0] x_in; // 第1步新数据放进最左边shift_reg[0] for(i1; iTAP_NUM; ii1) shift_reg[i] shift_reg[i-1]; // 第2步所有旧数据整体右移一格移位过程演示8 阶 FIR假设移位前[0]A(新)、[1]B、[2]C、[3]D、[4]E、[5]F、[6]G、[7]H采样使能到来先把新采样x_inX送入[0]再执行 for 循环移位shift_reg[1]取原来[0]的 Ashift_reg[2]取原来[1]的 B……shift_reg[7]取原来[6]的 G移位后状态[0]X、[1]A、[2]B、[3]C、[4]D、[5]E、[6]F、[7]G最末尾旧数据 H 被直接丢弃实现先进先出的采样缓存。4. 为什么 i 从 1 开始不从 0shift_reg[0]单独赋值新输入x_in不需要从左边拿数据如果 i 从 0 开始会出现shift_reg[0] shift_reg[-1]下标越界语法报错。5. 硬件层面本质Verilog 里always(posedge clk)内部的 for 循环是并行执行不是软件 C 语言串行循环 综合后生成一条级联移位寄存器链每来一次采样时钟整组采样集体右移一位专门给 FIR 提供延时序列x[n],x[n-1],...,x[n-N1]满足卷积公式的延时需求。6. 一句话总结这条 for 循环的作用 当有新采样输入时把移位寄存器里所有历史采样依次向右挪一格腾出第一个位置存放最新采样丢掉最老旧的采样为 FIR 滤波提供不同延时的输入数据。