当前位置: 首页 > news >正文

FPGA 数字信号处理(二):并行 FIR 滤波器的 Verilog 全流程设计与实现

前言

作为 FPGA 数字信号处理系列的第二篇,本文聚焦 DSP 系统中最常用的 FIR 滤波器,从基础理论到硬件落地,完整讲解15 阶低通并行 FIR 滤波器的设计全流程:包含 FIR 滤波器原理推导、MATLAB 系数量化、Verilog 并行架构实现、Testbench 文件级仿真验证,以及最终的工程资源与性能分析,所有代码与工程均可直接复现。

一、数字滤波器分类与选型

数字滤波器是数字信号处理的核心模块,通过对输入序列进行数学运算,提取特定频率分量、抑制噪声或干扰。从实现结构上可分为两大类:FIR(有限长单位冲激响应)与 IIR(无限长单位冲激响应),二者核心差异如下:

表格

特性维度FIR 滤波器IIR 滤波器
相位特性可实现严格线性相位,信号无相位失真非线性相位,不同频率分量延时不同
系统稳定性无反馈回路,系统绝对稳定存在反馈环路,设计不当易出现振荡
硬件资源阶数越高资源消耗越大相同滤波性能下资源占用显著更少
设计难度简单直观,窗函数、最优法均可快速实现需兼顾幅度响应与稳定性,设计复杂度高

线性相位的工程意义

绝大多数工程场景优先选择 FIR 滤波器,核心原因是其线性相位特性—— 当滤波器系数满足对称条件时,通带内所有频率分量的群延时完全一致,信号波形不会发生相位失真。

  • 时域角度:输入信号仅产生固定的整体延时,波形形状保持不变;
  • 频域角度:各频率分量的相对相位关系保持恒定,不会出现信号畸变。

对于调制解调、图像信号处理、高速数据采集等对波形保真度要求高的场景,线性相位是硬性要求;仅当只关注频率成分、不关心波形失真时(如单纯频谱提取),可选用 IIR 滤波器节省资源。

二、FIR 滤波器核心原理

2.1 卷积运算本质

FIR 滤波器的输出是输入信号x(n)与单位冲激响应h(n)的线性卷积,公式如下: \(y(n) = \sum_{k=0}^{N-1} h(k) \cdot x(n-k)\) 其中N为滤波器抽头数(阶数 + 1),h(k)为滤波器系数。

从硬件角度看,FIR 的本质是抽头延迟线 + 乘法器阵列 + 加法器链:输入信号逐级寄存形成延迟链,每一级延迟信号与对应系数相乘,所有乘积相加得到最终输出。

2.2 直接型硬件架构

FIR 有直接型、级联型、频率采样型、格型四种结构,其中直接型结构最贴合 FPGA 的硬件实现逻辑,也是本文采用的架构。

对于 N 抽头的线性相位 FIR,系数满足偶对称h(k) = h(N-1-k),因此可以将对称位置的输入数据先相加、再与系数相乘,乘法器数量直接减少一半,大幅降低硬件资源消耗。

以本文 16 抽头(15 阶)FIR 为例:16 个系数两两对称,仅需 8 个乘法器即可完成运算,这也是后续 Verilog 代码的核心优化思路。

三、MATLAB 滤波器系数设计与量化

FPGA 实现 FIR 的第一步是完成系数设计与量化:先通过 MATLAB 设计满足指标的浮点系数,再量化为定点整数适配 FPGA 的定点运算逻辑。

3.1 设计指标

  • 采样频率:2kHz
  • 滤波器类型:低通
  • 截止频率:500Hz
  • 滤波器阶数:15 阶(抽头长度 16)
  • 系数量化位宽:12bit 有符号
  • 输入数据位宽:12bit 有符号

3.2 MATLAB 完整实现代码

采用汉明窗函数法设计浮点系数,完成 12bit 定点量化,并输出可直接用于 Verilog 的十六进制系数,同时对比量化前后的幅频响应:

matlab

%% 15阶低通FIR滤波器设计与量化 clear; clc; close all; % 设计参数 Fs = 2000; % 采样频率 Hz Fcut = 500; % 截止频率 Hz N_order = 15; % 滤波器阶数 width_coeff = 12; % 系数量化位宽 % 窗函数法设计浮点系数 b = fir1(N_order, Fcut/(Fs/2), 'low', hamming(N_order+1)); % 系数量化为12bit有符号整数(Q11格式:1位符号+11位小数) b_quant = round(b * 2^(width_coeff-1)); b_quant = int16(b_quant); % 打印十进制与十六进制系数 fprintf('十进制系数:\n'); disp(b_quant); fprintf('十六进制系数(3位):\n'); disp(dec2hex(b_quant, 3)); % 幅频响应对比 figure; freqz(b, 1, 1024, Fs); hold on; freqz(double(b_quant)/2^(width_coeff-1), 1, 1024, Fs); legend('浮点系数','12bit量化系数'); title('浮点与量化后滤波器幅频响应对比'); grid on;

3.3 量化注意事项

量化位数直接决定滤波精度与资源消耗,设计时需折中权衡:

  • 量化位宽越低,DSP、寄存器资源越少,但通带波纹增大、阻带衰减下降;
  • 必须在 MATLAB 中提前验证量化后的频率响应,确保满足设计指标后再移植到 FPGA。

本文量化后的 8 个对称系数(十六进制)为:000ffd00f02ef8bef924e7ff,与后续 Verilog 代码一一对应。

四、Verilog 并行 FIR 架构实现

并行结构的核心是:所有乘法运算在同一时钟周期内并行完成,每个时钟周期输出一个滤波结果,吞吐率与系统时钟频率一致,适合高速信号处理场景。

整体架构分为四级流水线:输入移位寄存器 → 对称数据相加 → 系数乘法运算 → 乘积累加输出

4.1 模块接口定义

verilog

module fir_parallel_15taps ( input rst, // 复位信号,高电平有效 input clk, // 系统时钟,频率2kHz input signed [11:0] Xin, // 输入数据,12bit有符号 output signed [28:0] Yout // 输出数据,29bit全分辨率 );

位宽计算说明:12bit 系数 × 13bit 相加数据 = 25bit 有符号乘积;8 个 25bit 数累加需扩展 3bit 位宽,最终输出 29bit 全分辨率结果,无截位精度损失。

4.2 输入移位寄存器链

将输入数据逐级寄存,形成 16 级延迟线,对应卷积公式中的x(n-k)

verilog

reg signed [11:0] Xin_Reg [15:0]; // 16级移位寄存器,每级12bit位宽 reg [3:0] i,j; always @(posedge clk or posedge rst) begin if (rst) begin // 复位时所有寄存器清零 for (i = 0; i < 16; i = i + 1) Xin_Reg[i] <= 12'd0; end else begin // 数据移位:新数据进入第0级,其余逐级后移 for (j = 0; j < 15; j = j + 1) Xin_Reg[j+1] <= Xin_Reg[j]; Xin_Reg[0] <= Xin; end end

4.3 对称系数数据相加

利用系数对称性,将对称位置的输入数据先相加,将 16 路乘法运算缩减为 8 路:

verilog

reg signed [12:0] Add_Reg [7:0]; // 相加后位宽扩展1bit,共13bit有符号 always @(posedge clk or posedge rst) begin if (rst) begin for (i = 0; i < 8; i = i + 1) Add_Reg[i] <= 13'd0; end else begin // 符号位扩展后相加,避免有符号数运算溢出错误 for (i = 0; i < 8; i = i + 1) Add_Reg[i] <= {Xin_Reg[i][11], Xin_Reg[i]} + {Xin_Reg[15-i][11], Xin_Reg[15-i]}; end end

关键细节:两个 12bit 有符号数相加前,必须通过拼接运算符{}扩展符号位,否则负数运算会出现符号错误,导致结果异常。

4.4 乘法器阵列

例化 8 个带寄存器输出的硬件乘法器 IP 核(Vivado 中mult_genIP),完成系数与数据的乘法运算:

verilog

// 8个12bit量化系数(利用对称性缩减后) wire signed [11:0] coe [7:0]; assign coe[0] = 12'h000; assign coe[1] = 12'hffd; assign coe[2] = 12'h00f; assign coe[3] = 12'h02e; assign coe[4] = 12'hf8b; assign coe[5] = 12'hef9; assign coe[6] = 12'h24e; assign coe[7] = 12'h7ff; // 乘法器输出:12×13bit有符号乘法,结果25bit有符号 wire signed [24:0] Mout [7:0]; // 例化8个乘法器IP核 mult_gen_0 Umult0 (.CLK(clk), .A(coe[0]), .B(Add_Reg[0]), .P(Mout[0])); mult_gen_0 Umult1 (.CLK(clk), .A(coe[1]), .B(Add_Reg[1]), .P(Mout[1])); mult_gen_0 Umult2 (.CLK(clk), .A(coe[2]), .B(Add_Reg[2]), .P(Mout[2])); mult_gen_0 Umult3 (.CLK(clk), .A(coe[3]), .B(Add_Reg[3]), .P(Mout[3])); mult_gen_0 Umult4 (.CLK(clk), .A(coe[4]), .B(Add_Reg[4]), .P(Mout[4])); mult_gen_0 Umult5 (.CLK(clk), .A(coe[5]), .B(Add_Reg[5]), .P(Mout[5])); mult_gen_0 Umult6 (.CLK(clk), .A(coe[6]), .B(Add_Reg[6]), .P(Mout[6])); mult_gen_0 Umult7 (.CLK(clk), .A(coe[7]), .B(Add_Reg[7]), .P(Mout[7]));

IP 配置说明:mult_gen_0配置为有符号乘法,A 端口 12bit、B 端口 13bit,开启输出寄存器,匹配流水线时序。

4.5 乘积累加输出

将 8 路乘法结果相加,得到最终滤波输出:

verilog

reg signed [28:0] sum; reg signed [28:0] yout; reg [3:0] k; always @(posedge clk or posedge rst) begin if (rst) begin sum <= 29'd0; yout <= 29'd0; end else begin yout <= sum; // 寄存输出,改善时序收敛 sum = 29'd0; // 累加前清零 for (k = 0; k < 8; k = k + 1) sum = sum + Mout[k]; // 8个乘积结果累加 end end assign Yout = yout; endmodule

五、Testbench 文件级仿真验证

为了精准验证滤波效果,采用文件读写方式搭建 Testbench:从 TXT 文件读取 MATLAB 生成的测试激励,将滤波结果写回 TXT 文件,便于后续在 MATLAB 中做定量对比与分析。

5.1 完整 Testbench 代码

verilog

`timescale 1ns / 1ps module tb_fir_parallel; // 参数定义 parameter CLK_PERIOD = 500000; // 2kHz时钟,周期500000ns(0.5ms) parameter DATA_NUM = 1024; // 测试数据总点数 // 信号定义 reg clk; reg rst; reg signed [11:0] din; wire signed [28:0] dout; // 例化待测FIR模块 fir_parallel_15taps u_fir ( .rst(rst), .clk(clk), .Xin(din), .Yout(dout) ); // 生成系统时钟 initial begin clk = 0; forever #(CLK_PERIOD/2) clk = ~clk; end // 读取TXT激励数据 reg [11:0] stimulus [1:DATA_NUM]; integer i; initial begin $readmemb("sin_input.txt", stimulus); // 读取二进制格式数据文件 i = 0; rst = 1; #(CLK_PERIOD*2); rst = 0; repeat(DATA_NUM) begin i = i + 1; din = stimulus[i]; #CLK_PERIOD; end $finish; end // 将滤波结果写入TXT文件 integer file_out; initial begin file_out = $fopen("fir_output.txt"); if (!file_out) begin $display("Error: cannot open output file!"); $finish; end end wire rst_write = clk & (~rst); // 复位期间禁止写入数据 always @(posedge rst_write) begin $fdisplay(file_out, "%d", dout); end endmodule

5.2 仿真流程说明

  1. 先用 MATLAB 生成测试信号(如 200Hz+800Hz 混合正弦信号、白噪声信号),量化为 12bit 后写入sin_input.txt
  2. Testbench 通过$readmemb系统任务读取数据,逐周期输入到 FIR 模块;
  3. 滤波结果通过$fdisplay系统任务写入fir_output.txt
  4. 将输出文件导入 MATLAB,绘制时域波形与幅频曲线,定量验证滤波效果。

5.3 文件操作注意事项

  • 数据文件需放在仿真工作目录下,否则需填写完整绝对路径;
  • 路径分隔符使用正斜杠/,与 Windows 系统默认的反斜杠\不同;
  • 读取二进制格式用$readmemb,读取十六进制格式用$readmemh,需与文件内数据格式匹配。

六、仿真结果分析

6.1 混合正弦信号滤波

输入信号为 200Hz+800Hz 的混合正弦波,经过 500Hz 低通滤波后:

  • 低于截止频率的 200Hz 分量完整保留,幅度衰减符合通带指标;
  • 高于截止频率的 800Hz 分量被大幅衰减,达到阻带抑制要求;
  • 输出信号波形平滑,无明显相位失真,验证了线性相位特性。

6.2 白噪声信号滤波

输入白噪声信号经过低通滤波后,高频分量被显著抑制,输出信号频谱集中在 0~500Hz 范围内,与设计截止频率一致,滤波效果符合预期。

七、资源与性能分析

以 Xilinx Artix-7 系列 FPGA 为例,本设计综合后的核心资源占用与性能如下:

表格

资源类型占用数量说明
DSP48E18 个对应 8 个硬件乘法器,利用对称性缩减了一半
触发器 FF约 150 个移位寄存器、流水线寄存器、输出寄存器
LUT约 100 个加法逻辑、控制逻辑与布线资源

性能特点

  • 吞吐率:每个时钟周期输出 1 个结果,最高吞吐率等于系统时钟频率;
  • 延迟:从输入到输出共 3 级流水线,总延迟约 3~4 个时钟周期;
  • 适用场景:中低阶、高速率的滤波需求,如高速 AD 采样后实时滤波。

八、设计关键注意事项

  1. 有符号数运算规范:Verilog 中进行带符号数加减乘时,必须保证位宽匹配、符号位正确扩展,避免出现符号错误导致的功能异常。
  2. 系数量化验证:量化前必须在 MATLAB 中验证量化后的频率响应,位宽不足会导致阻带衰减不达标、通带波纹增大。
  3. 时序优化方法:高阶并行 FIR 的累加链易成为关键路径,可采用加法树结构、插入流水线寄存器提升最高运行频率。
  4. 输出截位策略:全分辨率输出位宽较大,实际工程中可根据动态范围需求截位,进一步节省后续模块资源。

九、完整工程下载

本文配套完整可运行 Vivado 工程包,包含 Verilog 源码、Testbench、MATLAB 系数生成脚本、仿真脚本、测试数据文件,解压后可直接编译运行:

工程下载地址:https://download.csdn.net/download/fpgadesigner/10462288

总结与预告

本文完整实现了基于系数对称性优化的并行 FIR 滤波器,从 MATLAB 系数设计到 Verilog 硬件落地,覆盖了 FPGA 数字滤波的全流程。并行结构凭借高吞吐率的优势,在高速信号处理场景中应用广泛,但资源随阶数线性增长的特性也限制了其在高阶滤波器中的使用。

后续系列文章将继续讲解:

  • 串行结构 FIR 滤波器的 Verilog 设计
  • 分布式算术(DA)结构 FIR 实现
  • Vivado/Quartus FIR IP 核的调用与配置
  • 多相滤波、半带滤波器等高级结构
http://www.gsyq.cn/news/1524068.html

相关文章:

  • 2026重庆二手名表回收怎么选?本地7家实体门店实测对比行业避坑指南 - 薛定谔的梨花猫
  • 2026年成都CPPM采购经理报名资料费用和试听课怎么领取?众智商学院www.zzpxedu.com、400-068-2368、冯老师18610089571说明 - 众智商学院官方
  • 中山黄金回本地可上门服务。收避坑必看!正规商家实测对比,安全变现指南 - zzlzzl6688
  • 合肥没达到普高线怎么参加高考?学校推荐! - 小张zc
  • 2026 汕头黄金回收测评报告 海量用户真实打分汇总 - 靖昱黄金回收
  • 063、STM32项目分享:智能儿童防丢书包系统
  • 深入解析MPC823 LCD控制器:从DMA与FIFO原理到嵌入式GUI驱动实战
  • MiniMax M3开源:稀疏注意力架构重塑长上下文游戏规则
  • 2026年亳州中考失利不用慌!合肥这所卫校3+2医学影像班,五年大专毕业进医院 官方最新发布 - cc江江
  • 2026上海家装质价比报告:七家让业主“花得值、住得安”的企业 - 速递信息
  • 美团礼品卡回收新手操作教程(2026年最新版) - 可可收公众号
  • 2026年南京抖音推广公司怎么选?核心维度与实操标准 - 速递信息
  • MPC8272 USB控制器参数RAM与缓冲区描述符机制深度解析
  • 2026 浙江温州 AI 营销服务商 TOP5:GEO 技术实力榜单 - 速递信息
  • MPC823 SCC2 IrDA驱动开发:从协议原理到寄存器配置实战
  • 如何在Windows上轻松安装安卓应用:APK-Installer终极完整指南
  • qmcdump:开源音频解密工具,让QQ音乐加密格式重获自由
  • 英雄联盟Akari助手:提升游戏效率的智能工具箱
  • MPC8540 e500核心L1缓存与MMU寄存器配置实战指南
  • 2026心理健康指导师证书报考全解 | 报考条件、有用吗、怎么考、含金量怎么样、学校心理咨询室就业方向、考试内容、拿证时间、官方报名渠道一文讲透 - 教育推荐官【官方】
  • Windows系统文件bcryptprimitives.dll文件丢失找不到问题解决
  • 2026年安徽初三考不上高中可以上什么卫校?三年制中专和3+2汇总 - 小张zc
  • 2026年众智商学院六西格玛长春绿带黑带报名费用怎么确认?资料试听课班期咨询入口官网400冯老师 - 众智商学院官方
  • 2026山东一卡通回收价格行情以及安全快捷回收流程详解 - 可可收公众号
  • 嵌入式网络QoS与流控:基于MPC8313E eTSEC的硬件实现详解
  • 东莞黄金回收哪家口碑好?避坑必看!正规商家实测对比,安全变现指南 - zzlzzl6688
  • PotPlayer字幕翻译插件完全指南:3步实现免费实时双语字幕
  • 5分钟掌握专业级抖音内容备份方案:从单视频到批量管理的完整指南
  • 斜瓦天沟案例|宝山区天馨花园斜瓦天沟防水 - 十大品牌榜单
  • 如何快速解决老游戏兼容性问题:DDrawCompat终极修复方案完整指南