﻿# DTMFの仕組み

## 概要
DTMF（Dual-Tone Multi-Frequency）は、電話の押しボタンを音で表現する方式です。1つのキーは「低群1周波数 + 高群1周波数」の2つの正弦波の同時発生で表されます。

- 低群（Row）: 697 / 770 / 852 / 941 Hz
- 高群（Column）: 1209 / 1336 / 1477 / 1633 Hz

この組み合わせにより、0-9, `*`, `#`, A-D（拡張キー）を一意に識別できます。

## 周波数マトリクス
|      | 1209 Hz | 1336 Hz | 1477 Hz | 1633 Hz |
|------|---------|---------|---------|---------|
| 697 Hz | 1 | 2 | 3 | A |
| 770 Hz | 4 | 5 | 6 | B |
| 852 Hz | 7 | 8 | 9 | C |
| 941 Hz | * | 0 | # | D |

## なぜ2周波数なのか
単一周波数だと、雑音・音声・回線歪みで誤認しやすくなります。2周波数同時検出にすることで、

- 誤検出率を下げる
- キー数を少ない帯域で効率的に表現する
- アナログ回線でも比較的安定して扱える

という利点があります。

## 生成（送信）側の技術要素
キーに対応する2つの正弦波を加算して短時間出力します。

- サンプリング周波数例: 8 kHz（電話帯域で一般的）
- 各トーン長: 40〜100 ms程度
- キー間ギャップ: 40 ms以上を確保する実装が多い
- レベル管理: 低群/高群のレベル差（twist）を規定範囲に収める

離散時間信号としては以下の形です。

```text
x[n] = A_low * sin(2π f_low n / Fs) + A_high * sin(2π f_high n / Fs)
```

ここで `Fs` はサンプリング周波数、`f_low` と `f_high` はキーに対応する周波数です。

## 検出（受信）側の技術要素
受信信号を短いフレームに分割し、8個のDTMF周波数成分のエネルギーを評価します。

主な手法:

- Goertzel法
  - 特定周波数だけを効率的に評価できる
  - DTMFのように対象周波数が少数固定な場合に軽量
- FFT
  - 広帯域解析に向く
  - 実装は汎用的だが、DTMF専用では計算量が増えやすい

一般的な判定フロー:

1. フレーム化（例: 20〜40 ms）
2. バンドパス/前処理（任意）
3. 各候補周波数のパワー算出
4. 低群最大1本 + 高群最大1本を選定
5. 閾値判定（SNR、相対レベル、twist、総合エネルギー）
6. 最小継続時間を満たしたら確定

## 実装時に重要な判定条件
誤検出を減らすため、単にピーク最大を取るだけでは不十分です。

- 最小オン時間（tone duration）
- 最小オフ時間（interdigit pause）
- Twist制限（低群と高群のレベル差）
- 2ndピーク抑圧（近傍ピークが大きすぎないこと）
- 音声区間での誤検出対策（speech immunity）

## Webアプリ実装での注意点
ブラウザでDTMFを扱う場合は、Web Audio APIを使う構成が一般的です。

- 生成: `OscillatorNode`を2本同時に鳴らして`GainNode`でレベル調整
- 検出: `AudioWorklet`または`AnalyserNode` + 独自解析
- 遅延/ジッタ: バッファサイズで検出安定性とレイテンシをトレードオフ
- サンプリング周波数差: 44.1k/48k環境で係数計算を都度合わせる

## 参考設計パラメータ（目安）
- Frame長: 205サンプル@8kHz（約25.6ms）
- 判定更新周期: 10〜20ms
- 検出確定: 40ms以上連続一致
- 解除確定: 30〜40ms不一致

## まとめ
DTMFは「固定8周波数から低群1本・高群1本を同時検出する」シンプルな方式ですが、実運用ではレベル差・継続時間・雑音耐性を含む判定設計が品質を左右します。Web実装でも、生成は容易・検出は判定ロジックが肝、という点が重要です。
