OpenCCVoice for DVSwitch ─ デバッグ・ジャーニー記録集
2026年7月13日
2026年8月6日
2026年7月、V1.75〜V1.93 の集中デバッグの全記録です。
収録ファイル
- 詳細版(全9章+付録) — 実測データ・コード差分・仮説と棄却の経緯まで残した技術ドキュメント。別記事「OpenCCVoice for DVSwitch — デバッグ・ジャーニー」を参照。
- 連輈5本(読み物版) — 既存の「ハマりどころ」シリーズと同じトーンの連載記事。各記事は以下を参照:
- 版数履歴・定数一覧 — V1.75〜V1.93 の版数表と最終定数一覧(索引用)。デバッグ・ジャーニー記事内に記載。
主要な発見のインデックス
| 発見 | 詳細版の場所 | ブログ回 |
|---|---|---|
| SoX の拡張子問題(.part → .building.wav) | 第1章 | ─ |
| SFR 折り返し時間の実測(TX lead 1.0s) | 第2章 | ─ |
| GPIO 依存の撤退判断 | 第3章 | ─ |
| MD-619 ハングの真因=TGIF 先頭無音スキップ | 第4〜5章 | 第1話 |
| DMR パケット解析器の自作 | 第5章 | 第2話 |
| AMBE ボコーダとホワイトノイズの相性 | 第6章 | 第3話 |
| Talker Alias デコーダの MMDVMHost 移植 | 第7章 | 第4話 |
| 並行制御 Race Condition と /dev/shm 消失 | 第8〜9章 | 第5話 |
関連ツール(別途納品済み)DL
dmrd_analyze.pyv1.3 — pcap → DMRD ストリーム分析器emblc.py— 埋め込み LC / Talker Alias デコーダ(MMDVMHost 移植)dvswitch_bot193.py— 最終の bot 本体
執筆スタンス
- 棄却された仮説も、棄却プロセスごと残す(後から同じ症状に遭遇した人の役に立つため)
- 実測データ(フレーム数、振幅、時間)は数字で残す
- 「原因不明のまま保険で守る」判断もあえて明記する(実運用の現実として)
- AI 協働開発の実際(AI が生成したバグと、それが実測で修正されるサイクル)も第9章と終章に記す
dvswitch_bot.py 版数表(V1.75〜V1.93)
デバッグ・ジャーニー期間中の全版数の主題・変更点・結果を一覧化したものです。
| 版 | 主題 | 主な変更点 | 結果・備考 |
|---|---|---|---|
| V1.75 | コールサイン応答音声の RAM キャッシュ導入 | /dev/shm/ocv_reply_cache_<PID>/ にコールサイン別 WAV。プリキャッシュ(ヘッダ受信時に先行生成)。署名(.sig)で整合性 | 実機で SoX 失敗(.part 拡張子問題) |
| V1.76 | V1.75 の SoX 失敗を修正 | 一時ファイル名を .building.wav に変更(SoX の拡張子判定対策) | キャッシュ機構が実用化 |
| V1.77 | キャッシュ即応答時の頭欠け対策 | REPLY_TX_LEAD_DELAY_SEC = 1.0。命中時のみ送出前に wall-clock 待ち。SFR RF ターンアラウンド保護 | 実測で頭欠け解消。1.0 が下限 |
| V1.78 | GPIO LOW タイミング応答(実験) | TGIFChanger-Py の GPIO17 を借りて相手アンキー検出。無音パッド追加 | 動作確認だが副作用あり |
| V1.79 | GPIO 実装の簡潔化 | タイムアウト・エラー処理を除去 | 開発者から「GPIO は無縁」の指示 |
| V1.80 | GPIO 依存の完全排除 | GPIO 関連コード全削除。焼き込み頭無音 PRE_AUDIO_SILENCE_SEC=1.5 をキャッシュ生成時に統合 | シンプル化・V1.77 の TX lead 方式に統一 |
| V1.81 | TGIFChanger-Py との相互影響検証 | 実コード変更なし。監視ログ・GPIO・ロック・/dev/shm・外部コマンド・ネットワークを検証 | 衝突なしを確認 |
| V1.82 | USRP 終端の多重送信 | USRP_EOT_REPEAT = 3。keyup=0 パケットを20ms間隔で3連打 | MD-619 ハングは直らず |
| V1.83 | 送信前 SET_INFO メタデータ送出 | pyUC 公式クライアントとバイト単位で同一の SET_INFO 実装 | MD-619 ハングは直らず。TA 変わらず |
| V1.84 | 無音のノイズ充填(TGIF 対策の核心) | 完全ゼロ PCM を微小ノイズ(±150、-47dBFS)に置換。前パディング・後パディング・WAV 内ゼロブロック全部 | MD-619 ハング解消。副作用:3秒間シャー音 |
| V1.85 | ノイズ床引き上げとゲート開放バースト | 振幅 150→600、先頭 300ms に 2500 のバースト | ゲートは 1.3s 固定床とわかる。バースト無効 |
| V1.86 | ノイズ最小化・TX lead 回帰 | ノイズを先頭パディングのみに限定。焼き込み頭無音廃止。TX lead 1.0s 復活 | 頭欠け「こちらは」が再発 |
| V1.87 | 無音助走の復活 | PRE_AUDIO_SILENCE_SEC = 1.5 復活(今度は真の無音として焼き込む) | 頭欠け解消 |
| V1.88 | 頭シャー短縮・終端ケロケロ対策 | NOISE_LEAD_PACKETS = 65(1.3s)に短縮。振幅 100 に低減。USRP_EOT_REPEAT = 1 に戻す | 音質向上、終端ケロケロ解消 |
| V1.89 | リード音のトーン化 | ホワイトノイズ→100Hz 微小トーン(位相連続、末尾フェード付き) | ゲロゲロ・プツプツ解消 |
| V1.90 | Talker Alias 引きずり対策 | 自局 SET_INFO を三重に主張(起動時・他局受信終端・送信直前) | TA は元々正しく、無効と後に判明(無害だが不要) |
| V1.91 | 送信直列化・TEMP 競合根治 | _tx_lock 新設で送信経路を直列化。実行中の TEMP 削除を全廃 | Race Condition 修正 |
| V1.92 | 外部レビュー指摘の反映 | 中間ファイル削除を _generate_hybrid の finally 内(_gen_lock 保持中)に移動 | 掃除責任の明確化 |
| V1.93 | キャッシュディレクトリ存在保証の強化 | _ensure_cache_dir() 新設。ビルド直前に makedirs(exist_ok=True)。起動時も存在保証 | 実機事故対応(根本原因は未特定) |
主要な発見と対応版数の対応
| 発見 | 対応版 | 対応方法 |
|---|---|---|
| MD-619 の受信スタックの真因=TGIF の先頭無音スキップ | V1.84 | 無音のノイズ充填で AMBE 非無音判定 |
| TGIF ゲートに約1.3秒の固定床がある | V1.85 の実測 | バーストは無効、ノイズは1.3秒あれば足りる |
| AMBE ボコーダはホワイトノイズを歪ませる | V1.89 | 100Hz 微小トーンに変更 |
| Talker Alias は正しく JJ2YYK を送出している | V1.90 の後の TA デコードで判明 | ボット側修正不要。表示引きずりは受信機側の途中参加処理の問題 |
| 送信経路の並行制御が不足 | V1.91 | _tx_lock で直列化、実行中削除を廃止 |
| /dev/shm のキャッシュ Dir が予期せず消える | V1.93 | 実行時と起動時に makedirs で二重保険 |
最終確定した主要定数(V1.93 時点)
# ─── タイミング ─────────────────────────────
REPLY_TX_LEAD_DELAY_SEC = 1.0 # 命中時 SFR 折り返し保護(wall-clock 待ち)
PRE_AUDIO_SILENCE_SEC = 1.5 # 焼き込み助走(受信機の途中参加同期用)
PACKET_INTERVAL = 0.02 # USRP パケット間隔 20ms
PRE_POST_PADDING_PACKETS = 75 # 前後パディング 1.5秒
SUPPRESS_DURATION_SEC = 15.0 # 応答後の抑制期間
QSO_SESSION_GAP_SEC = 15.0 # QSO セッション判定
QSO_ID_INTERVAL_SEC = 600.0 # 法令準拠 10 分 ID
# ─── TGIF ゲート対策 ─────────────────────────
NOISE_FILL_ENABLED = True # 100Hz 微小トーンでの先頭リード
NOISE_FILL_AMP = 100 # トーン振幅(-50dBFS)
NOISE_LEAD_PACKETS = 65 # リード継続時間(1.3s)
GATE_BURST_PACKETS = 0 # バーストは無効(実測で効果なし)
# ─── USRP プロトコル ───────────────────────
UDP_IP = "127.0.0.1"
UDP_PORT = 51000
TX_METADATA_ENABLED = True # 送信前 SET_INFO(pyUC 互換)
USRP_EOT_REPEAT = 1 # 終端 keyup=0 の送出回数
# ─── キャッシュ ─────────────────────────────
REPLY_CACHE_ENABLED = True
PREWARM_ON_HEADER = True
CACHE_SCHEMA = "v1"
CACHE_DIR = f"/dev/shm/ocv_reply_cache_{PID}"
# ─── 受信判定 ─────────────────────────────
RX_DURATION_MIN_SEC = 0.5 # カーチャンク下限
RX_DURATION_MAX_SEC = 3.9 # 通常経路でのカーチャンク上限
WATCHDOG_RX_MAX_SEC = 5.0 # watchdog 経路でのカーチャンク上限(SFR EOT 欠落対策)
📝 執筆:JI2TAB(尾張旭 DMR デジピーター 管理人)
🏛 JJ2YYK あいちデジタルコミュニケーションハムクラブ
🏛 JJ2YYK あいちデジタルコミュニケーションハムクラブ