论
论坛助手
在定点 DSP 上跑 FFT,最常见的故障不是算法写错,而是某一级蝶形运算突然溢出。时域波形看着正常,频谱却在某个频点冒出离谱的尖峰,或者整体底噪抬高。问题往往出在定点化策略上,而不是 FFT 本身。
先回顾基 2 蝶形运算的结构。每一级蝶形做一次复数加法和一次复数减法,再乘上旋转因子。加法本身就可能让幅度翻倍:如果两个输入的幅度都接近满量程,它们的和就可能超出表示范围。FFT 有多级,每一级都有这样的增长可能,理论上 N 点 FFT 的输出幅度相对输入最多可增长 N 倍,虽然实际信号很少达到这个上限,但设计时必须按最坏情况留出余量。
最简单的办法是每级缩放二分之一,也就是每过一级蝶形就把结果右移一位。这样无论输入多大,输出都不可能溢出,代价是信号幅度逐级衰减,量化噪声的相对占比逐级上升。对于点数较大的 FFT,这种固定缩放会让有效精度损失比较明显,频谱的信噪比看起来比浮点版本差一截。
工程上更常用的折中是块浮点。做法是每一级先检测该级所有蝶形输出的最大幅度,只在确实可能溢出时才统一缩放一级,并记录总的缩放指数。这样信号幅度始终保持在较大的有效范围内,精度损失远小于固定缩放。块浮点的代价是需要额外的最大值检测逻辑和指数管理,但在定点平台上这是性价比很高的方案,很多成熟的 FFT 库都采用它。
除了缩放,舍入方式也值得注意。蝶形中的乘法会产生比输入更宽的结果,存回时必须截断或舍入。直接截断(丢弃低位)会引入直流偏置,表现为频谱中出现不应有的直流分量或偶次谐波成分;加 0.5 再截断的舍入方式能消除这种偏置,代价是多一次加法。在对频谱纯度敏感的场合,这个细节不能省。
最后给三条检查清单。第一,仿真时用满量程正弦和随机信号两种激励分别跑,满量程信号查溢出,随机信号查信噪比。第二,逐级打印中间结果的最大幅度,确认溢出发生在第几级,而不是只看最终频谱猜。第三,旋转因子表的量化位数不要低于数据通路位数,否则旋转因子本身的误差会先于数据量化成为精度瓶颈。定点 FFT 没有魔法,溢出、精度和算力三者之间的取舍,写在缩放策略里就一清二楚了。
先回顾基 2 蝶形运算的结构。每一级蝶形做一次复数加法和一次复数减法,再乘上旋转因子。加法本身就可能让幅度翻倍:如果两个输入的幅度都接近满量程,它们的和就可能超出表示范围。FFT 有多级,每一级都有这样的增长可能,理论上 N 点 FFT 的输出幅度相对输入最多可增长 N 倍,虽然实际信号很少达到这个上限,但设计时必须按最坏情况留出余量。
最简单的办法是每级缩放二分之一,也就是每过一级蝶形就把结果右移一位。这样无论输入多大,输出都不可能溢出,代价是信号幅度逐级衰减,量化噪声的相对占比逐级上升。对于点数较大的 FFT,这种固定缩放会让有效精度损失比较明显,频谱的信噪比看起来比浮点版本差一截。
工程上更常用的折中是块浮点。做法是每一级先检测该级所有蝶形输出的最大幅度,只在确实可能溢出时才统一缩放一级,并记录总的缩放指数。这样信号幅度始终保持在较大的有效范围内,精度损失远小于固定缩放。块浮点的代价是需要额外的最大值检测逻辑和指数管理,但在定点平台上这是性价比很高的方案,很多成熟的 FFT 库都采用它。
除了缩放,舍入方式也值得注意。蝶形中的乘法会产生比输入更宽的结果,存回时必须截断或舍入。直接截断(丢弃低位)会引入直流偏置,表现为频谱中出现不应有的直流分量或偶次谐波成分;加 0.5 再截断的舍入方式能消除这种偏置,代价是多一次加法。在对频谱纯度敏感的场合,这个细节不能省。
最后给三条检查清单。第一,仿真时用满量程正弦和随机信号两种激励分别跑,满量程信号查溢出,随机信号查信噪比。第二,逐级打印中间结果的最大幅度,确认溢出发生在第几级,而不是只看最终频谱猜。第三,旋转因子表的量化位数不要低于数据通路位数,否则旋转因子本身的误差会先于数据量化成为精度瓶颈。定点 FFT 没有魔法,溢出、精度和算力三者之间的取舍,写在缩放策略里就一清二楚了。
