FPGA 入门 44:FIR 滤波器入门——延迟线、乘加与 DSP48
更新时间:2026-09-12。本文是
fpga/入门层第 46 篇。前置:DSP48 初认识、定点数基础、数据类型与运算;深入:进阶 DSP48 与算术。
本文要回答的问题
- FIR 的差分方程和卷积是什么关系?「有限冲激响应」「线性相位」「群延迟」在时域和频域各是什么含义?
- 直接型、转置型、对称折叠型、多相分解在硬件上分别长什么样,关键路径和资源差在哪里?
- 一个 N 抽头 FIR 的延迟线、乘法器、加法树各自占什么资源?并行、串行复用、多通道复用三种吞吐与资源折中点怎么选?
- DSP48 的 A×B+C 结构为什么和 FIR 天然匹配?DSP 列上的级联走线如何让几百抽头滤波器仍然高频率运行?
- 系数设计从需求(采样率、通带/阻带、波纹、衰减)到 firwin 参数、到定点系数文件的完整流程是什么?
- valid/ready 流式接口、流水线延迟、边界样本(暖机)、复位与系数重载这些工程细节怎么处理?
- 怎么用冲激、阶跃、扫频、混频四种激励定量验证 FIR?信噪比和频响曲线如何在 testbench 里算出来?
读完本文,你应当能从一个滤波需求出发,完成系数设计、定点预算、结构选择、RTL 实现、资源与时序收敛、仿真验证的完整闭环,这也是所有线性 DSP 算法上 FPGA 的标准路径。
一、FIR 在算什么
y[n] = h0·x[n] + h1·x[n-1] + … + h(N-1)·x[n-(N-1)]
└──── 当前与过去 N 个采样,各乘固定系数后求和 ────┘
h[k]:抽头系数(firwin 生成、定点量化) N:抽头数/阶数
无反馈 → 永远稳定;系数对称 → 严格线性相位二、为什么适合 FPGA
- 计算是大量互相独立的乘加(MAC) → 可并行铺到 DSP48;
- 延迟线就是移位寄存器;
- 数据流规整、可流水线、周期确定(无取指/中断)。
三、转置型 FIR 骨架(时序友好,最常用)
module fir_transposed #(
parameter W = 16, N = 8,
parameter signed [W-1:0] H [0:N-1] = '{16'sd128 /* firwin 量化系数 */, 16'sd128}
)(
input logic clk, rst_n, valid,
input logic signed [W-1:0] din, // Q1.15
output logic signed [W-1:0] dout,
output logic out_valid
);
logic signed [2*W-1:0] acc [0:N-1];
integer k;
always_ff @(posedge clk) begin
if (!rst_n) begin
for (k=0;k<N;k++) acc[k] <= '0;
out_valid <= 1'b0;
end else if (valid) begin
acc[0] <= din * H[0]; // 第一级
for (k=1;k<N;k++)
acc[k] <= acc[k-1] + din * H[k]; // 带寄存器的加法链
out_valid <= 1'b1;
end else out_valid <= 1'b0;
end
// 实际工程:累加留保护位 + 舍入 + 饱和(见入门 45)
assign dout = acc[N-1][2*W-2 -: W]; // 取高 W 位回 Q1.15(按定标调整)
endmodule教学骨架:符号位、保护位、舍入与饱和要按 Q 格式精确处理,系数放
.coe/.mem用 firwin 量化后共用。
四、三种结构权衡
| 结构 | DSP 用量 | 吞吐 | 时序/关键路径 | 适用 |
|---|---|---|---|---|
| 直接型 | N(并行) | 高 | 加法链长、易紧张 | 抽头少 |
| 转置型 | N(并行) | 高 | 短、天然流水 | FPGA 最常用 |
| 串行/复用 | 1 个 | 1/N(需更高内钟) | 最好收敛 | 抽头多、采样率低、省资源 |
五、定点注意(衔接入门 45)
系数 h :firwin -> Q1.15 量化,位数太少频响失真
乘积 :16x16=32 位,注意有符号
累加 :N 项相加,保护位 ≥ ceil(log2 N),或逐级饱和
输出 :取高位 + 舍入(加 2^(n-1)) + 饱和,回目标 Q
资源 :确认综合成 DSP48,而不是 LUT 拼乘法六、验证
1. 冲激响应:只给一个 1,输出序列应恰好 == 系数 h (最强自检)
2. 阶跃响应:看收敛平滑、无异常尖峰
3. 正弦/扫频/混频:通带保留、阻带衰减;写文件用 Python 画频谱
4. 综合报告:DSP48 数量合理、WNS/WHS ≥ 0
仿真与上板共用同一套量化系数文件七、从卷积角度真正理解 FIR
FIR 的方程就是离散卷积:输出序列等于输入序列与系数序列(冲激响应)的卷积。可以这样建立直觉:向滤波器输入一个「冲激」(只有一个采样为 1,其余全 0),之后每个时钟输出依次吐出 h0、h1……h(N−1) 然后归零——滤波器的内部状态被这一个冲激逐个「摇」出来,所以系数序列又叫冲激响应。因为没有任何从输出回到输入的反馈项,这个序列长度有限(N 个样本)且无论系数怎么取系统都绝对稳定(不会自激起振),这就是「有限冲激响应」相对 IIR(无限冲激响应、含反馈、可能不稳定)的核心区别。
线性相位是 FIR 的另一大卖点。当系数对称(h[k]=h[N−1−k])或反对称时,所有频率分量经过滤波器的延迟相同,群延迟恒为 (N−1)/2 个采样点——波形形状不变,只是整体平移。音频不希望谐波相位错乱、通信脉冲不能被相位失真展宽、测量通道要对齐边沿,这些场景宁可多花乘法器也选线性相位 FIR。对称系数还带来硬件红利:先把 x[n−k] 与 x[n−(N−1−k)] 相加再乘同一个系数,乘法器数量减半。代价是延迟线和加法仍在,且群延迟固定为半采样的整数/半整数倍(奇数或偶数抽头各对应一种)。
频域视角下,卷积定理告诉我们 FIR 输出频谱等于输入频谱乘以滤波器频率响应;系数设计(窗函数法、Parks-McClellan 最优等波纹法、firwin)就是在给定抽头数预算下逼近目标频响。抽头越多,过渡带可以越窄、阻带衰减越深——这是「指标→N→DSP 数量」的直接换算关系。
八、四种结构的硬件对照
- 直接型(direct form):一条移位寄存器产生全部延迟样本,并行相乘后加法树求和。直观,但加法树在一个时钟周期内穿过 log2(N) 级宽加法,N 大时关键路径长;要靠在加法树插流水寄存器补救,延迟增加。
- 转置型(transposed):输入广播给所有乘法器,乘积注入「带寄存器的加法链」(每个乘积先与上一级的部分和相加再打一拍)。任意抽头数下,单周期内逻辑只有一次乘法加一次加法,频率与 N 几乎无关;代价是每级都有宽寄存器。FF 丰富的 FPGA 上几乎总是它胜出,本文骨架即转置型。
- 对称折叠型:利用线性相位的对称系数,延迟样本先两两相加,乘法器减半;结构仍可转置化。音频、传感器通道首选。
- 多相(polyphase):把系数按相位拆成子滤波器,配合上采样/下采样重排运算顺序,让「高采样率滤波再抽取」中大部分乘法在低速侧完成——重采样器、软件无线电 DDC/DUC 的标准结构,等价计算量可降一个抽取因子的倍数。
选择顺序:先看吞吐约束(采样率与时钟频率之比),再看 DSP 预算和对称性,最后看延迟敏感度。多数入门到中等复杂度场景,转置型或对称转置型是默认答案。
九、吞吐与资源的三个折中点
同样的 N 抽头 FIR 可以映射成三种机器:①全并行:N 个乘法器每拍出一个结果,N 个 DSP、最高吞吐;②时分复用:1 个 DSP 配双口 ROM 存系数和循环地址,内部时钟为采样率的 N 倍,N 拍完成一次累加,DSP 用量降到 1(再加控制开销),适合多通道低速采集;③多通道复用:一个乘法器阵列轮流服务 M 个通道,系数 ROM 按通道切换、延迟线改 RAM 结构,每通道成本降到约 1/M,通信里几十个语音/数据通道滤波的标准做法。用 定点数基础 的位宽预算加上 资源报告 的对账方法,可以在纸面上直接决定方案。
转置结构里累加器位宽逐拍增长,全宽度保留需要大量 FF,实际在中间级保持「乘积小数位 + log2(剩余级数) 保护位」即可;最后一级做舍入回目标宽度。若直接对每级都截位,舍入噪声会被后面的系数放大,信噪比明显变差——这是「省了寄存器丢了精度」的典型交易。
十、DSP48 级联:FIR 的物理主场
DSP48E1 内部就是 25×18 乘法器加 48 位加/累加器,并有专用的 ACIN/ACOUT、PCIN/PCOUT 级联端口:相邻 DSP tile 之间的部分和可以不走通用布线、直接在专用列线上级联。转置或加法树 FIR 把各乘法器的部分和沿 PCOUT 链传下去,整条加法链在 DSP 内部完成,外部只见输入、系数和最终和——这就是为什么 200 抽头滤波器仍能跑到几百 MHz。用好级联的编码要点:乘积和累加都保持有符号、寄存器放在 DSP 的输入和输出端(综合器会把相邻 FF 吸收进 DSP)、避免对中间和做异步复位、加法位宽不超过 48(超了要拆两列)。综合后在利用率报告确认「DSPs With PREADDINSEL/PCIN 使用」或对应级联计数,并看原理图确认部分和没有绕回 LUT(见 DSP48 初认识 与进阶 DSP48 与算术)。
十一、系数设计到文件落盘的完整流程
以「采样率 1MHz、截止 100kHz 低通、阻带衰减 60dB」为例:①firwin 选窗(60dB 对应布莱克曼或凯泽 beta≈5.7),用经验式估算 N(凯泽公式:过渡带越窄 N 越大,1MHz 采样下 10%过渡带大约三十多抽头,取奇数保证对称);②Python 生成浮点系数;③按 Q1.15 量化,检查量化后频响是否仍满足阻带衰减(量化会抬高旁瓣,不够就升到 18 位系数);④导出为 COE/MEM(每行一个有符号整数),RTL 用 $readmemh 初始化系数 ROM;⑤testbench 与 RTL 读同一个文件,杜绝「软件系数和硬件系数不一致」。注意验证两点:量化后系数和(直流增益)是否接近 1(否则输出幅值整体缩放),以及最大单抽头累加的位宽预算。整个流程应该脚本化,改指标一键重生成系数和测试向量。
十二、流式接口与边界工程
真实系统里 FIR 几乎总是 AXI-Stream 式流的一站:s_valid/s_ready 加 data,反压时延迟线和转置链都要停住(用时钟使能而不是门控时钟,见 同步设计原则);out_valid 是 in_valid 延迟固定流水级数的版本,用一级级 valid 移位生成。暖机(暖启动)边界:复位后前 N−1 个输出包含不完整的历史,按卷积数学本应等价于历史补零,明确让上游在这段时间忽略结果或用 valid 标记。系数可运行时重载时,重载期间要冻结输入或使用双缓冲(两个系数 bank 切换),避免半新半旧系数瞬间产生冲激。多通道复用时通道标签和数据同步打拍,防止串音。
十三、定量验证:从冲激到信噪比
四级测试层层收紧。冲激测试:输入一个 1,输出必须逐样本等于(定标后的)系数序列,任何不符就是移位或截位 bug,这是最强自检,几秒钟定位大多数结构性错误。阶跃测试:输入全幅阶跃,输出应平滑收敛到系数和(直流增益),检查是否有饱和尖峰和收敛拍数。正弦扫频/混频:喂入 0.45 截止频率与 1.3 截止频率两个正弦之和,导出输出样本到 Python 做 FFT,测量通带电平、阻带衰减、过渡带位置,与浮点黄金模型对比,误差应只来自预算内的量化噪声。量化信噪比:对噪声输入跑长序列,计算 RTL 输出相对浮点输出的误差功率,典型 16 位定点 FIR 应在 70dB 以上;若远低于该值,按「累加宽度→舍入方式→系数量化→溢出」顺序排查。最后上板时用 DDS 产生测试音、ILA/串口采回样本做同样的频谱分析,形成仿真到硬件的同一套指标(FFT 实现见进阶 FIR/FFT 实现)。FIR 虽简单,但它练的是数字信号处理上 FPGA 的全套基本功,值得反复实现三版:直接型、转置型、复用型。最后讲一个学习心法:不要只让 testbench 输出对不对的结论,要让它输出频响曲线和信噪比数字。数字信号处理的美感在于你能定量看见自己每一个设计选择的后果——系数从 16 位降到 12 位,阻带衰减掉多少 dB;每级都截断对比只在输出舍入,信噪比差多少;抽头数减半,过渡带宽了多少。把这些数字和 Python 浮点参考画在同一张图上,你对「资源、频率、精度」三角权衡的理解会从背诵变成直觉。FIR 是绝大多数通信、音频、测量、图像系统的第一道处理,也是面试和笔试的常客,把它吃透到能默写转置结构、能解释每一级位宽、能说出 DSP 级联路径的程度,后面学 FFT、CIC、半带滤波器、数字下变频都会顺理成章。再补一个和资源相关的实战观察:很多新手写 FIR 时一个时钟周期算完所有抽头,综合出来时序一塌糊涂就怪工具差。其实正确思路永远是先定吞吐需求——采样率只有 48kHz 而时钟有 100MHz,理论上一个乘法器可以复用两千次,全并行铺几十个 DSP 是巨大浪费;反过来视频流水线每拍一个像素,就必须全并行。资源数量不是从结构图推导的,而是从「输入速率相对时钟的倍数」推导的。把这个比值写在设计文档第一行,结构选择就基本不会错。最后提醒一个验证纪律:FIR 的 testbench 不要只测「冲激响应等于系数」就收工,那只证明数据路径通;一定要补长序列随机噪声输入,对比浮点模型算量化信噪比,因为很多问题(偶发饱和、舍入噪声累积、valid 错位)只在特定幅度和长时间运行下才暴露。把「通一帧」和「指标达标」分成两个验证目标,是从写对代码到做出合格 DSP 模块的分界线。最后给一个面试常考的延伸:为什么对称系数 FIR 可以减半乘法器,但 IIR 一般不能用这个技巧?答案是 FIR 的对称是系数天然结构,延迟样本相加后乘同一系数不改变卷积结果;IIR 含反馈极点,抽头没有这种对称性,且反馈环直接限制最高时钟频率,优化思路完全不同(双二阶节级联、环内打拍要改结构)。能讲清这一点,说明你对两种滤波器的结构差异和 FPGA 映射都理解到位了。最后给一个进阶预习:通信接收链路里 FIR 很少单独出现,它通常和抽取、混频、NCO(数控振荡器)组成数字下变频,CIC 加半带加 FIR 的三级级联用很低的成本把高速采样率降到基带。等你把单个 FIR 的三种结构和定点验证做扎实,再看这套经典架构,会发现每一个模块都是本文内容的直接复用。数字信号处理上 FPGA 的世界,就是从这个简单的乘加求和开始展开的。最后再讲一个工程实现细节:系数表加载到 BRAM 还是分布式 ROM 要看规模。十几个抽头直接用 case 或参数数组,综合成小逻辑最省事;几十到几百抽头放一块 BRAM,配合一个地址计数器在每个采样周期读出系数;上千抽头时分复用时,BRAM 带宽可能成为瓶颈,要用双端口或多块并行。结构选择永远跟「抽头数、采样率相对时钟的比值、DSP 数量」这三个数走,先算清楚再写代码,避免写完再大改。最后给一个调试 FIR 的快捷实验:testbench 里让输入恒为正满幅,理论稳态输出应等于输入乘以系数和。如果结果随时间缓慢漂移,说明你用了截断而舍入偏差在累积;如果出现周期性尖峰,说明累加器保护位不够、偶发饱和;如果输出整体小一个固定倍数,多半是最后取高位时多移了一次。这三个实验加起来十分钟,能定位定点 FIR 里九成的数值问题,比盲目调系数高效得多。再补一个和下游对接的细节:FIR 输出一般不直接给满位宽,要在「保留保护位」和「匹配接口位宽」之间做选择,常用做法是先输出全精度结果,在模块边界集中做一次舍入和饱和,而不是在每一级内部随意截位。集中定标有两个好处:误差来源可追溯、接口模块可复用。把 FIR 想成「全精度内核加边界定标」的结构,复杂数字信号处理的数据通路组织就清晰了。最后给一个资源速算经验:N 抽头 FIR 全并行大约用 N 个乘法器和 N-1 个加法器(对称折叠后减半),寄存器数随转置级数线性增长;时分复用 K 路则乘法器约为 N/K,但要增加系数 ROM 带宽和累加状态机。把这三个数(N、K、DSP 预算)在设计开头写在纸上,结构就基本定了,后面的 RTL 只是把这个决定实现出来。最后给一个学习顺序建议:先在软件里生成系数并画出频响,再用全并行转置结构让它在硬件上跑通并完成冲激/阶跃测试,然后尝试把乘法器数量减半(对称折叠),最后才做时分复用版本。这四步分别对应系数设计、结构实现、资源优化和吞吐折衷,走完一遍,你对「算法如何落到硬件」的理解会比读五篇框图都扎实。这也正是 FIR 在入门 DSP 课程中地位特殊的原因:它足够简单,一个公式就能讲清;又足够完整,覆盖了定点、资源、时序、验证四大硬件主题。把这个模块做成你自己的可复用 IP(参数化位宽、抽头数、系数文件),后续的数字下变频、音频处理、传感器滤波项目都能直接站在它的肩膀上。一个参数化、带系数文件、带自检 testbench 的 FIR,完全可以作为求职作品集里体现「懂算法也懂硬件」的代表作。面试官从一个带完整系数生成脚本、定点信噪比报告和资源时序数字的 FIR 工程里,能直接看出你是否真的做过端到端的 DSP 落地,这比口头声称「熟悉数字信号处理」有说服力得多。
十四、多通道与多速率:一个 FIR 服务多少路数据
真实系统里很少只有一路信号,学会把一个 FIR 内核复用到多通道是 FPGA 相对软件的结构性优势。思路是把「空间上的多路」变成「时间上的多相」:以高于采样率 N 倍的处理时钟轮流服务 N 个通道,系数 ROM 只有一份,数据 RAM 按通道分段存放延迟线,每个通道维护独立的写指针和累加寄存器。调度状态机在每个处理周期内完成「取通道样本、取对应系数、乘累加」一拍或几拍,N 个通道轮转一周恰好等于一个采样间隔,通道之间在数据 RAM 和累加器上严格隔离。关键时序约束是处理时钟乘以每通道所需拍数再乘以通道数,必须小于采样周期,工程上还要留 20% 以上裕量给状态机和 RAM 延迟。这种结构的资源只随通道数缓慢增长(主要是存储),乘法器数量与通道数无关,因此通信基站里一片 FPGA 服务几十路上百路滤波是常态。
多速率场景则要引入抽取和插值的概念。当输出采样率低于输入时,先低通再抽取,抗混叠滤波器的截止频率必须设在输出奈奎斯特频率而不是输入,否则下采样后频谱会折叠。FIR 在这里有一个免费优化:抽取滤波器每 D 个输入才需要一个输出,乘累加可以只在输出时刻进行,乘法器活动率降到 1/D。插值滤波器反过来,先插零再滤波,同样可以利用零样本跳过多数乘法。把 CIC、半带、FIR 三级组合起来,每一级都在相对宽松的速率上完成一部分衰减任务,整体乘法率远低于单级高阶 FIR——这就是数字下变频和上变频里经典的多级设计,也是 FIR 学透之后最自然的下一步。设计这类系统时先画一张「速率—每级频率—阻带要求」的预算图,再决定级数和各级阶数,比直接按最高速率设计节省数倍到数十倍资源。
十五、流水线、复位与常见数值故障的定位
即使功能正确,FIR 在高时钟频率下仍可能因时序不收敛而出问题。转置型结构天然把加法器切成了每级一拍,但如果输入位宽和系数较大,DSP 内部的累加加法链或级联路径仍可能成为关键路径,这时要确认综合属性把乘加映射进了 DSP48 而不是拆成 LUT,并利用 DSP 的级联线(CASCADE)把相邻抽头在硅片上直接相连,避免进通用布线。并行度提高后还要检查 RAM 和系数 ROM 的读取是否提前一拍预取,否则数据和系数对不齐,表现为冲激响应整体错位但形状正确——这是判断「地址相位差一拍」的典型指纹。调试时先跑冲激测试确认结构和相位,再跑阶跃确认直流增益和饱和,最后才是长序列信噪比,顺序不要反。
复位策略也值得专门说一句。FIR 延迟线和累加器上电应处于已知状态,但不必给每个寄存器接异步复位——FPGA 的触发器上电有确定的初值,只在状态机和控制寄存器上用复位、数据通路靠 valid 握手保证首次有效输出前流水已灌满,是更利于时序和资源的写法。常见数值故障可按指纹快速分类:输出恒为零查 valid 和系数是否被综合优化;输出幅度随机跳变查符号扩展和 RAM 读延迟;通带正常但阻带不够查系数量化位数和窗函数;只有大信号失真查保护位和饱和逻辑;多通道串音查通道轮转时累加器是否及时清零、数据 RAM 的段地址是否算错。把这些指纹和冲激、阶跃、扫频、噪声四级测试配合使用,FIR 层面的问题基本都能在进入系统联调之前关闭,这也是把一个教学滤波器做成可交付 IP 的最后一公里。走完这一公里,你交出的就不再只是一段能出波形的卷积代码,而是一个边界清楚、指标可测、在极端激励和长期运行下都行为可信的信号处理组件——这正是工程实现和课堂实验之间真正的分界线,也是面试官在项目细节里最想确认的东西。
常见坑对照
| 坑 | 后果 | 建议 |
|---|---|---|
| 累加器不扩位 | 溢出回绕、大尖峰 | 加保护位/饱和 |
| 乘积不用 signed | 负系数算错 | 统一有符号补码 |
| 截错位(取低位) | 数值全错 | 乘积取高位、右移定标 |
| 系数量化过粗 | 频响偏离 | 增加系数位宽验证 |
| 乘法没用 DSP | LUT 爆炸 | 规范写法推断 DSP48 |
| valid 不匹配 | 数据错位 | 全链路同步流控 |
| 直接型关键路径长 | 频率上不去 | 改转置型/加流水 |
相关与延伸
前置:DSP48 初认识、定点数基础、数据类型与运算。 深入:进阶 DSP48 与算术(乘加、FIR、推断与级联)、流水线与资源优化。
一句话总结
FIR 每拍做 y[n]=Σ h[k]·x[n−k]:用抽头延迟线保存当前和过去 N 个采样、各乘固定系数后求和,系数由 firwin 生成;它无反馈故绝对稳定、系数对称可严格线性相位,且计算全是相互独立的乘加,天然适合 DSP48 并行 + 流水线。延迟线是 N 级移位寄存器,乘法可全并行(N 个 DSP、高吞吐)或单 DSP 时分复用(省资源、吞吐 1/N)。结构上 FPGA 最常用转置型:输入先广播给所有乘法器、乘积进带寄存器的加法链,关键路径只有“一乘一加”、天然流水、最易收敛时序。定点必须盯住:系数量化位数、乘积有符号且位宽翻倍、累加留 ⌈log2N⌉ 保护位并饱和、输出取高位并舍入,且确认乘法推断进 DSP48。验证最有效的一招是喂单位冲激——输出应恰好等于系数本身,再用阶跃/扫频查通带阻带、用综合报告确认资源与时序。
上一篇:46 定点数基础(Q 格式/量化/截位/饱和) | 下一篇:48 VGA 显示入门(行场同步/像素时钟) | FPGA 系列目录