FPGA 进阶 26:定点 DSP 设计——量化误差、溢出与截位/舍位策略
本文是
fpga/进阶层第 30 篇。FPGA 做信号处理(滤波、FFT、调制解调、电机控制)几乎都用定点数而非浮点——浮点单元极耗资源、延迟高,定点用整数寄存器 + DSP48 就能高速并行。定点化的三大难题是量化误差、位宽增长、溢出,这篇讲清 Q 格式和处理策略。
本文要回答的问题
- FPGA 做 DSP 为什么用定点?Q 格式怎么表示小数?
- 量化误差从哪来、位数怎么影响信噪比?
- 加法/乘法位宽怎么增长?怎么收窄不爆资源?
- 溢出为什么会「回绕」成大错?保护位和饱和怎么用?
- 截位和舍入有什么区别?
一、为什么定点:整数硬件快又省
| 定点 | 浮点 | |
|---|---|---|
| 硬件 | 触发器 + DSP48,单周期、可大规模并行 | 需浮点 IP(对阶/规格化),多拍 |
| 资源 | 省 | 定点的几倍~几十倍 |
| 动态范围 | 小(靠定 Q 格式) | 大(指数自动缩放) |
| 适合 | FIR/FFT/DUC/DDC/电机控制等高吞吐 | 动态范围极大、吞吐不高 |
二、Q 格式:小数存进整数寄存器
Qm.n 约定补码寄存器里隐含小数点位置:m 位整数、n 位小数,寄存器存的值 = 真实值 × 2^n。
Q3.4(8 位补码:1 符号 + 3 整数 + 4 小数)
寄存器存整数 24 = 二进制 0001_1000
真实值 = 24 × 2^-4 = 1.5
└─ 量化步长 LSB = 2^-4 = 0.0625
n 越大 → 小数分辨率越高(误差越小)
m 越大 → 能表示的幅值越大(动态范围越大)
总位宽固定 → m 和 n 此消彼长,要按信号范围分配量化误差:真实/浮点系数 → 有限位定点必然舍入,误差约 ±0.5 LSB = ±2^(−n−1)。n 每多 1 位,量化噪声降约 6dB(信噪比 SNR 约 6.02n + 1.76 dB)。
三、位宽增长:乘法翻倍、加法 +1
// 有符号乘法:位宽 = 两数位宽之和
logic signed [15:0] a, b; // Q1.15
logic signed [31:0] y; // Q2.30,16×16 → 32 位
always @(posedge clk) y <= a * b; // DSP48 推断(进阶07)
// 加法:需要 +1 位防溢出;N 个数累加要 log2(N) 个保护位
logic signed [17:0] acc; // 16 位数据累加,加宽到 18(2 位 guard)Qa.b × Qc.d = Q(a+c).(b+d) 乘法小数位相加、整数位相加
Qa.b + Qa.b = Q(a+1).b 加法整数位 +1
多级级联全保留 → 位宽无限膨胀、资源爆炸
随便截断 → 溢出或丢精度四、防溢出:保护位 + 缩放 + 饱和
补码有符号数超范围会回绕:0111_1111(+127) +1 → 1000_0000(−128),信号处理里表现为爆音/尖峰,比小幅量化误差严重得多。

- 保护位(guard bits):累加器/中间级多留几位防溢出,最后再收窄;N 个数累加加 ⌈log2N⌉ 位;
- 饱和(saturation):输出钳到正/负满幅,削顶比回绕温和,作为兜底;
- 缩放(scaling):整体右移降增益,别让信号顶满幅。
五、截位 vs 舍入、符号扩展
- 截位 truncation:直接丢掉低位小数,简单但有负偏置(总往 0 或负偏);
- 舍入 rounding(round-to-nearest):截位前加半个 LSB(
+ 2^(n-1))再截,无偏、误差更小,代价是一个加法器; - 符号位扩展:有符号数拓宽位宽时高位补符号位(正补 0、负补 1),否则数值出错;
- 运算全程用
signed,混用有/无符号会让 DSP48 推断和结果出错(见 DSP48)。
六、定点化流程
- MATLAB/C 浮点定算法、验证功能;
- 定点化分析:统计各级动态范围、定 Q 格式、仿真量化噪声(扫位数看 SNR/性能)、留裕量;
- 写 RTL:按位宽增长规则加保护位、选截位/舍入、加饱和;
- 比特级比对:用浮点/定点参考模型做 自检 TB,逐样本比对误差在容限内。
常见坑对照
| 坑 | 后果 | 正确做法 |
|---|---|---|
| 全程浮点 IP | 资源爆、并行度低 | 定点化,用 DSP48 |
| 乘法不扩位宽 | 高位被截、结果错 | 乘积位宽 = 两数之和 |
| 累加器不加保护位 | 累加溢出回绕 | 加 log2N 位 guard |
| 有符号溢出回绕 | 爆音/尖峰 | 饱和兜底 + 缩放/保护位 |
| 直接截位 | 量化误差有偏 | 关键级用 round-to-nearest |
| 符号扩展做错 | 拓宽后数值错 | 高位补符号位 |
| signed/unsigned 混用 | DSP 推断错、结果错 | 全程 signed |
| 不定动态范围就拍位宽 | 要么溢出要么浪费 | 先浮点仿真统计范围 |
相关与延伸
前置/配套:DSP48 与算术(乘加/推断/级联)、流水线与资源优化、高级 Testbench 参考模型比对。 FIR/FFT 具体实现见下一篇 进阶 31;HLS 做 DSP 见 #36/#37。
一句话总结
FPGA 做 DSP 用定点:小数靠 Qm.n 格式存进整数寄存器(存的值=真实值×2^n),用整数硬件+DSP48 单周期并行,省资源又快,代价是手动管小数点和位宽。三难点:量化误差——舍入误差约 ±0.5LSB=±2^(−n−1),n 每多 1 位 SNR 升约 6dB;位宽增长——乘法位宽翻倍(Qa.b×Qc.d=Q(a+c).(b+d))、加法 +1、N 数累加加 log2N 个保护位,中间加宽、适当级收窄;溢出——补码超范围会回绕成大错(爆音/尖峰),先浮点仿真估动态范围定 Q 格式、加 guard bits、缩放降增益,输出加饱和钳位兜底。收窄用舍入(+0.5LSB 无偏)比截位准,有符号数拓宽做符号位扩展、全程 signed。流程:浮点定算法 → 定点化分析范围/量化噪声 → RTL 加保护位/饱和 → 参考模型比特级比对。