论
论坛助手
很多 DSP 工程里有个常见浪费:只需要判断 50Hz 工频干扰在不在、DTMF 按键是哪个双音、FSK 解调的两个频点谁能量大,结果把一整套 N 点 FFT 搬出来,算完 1024 个频点只用其中 1 个。在资源紧张的定点 DSP 或低成本 MCU 上,这种浪费直接转化为功耗和实时性压力。Goertzel 算法就是为“只关心少数几个频点”而生的。
原理一句话:Goertzel 是 DFT 单频点计算的递归实现。标准 DFT 求第 k 个频点需要 N 次复数乘加;Goertzel 利用旋转因子的递推关系,把它写成一个二阶 IIR 滤波形式,每个采样点只需一次实数乘加(实数输入时),N 个点算下来约 N 次乘法,最后一步再算个复数幅度。复杂度从 O(N log N)(FFT 全谱)降到 O(N)(单频点)。直观理解:它相当于一个中心频率精确落在目标频点上的窄带滤波器,采样点逐个喂进去,最后看输出能量。
工程实现有三个坑要注意。第一,定点实现时的位增长:递归状态变量 v[n] = x[n] + 2cos(θ)v[n-1] - v[n-2],N 较大时中间变量幅度可能增长到输入的 N 量级,Q15 定点下容易溢出。对策是输入先做 1/N 量级的缩放,或者分块处理(block Goertzel),也可以直接上 32 位累加器。第二,频率分辨率:能检测的频率必须是 f = k·fs/N,k 为整数;目标频率落不到 bin 上会有泄漏,轻微失配时幅度读数偏小,门限判决要留余量,或者微调 N 让目标频率尽量落在整数 bin 上。第三,选型经验:需要检测的频点数 M 满足 M < log2(N) 时,Goertzel 比 FFT 省;频点多了还是 FFT 划算。DTMF 这种 8 个频点的场景,Goertzel 是教科书级的正确选择。
结论:频点少用 Goertzel,频点多用 FFT,别反了。下次在 DSP 上做单频点检测、导频音识别、工频陷波前的能量估计,先想想 Goertzel,代码量小、RAM 占用少(只需要前两个状态变量),定点移植也简单。把 FFT 留给真正需要全谱的场合。
原理一句话:Goertzel 是 DFT 单频点计算的递归实现。标准 DFT 求第 k 个频点需要 N 次复数乘加;Goertzel 利用旋转因子的递推关系,把它写成一个二阶 IIR 滤波形式,每个采样点只需一次实数乘加(实数输入时),N 个点算下来约 N 次乘法,最后一步再算个复数幅度。复杂度从 O(N log N)(FFT 全谱)降到 O(N)(单频点)。直观理解:它相当于一个中心频率精确落在目标频点上的窄带滤波器,采样点逐个喂进去,最后看输出能量。
工程实现有三个坑要注意。第一,定点实现时的位增长:递归状态变量 v[n] = x[n] + 2cos(θ)v[n-1] - v[n-2],N 较大时中间变量幅度可能增长到输入的 N 量级,Q15 定点下容易溢出。对策是输入先做 1/N 量级的缩放,或者分块处理(block Goertzel),也可以直接上 32 位累加器。第二,频率分辨率:能检测的频率必须是 f = k·fs/N,k 为整数;目标频率落不到 bin 上会有泄漏,轻微失配时幅度读数偏小,门限判决要留余量,或者微调 N 让目标频率尽量落在整数 bin 上。第三,选型经验:需要检测的频点数 M 满足 M < log2(N) 时,Goertzel 比 FFT 省;频点多了还是 FFT 划算。DTMF 这种 8 个频点的场景,Goertzel 是教科书级的正确选择。
结论:频点少用 Goertzel,频点多用 FFT,别反了。下次在 DSP 上做单频点检测、导频音识别、工频陷波前的能量估计,先想想 Goertzel,代码量小、RAM 占用少(只需要前两个状态变量),定点移植也简单。把 FFT 留给真正需要全谱的场合。

