版块:DSP

在 DSP/ FPGA 上做定标 FIR,一半的人怕"溢出",一半的人怕"精度不够",本质都是同一件事:字长预算没做在前面。这篇给一套可操作的 Q 格式流程和算例。

一、Qn.m 记法与两个铁律

Q 格式:n 位整数 + m 位小数 + 1 位符号(或无符号记 UQ)。

- 表示范围:负 2^n ~ (2^n − 2^-m)
- 量化步长:2^-m

铁律 1:加法/减法 —— 只要整数位足够就安全,结果是两者整数位的极大者;
铁律 2:乘法 —— 小数位直接相加(Q4.12 × Q4.12 → Q8.24),字长翻倍,必须"乘完先定标再存"。

二、FIR 定标三步

y[k] = Σ bᵢ · x[k−i]

第一步:系数定标。取 b_max = max|bᵢ|。低通滤波 b₀ 通常最大(DC 增益≈1 时 b₀ ≤ 1),系数用 Q0.15(16 位)常见。
第二步:输入信号定标。ADC 输出 x∈[-1,1) 是 Q1.15/Q0.15;信号若已知峰均比小,留 2~3 位整数余量 → Q4.11 之类。
第三步:累加器字长预算(关键):

A_bits = X_bits + log2(N) + Σlog2(|b_max|) + margin

即:输入位宽,加上"N 项累加带来的最坏 log2N 增长",再扣掉"系数和小于 1 带来的实际增益"。
低通 DC 增益=1 的 FIR:最坏瞬时增益由 Σ|bᵢ| 决定(Gibbs 振铃系数和可达 1.2~1.5),所以一般按增益 ≤+0.4 dB(1.3 倍)+ 输入峰 → 整数位增加约 2 位 + 3~5 冗余。

算例:Q1.15 输入、48 阶、Σ|b|=1.34 的低通:
中间累加理论增长 log2(48×1.34/2)≈4.7 位 → 累加器用 16+8=24 位安全,或保守用 32 位。乘 16 位系数产生的 31 位乘积取高 24 位+保留保护带。32 位累加器是 DSP 上的默认答案;FPGA 里按 24~28 省 DSP 资源要给出理由。

三、舍入 vs 截尾,与死区

1. 截尾(丢低位)引入恒定负偏置 → 直流误差、微分信号"死区抖动";小信号长期截尾会把有用信息截没了;
2. 舍入(round-to-nearest)方差小 12 倍,但需要 +½LSB 的硬件代价;
3. 环状滤波器(谐振/积分器、IIR)里截尾会造成"零输入极限环振荡",这类结构必须舍入或用饱和算术。

四、动态定标与饱和

- 定点链路上每级"定标点"(re-scaling)显式写出:乘后右移几位 = 该级的增益归一;写进系数文件,仿真和实现共享同一份表,防止"改一处漏三处"。
- 饱和(saturation)用在"出信号口"(DAC/接口),保护带用在"中间级"。全程饱和反而改变滤波器频率响应(等效加了非线性)。
- 验证手段:给"满幅正弦 + 阶跃 + 最坏占空比方波"三组激励跑 MATLAB/C 定点模型与系数级 RTLS 对比,记录最大相对误差和溢出概率(溢出应为绝对零)。

五、常见翻车点自查

- 系数位宽 16 位,但把"整带通系数 ×2 或 ×½"的增益补偿忘写 → 频响全对但幅值错 6 dB;
- 输入信号在 ADC 前有 PGA 增益档位切换,不同档的 Q 格式不同,切换瞬间数据混叠——用状态字同步;
- 浮点转定点工具"自动定标"出来的系数和默认舍入,仿真通过不代表 FPGA 资源可布。

你们在 4G/电力谐波/超声/光通信 DSP 场景里定标 FIR 的经验帖欢迎回帖,特别想听听带饱和反馈的梳状滤波器的极限环实战解法。