
本文概述
FIR滤波器是FPGA数字信号处理中最基础也是最常见的模块,属于面试高频考点。FIR的核心是乘加运算,输入信号经过延迟抽头,每个抽头乘以系数后求和得到输出。FPGA中常用的实现结构有直接型、转置型和分布式算法三种:直接型结构直观易理解,转置型更适合高速时钟,分布式算法用查找表代替乘法器可以节省DSP资源。设计FIR需要关注系数量化、位宽增长、流水线级数和资源利用率之间的平衡。
核心要点速览
FIR = 有限长单位脉冲响应,核心公式 y(n) = Σ h(k) × x(n-k)
三种常用结构:直接型、转置型、分布式算法(DA)
系数一般用MATLAB或Python设计,需量化为定点数
输出位宽 = 输入位宽 + 系数字宽 + log2(N阶数)
选择结构要看:阶数、采样率、DSP资源、输入位宽
一、面试官考察点
理论基础
FIR和IIR的区别
FIR的线性相位特性
抽头系数的含义
硬件实现
常用实现结构
资源和速度权衡
位宽增长处理
工程经验
系数设计和量化
实际调试问题
仿真验证方法
二、回答思路
第一部分:FIR的基本原理
在说FPGA实现之前,先把FIR的原理说清楚。FIR是有限长单位脉冲响应滤波器,意思是单位脉冲响应的长度是有限的。输出等于输入和单位脉冲响应的线性卷积。
简单说就是:输入信号经过一串延迟寄存器,每个延迟抽头的信号乘以对应的滤波器系数,所有乘积加起来就是输出。阶数等于抽头数减一,阶数越高,滤波器的过渡带越陡,性能越好,但需要的乘法器和资源也越多。
选FIR主要是因为稳定和线性相位,在数字通信、图像处理这些对相位敏感的场合必须用FIR。而且FPGA里乘法器很多,做多阶FIR也不是问题。
第二部分:系数设计
FIR的系数不是拍脑袋定的,是用专门的滤波器设计工具算出来的。我一般用MATLAB的fdatool或者filterDesigner,或者Python的scipy.signal.firwin函数。
设计滤波器的时候要先确定几个指标:滤波器类型(低通、高通、带通、带阻)、采样率、截止频率、通带纹波、阻带衰减。然后选设计方法,常用的有窗函数法和等波纹法。窗函数法简单直观,等波纹法在同样阶数下性能更好。
设计出来的系数是浮点数,FPGA里不能直接用,需要量化成定点数。量化的时候要考虑量化位数对滤波器性能的影响,位数太少的话通带纹波和阻带衰减都会变差。我一般先量化成16位,仿真看效果行不行,不行就加位数。量化的方式也有讲究,一般用四舍五入比直接截位误差小。
第三部分:FPGA实现结构
FPGA里实现FIR,常用的结构有三种,各有适用场景:
直接型
结构最直观,跟公式对应
输入延迟链 + 乘法器 + 加法树
阶数高时输入扇出大
加法树路径长,不利于高速
适合低阶、低速场景
转置型
输入同时到所有乘法器
乘法结果经寄存器链累加
关键路径短,容易跑高速
每个加法器后插寄存器
适合高阶、高速场景
分布式(DA)
用查找表代替乘法器
省DSP资源,只用BRAM
适合系数固定、位宽不大
串行处理,采样率受限
可以多级展开提升速度
我之前那个项目用的是转置型结构,因为采样率20MHz,时钟要跑在100MHz以上,转置型时序更容易收敛。而且32阶的话,用32个DSP乘法器也不算多,资源是够的。
转置型FIR的Verilog代码大概是这样的结构:
这是一个简化的示意代码,实际项目中还要考虑复位、输出截位、系数对称性优化等。
第四部分:位宽和截位
FIR滤波器有一个很重要的问题就是位宽增长。假设输入是N位,系数是M位,N阶滤波器,乘法器输出就是N+M位,加法树加完之后最多再增加log2(N)位。所以输出位宽大约是N+M+log2(N)。32阶16位输入16位系数的话,输出大约是16+16+5=37位,一般用40位或者直接用DSP的输出位宽。
但最后输出一般不需要这么多位,要截位。截位的时候要注意不能截得太狠导致信噪比不够。通常做法是先算好需要的输出位宽,然后根据增益和噪声要求决定截几位。截位方式有直接截位和四舍五入,四舍五入误差小一点但逻辑稍微复杂。
三、追问环节
具体做法是:先把对称的两个输入加起来,再乘以一个系数,这样乘法器的数量就减少了一半。比如32阶对称FIR,本来要32个乘法器,现在只要16个就够了,节省一半DSP资源。
不过要注意,先加后乘虽然省了乘法器,但加法器的位宽会多一位,而且路径上多了一个加法器的延迟,时序上要考虑一下。
追问2:什么是半带滤波器?有什么优势?
半带滤波器是一种特殊的FIR滤波器,它的通带和阻带关于二分之一采样频率对称,而且近一半的抽头系数是零。因为有很多零系数,所以实际需要的乘法器数量大约只有普通FIR的一半,资源利用率高很多。
半带滤波器常用在2倍抽取或插值的场合,比如多速率信号处理中的半带抽取器、半带插值器。配合2倍采样率变化,每两个采样点算一次,进一步减少计算量。如果做多级降采样,第一级常用半带滤波器,效率很高。
追问3:如果采样率很高,单时钟周期算不完怎么办?
如果采样率太高或者阶数太多,一个时钟周期算不完,有几个优化方向。第一个是加流水线,在加法树中间插寄存器,把长路径拆短,这样可以跑更高的时钟频率。转置型结构本身就是部分流水线的。
第二个是用全并行结构,就是每个抽头一个乘法器,一拍出结果,速度最快但用的乘法器也最多。第三个是串行结构,用一个乘法器时分复用,多个抽头共用一个乘法器,几拍算完一个输出,省资源但速度慢。
还有一种是多相分解,把一个N阶滤波器拆成M个相,每个相处理一部分系数,适合多速率系统。总之就是速度和资源的权衡,看项目更看重哪个。
追问4:你怎么验证FIR滤波器做的对不对?
我一般分几步验证。第一步是单元仿真,给一个已知的输入信号,比如冲激响应或者阶跃信号,看输出是不是跟MATLAB算的一致。第二步是频域验证,给一个正弦扫频信号,或者用白噪声输入,算输出的频谱,看滤波器的幅频响应对不对。第三步是上板验证,用信号发生器输入不同频率的正弦波,用逻辑分析仪抓输出波形,算增益,跟仿真结果对比。
还有一个方法是把MATLAB或者Python算出来的参考输出做成文件,仿真的时候逐点对比,这样最严谨。位宽量化的影响也可以在这个过程中验证,看量化后的效果跟浮点参考比差多少。
四、失分表达
面试官问的是你的设计能力,不是调用IP的能力。要能讲清原理、结构、参数选择的考量。
要理解位宽增长的规律,知道怎么计算需要的位宽,截位也要有依据,不能想当然。
五、准备动作
理论准备
FIR原理和线性相位特性
直接型和转置型的结构差异
位宽增长的计算方法
动手准备
用MATLAB或Python设计一个低通FIR
写一个简单的FIR Verilog代码
做一个简单的Testbench验证
项目准备
准备一个FIR相关的项目案例
说清楚指标、结构、资源和遇到的问题
能画出结构框图更好
面试官你好,关于FIR滤波器的FPGA设计与实现,以上是我的理解和实际经验
要不要我具体讲一下分布式算法的实现思路?

扫码关注





























