実電波が、映像になった ── 自作ワンセグ復調器#4:壁アンテナでC/Nの壁を越え、逆拡散→RSでMPEG-TSを解き、テレビが映るまで

#3 は、C/Nの壁に阻まれて終わった。FECは雑音床を超えられず、誤り訂正が効かない ── 較正でそれを証明したところまでだった。今回はその壁を物理で殴って越え、そこから RS復号・エネルギー逆拡散まで一気に解いて、ついに ── 自作の復調器で、実際のテレビが映った。IQサンプルから、フルスクラッチのRustコードだけで、生の地デジ電波が動く映像になるまでの最終回。

壁を殴る ── 付属アンテナから、壁のTV端子へ

#3までは付属のロッドアンテナ。床から+11dBしか出ず、EVMは98%。ここが全ての元凶だった。そこで 壁のTVアンテナ端子に、F型→SMAの変換をかませて直結した。信号が強いので、逆にゲインは最大49.6ではなく30に下げる(強すぎるとADCが飽和して崩れる)。録り直して同じ処理を流すと、数字が一変した:

            付属アンテナ      壁アンテナ
SPコヒーレンス   0.84       →   1.000
EVM             98%        →   16.3%
FEC一致率        0.894      →   1.00000   ← 誤り0でロック

Viterbiが完璧にロックした。#3の較正で「雑音床0.928を超えない」と突き止めた、まさにその壁を越えた瞬間だ。ビットはもう1つも間違っていない。あとは、この綺麗なビット列をTSパケットに組み直すだけ ── のはずだった。

TSパケットの影 ── 0x47は出た、でも中身が読めない

Viterbiの出力をバイトに詰め、Forneyのバイトデインターリーブをかけると、MPEG-TSの同期バイト 0x47 が、204バイトごとに命中率100%で立った。TSパケットの骨格は確かに出た。ところが、パケットの中身(ペイロード)をリードソロモン(204,188)にかけると、1ブロックも符号語にならない。ビットは完璧なのに、だ。

ここで危うく「同期は出た」で満足しかけた。だが罠がある:Forneyインターリーバは同期バイトを遅延0の枝に通すので、0x47は何もしなくても204周期で生き残る。つまり 0x47 が並んでも、ペイロードが正しく組み直せている保証にはならない。合成データで自分のインタ↔デインタが逆変換になることは確認済み。なのに実データが通らない。丸一日、ここで唸った。

二つの取り違え ── 順序と、周期

詰まったら参照実装(gr-isdbt)のブロック接続を睨む。すると受信の並びが byte-deint → エネルギー逆拡散 → RS になっている。DVBは「スクランブル→RS」だが、ISDB-Tは順序が逆で、RSのに全体をスクランブルしている。だから受信側はRSより先に逆拡散しないと符号語に戻らない。僕はRSを先にかけていた。順序を直すと ── まだ13%。惜しい、でも足りない。

13%の内訳を直接ダンプして眺めた。すると成功ブロックが8個だけ連続して、あとは崩れている。これは「PRBSのリセット周期が、僕の思っている8ブロックではない」というサインだ。周期を8に決め打ちしていたのを、広く総当たりにした。そして周期を64付近にした瞬間 ── パターンが ...........########################延々と成功に変わった。決め手は、成功ブロックのPIDを表示したこと:

成功ブロックのPID:
  0x1fff  ← ヌルパケット(TSの定番パディング)
  0x0151 0x0152 0x0150  ← 1セグのサービス(映像・音声・PCR)
  0x0001 0x0010 0x0024  ← PSI/SI(番組情報テーブル)
RS復号成功率: 99.7%(3271/3282 パケット)

0x1fff0x0151 が並んだ瞬間、鳥肌が立った。これはまぎれもない、本物のMPEG-TSだ。ランダムなノイズからは絶対に出ない、放送の構造そのもの。

そして、テレビが映った

出来上がった .tsffprobe に食わせる:

Input: MPEG-TS (MPEG-2 Transport Stream), 3 streams
  Stream #0: Audio: aac, 48000 Hz, stereo
  Stream #1: Video: h264, 320x180        ← ワンセグ解像度そのもの
  Stream #2: (データ/字幕)

H.264の映像 320×180 と、AACの音声。ワンセグの規格そのものだ。最後に ffmpeg で1フレーム抜き出す。IQサンプルから、②同期→③等化→④TMCC・デインターリーブ→⑤Viterbi+RS→⑥逆拡散、その全部を自分で書いたコードだけを通り抜けてきた、生の地デジ電波の、その画がこれ:

自作ワンセグ復調器で実電波から復号したテレビ映像。関西テレビの朝の番組、時計は9:39、値下げのテロップ
自作復調器が実電波から取り出した1フレーム(関西テレビ・ch17)。時計「9:39」、テロップ「値上げラッシュの中…”応援値下げ”続々登場」。IQ → 自作コード → 映像。320×180のH.264が、確かにデコードできている。

映った。本当に、テレビが映った。 u8のIQバイト列でしかなかったものが、OFDMのシンボルになり、QPSKの点になり、ビットになり、パケットになり、H.264になって、人の顔と、時計と、テロップになった。全部、この手で書いたRustのコードの中で起きたことだ。

完成 ── ①から⑥まで

  • ① RF入力(rtl_sdr 生IQ)… ✅
  • ② OFDM同期(CP自己相関)… ✅
  • ③ チャネル等化(スキャッタードパイロット)… ✅ QPSK
  • ④ TMCC復号+周波数/時間/ビットデインターリーブ+QPSKデマップ … ✅
  • ⑤ FEC(Viterbi 2/3 + RS(204,188))… ✅
  • ⑥ エネルギー逆拡散 → MPEG-TS出力 … ✅ H.264 320×180 が再生できた

振り返ると、この最終回で効いたのは全部「数字を疑い、直接見る」だった。「0x47が出た」で止まらず、ペイロードをRSで検算する。「13%」で諦めず、成功パターンを可視化して周期のズレに気づく。PIDを表示した瞬間に勝ちが見えた。#1の「ロックした≠正しくロックした」から始まったこの姿勢が、最後まで通用した。

ワンセグは無スクランブル。だから復調に成功すれば、こうして本当に映る。GNU Radioに頼らない、現代のRust実装 ── 調べた限り誰もやっていなかったこの一台が、いま実電波で動いている。次は WASM+WebUSB でブラウザに載せて、「URLを開くとテレビが映る」ところまで持っていきたい。……が、それはまた別の話。まずは、映った。それで十分だ。

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

IP: 取得中...
216.73.216.194216.73.216.194