Skip to content

billzi2016/DTMF-Encod-Decode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Robust-DTMF-Codec

一个使用 Python 实现的 DTMF(双音多频)编码与解码项目。

本项目当前已经包含两条主线能力:

  1. DTMF Encoder

    • 将按键字符串(如 123#A)编码为标准 DTMF 双音音频
    • 支持输出为内存中的 PCM 浮点样本
    • 支持导出为 .wav 文件
  2. DTMF Decoder

    • .wav 文件或内存样本进行 DTMF 解码
    • 核心检测算法使用 Goertzel
    • 支持常见采样率输入
    • 第一版会自动重采样到内部工作采样率 8000 Hz
    • 支持滑动窗口扫描与状态机去重,避免长按重复输出

项目特点

  • 核心解码算法使用 Goertzel,不依赖全频域 FFT
  • 支持 0-9*#A-D 全部 16 个标准 DTMF 按键
  • 内部采用模块化设计,编码器与解码器职责分离
  • 针对噪声和误报加入了峰值集中度、Twist、绝对阈值等判定逻辑
  • 正式实现中使用了中文注释,方便后续继续维护

当前目录结构

DTMF-Encod-Decode/
├── PRD.md
├── README.md
├── assets/
├── docs/
├── src/
│   ├── dtmf_decoder/
│   │   ├── __init__.py
│   │   ├── audio.py
│   │   ├── cli.py
│   │   ├── config.py
│   │   ├── detector.py
│   │   ├── goertzel.py
│   │   ├── scanner.py
│   │   └── state_machine.py
│   └── dtmf_encoder/
│       ├── __init__.py
│       └── encoder.py
└── tests/
    ├── __init__.py
    ├── test_audio.py
    ├── test_detector.py
    ├── test_encoder.py
    ├── test_goertzel.py
    ├── test_scanner.py
    └── test_state_machine.py

模块说明

src/dtmf_decoder/

  • config.py
    • 管理解码参数、频率表、Twist 门限、窗口长度、步长等配置
  • audio.py
    • 读取 .wav
    • 执行单声道归一化
    • 在必要时自动重采样到内部工作采样率
  • goertzel.py
    • 对单帧样本计算 8 个目标频率的能量
  • detector.py
    • 根据频率能量完成合法 DTMF 判定
  • scanner.py
    • 对长音频做滑动窗口扫描
    • 汇总逐帧结果
    • 输出最终去重后的按键串
  • state_machine.py
    • 对连续帧结果做去重
  • cli.py
    • 提供命令行编解码入口

src/dtmf_encoder/

  • encoder.py
    • 根据按键字符串生成 DTMF 双音
    • 支持输出浮点样本或写出 .wav

解码设计说明

1. Goertzel 核心思路

DTMF 只关心固定的 8 个标准频率:

  • 低频组:697770852941
  • 高频组:1209133614771633

因此没有必要对整段频谱做 FFT
本项目使用 Goertzel 算法逐帧计算这 8 个目标频点的能量,降低无关计算。

2. 滑动窗口

  • 窗口长度:205
  • 步长:102
  • 内部工作采样率:8000 Hz

这样既能区分各个 DTMF 频率,又能减少漏检。

3. 抗误报逻辑

检测并不是简单地取两个最大频率,而是同时做以下检查:

  • 绝对能量阈值检查
  • 高频与低频的 Twist 比例检查
  • 同组内最大峰值与次大峰值的集中度检查

4. 去重策略

一个按键通常持续几十到上百毫秒,会跨越多个窗口。
如果不做处理,解码结果会变成类似 5555

本项目使用状态机去重:

  • 同一个按键连续出现时只记录一次
  • 只有当信号消失后再次出现,才算新的同键输入
  • 如果按键从一个值切换到另一个值,则立即记录新按键

采样率策略

本项目不要求输入音频必须是 8000 Hz

当前第一版策略是:

  1. 支持常见输入采样率,例如 800016000220504410048000 Hz
  2. 解码前自动重采样到内部工作采样率 8000 Hz
  3. 后续所有 Goertzel 检测参数都基于内部工作采样率执行

这样做的原因:

  • 不限制用户输入来源
  • 保持窗口参数和阈值体系稳定
  • 先把第一版工程复杂度控制住

编码设计说明

编码器会为每个按键找到对应的:

  • 一个低频
  • 一个高频

然后将两个正弦波叠加,生成双音信号。

默认参数:

  • 输出采样率:8000 Hz
  • 单键持续时间:100 ms
  • 按键间静音:50 ms
  • 输出幅度:0.8

编码器也支持自定义这些参数。

安装与环境

建议环境:

  • Python 3.10+

当前实现优先使用标准库,不强依赖第三方科学计算包。

命令行使用

1. 编码为 WAV

PYTHONPATH=src python3 -m dtmf_decoder.cli encode "123#A" output.wav

可选参数:

PYTHONPATH=src python3 -m dtmf_decoder.cli encode "123#A" output.wav \
  --sample-rate 16000 \
  --tone-ms 120 \
  --silence-ms 60 \
  --amplitude 0.8

2. 解码 WAV

PYTHONPATH=src python3 -m dtmf_decoder.cli decode input.wav

输出内容为最终去重后的按键字符串。

Python 调用示例

1. 直接编码

from dtmf_encoder import DTMFEncoder

encoder = DTMFEncoder()
samples = encoder.encode("13800138000")
encoder.write_wav("dial.wav", "13800138000")

2. 直接解码内存样本

from dtmf_decoder import DTMFScanner

scanner = DTMFScanner()
result = scanner.scan_samples(samples, sample_rate=8000)
print(result.decoded_text)

3. 解码 WAV 文件

from dtmf_decoder import decode_wav_file

decoded = decode_wav_file("dial.wav")
print(decoded)

示例脚本

项目里已经提供了一个完整示例:

这个脚本会执行完整回环:

  1. 取圆周率前 100 位数字
  2. 生成 DTMF 音频
  3. 输出示例文件
  4. 再对这个音频执行解码
  5. 检查解码结果是否与原始输入完全一致

运行方式:

PYTHONDONTWRITEBYTECODE=1 PYTHONPATH=src python3 examples/pi_roundtrip.py

当前保留的示例音频文件:

这个示例文件已经实际跑通过,当前结果是:

  • 原始长度:100
  • 解码长度:100
  • 是否完全一致:True

测试

当前测试覆盖以下能力:

  • Goertzel 对目标频率的响应
  • 单帧 DTMF 检测
  • 噪声拒识别
  • 自动重采样路径
  • 长音频扫描解码
  • 去重状态机
  • 编码结果回环解码
  • 非法字符输入异常

按你当前项目规则,测试命令需要确认后再执行。
建议执行命令:

PYTHONPATH=src python3 -m unittest discover -s tests -v

当前限制

  • 重采样目前使用纯 Python 线性插值实现,优先保证可读性和工程可控性
  • 当前主要支持 .wav 输入,实时流接口还没有单独封装
  • 抗噪参数已经有基础实现,但后续仍建议结合真实样本继续调参

后续建议

可以继续推进的方向:

  1. 增加实时流式解码接口
  2. 增加更强的重采样实现
  3. 为 CLI 增加批量处理能力
  4. 引入真实录音样本做参数标定
  5. 增加可视化调试工具,输出逐帧能量和判定结果

About

Robust DTMF encoder and decoder in Python, featuring Goertzel-based detection, WAV support, resampling, and state-machine deduplication.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages