这一篇在干嘛?
最常用的滤波器:从卷积公式讲到转置结构、线性相位、流水线与分布式算法(DA),最后落地到 FIR 设计与 IP 内核。 原书代码为 VHDL,本篇所有代码已改写为 Verilog。
- 3.1 数字滤波器概述
- 3.2 FIR理论
- 例3.1 可编程FIR滤波器
- 3.3 设计 FIR 滤波器
- 3.4 常系数FIR设计
- 例3.2 4抽头直接FIR滤波器
- 例3.3 改进的4抽头直接FIR滤波器
- 直接形式的流水线 FIR 滤波器
- 算法3.4 简化加法器图
- 例3.5 F6半带滤波器的简化加法器图
- 定理3.6 RAG等价变换
- 流水线 RAG FIR 滤波器
- 例 3.7 有符号 DA FIR 滤波器
- 采用逻辑单元的分布式算法
- 例3.8 5输入DA表
- 采用嵌入式阵列模块的 DA
- 加速 DA 滤波器
- 例3.9 DA FIR滤波器的开环形式
- BEGIN
- 例 3.10 F6 半带滤波器的 IP 生成
- 3.5 练习
自测一下
FIR 滤波器"线性相位"的条件是什么?为什么重要?
系数对称(h[n] = h[N-1-n])时相位严格线性。线性相位意味着所有频率分量延迟相同,波形不会发生相位失真——这对音频/图像至关重要。
转置结构比直接结构的 FIR 好在哪?
转置结构天然形成流水线寄存器,不需要额外插入寄存器就能跑高时钟;加法链从串行长链变成并行短链,关键路径短。
分布式算法(DA)为什么不用乘法器?
DA 把”系数乘输入再累加”重组为对输入各 bit 的查表:系数组合预先存进 LUT,按 bit 位移位累加即可。FPGA 的 LUT 资源丰富,查表比乘法器更快更省。
FIR 系数怎么用 MATLAB 得到?
用 fir1/firpm(Parks-McClellan 等纹波)或 fdatool 设计,指定阶数/边界频率/窗或权重,输出量化为 FPGA 字长的定点系数,再验证量化后频响是否仍满足指标。
第3章 FIR 数字滤波器(上):结构、设计与常系数实现
3.1 数字滤波器概述
什么是数字滤波器
数字滤波器的任务,是按照我们的意愿去修正或改变信号的特性——可以是在时域里,也可以是在频域里。最常见、最重要的一类数字滤波器是线性时不变滤波器(Linear Time-Invariant, LTI)。“线性”指输入叠加时输出也叠加,“时不变”指今天输入一个信号和明天输入同样的信号,系统行为完全一样。
LTI 滤波器与输入信号的相互作用,通过一个叫线性卷积的过程完成,记作 : 是滤波器的脉冲响应(可以理解为滤波器的”指纹”), 是输入信号, 是输出。卷积的正式定义是:
直观地说:想要算出第 个输出点,就把滤波器系数”反着套”在输入序列最近的一段时间上,逐点相乘再全部加起来。
FIR 与 IIR 的区别
LTI 数字滤波器分为两大类:
- FIR(Finite Impulse Response,有限脉冲响应):脉冲响应只有有限个采样值,式(3-1)的无限累加退化成每个输出时刻的有限次累加;
- IIR(Infinite Impulse Response,无限脉冲响应):脉冲响应理论上无限长,需要实现无限累加和(第 4 章讨论)。
“不用会怎样”的反问在这里很自然:正因为 FIR 的累加是有限的,它天然稳定、可以做到严格线性相位,也最容易在 FPGA 上用流水线跑出高速度——这是本章选择它的原因。
为什么用数字滤波器取代模拟滤波器
研究数字滤波器的动机在于:它们正日益成为最主要的 DSP 运算,正在迅速取代用 RLC 元件和运算放大器搭建的传统模拟滤波器。两者思路完全不同:
- 模拟滤波器用拉普拉斯变换的微分方程描述,在时域或 s(拉普拉斯)域分析,只能用于 IIR 设计;
- FIR 通常直接用计算机规范和算法设计,天然适合数字实现。
本章假定 FIR 滤波器已经设计完成,重点放在:先简要回顾 FIR 的设计过程,再讨论如何用 FPGA 高效地实现它。
3.2 FIR 理论
从卷积到传递函数
带常系数的 FIR 滤波器是一种 LTI 系统。对输入序列 ,长度为 (即 阶)的 FIR 输出由有限卷积和给出:
其中 到 是滤波器的 个系数,它们恰好就是 FIR 的脉冲响应。在 z 域中描述更便捷,传递函数 定义为:
抽头延迟线结构
图 3-1 直接形式的 FIR 滤波器
图 3-1 画出了长度为 的 FIR:它由”抽头延迟线”、加法器和乘法器混合构成。输入信号沿一串寄存器逐拍向后传递,每个寄存器节点引出一个”抽头”,抽头信号乘以对应的滤波器系数(也叫”抽头权重”),所有乘积累加就是输出。过去人们也称 FIR 为”横向滤波器”,说的就是这种抽头延迟线结构。
看懂这张图,FIR 的硬件成本就一目了然: 个乘法器、 个加法器、 级延迟寄存器。后面所有优化都在压缩这三样东西。
全零点滤波器
式(3-4)中多项式 的根定义了滤波器的零点,根的个数就是阶数 。FIR 只有零点、没有极点,所以有时被称作”全零点滤波器”。
有一个容易混淆的点:第 5 章会讲一类重要的 CIC 滤波器,它是递归的,但仍然是 FIR。这之所以可能,是因为递归部分产生的极点恰好被非递归部分抵消掉了,等效的零极点图只剩零点。也就是说:非递归滤波器一定是 FIR,但递归滤波器既可能是 FIR 也可能是 IIR。
图 3-2 结构和脉冲长度之间的关系
3.2.1 具有转置结构的 FIR 滤波器
直接 FIR 模型(图 3-1)有一个重要变形:转置 FIR 滤波器。构造方法只有三步:
- 交换输入和输出;
- 颠倒信号流的方向;
- 加法器与分支节点互换角色。
图 3-3 转置结构的 FIR 滤波器
数学上转置结构与原结构完全等价(同样的传递函数),但硬件上转置结构通常是 FIR 的首选实现方式,原因有二:
- 输入 广播到所有乘法器,不需要为输入准备额外的移位寄存器链;
- 各乘积沿寄存器逐级累加,寄存器天然分布在加法器之间,无须为高吞吐量再给加法器树添加额外的流水线级。
例3.1 可编程 FIR 滤波器
先回顾用 PDSP 计算积之和(SOP)的位宽要求(参阅 2.8 节):数据/系数位宽为 、滤波长度为 时,无符号 SOP 需要额外 位,有符号运算需要 个保护位。对 9 位有符号数据/系数、 的情况,加法器宽度必须是
为什么是 19 位? 两个 9 位有符号数相乘得 18 位;4 个这样的乘积相加,最坏情况下结果最多增大 倍,需要 2 个额外位,但其中 1 位被”两个符号位相乘只贡献一个有效符号位”抵消,所以净增 位,合计 19 位。少算一位会溢出,多算一位浪费资源。
原书 VHDL 改写为 Verilog,下面是长度为 4 的可编程滤波器(转置结构,系数可在线加载):
// 原书 VHDL 改写为 Verilog:可编程 FIR 滤波器发生器(转置结构)
module fir_gen #(
parameter W1 = 9, // 输入数据/系数位宽
parameter W2 = 18, // 乘积位宽 = 2*W1
parameter W3 = 19, // 加法器位宽 = W2 + log2(L) - 1
parameter W4 = 11, // 输出位宽
parameter L = 4 // 滤波器长度
)(
input wire clk,
input wire reset, // 异步复位
input wire load_x, // 0:加载系数 1:加载数据
input wire signed [W1-1:0] x_in, // 系统输入
input wire signed [W1-1:0] c_in, // 系数输入
output wire signed [W4-1:0] y_out // 系统输出
);
reg signed [W1-1:0] x;
reg signed [W1-1:0] c [0:L-1]; // 系数(抽头)阵列
reg signed [W3-1:0] a [0:L-1]; // 部分和阵列
wire signed [W2-1:0] p [0:L-1]; // 乘积阵列
integer i;
// 用 generate 例化 L 个乘法器(便于以后插入流水线级)
genvar g;
generate
for (g = 0; g < L; g = g + 1) begin : mul_gen
assign p[g] = c[g] * x;
end
endgenerate
// 加载过程:load_x=0 时系数沿抽头延迟线逐拍移位
always @(posedge clk or posedge reset) begin
if (reset) begin
x <= 0;
for (i = 0; i < L; i = i + 1) c[i] <= 0;
end else if (!load_x) begin
c[L-1] <= c_in; // 新系数从最高抽头进入
for (i = L-2; i >= 0; i = i - 1)
c[i] <= c[i+1]; // 系数向前移一格
end else begin
x <= x_in; // 每次装入一个数据样本
end
end
// SOP 过程:计算积之和(转置结构加法链)
always @(posedge clk or posedge reset) begin
if (reset) begin
for (i = 0; i < L; i = i + 1) a[i] <= 0;
end else begin
for (i = 0; i < L-1; i = i + 1)
a[i] <= {{(W3-W2){p[i][W2-1]}}, p[i]} + a[i+1]; // 符号扩展后累加
a[L-1] <= {{(W3-W2){p[L-1][W2-1]}}, p[L-1]}; // 第一个抽头只有寄存器
end
end
assign y_out = a[0][W3-1 -: W4]; // 系数为小数(|f[k]|<=1.0),相当于除以 256
endmodule这段代码的工作方式:当 load_x=0 时,系数被逐个装入抽头延迟线 c;否则数据字装入寄存器 x。第二段 always 块实现积之和:每个乘积 p[i] 先做一位符号扩展到 19 位,再与后级部分和 a[i+1] 相加,形成转置结构的加法链。所有乘法器通过 generate 循环统一例化,这为后续插入流水线级留好了口子。最后把 19 位 SOP 的高 11 位送给输出,等效于除以 256——因为假定的系数都是 的小数。该设计使用了 93 个 LE 和 4 个嵌入式乘法器,TimeQuest 缓慢 85C 模型下 。
要仿真这个长度为 4 的滤波器,选一组有代表性的系数——Daubechies DB4 小波滤波器系数:
FPGA 里没有小数,需要量化:把 4 个系数同时乘以 后四舍五入取整,得到 8 位精度(外加 1 位符号)的整数模型:
仿真的时序是:复位释放后的前 4 个时钟节拍,把系数 依次移入抽头延迟线 c;接着向寄存器 x 装入 100,检查滤波器的脉冲响应。一个时钟周期后嵌入式乘法器的结果 p(i) 就绪,第一个有效输出 y_out 出现在 375 ns 之后。输出各拍按 的比例出现——这正是”脉冲输入的响应就是滤波器系数”这一事实的硬件验证。
图 3-4 加载了 Daubechies 滤波器系数的 4 抽头可编程 FIR 滤波器的仿真
3.2.2 FIR 滤波器的对称性
FIR 脉冲响应的中心是一个重要的对称点。为方便起见,把这一点定义成第 0 次采样时刻,这样得到的滤波器描述就是因果的。对奇数长度的 FIR,因果模型为:
令 ,沿单位圆求传递函数就得到频率响应:
用 表示幅频响应,用 表示相位响应:
实际工作中,人们更多用相位和幅值来描述数字滤波器,而较少直接使用 z 域传递函数或复频率响应。
3.2.3 线性相位 FIR 滤波器
为什么需要线性相位
在通信和图像处理等应用中,信号经过滤波器后波形形状不能被扭曲,这一点至关重要。例如图像的边缘、通信码元的形状,一旦不同频率分量被延迟了不同时间,波形就会失真。衡量相位线性度的标准尺度是组延迟:
理想的线性相位滤波器,在关心频段内组延迟是一个常数——所有频率分量”手拉手”一起延迟,波形只平移、不变形。
对称性带来线性相位
从式(3-7)可以看出:只有当频率响应 是纯实或纯虚函数时,才可能实现固定组延迟。这就要求脉冲响应必须满足偶对称或奇对称: