3、数字信号处理基础:定点数表示、二进制补码、量化误差、溢出处理、常用运算单元
在FPGA中实现CORDIC与FFT等复杂算法,首先必须跨越一道关键门槛:如何用硬件友好的方式表示和处理数字信号。与浮点运算相比,定点数运算在资源消耗、时序收敛和功耗控制上具有显著优势,但同时也引入了量化误差、溢出风险等新问题。本章将系统梳理定点数表示、二进制补码、量化误差分析、溢出处理策略以及加法器、乘法器、移位器等基础运算单元的硬件实现要点,为后续CORDIC旋转迭代和FFT蝶形运算打下坚实的数字地基。
3.1 定点数表示与Q格式
核心原理
定点数表示的核心思想是在硬件中约定一个固定的二进制小数点位置,从而用整数运算来模拟实数运算。与浮点数相比,定点数不需要指数位和尾数位的动态对齐,因此加法器和乘法器的硬件结构可以大幅简化。在FPGA的DSP设计中,最常用的定点数格式是Q格式,记作Qm.n,其中m表示整数位宽(含符号位),n表示小数位宽,总位宽为m+n。例如Q1.15表示1位符号位、0位整数位、15位小数位,能够表示-1.0到0.999969482421875之间的数,精度为2⁻¹⁵。
选择Q格式时需要综合考虑动态范围和精度两个维度。动态范围由整数位宽m决定,精度由小数位宽n决定。对于CORDIC算法,输入和输出通常限制在[-1, 1]区间,因此Q1.15格式是经典选择;对于FFT,中间蝶形运算的增益可能导致数据增长,需要预留更多整数位,例如Q4.12或Q8.8格式。实际工程中,需要根据信号的统计特性(峰值、RMS值、信噪比要求)来量化确定位宽。
| Q格式 | 总位宽 | 整数位(含符号) | 小数位 | 动态范围 | 精度 | 典型应用 |
|---|---|---|---|---|---|---|
| Q1.15 | 16 | 1 | 15 | [-1, 1) | 3.05e-5 | CORDIC、FFT输入 |
| Q4.12 | 16 | 4 | 12 | [-8, 8) | 2.44e-4 | FFT中间级 |
| Q8.8 | 16 | 8 | 8 | [-128, 128) | 3.91e-3 | 滤波器系数 |
| Q16.16 | 32 | 16 | 16 | [-32768, 32768) | 1.53e-5 | 高精度累加 |
判断方法
在实际项目中,选择Q格式可以遵循以下操作流程:
- 分析信号动态范围:采集或仿真获取信号的峰值幅度,确定整数位宽m,确保m ≥ log₂(峰值)+1(含符号位)。
- 确定精度需求:根据系统SNR或EVM指标,计算所需的最小精度,确定小数位宽n。
- 评估中间运算增长:对于FFT蝶形运算,每级增益最大为2,需要预留log₂(N)位防止溢出。
- 硬件资源权衡:位宽每增加1位,乘法器资源增加约2倍,需在精度和资源间折中。
localparam Q_FORMAT = 15;,便于后续调整。同时,在仿真阶段使用定点数模型与浮点模型对比,验证量化误差是否在可接受范围内。
3.2 二进制补码与运算规则
核心原理
二进制补码是FPGA中处理有符号数的标准编码方式。补码的最大优势在于:加法和减法可以统一为加法运算,无需额外的符号判断逻辑。n位补码能表示的范围是[-2ⁿ⁻¹, 2ⁿ⁻¹-1]。例如8位补码范围为[-128, 127]。补码的取反加一规则使得求相反数只需一个加法器周期。
在硬件实现中,补码运算需要特别注意两个问题:符号扩展和位宽匹配。当两个不同位宽的数相加时,需要先将短位宽的数进行符号扩展(正数补0,负数补1)到相同位宽。乘法运算中,两个n位补码相乘结果为2n位,需要保留完整的2n位结果以避免精度损失。
操作流程
补码运算的标准流程如下:
- 统一位宽:将所有参与运算的数符号扩展至最大位宽。
- 执行加法/乘法:使用标准二进制加法器或乘法器完成运算。
- 结果截取:根据目标Q格式,对结果进行舍入或截断。
- 溢出检测:检查运算结果是否超出目标位宽范围。
// 补码加法示例:两个Q1.15格式数相加
wire signed [15:0] a, b;
wire signed [16:0] sum_ext;
assign sum_ext = {a[15], a} + {b[15], b}; // 符号扩展至17位防止溢出
// 若需要16位输出,可截取高16位或进行饱和处理
3.3 量化误差分析与处理
核心原理
量化误差来源于有限位宽对连续信号的近似。在定点数系统中,量化误差主要分为两类:输入量化误差(ADC转换时产生)和运算量化误差(乘法、加法后截断产生)。对于均匀量化,量化误差e服从均匀分布,其方差为Δ²/12,其中Δ=2⁻ⁿ为量化步长。信噪比SNR与位宽的关系为:SNR ≈ 6.02N + 1.76 dB,其中N为小数位宽。
在CORDIC和FFT算法中,量化误差会随着运算级数累积。例如,N点FFT的蝶形运算中,每级运算都会引入舍入误差,最终输出信噪比约为:SNR_FFT ≈ 6.02B - 10log₁₀(N) + 常数,其中B为数据位宽。这意味着数据位宽每增加1位,SNR提升约6dB,但FFT点数每增加一倍,SNR下降约3dB。
案例拆解:FFT定点化误差分析
假设设计一个256点FFT处理器,输入数据为Q1.15格式,要求输出SNR不低于60dB。根据公式SNR ≈ 6.02B - 10log₁₀(256) + 1.76,代入B=16得到SNR ≈ 96.32 - 24.08 + 1.76 = 74dB,满足要求。但如果使用B=12位,SNR ≈ 72.24 - 24.08 + 1.76 = 49.92dB,不满足要求。因此,16位数据位宽是256点FFT的合理选择。
$round 函数或手动实现四舍五入逻辑。
3.4 溢出处理策略
核心原理
溢出是定点数运算中最危险的错误,会导致结果符号翻转,产生严重失真。溢出处理主要有两种策略:饱和处理(Saturation)和环绕处理(Wrap-around)。饱和处理将超出范围的结果钳位到最大值或最小值,适用于音频、视频等对突变敏感的信号;环绕处理则让数据自然回绕,适用于通信系统中的模运算场景。
在硬件实现中,饱和处理需要额外的比较器和多路选择器,会增加逻辑延迟。一种折中方案是位宽扩展:在运算链中逐步增加位宽,确保中间结果不会溢出,仅在最终输出时进行饱和或截断。例如,FFT蝶形运算中,每级加法后增加1位,乘法后增加2位,可以有效防止中间溢出。
操作流程
| 策略 | 实现方法 | 硬件开销 | 适用场景 |
|---|---|---|---|
| 饱和处理 | 比较器 + 多路选择器 | 中等 | 音频、图像处理 |
| 环绕处理 | 直接截断高位 | 低 | 通信调制解调 |
| 位宽扩展 | 逐级增加位宽 | 高(资源增加) | 高精度FFT/CORDIC |
3.5 常用运算单元:加法器、乘法器、移位器
核心原理
加法器、乘法器和移位器是构成CORDIC和FFT算法的基本运算单元。在FPGA中,这些单元可以直接调用DSP48E1硬核资源,也可以使用LUT逻辑实现。DSP48E1支持25×18位乘法、48位累加,是高效实现乘累加运算的关键。
加法器:FPGA中的加法器通常采用进位链(Carry Chain)结构,延迟与位宽成正比。对于大位宽加法,可以采用流水线结构或进位选择加法器(Carry-Select Adder)来优化时序。
乘法器:乘法器的实现方式包括LUT乘法器、分布式算术乘法器和DSP48硬核乘法器。在CORDIC中,乘法器用于缩放因子补偿;在FFT中,乘法器用于旋转因子复数乘法。复数乘法需要4个实数乘法器和2个加法器,但可以通过优化减少为3个乘法器。
移位器:移位器在CORDIC算法中至关重要,每次迭代需要将数据右移i位(i为迭代次数)。FPGA中的桶形移位器(Barrel Shifter)可以在一个时钟周期内完成任意位数的移位,但资源消耗较大;对于固定移位次数,可以使用简单的线网连接实现零成本移位。
案例拆解:CORDIC迭代中的运算单元组合
以CORDIC旋转模式为例,每次迭代的核心运算为:
x_next = x - (y >> i) * d_i;
y_next = y + (x >> i) * d_i;
z_next = z - atan_lut[i] * d_i;
其中d_i为旋转方向(±1),atan_lut[i]为预存的反正切值。该迭代需要2个移位器(右移i位)、2个加法器/减法器、1个查找表。在硬件实现中,移位操作通过硬连线实现(零逻辑资源),加减法器使用DSP48或LUT实现。整个CORDIC核的吞吐率取决于加法器的延迟和流水线级数。
常见误区与总结复盘
- 误区一:忽视符号扩展。在补码加法中,未进行符号扩展会导致结果错误。务必先将所有操作数扩展至相同位宽。
- 误区二:截断代替舍入。截断会引入直流偏置(DC Bias),导致频谱泄漏。应使用舍入或抖动(Dithering)技术消除偏置。
- 误区三:溢出检测滞后。应在运算的同时检测溢出,而非事后检查。使用Verilog的
signed比较器可以实时判断。 - 误区四:位宽规划不足。FFT中间级数据增长是必然的,必须预留足够的整数位,否则溢出将导致灾难性错误。