Goertzel 算法模拟器 返回
信号处理模拟器

Goertzel 算法模拟器 — DTMF 单周频检测

用 Goertzel 法检测 DTMF 16 键。二阶 IIR 滤波器以 O(N) 计算 8 个 DFT 频率块,从行列最强周频判定按键。通过实时可视化直观学习嵌入式比 FFT 更轻量的单周波数检测原理。

参数设置
DTMF 按键编号
噪声级别
采样率 F_s
Hz
帧长 N

按键排列 — 0:'1' 1:'2' 2:'3' 3:'A' / 4:'4' 5:'5' 6:'6' 7:'B' / 8:'7' 9:'8' 10:'9' 11:'C' / 12:'*' 13:'0' 14:'#' 15:'D'

暂停时,拖动滑块即可即时更新结果。

计算结果
目标周频
检测强度 |X(k)|
检测判定
节省运算 vs FFT
输入信号与 Goertzel 检测强度

上段=逐采样点处理输入 x[n](黄=扫描线)/下段=目标周频扫描的检测强度 |X(k)|(在音调周频处出现尖峰)

理论与主要公式

Goertzel 算法针对目标周频 f 最接近的频率块 k = round(f·N/F_s),用二阶 IIR 递推式直接计算幅度²。

角周频与系数 c:

$$\omega = \frac{2\pi k}{N},\qquad c = 2\cos\omega$$

二阶 IIR 递推式(s_{-1} = s_{-2} = 0):

$$s_n = x_n + c\,s_{n-1} - s_{n-2}$$

N 个采样点后的幅度²(频率块功率):

$$|X_k|^2 = s_{N-1}^2 + s_{N-2}^2 - c\,s_{N-1}\,s_{N-2}$$

单个频率块计算量为 O(N),M 个周频则为 O(N·M)。与 FFT 整体 O(N log N) 相比,需要检测的频率块越少,Goertzel 越优势。

Goertzel 算法模拟器说明

🙋
既然有 FFT,为什么还要特别用 Goertzel 这个算法呢?
🎓
简单说,Goertzel 是「只需要 1 个周频块」场景的专家。FFT 计算所有 N 个频率块,复杂度 O(N log N),但 DTMF 检测只需要 8 个周频,这样 FFT 就大材小用了。Goertzel 单个频率块 O(N),只用 3 个变量的二阶 IIR 滤波器搞定,非常适合嵌入式单片机。改变模拟器里的按键,你会发现实际上只需检测行列各 1 个周频。
🙋
「二阶 IIR」是什么?听起来有点复杂…
🎓
其实很简单。就是递推式 $s_n = x_n + c\,s_{n-1} - s_{n-2}$,每步迭代一次就行。系数 $c = 2\cos(2\pi k/N)$ 开始只算一次。状态变量就 $s_{n-1}$ 和 $s_{n-2}$ 两个,内存用不了 3 个字。最后 $|X_k|^2 = s_{N-1}^2 + s_{N-2}^2 - c\,s_{N-1}s_{N-2}$ 就出来了。DSP 的乘累加指令非常适合。
🙋
模拟器里「噪声级别」增大时,条形图会摇晃。实际硬件怎么判定呢?
🎓
好问题。实际产品要加多重判定:最强频率块的电平要超过最小检测电平,行列电平比要在 ±6 dB 内,与第二强频率块的比(扭曲度)要在规定范围,音调持续时间 40 ms 以上——用 AND 逻辑全满足才判为有效按键。即便噪声让最强频率块一瞬间切换,持续时间条件也能挡掉误检。这个规定写在 ITU-T Q.24 标准里。
🙋
「帧长 N」变大时,会发生什么?
🎓
N 越大,周频分辨率 $\Delta f = F_s/N$ 越细,相邻周频的分离越清楚。但计算量也线性增加。F_s=8 kHz,N=205 时 $\Delta f \approx 39$ Hz,这是 DTMF 的经典配置。帧太短的话各 bin 会从 DTMF 周频位置偏离,检测强度下降。模拟器里把 N 从 128 调到 1024,条形图的选择性会明显变化。

常见问题

需要检测特定周频的场景都有。比如电力系统周频监测(50/60 Hz 及其高调波分析)、工业传感器载波检波、超声波测距回波检测、无线电 CTCSS/DCS 音调检测、医疗设备脉搏检测等。共同点都是「不需要全部 N 个频率块,就要数个块的高速检测」。
基本形式假设 k 是整数。但有个扩展版叫广义 Goertzel,支持任意实数 k。这样即使目标周频不在 DFT 格子上,也能抑制谱泄漏、精密估计幅度。电力系统周频估计(频率偏离 50 Hz 的情况)这类应用就很重要。
二阶 IIR 滤波器的内部状态容易发散,N 很大时 s_n 的动态范围暴增。要么提前缩放输入(比如乘以 1/N),要么每步用饱和算术防止溢出。用 Q1.15 或 Q1.31 定点时,系数 c 通常量化到 Q14 以抑制误差。
可以。最后一步算复数 DFT 值 X_k = s_{N-1} − e^{-jω} s_{N-2},就有实部虚部,atan2 求位相角。本模拟器只演示幅度检测,但 AM/FM 解调、同步检波这些要用位相,实现时就要用复数输出版本。只要幅度的话省掉一次乘法,这也是 Goertzel 的简洁优点。

实际应用

电话通信 DTMF 解码:固定电话、IP 电话、自动应答系统 (IVR) 在实时检测用户按键时,标准做法就是 Goertzel 法。模拟线路接收的是语音与 DTMF 叠加的信号,接收端 8 个 Goertzel 滤波器并行运行,通过电平比、持续时间、扭曲度等多重判定提取有效按键。VoIP 虽然可用 RFC 2833 数字传输 DTMF,但互操作需求依然让 Goertzel 解码器常驻线路。

电力系统频率分析:50 Hz/60 Hz 及其高调波(150/180、250/300、350/420 Hz 等)的幅度需要连续监测,用于电能质量评估。不是对所有周频做 FFT,而是只用 Goertzel 计算那数根目标高调波,这样 CPU 负荷大幅下降,告警响应也快。配合广义 Goertzel,还能在系统周频略偏离 50 Hz 时精密推估幅度。

无线电 CTCSS/DCS 音调检测:业余和专业无线电广泛用 CTCSS 方式(亚音频 67~250 Hz,约 50 种)标记信号组。接收机持续监听目标音调的 Goertzel 输出,当电平超阈值才开放扬声器。这是 Goertzel 最擅长的场景:低频、少数频率块。

嵌入式设备载波检波:FSK 调制解调器前导检测、超声传感器回波强度测量、脉搏血氧仪心率同步等,ARM Cortex-M 级单片机「只需数根周频、要 FFT 级精度」的需求中,Goertzel 被广泛应用。CMSIS-DSP 库也提供了基于 biquad 的 Goertzel 实现,配合硬件乘法器,可以在微秒级时间内处理一个帧。

常见误解与注意事项

最普遍的误解是「Goertzel 总比 FFT 快」。其实有个损益分岐点——当需要的周频数 M 达到 log₂N 数量级就超过了。比如 N=1024,log₂N = 10,若需检测 10 个以上频率块,FFT 一次性全算反而更快。模拟器的「计算量」卡片显示 Goertzel 的 N·M,心里要和 FFT 的 N·log₂N 比一下。Goertzel 赢家条件是「频率块少」且「目标 bin 提前知道」。

另一常见问题是忽视目标周频贴近 DFT 格子的重要性。标准 Goertzel 用 k = round(f·N/F_s) 取整,若目标周频偏离 bin 中心就产生「频谱泄漏损耗」,最大能掉 3.9 dB(ΔdB ≈ 20log₁₀(sinc(0.5))),幅度推估严重下降。DTMF 用 F_s=8000,N=205 就是精巧选择,8 个 DTMF 周频都贴近 DFT 格子。模拟器改变 N 时条形图高度变化,就是这个频谱泄漏效应。

最后是「Goertzel 输出大=检测成功」的短路逻辑。单选最强 bin 在噪声和语音高调波干扰下极易误判。实机必须多条件 AND:最强频率块绝对电平超过最小检测电平、行列比在 ±6 dB 内、与次强频率块的比在规定范围、音调持续 ≥40 ms、静音间隔 ≥40 ms——全满足才算有效按键。模拟器噪声拉到 1.0 会看到最强频率块频繁切换,直观说明单纯选最强的危险。

使用指南

  1. 在 8kHz~16kHz 范围内设置采样周频 (slFsVal),推荐电话网标准 8kHz
  2. 将帧长 (slNVal) 设为 80~160 采样点,确保 10~20ms 观察窗口
  3. 从 0~15(16 键)选择检测目标按键 (slKeyVal),生成相应 DTMF 周频成分
  4. 调整噪声级别 (slNoiseVal) 到 0~50dB,评估实环境鲁棒性
  5. 运行模拟后,从最强行周频和最强列周频确认判定按键

具体计算示例

用 Fs=8kHz、N=160 采样点检测按键「5」(行 770Hz、列 1336Hz)时,Goertzel 计算量为 N·M=160×8=1280 次乘法即可完成。比之 2048 点 FFT 需 2048log₂(2048)≈22000 次乘法,轻量约 17 倍。加入 15dB 噪声后,行周频 bin=(770/8000)×160≈15.4、列周频 bin≈21.4 在离散 bin 内仍能分离,通过峰值检测精确判定「5」。在 ARM Cortex-M4 @100MHz 嵌入式 DSP 上处理时间仅约 13 微秒。

实务注意事项