4、FFT的硬件架构基础:流水线架构与SDF架构对比、复数乘法器与旋转因子生成

各位同学,咱们今天聊点硬核的。FFT在FPGA上怎么落地?说白了,就是两个核心问题:用什么架构,以及怎么算复数乘法。我在项目里见过太多人一上来就写代码,结果资源爆了或者时序跑不通。嗯,咱们先把地基打牢。

4.1 流水线架构 vs 单路径延迟反馈架构

先说说两种主流架构。我个人习惯把流水线架构叫做“空间换时间”的典型代表。你想想看,每一级都配一个独立的蝶形运算单元,数据像流水一样往下推。好处是什么?吞吐量高啊!每拍都能出一个结果。

但代价也很明显——资源消耗大。我记得有一次做16K点的FFT,用全流水线架构,光乘法器就用了小一百个,片子差点没布下。

流水线架构特点:

  • 每一级都有独立的蝶形单元
  • 数据流单向,无反馈路径
  • 吞吐率 = 时钟频率(每拍一个结果)
  • 资源消耗:O(N·log₂N) 级别

那单路径延迟反馈架构呢?说白了就是“时间换空间”。它只用一个蝶形单元,通过反馈路径反复使用。数据进来后,先存到延迟线里,等凑够了再算。

我的经验:如果资源紧张,比如在低成本FPGA上做中低速率FFT,SDF架构是首选。我曾经在一个项目里用SDF架构,把乘法器用量从48个降到了8个,片子瞬间就布通了。

来,咱们直接看个对比表:

对比项 流水线架构 SDF架构
蝶形单元数量 log₂N 个 1 个
存储需求 N/2 个复数 N-1 个复数
吞吐率 1 结果/时钟 1 结果/时钟(有初始延迟)
控制逻辑 简单 中等
适用场景 高速、连续流 资源受限、中低速

为什么会这样?你想想看,流水线架构每级都在算,而SDF架构是串行复用。我建议初学者先从SDF架构入手,把蝶形运算的逻辑吃透了,再去看流水线架构会轻松很多。

避坑指南:我曾经在SDF架构里犯过一个低级错误——延迟线的深度没算对。N点FFT,第一级的延迟线长度是N/2,第二级是N/4,以此类推。少一个周期都不行,数据会乱套。

4.2 复数乘法器设计

好,架构选完了,接下来就是核心运算单元——复数乘法器。FFT里最耗资源的就是它了。

一个标准的复数乘法:

(a + jb) × (c + jd) = (ac - bd) + j(ad + bc)

你看,需要4个实数乘法器和2个加法器。但咱们做FPGA的,能省则省。有个经典优化方法:

// 优化后的复数乘法器(3乘法器方案)
temp1 = c × (a + b)
temp2 = a × (d - c)
temp3 = b × (c + d)
real = temp1 - temp3
imag = temp1 + temp2

嗯,这里要注意:虽然乘法器从4个减到了3个,但加法器从2个增加到了5个。在FPGA里,乘法器资源通常比加法器金贵得多。我个人习惯在乘法器紧张的芯片上用这个方案,比如7系列以下的Xilinx片子。

关键点:复数乘法器的位宽选择直接影响精度和资源。我建议输入数据位宽和旋转因子位宽保持一致,这样乘法器输出位宽自动翻倍,再截断到合适位宽。

4.3 旋转因子生成

旋转因子,就是那个W_N^k = e^(-j2πk/N)。说白了就是一组正弦余弦值。怎么生成?两种路子:

  1. 实时计算:用CORDIC算法现场算。好处是不占存储,坏处是延迟大、精度一般。
  2. 查表法:提前算好存到ROM里。这是工程中最常用的方法。

我建议用查表法。为什么呢?因为FFT的旋转因子有对称性,你只需要存1/4周期就够了。

// 旋转因子ROM生成示例(Verilog风格)
// 只存储0~π/2范围内的cos值
reg [DATA_WIDTH-1:0] cos_rom [0:ROM_DEPTH-1];

// 地址映射:利用对称性
// 实际角度 = (addr / ROM_DEPTH) * π/2
// 其他象限通过符号变换得到

我的经验:旋转因子的量化精度很关键。我曾经用16位量化,结果FFT出来的信噪比差了3个dB。后来改成18位,效果立竿见影。记住:旋转因子的位宽最好比数据位宽多2位,这样截断误差小。

还有个细节——旋转因子的存储顺序。流水线架构里,每一级需要的旋转因子都不一样。我习惯用计数器生成地址,然后查表得到对应的正余弦值。这样控制逻辑简单,时序也好收敛。

注意:查表法的ROM初始化一定要用同步复位。我曾经吃过异步复位的亏,上电后ROM内容没稳定,FFT算出来的全是乱码。嗯,从那以后我再也不敢偷懒了。

4.4 架构选择实战建议

最后,给各位一个实用建议。做FFT硬件架构时,先问自己三个问题:

  • 数据率多高? 如果时钟能覆盖,SDF架构更省资源。
  • 资源预算多少? 乘法器少于20个?老老实实用SDF。
  • 延迟要求严吗? 流水线架构的初始延迟更小。

我记得有个项目,客户要求256点FFT,数据率只有10MHz。我用SDF架构,只用了4个乘法器,片子成本降了30%。客户很满意,我也省心。

好了,这一章的内容就到这。下一章咱们聊聊FFT的定点实现和溢出处理,那可是个坑多的地方。