前回の続きから表示しています

ソフトウェア無線工学

深宇宙通信のためのSDR — ディジタル化の理論からGNU Radio実装まで。 『深宇宙通信工学』(SpaceCOM教科書)の姉妹編。
■ 本書について
想定読者: 学部で信号処理・通信の基礎(フーリエ変換・dB・複素数)に一度は触れた工学系の読者。SDRは初めてで構わない。宇宙機通信の全体像は姉妹編『深宇宙通信工学』が詳しいので併読を勧めるが、本書だけでも読み通せるよう、必要な概念は登場時に短く説明し直す。
本書の範囲: 姉妹編が「電波が届くか・復調できるか」の理論を扱ったのに対し、本書はその理論をディジタル領域(ソフトウェア)でどう実現するかを扱う。ADC/DACと量子化・ジッタの物理、IQ信号とディジタルダウンコンバージョン、同期ループの離散時間設計、そしてGNU Radioによる実装と検証までを一続きに追う。
構成: 第0章が前提知識の速修、第I〜III部が理論、第IV部が実装、第V部が宇宙システムへの適用である。各章末の「GNU Radioで試す」枠はその章の理論を数分で確認できる最小実験、「直観でつかむ」枠は数式に入る前のイメージ作りである。難しく感じたら、まず第0章と各章の「直観でつかむ」だけを拾い読みして2周目で数式に入る読み方を勧める。
記法: log は常用対数 log₁₀。標本化周波数は f_s、標本周期は T_s = 1/f_s、離散時間信号は x[n] = x(n·T_s) と書く。コードは GNU Radio 3.10 系 + Python 3 を前提とする。

第0章準備 — SDRを学ぶための最小知識

■ この章で学ぶこと
本編を読むのに必要な前提を1章に圧縮した速修コースである。dB・複素指数・スペクトルの復習、 通信の最小語彙、そしてGNU Radioとは何か。すでに身についている読者は記号表(0.6節)だけ 確認して第1.1章へ進んでよい。逆に本編で迷子になったら、いつでもここへ戻ってくること。

0.1 SDRとは何か — 3行で

無線機の仕事は「電波の波形に情報を乗せる/波形から情報を取り出す」ことである。 昔はこれを専用の電子回路(ミキサ・フィルタ・検波器…)で行った。 SDR(ソフトウェア無線)は、波形を数値の列に変換してしまい、以降の処理をぜんぶ プログラムで行う無線機である。回路をハンダ付けする代わりにコードを書く——だから 設計変更が速く、打ち上げた後の探査機の無線機さえ書き換えられる。

◇ 直観でつかむ — 本書全体の地図
受信の流れはたった5段である: ①電波を電圧に(アンテナ・増幅器)→ ②電圧を数列に(ADC。第I部=ここの物理)→③数列を「ゆっくりした複素数の列」に整える (DDC。第II部)→④タイミングと位相を合わせて記号を読む(同期。第III部)→ ⑤ビット列を組み立てる(フレーム。第IV部で全部実装)。 迷ったら「いま自分は5段のどこの話を読んでいるか」を確認するとよい。

0.2 数学の速修 — dB・複素指数・スペクトル

dB(デシベル): 比の対数表現。電力比は 10log₁₀、電圧比は 20log₁₀。 暗算に使うのは3つだけ——×2 = +3 dB、×10 = +10 dB、×1/2 = −3 dB(電力比)。 「6 dB良い」=電力4倍、「20 dB」=100倍。掛け算が足し算になるので、 長い受信チェーンの利得・損失を足し引きだけで追える。これがdBを使う理由のすべてである。

複素指数 e^{jθ}: 複素平面上の「角度θの位置にある半径1の点」。 θ = 2πft と時間で回せば回転する点になり、これが周波数 f の波の複素表現である (オイラーの公式 e^{jθ} = cosθ + j sinθ で実部を取れば普通のコサイン波)。 本書で複素数が出てきたら、常に「回転する点」を思い浮かべればよい。 回転を速める=周波数を上げる、回転の向き=周波数の符号、点の角度=位相、である。 詳しくは第2.1章で改めて導入する。

スペクトル: 信号を「どの周波数の回転がどれだけ混ざっているか」の成分表にしたもの。 FFT(高速フーリエ変換)で計算し、横軸が周波数・縦軸が強さのグラフとして表示する。 本書の図とGNU Radioの Frequency Sink は全部これである。 「時間波形で見えないことがスペクトルでは一目でわかる」場面が繰り返し登場する。

0.3 通信の最小語彙

用語意味
搬送波(キャリア)情報を運ぶための高周波の正弦波。探査機なら数GHz。情報は搬送波の振幅・位相・周波数の変化として乗る。
変調 / 復調情報を搬送波に乗せる操作/取り出す操作。本書の主題は復調の実装である。
ベースバンド搬送波に乗せる前(降ろした後)の、0 Hz付近のゆっくりした信号。ディジタル処理はほぼここで行う。
BPSKビット0/1を位相0°/180°で表す最も基本の位相変調。波形を「±1を掛けたコサイン波」と思えばよい。
シンボルとビット1回の変調で送る単位がシンボル。BPSKでは1シンボル=1ビット。1秒あたりのシンボル数がシンボルレート[baud]。
BERビット誤り率。受信品質の最終指標。理論曲線と実測を比べるのが受信機の「検収」になる。
C/N₀, E_b/N₀信号と雑音の比の物差し。C/N₀は搬送波電力÷雑音電力密度[dBHz]、E_b/N₀は1ビットあたりエネルギー÷雑音密度[dB]。回線設計(姉妹編)から受信機設計への「引き継ぎ書類」がこの数字である。
PLL位相同期ループ。入力の正弦波に自分の発振器の位相を追従させるサーボ(自動追尾装置)。受信機の心臓部で、第3.1章で作る。
整合フィルタ「探している波形の形」をテンプレートとして信号に照合するフィルタ。雑音の中から信号を最も有利に取り出せることが証明されている(第3.2章)。
フレームとASMビット列は一定長の「フレーム」に区切って送る。先頭に置く既知パターン(ASM)を受信側が探して区切りを知る。

0.4 GNU Radioとは

信号処理の部品(ブロック)を画面上で線でつないで無線機を組み立てる、 オープンソースのSDRフレームワークである。「乗算」「フィルタ」「PLL」のような ブロックが数百種類用意されており、レゴのように組むとフローグラフ(=動く受信機)になる。 GUIエディタ(GNU Radio Companion, GRC)で組んでも、Pythonで直接書いても等価で、 本書は学習をGRC・成果物をPythonで扱う(第4.1章)。 ブロックの中身が知りたければソースコードを読める——ブラックボックスがないことが 教材として決定的に優れている。

0.5 本書の読み方 — 3つの経路

読者推奨経路
初学者(SDRも宇宙通信も初めて)第0章→各章の「直観でつかむ」と「GNU Radioで試す」だけで1周→2周目に数式と設計表→第4.3章を写経。
DSPは知っているがSDRは初めて第I部は1.3.6節・1.4章など宇宙特有の話題を拾い読み→第II部から精読。
実装を急ぐ(研究で今すぐ使う)第4.3章から入り、出てくる参照(θ_nの式・周波数プラン等)を遡って読む。急がば回れではあるが、動くものが先にあると理論も速く入る。

0.6 記号表

記号意味初出
f_s, T_s標本化周波数、標本周期(= 1/f_s)1.2
B信号の帯域幅1.2
N, ΔADCのビット数、量子化の刻み幅1.3
σ_jクロックジッタ(rms)1.4
z[n] = I + jQ複素ベースバンド信号(IQ信号)2.1
f_c, f_sc搬送波周波数、副搬送波周波数2.1, 4.3
m位相変調の変調指数 [rad]4.3
B_n, ζ, θ_nループ雑音帯域幅、減衰係数、正規化ループ帯域(GNU Radioのloop_bw)3.1
ρループSNR(位相ジッタ1/√ρの根拠)3.1
sps1シンボルあたり標本数(samples per symbol)3.2
R_bビットレート [bps]4.3
■ まとめ
  • SDR=波形を数列にして以降を全部プログラムで処理する無線機。受信は5段(電圧化→数列化→複素整形→同期→フレーム)。
  • 道具は3つ: dB(×2=+3dB)、e^{jθ}(回転する点)、スペクトル(周波数の成分表)。
  • C/N₀・E_b/N₀は回線設計からの引き継ぎ書類。受信機設計はこの数字から始まる。
  • 難しければ「直観でつかむ」だけで1周する読み方が公式ルートである。
第 I 部 ディジタル化の基礎 — 現代受信機の入口
アンテナに届いた連続波形を数列に変える、その一点にSDRのすべてが懸かっている。標本化と量子化で何が保存され何が失われるのか、クロックの揺らぎがどこまで性能を規定するのかを定量化する。ここで導く数式が、以降のアーキテクチャ設計と実装の判断基準になる。

第1.1章なぜSDRか — 探査機通信とソフトウェア無線

■ この章で学ぶこと
ソフトウェア無線(SDR)とは何か、なぜ深宇宙通信の地上局も探査機搭載機器もSDR化したのか、 そして「どこからディジタルにするか」という設計軸を掴む。本書全体の見取り図である。
◇ 直観でつかむ — なぜわざわざソフトウェアにするのか
理由はひとつ、作った後で変えられるから。地上局なら、1台の装置で 全ミッション・全周波数帯・全変調方式を設定変更だけで受けられる。 探査機なら、打ち上げた後に無線機の中身を更新できる——これは 「二度と手が届かない機器」にとって決定的な価値である。
代わりに払う代償も明確で、すべての信号がADCという1つの関門を通ることになる。 だから本書は華やかなアルゴリズムより先に、その関門の物理(第I部)から始める。

1.1.1 SDRの定義 — 無線機を書き換え可能にする

ソフトウェア無線(Software Defined Radio, SDR)とは、変復調・フィルタリング・同期といった 無線機の信号処理機能を、専用アナログ回路ではなくソフトウェア(またはFPGA等の書き換え可能ロジック)で 実現する無線機である。アナログ部の仕事は「電波をADCが食える形に整える」ことだけに縮小され、 それ以降のすべて——ダウンコンバージョン、フィルタ、復調、同期、復号——は数値計算になる。

この定義の含意は大きい。数値計算である以上、無線機の性格は打上げ後・納入後でも書き換えられる。 新しい誤り訂正符号への対応、ループ帯域の変更、観測モードの追加が、ハードウェア改修なしに可能になる。 逆に言えば、SDRの性能限界はアナログ部とADC/DACが決める。だから本書は変換器の物理(第I部)から始める。

1.1.2 従来受信機とSDR受信機 — 何が置き換わったか

従来のアナログ受信機は、ミキサ・IFフィルタ・位相検波器・VCOといった専用回路の縦続だった。 SDR受信機ではこれらがすべてディジタル信号処理(DSP)ブロックに置き換わる。 両者の対応を見ると、本書の章立てがそのまま「置き換えの地図」になっていることがわかる。

従来(アナログ)受信機 LNA ミキサ×LO IFフィルタ水晶/SAW 位相検波器+VCO (PLL) ビット同期器アナログループ 復号器 SDR受信機 LNA 周波数変換(省略可) ADC DDC・フィルタ・同期・復調・復号 = すべてソフトウェア / FPGA ここが本書第I部:アナログ↔ディジタルの境界 第II〜IV部:境界の内側の世界
図1.1-1 従来受信機とSDR受信機。専用回路の縦続が「ADC+計算」に置き換わる。 性能の物理的上限はアナログ部とADCが、実現できる機能の上限はソフトウェアが決める。
アナログ実装ディジタル実装本書の章
ミキサ + LO(局部発振器)NCO + 複素乗算(DDC)第2.3章
IFフィルタ(水晶・SAW)FIR/CICフィルタ + デシメーション第2.3・2.4章
PLL(位相検波器 + VCO)ディジタルPLL(位相検出 + ループフィルタ + NCO)第3.1章
ビット同期器タイミング誤差検出器 + 補間器第3.2章
AGCアンプディジタルAGCループ第3.3章
ドップラ予測掃引(シンセサイザ)NCOへの予測値ステアリング第3.4章

1.1.3 深宇宙通信がSDR化した理由

地上局側。NASA DSNもESAもJAXAも、現在の深宇宙用受信機は完全にディジタルである。 理由は3つある。第一に共通化: 1つのディジタル受信機ハードウェアが、S/X/Ka帯・全ミッション・ 全変調方式を設定変更だけで受けられる。ミッションごとに専用復調器を作る時代は終わった。 第二に追従性: 新しい符号(LDPCなど)や新しい計測方式(PN測距など)への対応がソフトウェア更新で済む。 第三にオープンループ記録(第5.2章): 帯域全体をIQサンプルのまま記録しておけば、 後から何度でも・別のアルゴリズムで処理し直せる。電波科学や緊急時の微弱信号探索はこれに支えられている。

探査機側。搭載トランスポンダもSDR化が進む。JPLのElectra(火星周回機の中継無線機)や Iris(超小型深宇宙機用トランスポンダ、MarCOで飛行実証)は、FPGAベースの書き換え可能な無線機である。 打上げ後に相手ミッションに合わせてプロトコルを更新でき、1つのハードウェア設計を多数のミッションで 使い回せる。質量・電力・開発費のすべてで有利になる(第5.1章)。

【例1.1-1】「書き換えられる」ことの価値
火星周回機の中継無線機は、設計時には存在しなかった着陸機と将来通信することになる。 アナログ無線機なら相手側が周回機の仕様に完全に合わせるしかないが、SDRなら周回機側の プロトコルを軌道上で更新して歩み寄れる。実際にElectraは打上げ後のファームウェア更新で 新しい着陸ミッションへの対応を重ねてきた。深宇宙機は一度打ち上げたら二度と触れない—— だからこそ「触れる」部分をソフトウェアに移すことに価値がある。

1.1.4 設計軸 — どこからディジタルにするか

SDRの設計で最初に決めるのはADCを信号チェーンのどこに置くかである。 アンテナに近いほど柔軟性が上がり、アナログ部品が減るが、ADCへの要求(標本化周波数・ ダイナミックレンジ・消費電力)は厳しくなる。選択肢は大きく3つあり(第2.2章で詳述)、 RF直接サンプリング(アンテナ直後でディジタル化)、IFサンプリング(1回変換してから ディジタル化)、ゼロIF(IQミキサでベースバンドに落としてからディジタル化)である。 深宇宙地上局は伝統的にIFサンプリング、小型SDRデバイスはゼロIF、最新のRFSoC系は RF直接サンプリングが主流という住み分けになっている。

1.1.5 SDRの制約 — 万能ではない

ここまで利点を並べたので、限界も先に示しておく。「全部ソフトウェアにすればよい」 とはならない理由が3つある。どれも本書の後の章で具体的に扱う。

制約1: ダイナミックレンジ。従来のアナログ受信機は、 邪魔な信号(妨害波)をフィルタで落としてから増幅・検波していた。 SDRでは妨害波もいったんADCを通る。強い妨害波と微弱な目的信号が同時に入ってくると、 ADCの限られた段数を両方で分け合うことになり、ビット数が受信能力の限界を決めてしまう。 これは第1.3章の中心的な主題である。

制約2: 処理量。標本化周波数×ビット幅のデータを実時間で処理し続ける計算能力が要る。 たとえば100 MSPSの複素信号を16ビットで扱えば毎秒800 MBのデータ流になる。 汎用CPUで間に合わない処理はFPGAに置くしかなく、その線引きが設計の勘所になる(第2.5章)。

制約3: レイテンシ(遅延)。ソフトウェア処理はデータをある程度まとめて (バッファに溜めて)処理するため、必ずマイクロ秒からミリ秒の遅延が生じる。 片方向のテレメトリ受信なら無害だが、受信した信号に即座に応答するような機能 ——たとえば探査機が受信搬送波に同期して送り返すコヒーレント・ターンアラウンド——では 設計上の制約になる(第5.1.3節)。

1.1.6 本書のツールチェーン

実装の学習には GNU Radio を使う。オープンソースのSDRフレームワークで、 信号処理ブロックをフローグラフとして接続して受信機を組む(第4.1章)。 アマチュア衛星から電波天文、そして実際の深宇宙ミッションの信号解析まで実績があり、 gr-satellitesのような衛星通信特化の拡張も充実している。ハードウェアはRTL-SDR(数千円)から USRP(研究用)まで同じフローグラフで扱える。理論の各章末に置いた「GNU Radioで試す」枠を 積み重ねると、第IV部でそれらが1つの受信機に組み上がる構成にしてある。

Q. SDRと「ディジタル受信機」は同じものか?

ほぼ同義に使われるが、ニュアンスが違う。「ディジタル受信機」は実装手段がディジタルであることを、 「SDR」は機能がソフトウェアで定義され書き換え可能であることを強調する。 FPGAに焼き固めた復調器は前者ではあるが、再構成性を活かしていなければSDRの利点は半分しか使っていない。

Q. アナログ回路の知識はもう不要か?

むしろ逆である。SDRの性能はアナログフロントエンドとADCで頭打ちになるため、 雑音指数・ダイナミックレンジ・位相雑音といったアナログの語彙(姉妹編第1.4・4.4章)が そのままSDRの仕様書の語彙になる。SDRエンジニアはアナログとディジタルの境界に立つ仕事である。

■ まとめ
  • SDRは変復調・同期をソフトウェア/FPGAで行う無線機。性能上限はアナログ部とADC/DACが決める。
  • 深宇宙通信のSDR化の動機は、地上局では共通化・追従性・オープンループ記録、機上では打上げ後の書き換えとハードウェア共通化。
  • 設計の第一の決断は「ADCをどこに置くか」。柔軟性とADC要求のトレードオフである。
  • 制約はダイナミックレンジ・処理量・レイテンシ。「全部ソフトで」は成立しない。

第1.2章標本化 — 時間の離散化

■ この章で学ぶこと
連続波形を数列にしても情報が失われない条件(標本化定理)、失われるとどうなるか(エイリアシング)、 そして深宇宙受信機の定石である帯域通過標本化——IF信号をベースバンドに落とさず直接食う技法——を学ぶ。
◇ 直観でつかむ — 標本化とは「等間隔に写真を撮る」こと
連続した波形を、一定の間隔でパッ・パッ・パッと値を読み取って数列にする。これが標本化である。 間隔が十分に細かければ、点だけから元の波形を復元できる——直観的には 「波が1回上下する間に2回以上写真を撮れば、上下していることは記録できる」。これが「f_s > 2B」の中身である。 逆に撮る間隔が粗いと、扇風機の羽根が止まって見えたり逆回転して見えたりするのと同じことが起こる。 これがエイリアシングで、SDRで最初に覚えるべき失敗である。

1.2.1 標本化定理 — 情報は失われていない

まず言葉を決めておく。標本化(サンプリング)とは、連続的に変化する電圧 x(t) を 一定の時間間隔 T_s ごとに読み取り、数値の列に置き換える操作である。 この間隔 T_s を標本周期、その逆数 f_s = 1/T_s を標本化周波数と呼び、 単位はSPS(samples per second, 標本毎秒)を使う。 1秒に100万回読み取るなら f_s = 1 MSPS である。 得られた数列を x[n] と書く。n は何番目の標本かを表す整数で、 その値は元の波形の時刻 n·T_s における値、すなわち x[n] = x(n·T_s) である。

ここで自然な疑問が出る。連続だった波形を、点々の値に間引いてしまって本当に大丈夫なのか。 点と点の間で波形が何をしていたかは、記録されていないように思える。 これに答えるのが標本化定理である。信号に含まれる周波数成分が B Hz 以下に限られているとき (このような信号を「帯域 B に帯域制限されている」という)、標本化周波数が

f_{s} > 2B

を満たしていれば、標本列 x[n] から元の連続波形 x(t) を完全に復元できる。 これがNyquist–Shannonの標本化定理である。

「完全に」という言葉を軽く読まないでほしい。「だいたい復元できる」「実用上問題ない程度に近い」 という意味ではなく、数学的に一意に、誤差ゼロで元の波形が再構成できるという主張である。 再構成の手続きも具体的に与えられている。各標本点に sinc 関数(sin(πx)/πx の形をした、 その標本点で1・他の標本点で0になる関数)を置き、標本値を重みとして足し合わせればよい。 点と点の間の波形は「記録されていない」のではなく、 帯域制限という条件によって一通りに決まってしまう——だから記録する必要がなかったのである。

この定理がSDRの土台である。ディジタル化は情報を捨てる操作ではなく、 帯域制限された信号に対しては無損失の座標変換にすぎない。 以降の章で行うすべての信号処理は「数列は元の波形の完全な代理人である」という信頼の上に立っている。 逆に言えば、この前提(帯域制限と f_s > 2B)が崩れた瞬間に、以降の処理はすべて土台を失う。 次節でその崩れ方を見る。

なお境界の値 2B をナイキストレート、その半分の f_s/2 をナイキスト周波数と呼ぶ。 ナイキスト周波数は「このディジタル世界に存在できる最高周波数」であり、 本書に繰り返し登場する重要な境界線である。 実務では f_s を 2B ぎりぎりに取ることはせず、2〜3割、場合によっては数倍の余裕を持たせる。 その理由は1.2.3節で明らかになる。

1.2.2 スペクトルの複製とエイリアシング

標本化で何が起きているかは、時間波形を眺めていてもわかりにくい。 周波数の世界(スペクトル)で見ると、驚くほど単純な絵になる。

結論を先に言うと、標本化とは「スペクトルを f_s 間隔でコピーして並べる」操作である。 元の信号のスペクトルを X(f) と書くと、標本化後の信号のスペクトル X_s(f) は次のようになる。

X_{s}(f) = \frac{1}{T_{s}} Σ_{k=-∞}^{∞} X(f - k f_{s})

式の見方を説明する。Σ(総和)の中の X(f − k·f_s) は、元のスペクトルを 周波数軸上で k·f_s だけ右へずらしたものである。k は 0, ±1, ±2, … と すべての整数を走るので、元のスペクトルの複製が f_s 間隔で無限に並ぶ、と読める。 k = 0 の項が元のスペクトルそのもので、それ以外は標本化によって生まれた複製(イメージ)である。

さて、この絵から標本化定理の意味が見えてくる。元のスペクトルが 0 から B までの幅を持つとき、 複製は f_s 間隔で並ぶ。複製同士が重ならないためには、隣の複製が来る前に元のスペクトルが 終わっていなければならない。実信号のスペクトルは正負対称に ±B まで広がるので、 重ならない条件はちょうど f_s > 2B になる。 重なっていなければ、ローパスフィルタで元の1枚だけを切り出せる——これが復元の正体である。

では f_s が足りないとどうなるか。複製が元のスペクトルに食い込み、重なった部分では 元の成分と複製の成分が足し合わさってしまう。周波数 f にあった成分は、 f_alias = |f − k·f_s| という位置に化けて現れる。これがエイリアシング(折り返し)である。

エイリアシングが恐ろしいのは、起きてしまうと後からどんな処理をしても取り除けない点にある。 足し合わさった2つの値から元の2つを分離することは原理的に不可能で、 数列の上では「本物の信号」と「折り返してきた偽物」がまったく同じ姿をしている。 増幅器の歪みや雑音のような「劣化」とは性質が違い、情報が完全に失われる不可逆な事故である。 だからSDRの設計では、エイリアシングを事後に直す方法を考えるのではなく、 絶対に起こさない仕組みを入口に置く。それが次節のフィルタである。

0 −fₛ +fₛ fₛ > 2B:複製は重ならない 0 −fₛ +fₛ fₛ < 2B:複製が重なる = エイリアシング 折り返し成分が混入
図1.2-1 標本化はスペクトルを f_s 間隔で複製する。 複製が重なった瞬間、帯域外成分が帯域内に折り返り、以降どうやっても取り除けない。

1.2.3 アンチエイリアシングフィルタ — アナログ部の最後の仕事

エイリアシングを防ぐには、標本化する前に、ナイキスト周波数 f_s/2 より高い成分を 信号から取り除いておくしかない。この役目のフィルタを アンチエイリアシングフィルタ(AAF)と呼び、ADCの直前に置く。

ここで注意してほしいのは、AAFはディジタルフィルタでは代替できないことである。 SDRは「なんでもソフトウェアで」が売りだが、この1個だけは物理的なアナログ回路として 作らなければならない。理由は前節の通りで、折り返しはADCの中で起きるため、 ADCを通った後の数列を処理しても手遅れなのである。 SDRの設計でアナログ回路の知識が要る、という第1.1章の話の具体例がこれである。

設計の要点は遷移域(トランジション帯域)という考え方にある。 理想的なフィルタは「B Hzまでは完全に通し、それより上は完全に遮断する」という 垂直の壁を持つが、現実のフィルタにそんな壁は作れない。 通過域の端(B)から、十分な減衰が得られる阻止域の端(f_s − B)まで、 なだらかに落ちていく区間が必ずできる。この区間が遷移域である。

ここに設計上のトレードオフが生まれる。f_s を 2B ぎりぎりに設定すると、 遷移域として使える周波数の幅が狭くなり、短い距離で急激に落ちる急峻なフィルタが必要になる。 急峻なフィルタは段数(次数)が多くなり、部品が増え、通過域内の振幅のうねり(リプル)や 信号の波形を歪ませる群遅延の変化といった副作用も大きくなる。 逆に f_s に余裕を持たせれば、遷移域が広くなって緩いフィルタで足りる。 これが1.2.1節で「実務では f_s に余裕を持たせる」と述べた理由である。

【例1.2-1】オーバーサンプリングでフィルタを楽にする
帯域 B = 10 MHz の信号を f_s = 25 MSPS で標本化すると、AAFは 10 MHz から 15 MHz までの 5 MHz で阻止減衰(例えば60 dB)を達成せねばならず、10次近い急峻なフィルタになる。 f_s = 50 MSPS に上げれば遷移域は 10〜40 MHz の 30 MHz に広がり、 4〜5次の緩いフィルタで済む。標本化を速くしてアナログを楽にし、後段のディジタルフィルタで 追い込む——これがSDRの基本戦術である(第2.4章のデシメーションに続く)。

1.2.4 ナイキストゾーン — 折り返しを地図にする

折り返しがどこへ落ちるかを見通しよく扱うために、周波数軸を f_s/2 の幅で区切って 番号を振る。この区画をナイキストゾーンと呼ぶ。 0 から f_s/2 までが第1ゾーン、f_s/2 から f_s までが第2ゾーン、 一般に第nゾーンは (n−1)·f_s/2 から n·f_s/2 までである。 f_s = 100 MSPS なら、第1ゾーンは0〜50 MHz、第2ゾーンは50〜100 MHz、 第3ゾーンは100〜150 MHz、というように50 MHz刻みで区画が並ぶ。

この区画を使うと、標本化の作用が一言で言える。 標本化すると、すべてのゾーンにあった信号が第1ゾーンに折り重なって現れる。 ディジタル世界には第1ゾーンしか存在しないので、どのゾーンに居た信号も そこへ移されるしかない、と考えればよい。

移り方には規則がある。奇数番のゾーン(第1・第3・第5…)にあった信号は、 周波数の並び順を保ったまま平行移動して第1ゾーンに現れる。 偶数番のゾーン(第2・第4…)にあった信号は、周波数軸が左右反転して現れる。 これをスペクトル反転と呼ぶ。反転すると、元は上側にあった成分が下側に来る。 困った現象のようだが、ディジタル領域で複素共役を取る(第2.1.4節)だけで元に戻せるので、 実害はない。設計時に「反転するかしないか」を把握しておけば足りる。

ここで前節までの話と本章の後半がつながる。エイリアシングとは、 意図しないゾーンの信号が第1ゾーンに落ちてくることであり、 次節で学ぶ帯域通過標本化とは、意図したゾーンの信号を第1ゾーンに落とすことである。 物理現象としては同一で、違いは設計者がそれを望んだかどうかだけである。

1.2.5 帯域通過標本化 — IFを直接食う

◇ 直観でつかむ — 折り返しを「わざと」使う
前節では折り返し(エイリアシング)を「事故」として嫌った。ところが折り返し先は 計算で完全に予測できるので、狙った場所に落ちるように標本化速度を選べば、 折り返しがそのまま周波数変換(ミキサ)の代わりになる。 140 MHzの信号を、300 MSPSでなく100 MSPSで受けて40 MHzに「降ろす」—— ミキサ1段ぶんの回路がタダで手に入る。事故と技法の違いは、 設計者が結果を把握しているかどうかだけである。

ここまでは「標本化定理は f_s > 2B」と書いてきたが、この B は信号の帯域幅であって、 信号の最高周波数ではない。両者が一致するのは、信号が0 Hzから B までびっしり詰まっている 場合(ベースバンド信号)だけである。ところが受信機の中を流れるIF信号は、 たとえば中心 140 MHz・幅 10 MHz というように、高い周波数にある狭い帯域という形をしている。 この場合、最高周波数の2倍にあたる 300 MSPS のADCを用意する必要はない。

理由は前節のゾーンの絵で説明できる。信号が1つのナイキストゾーンの中に完全に収まるように f_s を選べば、その信号は他のゾーンの成分と重ならず、そのまま第1ゾーンへ移されて現れる。 情報は失われず、しかも周波数が低い側へ移動している——つまり 標本化そのものが周波数変換(ダウンコンバージョン)を兼ねてくれる。 ミキサとLOを1段省けるということであり、これが帯域通過標本化 (アンダーサンプリングとも呼ぶ)である。

条件を式にする。信号の帯域の下端を f_L、上端を f_H(したがって帯域幅は B = f_H − f_L)とすると、 「信号が第nゾーンにちょうど収まる」という条件は次の不等式になる。

\frac{2 f_{H}}{n} ≤ f_{s} ≤ \frac{2 f_{L}}{n-1}

使い方は次のとおりである。まず整数 n(1 以上 ⌊f_H / B⌋ 以下)をひとつ選ぶ。 この n が「信号を第何ゾーンに置くか」に対応する。 次に不等式に f_L と f_H の値を入れ、f_s の許される範囲を計算する。 範囲が空でなければ、その中から都合の良い f_s を選べばよい。 n を変えて何通りか計算し、ADCの速度・クロックの作りやすさ・データ量から選ぶのが実務である。 n = 1 のときは不等式の右辺が無限大になり、通常の標本化(f_s ≥ 2f_H)に戻る。 n が2以上の場合がアンダーサンプリングである。

前節の規則により、n が奇数ならスペクトルはそのままの向きで、 偶数なら反転して第1ゾーンに現れる。どちらでも復調に支障はないが、 設計書には明記しておくこと。

なお本節に出てきた「IF」という言葉は、従来のスーパーヘテロダイン受信機のIFと 同じものである。ただしSDRではIFが2種類に分かれる—— ここで扱った物理的に実在するIF(ADCの入力周波数)と、 標本化された数列の中で信号が置かれる位置としてのIFである。 両者の対応と、従来無線機の周波数体系がSDRのどこに写るかは第2.2.5節でまとめて整理する。

0 50 100 150 f [MHz] 第1ゾーン 第2ゾーン 第3ゾーン IF 135–145 MHz 折り返し後 35–45 MHz
図1.2-2 帯域通過標本化の例。IF 140 MHz・帯域 10 MHz を f_s = 100 MSPS で標本化すると、 信号は第3ゾーンに収まり、第1ゾーンの 40 MHz 中心に(反転せず)現れる。 300 MSPS のADCは不要——標本化がミキサを兼ねる。
【例1.2-2】f_s の候補を求める
f_L = 135 MHz、f_H = 145 MHz(B = 10 MHz)。n の上限は ⌊145/10⌋ = 14。 n = 3 を選ぶと 2·145/3 = 96.7 ≤ f_s ≤ 2·135/2 = 135 [MSPS]。 この範囲から、クロック生成の都合が良く、かつ境界に余裕のある f_s = 100 MSPS を選ぶ (140 MHz は 100 MSPS の第3ゾーンの中央付近に来て、40 MHz に折り返る)。 境界ぎりぎりの f_s はAAFの遷移域を失わせるので避ける。

うまい話には代償がある。帯域通過標本化には2つの負担が付いてくる。

第一に、入口のフィルタが難しくなる。通常の標本化ならAAFはローパスフィルタ (高い方を落とすだけ)で済むが、帯域通過標本化では帯域通過フィルタ (狙ったゾーンだけを通し、その上下すべてを落とす)が必要になる。 なぜそこまで厳しくするかというと、雑音のせいである。 熱雑音はあらゆる周波数に一様に存在するので、フィルタが甘いと第1・第2・第4…と すべてのゾーンから雑音が第1ゾーンへ折り重なって積み上がる。 重なるゾーンの数が m 個なら雑音電力は m 倍、つまり雑音床が 10log₁₀(m) dB 持ち上がる。 微弱信号を扱う深宇宙受信では、この数dBが致命的になり得る(演習1.2-2で計算する)。

第二に、クロックの純度への要求が厳しくなる。次章(第1.4章)で示すように、 標本化クロックの時間的な揺らぎが許される量は、標本化周波数ではなく 入力信号の周波数によって決まる。140 MHzの信号を食うなら、たとえ f_s が 100 MSPS でも、 140 MHzの波形を刻むのに見合った高純度クロックが要求される。 「ADCは安く済んだがクロック回路が高くついた」という設計はしばしば起きる。

1.2.6 実務での f_s の選び方

ここまでで f_s に関わる条件がいくつも出てきた。実際の設計では、 これらを同時に満たす値を探すことになる。「2Bより大きければ何でもよい」わけではない、 というのがこの節の要点である。次の表を上から順に確認していくとよい。

考慮点内容
ナイキスト余裕AAF遷移域のため、占有帯域の2.2〜2.5倍以上。
帯域通過条件IFサンプリングなら1.2.5節の不等式。ゾーン境界から1割以上の余裕を取る。
整数関係後段のデシメーション比が 2^k や小さい整数の積になるとフィルタ段が単純になる(第2.4章)。シンボルレートとの比が有理数で小さい分母だと再標本化が軽い。
クロック源基準周波数(10 MHz局標準など)から整数逓倍で作れる値はジッタ・スプリアスの管理が楽。
データ量f_s×ビット幅×2(IQ) が伝送路(USB/Ethernet)と記録装置に収まるか(第2.5章)。

1.2.7 再構成 — DAC側の標本化定理

送信側では、いままでの話がすべて逆向きに起きる。DACは数列を受け取って連続波形に戻す装置で、 その出力にも標本化と同じくf_s 間隔のスペクトル複製が現れる。 送信側ではこの複製をイメージと呼び、欲しい成分(第1ゾーン)以外は 不要な電波の放射になるので、アナログの再構成フィルタで落とす。 受信のAAFと送信の再構成フィルタは、同じ物理の表と裏である。

1つだけ受信側にない事情がある。DACは理想的な点(インパルス)を出すのではなく、 次の標本まで値を保持する階段状の波形を出す。この保持動作を ゼロ次ホールドと呼び、その影響で出力スペクトルには周波数が高くなるほど 振幅が下がる緩やかな傾斜がかかる。定量的な扱いは第1.5.4節で行う。

まとめると、受信で学んだことは鏡に映すだけで送信に使える。 本書が受信を中心に書かれているのはこのためで、送信特有の話題は第1.5.4節と 第4.3.3節(実際の送信機の実装)に限られる。

Q. 標本化定理は「2倍」なのに、なぜ実務では2.5倍も取るのか?

定理の2Bは無限に急峻なフィルタを仮定した数学的境界だから。実フィルタの遷移域、 ドップラによる周波数の移動幅、クロックの許容誤差を織り込むと2.2〜2.5倍が現実的な下限になる。 逆に10倍を大きく超える標本化は、データ量とジッタ要求(第1.4章)を無駄に重くするだけのことが多い。

Q. エイリアシングは常に悪か?

意図せず起きれば致命傷、意図して使えば設計技法である。帯域通過標本化は 「エイリアシングでIFをベースバンド近くへ運ぶ」技法にほかならない。 重要なのは、何がどのゾーンからどこへ折り返るかを設計者が完全に把握していることである。

▶ GNU Radioで試す — エイリアシングを見る
GRCで Signal Source(cosine, 周波数変数 f0)→ ThrottleQT GUI Frequency Sinksamp_rate = 32 kHz)を接続し、 QT GUI Rangef0 を 0〜32 kHz まで動かす。 f0 が 16 kHz を超えた瞬間、表示上のトーンが折り返して下降を始める(f0 = 20 kHz は 12 kHz に見える)。 「ディジタル世界には f_s/2 より上が存在しない」ことが体感できる。 次に Rational Resampler(decimation=2, 補間フィルタの taps を空欄=既定)を挟むと、 折り返し境界が 8 kHz に下がるが、既定のフィルタが折り返し成分を抑えることも確認できる。

章末演習

【演習 1.2-1】帯域通過標本化の設計
IF中心 70 MHz、帯域 8 MHz(66〜74 MHz)の信号に対し、n = 2 とした場合の f_s の許容範囲を求めよ。 またそのときスペクトルは反転するか。
解答
2·74/2 = 74 ≤ f_s ≤ 2·66/1 = 132 [MSPS]。n = 2(偶数ゾーンから折り返す)なのでスペクトルは反転する。 例えば f_s = 100 MSPS なら信号は第2ゾーン(50〜100 MHz)にあり、100 − 70 = 30 MHz 中心に反転して現れる。 反転はDDCで複素共役を取れば戻る。
【演習 1.2-2】雑音の折り返し
帯域通過標本化(n = 4)で、AAFを省略して広帯域の熱雑音がすべてのゾーンに一様に存在したとする。 第1ゾーンの雑音電力密度は、AAFを理想的に入れた場合に比べ何dB上がるか。
解答
実信号の標本化では第1ゾーンに折り重なるのは各ゾーン1枚ずつ、n = 4 なら4ゾーン分。 10log₁₀4 = +6.0 dB。G/T で戦う深宇宙受信でこれは致命的で、 帯域通過標本化ではAAF(帯域通過型)の阻止域性能が雑音性能に直結することがわかる。
■ まとめ
  • f_s > 2B なら標本化は無損失の座標変換。エイリアシングは起きたら最後、除去不能。
  • AAFはディジタル化できない宿命のアナログ部品。オーバーサンプリングでAAFを緩くするのがSDRの定石。
  • 帯域通過標本化は「狙ったナイキストゾーンをエイリアシングで運ぶ」技法。条件は 2f_H/n ≤ f_s ≤ 2f_L/(n−1)。
  • f_s の選定はナイキスト余裕・ゾーン余裕・整数関係・クロック源・データ量の同時最適化。

第1.3章量子化 — 振幅の離散化

■ この章で学ぶこと
振幅を有限ビットで表すことによる雑音の定量化(6.02N + 1.76 dB)、データシートの読み方(ENOB・SFDR)、 そして深宇宙受信ならではの結論——雑音に埋もれた信号は驚くほど少ないビット数で受かる——を導く。
◇ 直観でつかむ — 目盛りの粗い定規で測る
標本化が「いつ測るか」の離散化なら、量子化は「どこまで細かく読むか」の離散化である。 1 mm目盛りの定規では 0.5 mm 未満の差は読めず、読み値には最大±0.5 mmの誤差が残る。 この読み取り誤差が量子化雑音で、目盛りを細かく(=ビット数を増やす)すれば減る。 ビットを1つ増やすと目盛りが半分になり、誤差が半分=約6 dB改善——これが「6.02N + 1.76 dB」の正体である。 ただし本章の後半で、深宇宙受信では驚くほど粗い定規でも困らないという 意外な結論(1.3.6節)に至る。そこが本章の山場である。

1.3.1 量子化雑音の基本モデル

用語を定義する。ADCが表現できる電圧の最大幅をフルスケール V_FS と呼び、 Nビットの変換器はこの幅を 2^N 段に等分する。したがって1段の高さ(刻み幅、 LSB = Least Significant Bit の重みとも呼ぶ)は

Δ = \frac{V_{FS}}{2^{N}}

である。たとえばフルスケール2 V・12ビットなら Δ = 2/4096 ≈ 0.49 mV。 ADCは入力電圧を最も近い段に丸めるので、読み値には最大で ±Δ/2 の誤差が残る。 この丸め誤差を量子化誤差と呼ぶ。

設計に使うには、この誤差の大きさを1つの数で表したい。そこで統計的に扱う。 信号が十分に複雑で(つまり多数の段をまたいで刻々と動いていて)、 誤差が −Δ/2 から +Δ/2 の間をまんべんなく取ると仮定する。 この一様分布の分散を計算すると、次の値が得られる。

σ_{q}^{2} = \frac{Δ^{2}}{12}

(区間幅 Δ の一様分布の分散が Δ²/12 になることは、統計の教科書どおりの計算である。) これを量子化雑音の電力と呼ぶ。以降の議論はすべてこの1つの式から出発する。

ここで見落としてはいけない性質がある。Δ²/12 は信号の大きさをまったく含まない。 つまり量子化雑音の量は、大きな信号を入れても小さな信号を入れても変わらない。 したがって信号対雑音比(SNR)は、信号をフルスケール近くまで大きく振らせるほど良くなり、 小さい信号のままでは悪い。ここから実務上の結論が出る。 ADCを使いこなすとは、信号のレベルをこの固定された雑音床に対してどこに置くかを管理することである。 その置き場所の設計が1.3.5節、置き場所を自動で保つ仕組みが第3.3章のAGCである。

1.3.2 6.02N + 1.76 dB — 由来と適用限界

前節の Δ²/12 を使って、教科書でよく見る式を導いてみよう。 いちばん条件の良い信号——フルスケールいっぱいに振れる正弦波——を入れたとする。 振幅 V_FS/2 の正弦波の電力は V_FS²/8 である。これを雑音電力 Δ²/12 で割り、 Δ = V_FS/2^N を代入して整理し、10log₁₀ を取ってdBにすると次が得られる。

SNR_{q} = 6.02 N + 1.76\, [dB]

覚え方は「1ビット足すごとに約6 dB良くなる」である (6.02 の正体は 20log₁₀2 = 6.02、つまり刻み幅が半分になることの効果)。 具体的には8ビットで49.9 dB、12ビットで74.0 dB、16ビットで98.1 dBとなる。

ただしこの式は3つの前提の上に成り立っており、実機ではそのどれもがずれる。 この3点を意識できるかどうかが、式を暗記した人と使える人の差になる。

前提①: 信号がフルスケールいっぱいの正弦波である。 実際の信号は、クリップを避けるため意図的に小さめに入れる(1.3.5節)。 フルスケールより 12 dB 小さく使えば、SNRもその分だけ下がる。

前提②: 量子化誤差が白色雑音である。 入力が単純な周期波形だと誤差も周期性を持ち、雑音として散らばる代わりに 特定の周波数に鋭い線(スプリアス)として集まってしまう。対策が1.3.7節のディザである。

前提③: 雑音を 0 から f_s/2 の全域で積分している。 実際に使う信号帯域がそれより狭ければ、帯域外の雑音は後段のフィルタで捨てられ、 有効なSNRは式の値より良くなる。この効果が次節のプロセッシングゲインである。

データシートに載っている「SNR」も、この3前提の周辺で測定条件付きで定義されている。 入力周波数と入力振幅の条件を確認せずに数字を比較してはならない。

1.3.3 ENOB・SINAD・SFDR — データシートの読み方

実物のADCは、前節の理想式どおりには動かない。量子化誤差以外にも、 内部回路の熱雑音、入出力特性の曲がり(非直線性)、クロックの揺らぎ(第1.4章)が あるからで、公称Nビットの部品が 6.02N + 1.76 dB の性能を出すことはない。 では設計計算には何を使えばよいか。そのために2つの指標がある。

1つ目は SINAD(Signal-to-Noise-And-Distortion ratio)である。 正弦波を入れて出力を分析し、信号成分と、それ以外のすべて(雑音+歪み)の比を実測した値である。 2つ目は ENOB(Effective Number Of Bits, 実効ビット数)で、 実測したSINADを前節の式に逆代入して「これは何ビット相当の性能か」に翻訳した数である。

ENOB = \frac{SINAD − 1.76}{6.02}

たとえば公称14ビットのADCで SINAD = 68 dB と測れたなら、 ENOB = (68 − 1.76)/6.02 = 11.0 ビットである。 設計計算に使ってよいのは、公称の14ではなくこの11の方である。

もう1つ、深宇宙受信でとりわけ重要な指標が SFDR (Spurious-Free Dynamic Range, スプリアスフリー・ダイナミックレンジ)である。 これは信号と、出力に現れる最大の偽信号(スプリアス)との比を表す。 なぜこれが効くかというと、深宇宙の受信では「非常に強い信号と極端に弱い信号が同居する」 状況が普通だからである。強い信号が作った偽の線が、微弱な本物の信号のあたりに立ってしまえば、 平均的なSNRがいくら良くても探している信号は見つけられない。 平均的な雑音よりも、偽信号の高さが検出限界を決める場面が多いのである。

最後に読み方の注意を1つ。ENOBは入力周波数が高くなるほど悪化する (主犯はクロックの揺らぎで、第1.4章で理由がわかる)。 データシートには周波数を横軸にしたENOBのグラフが載っているので、 低い周波数での見栄えの良い数字ではなく、自分が実際に入力するIF周波数での値を読むこと。 帯域通過標本化(第1.2.5節)では入力周波数が高いので、この確認が特に重要になる。

1.3.4 オーバーサンプリングとプロセッシングゲイン

前節の前提③(雑音を f_s/2 まで全部数えている)を利用すると、 ビット数を増やさずにSNRを稼ぐ方法が見えてくる。

量子化雑音の総量 Δ²/12 は、0 から f_s/2 の範囲に一様に広がっている。 「総量が決まっていて、それが f_s/2 の幅に広がっている」ということは、 f_s を大きくすれば、単位周波数あたりの雑音密度は薄くなるということである。 一方、信号は帯域 B の中にしか居ない。したがって後段のディジタルフィルタで B の外側を捨ててしまえば、捨てた分の雑音がまるごと消え、信号だけが残る。 この効果を式に足すと次になる。

SNR = 6.02N + 1.76 + 10 log_{10}\big(\frac{f_{s}}{2B}\big)\, [dB]

追加された第3項がプロセッシングゲインである。 f_s/2B(オーバーサンプリング比)が4倍になるごとに 10log₁₀4 = 6 dB 稼げるので、 オーバーサンプリング4倍がADC 1ビット分に相当すると覚えるとよい。

ここで第1.2.3節の話とつながる。あのとき「f_s に余裕を持たせるとAAFが楽になる」と述べたが、 いま見たようにそれは同時にSNRも稼いでいた。速く粗く標本化して、 ディジタルフィルタで追い込むというSDRの基本戦術は、アナログ部品の負担軽減と 実効ビット数の向上を同時に達成しているのである。 この発想を極限まで推し進めた変換器がΣΔ型ADCで、第1.5.2節で扱う。

【例1.3-1】RTL-SDR(8ビット)はなぜ実用になるのか・その1
8ビットの量子化SNRは49.9 dB。しかし f_s = 2.4 MSPS で受けた帯域内から、 実際に使う信号帯域が 10 kHz なら、プロセッシングゲインは 10log₁₀(2.4×10⁶/2×10⁴) = 20.8 dB。 復調器から見た実効SNR上限は約70 dB相当になる。安価な8ビットSDRで狭帯域の衛星テレメトリが 受かる理由の半分はこれである(残り半分は次節)。

1.3.5 ローディングファクタ — どこまで振らせるか

1.3.1節の結論は「信号を大きく振らせるほどSNRが良くなる」だった。 では限界まで大きくすればよいのか——ここに落とし穴がある。

フルスケールを超えた入力に対して、ADCは最大値を出し続けるしかない。 波形の頭が平らに潰れるこの現象をクリッピング(飽和)と呼ぶ。 クリッピングは単に「少し歪む」では済まない。強い非線形動作なので、 複数の信号が混ざり合って新しい周波数成分を作り(相互変調)、 本来なかった場所にスペクトルを生む。量子化雑音より遥かに有害であり、 数dBのSNRを惜しんでクリップさせるのは完全に割に合わない。

厄介なのは、受信信号のピークがどこまで伸びるか事前に決まらない点である。 熱雑音を含む受信信号の振幅はガウス分布に従うので、 実効値(rms)の3倍・4倍のピークがたまに現れる。 そこで設計量としてローディングファクタ——信号の実効値がフルスケールの何分の1か——を決める。

定石は実効値をフルスケールの1/4程度、すなわち −12 dBFS に置くことである (dBFSはフルスケールを0 dBとした表し方)。 このとき4σ(実効値の4倍)までのピークが収まるので、 クリップの確率は 10⁻⁴ 以下に抑えられる。代償として、 理想式(フルスケール正弦波)に比べSNRは9 dBほど下がるが、 これはクリッピングを避けるために意図的に払う保険料だと理解すればよい。 そして運用中この置き場所を保ち続けるのが、第3.3章で扱うAGCの仕事である。

1.3.6 微弱信号と量子化 — 雑音がディザになる

ここからが本章の山場である。深宇宙受信という特殊な状況を考えると、 ここまでの常識がひっくり返る。

状況を確認しよう。数億km彼方から届く信号は極端に微弱で、 受信機の熱雑音に深く埋もれている。つまりADCの入口で支配的なのは信号ではなく雑音であり、 ADCが刻んでいるのはほぼ雑音の波形である。信号そのものの振幅は、 量子化の刻み幅Δよりはるかに小さいことすらある。

常識的には「刻み幅より小さい信号は丸められて消える」と思える。ところがそうならない。 ADCに入る雑音がLSBの1〜2倍以上あれば、信号がLSBよりずっと小さくても、 積分(相関処理)した後にはちゃんと現れるのである。

仕組みはこうである。雑音があるおかげで、入力は量子化の段の間を絶えず行き来している。 そこに微小な信号が加わると、どちらの段に丸められるかの確率がわずかに偏る。 1回の標本では見えないが、多数の標本を平均すればこの偏りが信号として浮かび上がる。 雑音が信号を段の間で揺すってくれることで情報が保存される—— これは1.3.7節で扱うディザとまったく同じ原理で、 深宇宙受信では自然の熱雑音が無料でディザの役目を果たしている。

この効果を定量化すると、量子化によるSNRの劣化(量子化損失)は、 雑音に対してレベルを最適に設定した場合、次の値になることが知られている。

ビット数SNR効率量子化損失主な用途
1ビット2/π = 0.637−1.96 dB初期のVLBI、極限のデータ量削減
2ビット0.881−0.55 dBVLBI・ΔDOR記録の標準
4ビット0.988−0.05 dBオープンループ記録
8ビット≈1−0.001 dB級汎用SDR

表の意味をよく見てほしい。たった2ビット——4段階しか区別できない変換器——でも、 失う感度は0.55 dBしかない。1ビット(正負の符号だけ!)でも2 dBである。 電波天文のVLBIや探査機の位置決定に使うΔDOR(姉妹編第3.2章)の記録が 伝統的に1〜2ビットなのはこのためで、感度をほとんど失わずに 記録するデータ量を桁で減らせるという、極めて有利な取引になっている。

ではなぜ普通の受信機は8ビットや14ビットを使うのか。ここが本節の結論である。 上の表はすべて「入っているのは雑音と微弱な目的信号だけ」という前提で成り立っている。 現実には、近くの通信局、レーダー、あるいは同じ探査機の別チャネルといった 桁違いに強い信号が同じ帯域に飛び込んでくる。 2ビットのADCでは、4段階すべてがその強信号の振幅に費われ、 微弱な目的信号は完全に潰れてしまう。

したがって正しい理解はこうである。ビット数は感度を買うための資源ではなく、 「強い信号と弱い信号を同時に扱う能力」=ダイナミックレンジを買うための資源である。 静かな帯域なら少ビットで足り、賑やかな帯域では多ビットが要る。 「高感度にしたいからビット数を増やす」という発想は、この節の理屈からは出てこない。

【例1.3-2】RTL-SDRはなぜ実用になるのか・その2
アンテナ雑音がADCのLSBを数カウント揺らすようゲイン配分してあれば(第3.3章)、 8ビットでの量子化損失は事実上ゼロで、感度はフロントエンドの雑音指数だけで決まる。 8ビットが問題になるのは、近所のFM放送局のような強信号が同じ帯域に飛び込み、 256段のうち250段をそれが占有してしまうときである。

1.3.7 ディザ — わざと雑音を足す

前節は「雑音があるおかげで助かる」話だった。逆の状況、 つまり入力があまりにきれいな場合に何が起きるかを見ておく。 これは1.3.2節の前提②(量子化誤差が白色である)が破れるケースである。

単一の正弦波のような規則的な入力では、量子化誤差も規則的なパターンを繰り返す。 誤差が信号と相関を持つと、それは白色雑音として広く散らばらず、 信号の高調波の位置に鋭い線(スプリアス)として集まる。 雑音の総量は同じでも、1か所に集中する方が有害である—— その線が探している微弱信号の場所に立てば、偽の信号として誤認されるからである。

対策は逆説的で、意図的に小さな雑音を加えてから量子化する。 これをディザと呼び、加える量はLSBの1/2から数倍程度である。 雑音のおかげで誤差のパターンが崩れ、集中していたスプリアスが砕けて 雑音床に均される。結果としてSFDR(1.3.3節)が改善する。 加えた雑音の分だけSNRは悪化するが、信号帯域の外(たとえば帯域端やDC近傍)に ディザを注入して後段のディジタルフィルタで捨てる方式にすれば、その犠牲もほぼなくなる。

実務上の位置づけを述べておく。深宇宙受信のADC入力には自然の熱雑音が十分にあるので、 通常の運用でディザを追加する必要はない。 ディザを思い出すべき場面は、信号発生器の出力をケーブルで直結する ループバック試験(第4.5.6節)のように「異常にきれいな信号」を入れるときである。 そこでスペクトルに林立するスプリアスを見て「機器が壊れた」と誤診しないための知識である。

1.3.8 量子化損失を回線に計上する

本章で扱った劣化は、最終的に回線設計(姉妹編第1.2章)の 実装損失という項目に計上される。実装損失とは、 理論上の理想的な受信機と実物の差を表す取りまとめ項目である。 SDR設計者は「実装損失は何dBか、その内訳は何か」を説明できなければならない。 本章の項目は次のように分解できる。適切に設計されていれば 合計0.2〜0.5 dB程度に収まる、いわば管理された損失である。

項目典型値設計変数
量子化損失(雑音支配時)0.05〜0.5 dBビット数とローディング(1.3.6節)
クリッピング損失≈0(設計で回避)ローディングファクタ(1.3.5節)
AAF帯域内リプル・ISI0.1〜0.3 dBフィルタ設計(第2.4章)
ジッタによるSNR劣化0.1 dB級クロック設計(第1.4章)
Q. 「ビット数が多いほど感度が良い」は正しいか?

誤解である。感度(微弱信号の検出限界)はフロントエンドの雑音温度が決め、 ADCの仕事は「その雑音床を量子化雑音より上に置いてもらう」ことだけ。 2ビットでも−0.55 dBしか損しない(1.3.6節)。ビット数が買っているのは感度ではなく、 強信号と微弱信号を同時に扱うダイナミックレンジである。

Q. データシートのSNRとENOB、どちらで設計すべきか?

自分のIF周波数・自分の入力レベルに近い条件のENOB(またはSINAD)で設計する。 公称ビット数と低周波での美しいSNRは、高いIFでの実力を保証しない。 特に帯域通過標本化(第1.2.5節)では入力周波数が高く、ENOBの周波数特性の読み込みが必須である。

▶ GNU Radioで試す — 量子化雑音とプロセッシングゲイン
Signal Source(cosine 1 kHz, amplitude 0.1)+ Noise Source(amplitude 0.02)を Add で合成し、Float To Char(scale = 127)→ Char To Float(scale = 1/127)で 「8ビットADC」を模擬して QT GUI Frequency Sink で前後を比べる。 scale を 7(3ビット相当)まで落とすと雑音床の持ち上がりが見える。 さらに Noise Source を 0 にすると、雑音床の代わりに高調波スプリアスが林立する—— ディザの効能(1.3.7節)が一目でわかる。FFTサイズを4096→32768に増やすと 表示上の雑音床が下がる(ビン幅が狭まる=プロセッシングゲイン)ことも確認しよう。

章末演習

【演習 1.3-1】ENOBの計算
12ビットADCのデータシートに、入力140 MHz・−1 dBFSで SINAD = 62 dB とある。ENOBはいくらか。 また f_s = 100 MSPS で帯域 1 MHz の信号を受けるとき、実効SNRの上限はいくらか。
解答
ENOB = (62 − 1.76)/6.02 = 10.0ビット。プロセッシングゲインは 10log₁₀(100/2) = 17.0 dB。 実効SNR上限 = 62 + 17 = 79 dB(−1 dBFSの信号に対して)。 実運用ではローディングファクタ分(−12 dB程度)下がる。
【演習 1.3-2】記録データ量のトレード
帯域 1 MHz のオープンループ記録を8時間行う。複素標本化 1.25 MSPS として、 8ビットI/Qと2ビットI/Qでの記録データ量と、感度の差を述べよ。
解答
8ビット: 1.25×10⁶ × 2 B × 28800 s = 72 GB。2ビット: その1/4の18 GB。 感度差は量子化損失の差 0.55 − 0.00 ≈ 0.5 dB。妨害波のない静かな帯域なら 2ビットが合理的で、これがVLBI式記録の伝統的選択である。
■ まとめ
  • 量子化雑音は Δ²/12。フルスケール正弦波で SNR = 6.02N + 1.76 dB、実力はENOBで読む。
  • オーバーサンプリングは 10log₁₀(f_s/2B) のプロセッシングゲイン。4倍 = 1ビット。
  • ガウス的信号は −12 dBFS 程度に置く。レベル管理はAGCの仕事。
  • 雑音に埋もれた信号は少ビットで受かる(2ビットで−0.55 dB)。ビット数はダイナミックレンジのための資源。
  • 量子化・クリップ・ジッタの損失は合計0.2〜0.5 dBに管理して回線の実装損失に計上する。

第1.4章クロックとジッタ

■ この章で学ぶこと
標本化クロックの時間揺らぎ(ジッタ)が振幅誤差に変換される機構と、その定量式 SNR = −20log₁₀(2πf_in σ_j)。高いIFを直接食うほどクロックに厳しくなる理由、 位相雑音との換算、そしてドップラ計測の性能がクロックで頭打ちになる構造を学ぶ。
◇ 直観でつかむ — シャッターを切るタイミングがブレる
標本化=写真撮影だとすると、ジッタはシャッターを切る時刻のブレである。 止まっている被写体ならブレても同じ値が写るが、高速で動く被写体だと少しの時間ずれが 大きな位置ずれになる。信号も同じで、速く変化する(高い周波数の)信号ほど、 同じ時間ブレが大きな振幅誤差になる。だからジッタの厳しさを決めるのは 「標本化の速さ」ではなく「入っている信号の周波数」——1.4.1節の式に f_s が出てこない理由がこれである。

1.4.1 アパーチャジッタ — 時間誤差は振幅誤差になる

第1.2章では「時刻 n·T_s ちょうどに標本を取る」と書いた。現実のADCはそうならない。 クロック回路の雑音により、実際に標本を取る時刻は目標からわずかにずれる。 このずれの実効値(rms値)を σ_j と書き、アパーチャジッタあるいは単にジッタと呼ぶ。 単位はピコ秒(ps = 10⁻¹² s)やフェムト秒(fs = 10⁻¹⁵ s)である。

時刻のずれが、なぜ信号品質の問題になるのか。ここが理解の要点である。 時刻が δt だけずれると、読み取る値は「本当に読みたかった値」から その瞬間の波形の傾き × δt だけずれる。式で書けば δx = (dx/dt)·δt である。 時間軸のずれが、傾きを介して振幅の誤差に変換される——これがジッタの本質である。

この式から重要な性質が読み取れる。傾き dx/dt が大きい信号、 すなわち速く変化する(周波数の高い)信号ほど、同じ時間ずれが大きな振幅誤差になる。 ゆっくりした信号ならタイミングが多少ずれても値はほとんど変わらないが、 急峻に変化する信号では致命的になる。

定量化しよう。周波数 f_in の正弦波 x(t) = A·sin(2πf_in·t) について 傾きの実効値を計算し、それに σ_j を掛けたものを誤差の実効値とみなして 信号との比を取ると、次の上限式が得られる。

SNR_{jitter} = −20 log_{10}(2π f_{in} σ_{j})\, [dB]

この式を眺めるときにいちばん注目してほしいのは、標本化周波数 f_s が どこにも現れていないことである。効いているのは f_in、すなわち 入力している信号そのものの周波数だけである。

この事実が実務に直結する。たとえば f_s = 100 MSPS というゆっくりした標本化でも、 食っている信号が140 MHzのIFであれば(つまり帯域通過標本化なら)、 要求されるのは140 MHzの波形を刻むのに耐えるクロック純度である。 第1.2.5節で「帯域通過標本化はジッタに厳しい」と予告したのは、この式のことだったのである。

1.4.2 数字の感覚を持つ

【例1.4-1】ジッタSNRの計算
σ_j = 1 ps のクロックで f_in = 140 MHz を標本化すると、 SNR = −20log₁₀(2π × 1.4×10⁸ × 10⁻¹²) = −20log₁₀(8.80×10⁻⁴) = 61.1 dB(ENOB約9.9ビット相当)。 同じクロックで f_in = 10 MHz なら 84.0 dB。σ_j = 100 fs の低ジッタクロックにすれば 140 MHzでも 81.1 dB。「12ビットADCを買ったのにジッタで10ビットしか出ない」は IFサンプリング設計の典型的な失敗である。

実際の設計では逆向きに使う。つまり「必要なSNR(=欲しいENOB)を確保するには、 クロックのジッタをいくら以下に抑えねばならないか」を求める。 前節の式を σ_j について解けばよい。

σ_{j,max} = \frac{1}{2π f_{in} · 10^{SNR/20}}

ここでもう一段の考慮が要る。ジッタによる劣化と、第1.3章の量子化による劣化は、 互いに無関係な独立した現象である。独立な雑音は電力で足し算になるので、 合成SNRは両者の電力和から計算する(演習1.4-2で実際に計算する)。

この合成の性質から、実務的な設計指針が出てくる。 2つの劣化が同じ大きさだと合成で3 dB損をするので無駄が多い。 目安は「ジッタSNRを量子化SNRより6 dB良くする」—— こうすればジッタ由来の劣化は合計で1 dB以内に収まり、 ボトルネックが量子化側だけに絞られる。逆にクロックを必要以上に高級にしても コストと消費電力を払うだけで性能は上がらない。 劣化要因を1つに絞り、他は余裕を持たせるのがバジェット設計の原則である。

1.4.3 位相雑音からジッタへ — L(f) の積分

ここで言葉の壁にぶつかる。ADCのデータシートはジッタを「○○ fs」という 時間の単位で書くが、水晶発振器やPLL ICのデータシートは 位相雑音 L(f) という別の量で品質を表す。 L(f) は「搬送波から f Hz 離れた位置に、1 Hz幅あたりどれだけの雑音電力があるか」を 搬送波電力との比で表したもので、単位は dBc/Hz(cはcarrier=搬送波の意)である。 発振器の純度を周波数の関数として細かく記述できるため、アナログ回路の世界ではこちらが標準である。

2つの言葉を換算する式が次である。クロックの周波数を f_clk として、

σ_{j} = \frac{\sqrt{2 ∫ 10^{L(f)/10} df}}{2π f_{clk}}

読み方を説明する。10^{L(f)/10} はdB表現を電力比に戻す操作で、 それを周波数について積分すると、雑音の総電力(位相の揺らぎの分散)が得られる。 その平方根を取って角周波数 2πf_clk で割ると、位相の揺らぎが時間の揺らぎに変換される。 要するに「位相雑音のグラフの下の面積を足し合わせ、時間の単位に翻訳する」操作である。

実務で最も注意すべきは積分範囲である。典型的には100 Hzから f_s/2 程度までを積分する。 下限を設ける理由は、それより遅い揺らぎは「ジッタ」として振幅誤差になるのではなく、 搬送波周波数の緩やかなずれとして現れ、後段の同期ループが追尾して吸収してくれるからである (第3.1章)。つまり同じ発振器でも、どの範囲を積分するかで「ジッタ値」は変わる。 データシートのジッタ値を、積分範囲を確認せずに比較してはならない

1.4.4 クロックの位相雑音は信号に転写される

ここまではジッタを「雑音床を持ち上げる要因」として扱ってきた。 ジッタにはもう1つ、別の現れ方がある。こちらは通信より計測で問題になる。

標本化という操作は、数学的には信号とクロックを掛け算することに相当する。 掛け算をすれば、クロックが持っている位相の揺らぎはそのまま標本化後の信号の 位相の揺らぎとして乗り移る。しかも入力周波数 f_in とクロック周波数 f_clk が違うとき、 転写される位相雑音は 20log₁₀(f_in/f_clk) だけ大きさが変わる。 高いIFを低い f_s でアンダーサンプリングする構成では f_in > f_clk なので、 位相雑音は増幅されて信号に乗り移ることになる。

なぜこれが深宇宙で決定的なのか。探査機の速度は、受信した搬送波の 周波数のずれ(ドップラ)から測る。周波数とは位相の時間変化なので、 搬送波位相の揺らぎは、そのまま速度計測の測定雑音になる(姉妹編第3.2章)。 通信なら「少し位相が揺れてもビットは読める」で済むが、計測では揺らぎが性能そのものである。

だから計測用の受信機では、クロックの純度が鎖のように連なる。 局の水素メーザ(極めて安定な原子周波数標準)から始まり、 周波数分配器、逓倍器を経てADCのクロックに至るまで、 すべての段を位相同期させ、各段で雑音を増やさないよう設計する。 この鎖のどこか一段でも安物のPLLを挟めば、そこが計測性能の限界(床)になる。 第4.5.4節でUSRPに外部基準を入れる話をするが、その行為の意味はここにある。

1.4.5 クロック設計の実務

項目指針
発振器の選択ジッタ性能は水晶(OCXO/TCXO)> 高品質PLL ≫ 汎用PLL/FPGA内部生成。ADCクロックをFPGAのロジックから直接出すのは論外(数十ps級)。
ジッタクリーナ基準クロックが汚い場合、狭帯域PLL+低雑音VCXOで「濾過」する専用IC(ジッタクリーナ)を挟む。
分配差動(LVPECL/LVDS)で短く等長に。ロジックゲート・FPGA経由の分配は段ごとにジッタが加算される。
電源クロック系の電源リプルは位相変調として現れる。専用LDOで隔離する。
基準への同期計測用途では局の10 MHz/100 MHz基準に必ず位相同期。フリーランのSDRは通信はできても計測には使えない。

1.4.6 決定論的な時刻 — タイムスタンプ

本章の最後に、ジッタとは別種の時間の問題を扱う。ジッタが 「標本間隔のランダムな揺らぎ」だったのに対し、こちらは 標本の絶対時刻——この標本は世界標準時(UTC)で何時何分何秒に取られたのか——という問題である。

なぜ必要かというと、電波で距離を測る仕組みがそうなっているからである。 測距は電波の往復時間を測ることであり、ΔDORは複数の局で受けた波形の到達時刻差を測ることである。 どちらも「いつ受けたか」がサブマイクロ秒の精度で分かっていなければ成立しない。 標本の間隔がどれほど正確でも、どの標本が正時なのか分からない記録は計測に使えない

実装は素直である。GPS受信機や局の時刻系から出る1PPS(1秒ごとに1回出るパルス)と 時刻情報をSDRに入力し、パルスが来た瞬間の標本番号を記録して 「標本#123456789 = UTC 12:00:00.000000」という対応表を作る。 以降はどの標本の時刻も、番号の差を f_s で割って計算できる。

USRPのような研究用SDRは、この用途のためにGPSDO(GPS同期発振器)を オプションで内蔵でき、標本番号に基づくタイムスタンプ機構を標準で備えている (具体的な使い方は第2.5.4節と第4.5.4節)。 「信号の経路」と同じ真剣さで「時刻の経路」を設計する—— これが計測用SDRシステムの作法である。

Q. ジッタとドリフトはどう違うのか?

時間スケールの違いである。標本ごとに独立に近い速い揺らぎ(ジッタ)はSNR劣化として現れ、 秒〜時間スケールの遅い周波数変化(ドリフト)は搬送波周波数のオフセットとして現れて 同期ループが追尾する。境界は同期ループの帯域で決まり、アラン分散(姉妹編第3.5章)の 横軸のどこを見ているかという話に対応する。

Q. 8ビットの安価なSDRでもジッタを気にすべきか?

量子化SNRが50 dB弱なので、σ_j が 2πf_in·σ_j < 10^{−2.8} 程度、 すなわち数psまでは量子化が支配的でジッタは見えない。安価なSDRを直接IFに使わず ベースバンド近くで使う限り、ジッタは普通は問題にならない。問題になるのは 多ビット・高IF・計測用途の三条件が揃ったときである。

章末演習

【演習 1.4-1】許容ジッタの逆算
f_in = 300 MHz のIFを直接サンプリングし、ジッタSNRとして74 dB(12ビット相当)を確保したい。 許容されるrmsジッタはいくらか。
解答
σ_j = 1/(2π × 3×10⁸ × 10^{74/20}) = 1/(1.885×10⁹ × 5012) = 106 fs。 これは高品質な専用クロックICと注意深い分配設計を要求する水準で、 「高いIFの直接サンプリングはクロックが主戦場」という第1.2.5節の警告が数字で確認できる。
【演習 1.4-2】劣化の合成
量子化SNR 74 dB(ENOB 12ビット相当)のADCを、ジッタSNR 74 dBのクロックで使った。合成SNRはいくらか。
解答
独立な雑音の電力和: SNR = −10log₁₀(10^{−7.4} + 10^{−7.4}) = 74 − 3.0 = 71 dB(ENOB 11.5ビット)。 同じ数字を並べると3 dB損する。片方を+6 dB良くすれば合成劣化は1 dB以内に収まる—— 「ボトルネックを1つに決めて他に余裕を持たせる」のが劣化バジェットの原則である。
■ まとめ
  • ジッタは信号の傾きを通じて振幅雑音になる。SNR = −20log₁₀(2πf_in σ_j)。効くのは f_s でなく f_in。
  • 位相雑音L(f)の積分がジッタ。積分範囲の明示なしにジッタ値を比較しない。
  • クロックの位相雑音は信号に転写され、ドップラ計測の床になる。計測用SDRは局基準に位相同期が必須。
  • ジッタSNRは量子化SNRより6 dB良くしてボトルネックを消す。
  • ランダムなジッタと別に、標本の絶対時刻(タイムスタンプ)が計測用途の必須要件。

第1.5章ADC/DACデバイスの実際

■ この章で学ぶこと
変換方式(SAR・パイプライン・ΣΔ・インタリーブ)ごとの得意分野、DAC特有の物理(sincロールオフとイメージ)、 データシートの歩き方、そして宇宙用部品ならではの制約を押さえ、デバイス選定ができるようになる。

1.5.1 変換方式の系譜

ADCの内部方式は多様だが、SDR設計者が知るべきは「方式が速度・分解能・電力のどこを トレードしているか」である。

方式分解能速度特徴と用途
フラッシュ〜8ビットGSPS級2^N個の比較器で一発変換。速いが分解能・電力が厳しい。単体では今や少数派で、パイプラインの初段部品。
SAR(逐次比較)12〜18ビット〜数十MSPS二分探索。低レイテンシ・低電力。計装・制御系の主役。狭帯域SDRにも。
パイプライン12〜16ビット〜GSPS粗い変換を段送りして高精度化。高速多ビットの主力で、IFサンプリング受信機の定番。変換レイテンシ(数〜十数クロック)を持つ。
ΣΔ(デルタシグマ)16〜24ビット〜数MSPS(帯域)1.5.2節。オーバーサンプリング+ノイズシェーピング。高分解能の王者。
時間インタリーブ8〜14ビット数〜数十GSPS1.5.3節。複数ADCを位相をずらして並列動作。RF直接サンプリングを可能にした立役者。

1.5.2 ΣΔとノイズシェーピング

ΣΔ(デルタシグマ)型は、第1.3.4節で見たプロセッシングゲインを 設計思想の中心に据えた変換器である。考え方は2段構えになっている。

第1段はオーバーサンプリング。1〜数ビットという極端に粗い量子化器を、 必要な帯域の何十倍から何百倍もの速さで回す。 1.3.4節の通り、オーバーサンプリング比を上げれば帯域内の実効雑音は下がる。

第2段がノイズシェーピングで、ここがΣΔの独創である。 量子化器を負帰還ループの中に置くと、量子化雑音のスペクトルを平坦ではなく 高い周波数側へ押しやることができる。信号がある低域の雑音を減らし、 その分を使わない高域へ追い出すわけである。 ループの次数を L とすると、帯域内雑音はオーバーサンプリング比の増加に対して 平坦な場合よりずっと急な (2L+1) 倍のペースで下がる。 あとは後段のディジタルフィルタ(第2.4章で扱うCICが定番)で 高域に掃き寄せた雑音ごと帯域外を捨てればよい。

結果として「粗い量子化器+速いクロック+ディジタルフィルタ」の組み合わせで 20ビット級の分解能が得られる。アナログの精度をディジタルの計算で買うという点で、 もっともSDR的な思想のADCと言える。主戦場はオーディオ帯から数MHz程度までの 高分解能用途で、広帯域の受信には向かない(オーバーサンプリングの余地がなくなるため)。

1.5.3 時間インタリーブとRF直接サンプリング

1個のADCコアの速度には限界がある。そこでM個のコアを並列に並べ、 クロックの位相を 1/M ずつずらして順番に動かすと、 全体としては M 倍の速さで標本を出せる。これが時間インタリーブで、 GSPS(毎秒10億標本)級のADCはほぼすべてこの構造をとっている。

代償は「コアが複数ある」ことそのものから来る。 各コアの利得・オフセット・実際の標本時刻はわずかに揃わない(ミスマッチ)ため、 その不揃いが周期的なパターンとなってスプリアスを生む。 現れる位置は f_s/M の整数倍 ± 入力周波数 で予測でき、 これをインタリーブスプリアスと呼ぶ。 現代のデバイスは動作中に自動較正して抑え込んでいるが、 較正が有効に働く条件(たとえば入力信号が途切れると較正が追随できないなど)が データシートに書かれているので、SFDRの数値と一緒に必ず確認する。

この技術の到達点が、ADC/DACとFPGAを同一チップに集積したRFSoC級のデバイスで、 数GSPSの直接RFサンプリングにより S帯はもちろんX帯近くまでミキサレス受信が視野に入る。 アナログ部が「アンテナ・LNA・フィルタ・ADC」だけになる直接RF構成(第2.2.4節)は、 地上局のみならず搭載機器の将来形として各機関が開発を進めている。

1.5.4 DACの物理 — ゼロ次ホールドとイメージ

DACは標本値を次の標本まで保持する階段波を出す(ゼロ次ホールド, ZOH)。 その伝達関数は sinc 型で、出力スペクトルに周波数依存の減衰がかかる。

|H_{ZOH}(f)| = \big|\frac{sin(π f / f_{s})}{π f / f_{s}}\big|,\, −20 log_{10}|H| ≈ 3.9 dB @ f = 0.45 f_{s}

帯域の端で最大4 dB近く落ちるこのsincロールオフは、ディジタル側に逆特性の 補償フィルタ(inverse-sinc)を置いて平坦化するのが定石である。 さらに f_s ± f, 2f_s ± f … の位置にイメージが出る。イメージはZOHのsincで 多少減衰しているだけなので、アナログの再構成フィルタで落とす。 送信のスプリアス規制(宇宙機では他系への干渉要求)に対し、イメージ・クロック漏れ・ 非線形歪みを合算して評価するのがDAC出力設計の実務である。

1.5.5 データシートの歩き方

SDR用のADC/DAC選定でデータシートから拾うべき項目を挙げる。 「公称ビット数と最大 f_s」だけ見て選ぶと必ず失敗する。

項目見るべき点
ENOB / SINAD自分のIF周波数・自分の f_s での値(第1.3.3節)。周波数特性グラフを読む。
SFDR妨害波環境で効く。較正条件とセットで。
アパーチャジッタADC内蔵分。外部クロックのジッタと電力和になる(第1.4章)。
入力帯域(アナログ帯域)帯域通過標本化では f_s/2 よりずっと高い入力周波数まで内部S/Hが追従できる必要がある。「入力帯域 > 使用IF」を確認。
レイテンシパイプライン段数。閉ループ(AGC・キャンセラ)に入れるなら効く。
インタフェース並列LVDSかJESD204B/Cか。JESD204は配線が楽だがリンク遅延の決定性(deterministic latency)設定が計測用途では重要。
電力GSPS級は数W。搭載機器では熱設計ごと決まる。

1.5.6 宇宙用ADC/DACの事情

搭載SDR(第5.1章)では民生の最先端デバイスは使えない。放射線環境(トータルドーズ、 シングルイベント)への耐性が実証された宇宙用・耐放射線品から選ぶことになり、 その選択肢は民生品より世代が数段古い——ビット数×速度の積で1〜2桁劣ると思ってよい。 したがって搭載側の設計は「少ないビットと控えめな f_s でどう成立させるか」という 制約充足問題になり、第1.3.6節(少ビットでも雑音支配なら損しない)と 帯域通過標本化(高いIFを低い f_s で食う)がそのまま設計の武器になる。 シングルイベントによるビット化けは、変換器そのものよりも後段のFPGAで対策する(第5.1章)。

Q. ADCとDACで設計の難しさはどちらが上か?

受信(ADC)である。送信は自分の信号だけを扱いレベルも既知だが、 受信は未知の強度の信号と妨害波が混在する世界をダイナミックレンジで受け止める必要がある。 本書が受信中心なのはこのためで、DAC側はsinc補償とイメージ除去を押さえればおおむね足りる。

Q. 「入力帯域」と「標本化周波数」の違いがまだ曖昧だ。

入力帯域は内部のサンプル&ホールド回路がアナログ的に追従できる周波数上限、 f_s は数列を吐く速さ。入力帯域 1 GHz・f_s 100 MSPS のADCなら、700 MHz の信号を アンダーサンプリングで受けられる(第7ゾーン)。逆に入力帯域が 200 MHz しかなければ、 いくら f_s があっても 700 MHz は受からない。

▶ GNU Radioで試す — DACのsincロールオフとイメージ
Signal Source(cosine, 8 kHz, samp_rate = 32 kHz)→ Repeat (interpolation = 8。同じ値を8回繰り返す=ゼロ次ホールドの模擬)→ QT GUI Frequency Sink(samp_rate = 256 kHz)。 32 kHz 間隔で並ぶイメージ(24, 40, 56 kHz…)と、周波数が上がるほど sinc则に沿って減衰していく様子が見える。RepeatRational Resampler(interpolation = 8, 適切なLPF)に替えると イメージが消える——これが「補間フィルタ=ディジタル再構成フィルタ」である(第2.4章)。

章末演習

【演習 1.5-1】方式の選定
次の各用途に適したADC方式を選び、理由を述べよ。 (a) X帯地上局のIF 140 MHz・帯域40 MHzのIFサンプリング (b) 探査機の電力系テレメトリ(DC〜1 kHz、16ビット) (c) 将来のS帯直接RFサンプリング受信機
解答
(a) パイプライン(100〜200 MSPS・14ビット級、入力帯域がIFをカバーするもの)。 (b) SARまたはΣΔ(速度不要・高分解能・低電力)。 (c) 時間インタリーブ(RFSoC級、数GSPS)。それぞれ速度・分解能・集積度の要求が決め手になる。
【演習 1.5-2】sincロールオフ
f_s = 200 MSPS のDACで 80 MHz の信号を出す。ZOHによる減衰はいくらか。
解答
f/f_s = 0.4。sinc(0.4) = sin(0.4π)/(0.4π) = 0.9511/1.2566 = 0.757 → −20log₁₀0.757 = 2.4 dB。 この分をinverse-sincフィルタで持ち上げるか、回線の損失として計上する。 第1イメージは 120 MHz に現れ、sinc減衰は −20log₁₀(sinc(0.6)) = 4.4 dBしかないので、 アナログ再構成フィルタで落とす必要がある。
■ まとめ
  • 方式は速度・分解能・電力のトレード: SAR(精密・低速)、パイプライン(高速多ビットの主力)、ΣΔ(オーバーサンプリング+ノイズシェーピングで高分解能)、インタリーブ(GSPS、スプリアスに注意)。
  • DACはZOHのsincロールオフ(帯域端で数dB)とイメージが宿命。inverse-sinc補償+再構成フィルタで対処。
  • 選定はENOB@自分のIF・SFDR・入力帯域・ジッタ・インタフェース・電力の総合判断。
  • 宇宙用は世代が古く、少ビット・低 f_s の制約下で第1.3・1.2章の理論が武器になる。
第 II 部 SDRアーキテクチャ — 信号の通り道
ADCが吐いた数列を、復調器が食べられる「ゆっくりした複素ベースバンド」に整えるまでの道程を設計する。IQ表現の数学、受信機アーキテクチャの選択、NCOとCICによるディジタルダウンコンバージョン、マルチレートフィルタ、そしてFPGAとCPUへの仕事の割り振りまで。

第2.1章複素ベースバンド — IQ信号の数学

■ この章で学ぶこと
SDRの世界の共通言語である複素信号(IQ信号)を導入する。なぜ複素数を使うのか、 「負の周波数」とは何か、複素ベースバンドへの変換で何が保存されるのか。 そしてアナログIQ処理の宿命であるIQ不平衡・DCオフセットまで。以降の全章がこの言語で書かれる。
◇ 直観でつかむ — 「回転する点」で波を表す
波を「上下する値」ではなく「くるくる回る点」として表すのが複素信号である。 点の回転の速さが周波数、回転の向きが周波数の符号(搬送波より上か下か)、 現在の角度が位相、原点からの距離が振幅。IとQは、その点の座標(横・縦)を 2本の信号として運んでいるだけである。
なぜこの表現が要るのか。実数の波形(上下する値)だけでは 「搬送波より2 kHz高い信号」と「2 kHz低い信号」が区別できないが、 回転する点なら向きが逆なので一目で違う。ドップラの正負も、上下側波帯も、この区別で扱える。 本書のこれ以降の処理は、ほぼ全部この「回る点」に対する操作である。

2.1.1 なぜ複素数か — 周波数の符号を区別する

まず、複素数を持ち出す動機をはっきりさせる。 普通の実数の信号 cos(2πft) をフーリエ変換すると、スペクトルには +f と −f の位置に対称な2本の線が立つ。この対称性は数学の都合で必ず生じるもので、 実信号の世界では+f と −f を区別する意味がない

ところが受信機の仕事は、その区別の連続である。 搬送波より少し上の成分と少し下の成分は違う情報を運んでいる(上側波帯と下側波帯)。 探査機が近づいているか遠ざかっているかで、ドップラのずれは正負が逆になる。 「LOより2 kHz高い信号」と「2 kHz低い信号」を混同する受信機は使い物にならない。 実数の表現では、この区別が構造的に表せない——これが複素数を導入する理由である。

複素数を使うと何が変わるか。複素指数 e^{j2πft} は、複素平面上を 回転する点として振る舞い、f が正なら反時計回り、負なら時計回りに回る。 つまり周波数の符号が回転方向として目に見える形で表現される。 実数の cos では失われていた情報が、複素表現では保たれるのである。

そこで信号を z(t) = I(t) + jQ(t) という複素数で表す。 実部 I を同相成分(In-phase)、虚部 Q を直交成分(Quadrature)と呼び、 2つ合わせて「IQ信号」と言う。ここで強調しておきたいのは、 IQ信号とは1本の複素信号を、実部と虚部という2本の実信号に分けて運んでいるだけだという点である。 IとQを「別々の2つの信号」と捉えると以降の議論がすべてわかりにくくなる。 常に「1つの回る点の、横座標と縦座標」と考えること。

2.1.2 複素包絡線 — 搬送波を剥がす

次に、複素表現がもたらす実用上の最大の利点を見る。

アンテナに届く実際のRF信号は、搬送波周波数 f_c の速い振動に、 伝えたい情報がゆっくりと乗った形をしている。式で書けば x(t) = A(t) cos(2π f_{c} t + φ(t)) であり、 情報は振幅の変化 A(t) と位相の変化 φ(t) に含まれている (前者を振幅変調、後者を位相変調と呼ぶ)。

ここで「搬送波の速い回転」の部分は、情報を運ぶ乗り物にすぎず、それ自体に情報はない。 そこで乗り物の回転だけを取り除き、情報の部分だけを複素数で表したものが次である。

z(t) = A(t) e^{jφ(t)} = I(t) + jQ(t)

この z(t) を複素包絡線(または複素ベースバンド信号)と呼ぶ。 注目すべき性質が2つある。第一に、情報は何も失われていない—— 振幅 A も位相 φ も z の中にそのまま入っている。 第二に、信号の帯域は変調の帯域 B だけになる。 8.4 GHzで振動する波形を追いかける必要はなく、 数MHz幅のゆっくりした複素数列を処理すればよい。

この2点のおかげで、SDRの信号処理はほぼすべて z(t) の上で行われる。 そして復調とは、z(t) から元の A(t) や φ(t) を読み出す操作にすぎない。 具体的には、振幅は複素数の絶対値 |z|、位相は偏角 arg(z)、 周波数は位相の時間変化(隣接標本の位相差)として取り出せる。 複雑に見える復調が、複素数の初等的な演算に還元される——これが次節の主題である。

【例2.1-1】BPSKの複素包絡線
BPSK(φ = 0 か π)の z(t) は実軸上の ±A の2点を行き来する。QPSKなら4点、 残留搬送波PM(姉妹編第2.1章)なら「一定半径の円周上を副搬送波で揺れる点」になる。 コンスタレーション図とは複素包絡線 z の軌跡のスナップショットである。

2.1.3 実信号→複素信号 — 2つの経路

アンテナから来るのは実数の電圧である。これを前節の複素包絡線に変換する方法は2つあり、 どちらを選ぶかが受信機アーキテクチャの分岐点になる(詳細は第2.2章)。

(a) アナログの直交ミキサで作る。 入力信号に cos(2πf_c t) を掛けたものと、−sin(2πf_c t) を掛けたものを別々に作り、 それぞれローパスフィルタを通すと、I と Q が直接得られる。 三角関数の積和公式から確かめられるが、直観的には 「基準の波と同じ向きの成分」と「90°ずれた向きの成分」を測っていると考えればよい。 ハードウェアはミキサ2個で済み小型だが、代償がある。 2つの経路のアナログ利得と位相を完全に揃えることは物理的に不可能で、 その不揃いが2.1.5節のIQ不平衡として現れる。この方式がゼロIF受信機(第2.2.2節)である。

(b) 実信号のまま標本化して、ディジタルで複素化する。 アナログ段では複素化せず、実信号のままADCに入れる。 その後、数列に対して複素指数 e^{−j2πf₀n·T_s} を掛けてフィルタすれば複素包絡線が得られる (この処理が第2.3章のDDCである)。 利点は明快で、ディジタルの cos と sin は数値の精度どおりに正確に直交するため、 IQ不平衡という現象が原理的に存在しない。 計測品質を要求される地上局がこちらを選ぶ最大の理由がこれである。 代償はADCの負担で、実信号は正負両側にスペクトルを持つため、 同じ帯域を扱うのに約2倍の標本化周波数が必要になる。

2.1.4 複素信号の基本操作 — SDRの四則演算

ここで本書の残り全体で使う道具を揃えておく。以下の6つの演算を組み合わせるだけで、 本書に登場する同期・復調アルゴリズムのほとんどが書ける。 表を読んだら、各行が「何をしている操作か」を自分の言葉で言えるか確認してほしい。

操作数式意味
周波数シフトz[n]·e^{−j2πf₀n·T_s}スペクトルを −f₀ 平行移動(ディジタルミキサ)。
複素共役z*[n]スペクトル反転(帯域通過標本化の偶数ゾーン補正に)。
振幅・電力|z|, |z|²包絡線検波・電力測定。位相情報を捨てる。
位相arg(z) = atan2(Q, I)位相復調。PLLの位相検出器の素。
周波数弁別arg(z[n]·z*[n−1])/2πT_s隣接標本の位相差=瞬時周波数。FM復調・FLLの素。
相関Σ z[n]·s*[n]既知系列との整合(ASM検出・測距相関・捕捉FFT)。

この6つがSDRにおける「四則演算」である。 GNU Radioのブロック名(Multiply ConjugateComplex to Arg など)も そのままこの表の言葉でできているので、表を覚えることは ブロック一覧を読めるようになることと同義である。

特に3行目以降の使い方を補足しておく。|z| は位相を捨てて強さだけを見る操作で、 電力測定やAGC(第3.3章)に使う。arg(z) は位相を数値として取り出す操作で、 位相変調の復調(第4.3章で実際に使う)とPLLの誤差検出(第3.1章)の心臓部である。 arg(z[n]·z*[n−1]) は隣り合う標本の位相差、すなわち瞬時周波数を与える。 「位相の差が周波数」という関係を1行の演算にしたもので、周波数のずれを測る全ての場面で登場する。

2.1.5 IQ不平衡とイメージ — アナログIQの宿命

2.1.3節(a)のアナログ直交ミキサで生じる問題を、定量的に押さえておく。 これは小型SDRデバイスを使う読者が必ず遭遇する現象である。

2つの経路(I側とQ側)には、避けられない不揃いが2種類ある。 増幅の度合いがわずかに違う利得差を ε、 2つのLOの位相差がぴったり90°からずれる直交誤差を δ(ラジアン)と書く。 この不揃いがあると、複素平面上で本来は真円を描くはずの信号がわずかに潰れた楕円になる。 そして楕円は「逆回転する成分」を含んでいるため、 スペクトル上では周波数 +f にある信号の鏡像が −f の位置に漏れて現れる。 これをイメージと呼び、漏れの少なさを表す指標が鏡像抑圧比 IRR である。

IRR ≈ 10 log_{10} \frac{4}{ε^{2} + δ^{2}}\, [dB]

数字の感覚を持とう。利得差が1%(ε = 0.01)、位相誤差が1°(δ = 0.017 rad)という —— 一見かなり良く揃っているように思える —— 状態でも IRR は約40 dBにとどまる。 未較正のアナログIQ回路は30〜40 dB台が相場である。 これは「自分の100分の1の強さの信号を偽物で潰せる」水準であり、 強弱の差が激しい宇宙通信の受信では十分に問題になる。 現代のSDRトランシーバICは、テスト信号や統計的手法で ε と δ を推定して ディジタルで逆補正する機能を内蔵し、50〜60 dB台まで改善している。

アナログIQにはもう1つの宿命がある。DCオフセットである。 LO(局部発振器)の信号が回路内を漏れて自分自身と混ざる(自己混合)と、 直流成分が生まれ、スペクトルの0 Hzに偽の線が立つ。 さらに半導体固有の1/f雑音(フリッカ雑音)も0 Hz付近に集まるため、 ゼロIF受信機のベースバンド0 Hz付近は「汚れた場所」だと考えるべきである。

デバイス側の較正機能を使っても残留は必ずある。 そこで実務では回路で戦うのではなく、周波数プランで避ける。 すなわち、受信したい信号をあえてLOから数百kHzずらした位置で受け、 汚れた0 Hz付近とイメージの位置から退避させ、 きれいなディジタル処理(DDC)で正確に0 Hzへ戻す。 この定石は第4.5.3節でUSRPの具体的な設定として再登場する。

Q. 負の周波数は物理的に実在するのか?

複素表現の中の数学的な座標である。実信号の世界では±fは常に対で存在し区別がなかった。 複素ベースバンドでは「搬送波より上か下か」という物理的に意味のある区別が、 周波数の符号として表現される。「LOより2 kHz下の信号」が「−2 kHzの複素トーン」になる—— 実在するのはその区別である。

Q. IQデータのファイルはなぜI,Q,I,Q…と交互に並ぶのか?

複素数1個=実数2個をそのまま直列化しているだけである。GNU Radioの complex64 は float32 のI, Qが交互に並ぶ形式で、記録ファイル(第4.5章のSigMF等)も同じ。 「1標本 = 8バイト」を忘れるとデータレート計算を半分に間違えるので注意。

▶ GNU Radioで試す — 複素トーンと周波数の符号
Signal Source(出力型をcomplex、cosine, +5 kHz)→ ThrottleQT GUI Frequency Sink。スペクトルに立つ線は+5 kHzの1本だけで、 −5 kHzには何もない——複素信号の世界を初めて見る瞬間である。周波数を−5 kHzにすると線が 左側へ移る。次に Complex to Real を挟んで実信号に落とすと±5 kHzの2本に戻る。 さらに Multiply Conjugate で信号自身の1標本遅延(Delay)との積を作り Complex to Arg を通せば、2.1.4節の周波数弁別器が完成する。

章末演習

【演習 2.1-1】IRRの要求値
受信帯域内に、希望波より30 dB強い信号がイメージ周波数に存在する。 イメージ漏れを希望波のC/N₀に対して無視できるレベル(希望波より20 dB下)に抑えるには、 IRRは何dB必要か。またε = δ と仮定すると許容ε はいくらか。
解答
IRR ≧ 30 + 20 = 50 dB。IRR = 10log₁₀(4/(ε²+δ²)) = 10log₁₀(2/ε²) = 50 → ε² = 2×10⁻⁵ → ε = 4.5×10⁻³、すなわち利得差0.45%・位相誤差0.26°を同時に達成する必要がある。 アナログ較正なしでは無理な水準で、ディジタル較正かIFサンプリング構成を選ぶ判断材料になる。
■ まとめ
  • IQ信号とは複素信号の実部・虚部。複素表現は周波数の符号(搬送波の上か下か)を区別するための言語。
  • 複素包絡線 z = A e^{jφ} は変調情報を完全保持し、帯域は変調帯域だけ。SDRの処理は全部 z の上で行う。
  • 実→複素の変換はアナログ直交ミキサ(軽いがIQ不平衡)かディジタルDDC(重いが完全直交)。
  • IQ不平衡はイメージ(IRR ≈ 10log(4/(ε²+δ²)))、LO漏れはDCスパイク。周波数プランで避けるのが実務。

第2.2章受信機アーキテクチャ

■ この章で学ぶこと
「ADCをどこに置くか」の3+1類型——スーパーヘテロダイン+IFサンプリング、ゼロIF、ローIF、 直接RFサンプリング——を、それぞれの障害(イメージ・DC・スプリアス)とともに比較し、 深宇宙地上局・小型SDR・搭載機器がなぜそれぞれの構成を選ぶのかを理解する。
◇ 直観でつかむ — 「ADCをどこに置くか」だけの話
受信機の構成の違いは、結局アンテナからADCまでの間に、アナログ回路をどれだけ挟むかだけである。 たくさん挟めば(ヘテロダイン)ADCは楽になるが部品が増える。何も挟まなければ(直接RF) 部品は消えるがADCに超高速・高精度が要る。その中間がゼロIF(一発でベースバンドへ落とす)。 どの構成でも出口は同じ「複素ベースバンド」なので、第III部以降の処理は共通である。 違いは「道中で拾う障害の種類」——それが本章の表の中身である。

2.2.1 スーパーヘテロダイン + IFサンプリング — 地上局の正統

RFを1〜2回のアナログ周波数変換で扱いやすいIF(例: 140 MHz や 1.2 GHz)に落とし、 IFを実標本化(多くは帯域通過標本化)してDDCで複素化する構成。 深宇宙地上局の受信系はほぼこれである。利点は、①IQ不平衡が原理的にない(第2.1.3節)、 ②IFの帯域通過フィルタが妨害波をADCの前で落とすためダイナミックレンジ要求が緩い、 ③LNAからIFまでを既存のアナログ設備(姉妹編第4.2章)と共用できる。 欠点はアナログ変換段のぶん部品が多いこと、そしてイメージ周波数対策 (ミキサのイメージはアナログのプリセレクタで落とす)が必要なことである。

2.2.2 ゼロIF(直接変換)— 小型SDRの標準

LOを搬送波と同じ周波数に置き、直交ミキサで一気に複素ベースバンドへ落とす構成。 IFフィルタが不要で集積に向くため、ADALM-Pluto、LimeSDR、携帯電話など ワンチップSDRトランシーバはほぼすべてこれである。 代償は第2.1.5節の全部——IQ不平衡・DCオフセット・LO漏れ・フリッカ雑音(1/f雑音が ベースバンドの0 Hz付近に被る)。「安く小さく広帯域に」はゼロIF、 「較正なしで計測品質」はIFサンプリング、という住み分けが基本である。

2.2.3 ローIF — 折衷案

LOを搬送波から数百kHz〜数MHzずらし、信号をDC付近から退避させた低いIFに置いてから ディジタルで0 Hzへ戻す構成。DCオフセットとフリッカ雑音の問題を回避できるが、 イメージ周波数(LOの反対側)に入る信号はIQ不平衡の分だけ漏れ込むため、 IRR要求は残る。実務では「ゼロIFデバイスをローIF的に使う」——第2.1.5節の定石——が広く行われる。

2.2.4 直接RFサンプリング — 将来の主流

アナログの周波数変換を全廃し、LNA(低雑音増幅器)と プリセレクタ(目的帯域だけ通す帯域通過フィルタ)を通したRF信号を、 GSPS級の高速ADCで直接標本化する構成である。

利点は、ミキサとLOに由来する障害がまとめて消えることである。 イメージ周波数の問題、LO漏れによるDC成分、LOに起因する相互変調—— これらは物理的にミキサが存在しなければ発生し得ない。 周波数プランはすべてディジタル領域(NCOの設定値)で完結し、 アナログ部の改造なしに受信周波数を変えられる。

制約も明確である。第一にADCの入力帯域とジッタで、 入力周波数 f_in が数GHzになると、第1.4章の式から 要求ジッタはフェムト秒級——専用の低雑音クロック設計が必須になる。 第二に消費電力で、GSPS級ADCは数Wを消費し、搭載機器では熱設計を左右する。 第三にダイナミックレンジで、フィルタで絞る前の帯域に入るすべての信号を ADCが受け止めなければならない(第1.1.5節の制約1がもっとも厳しく現れる形である)。

近年ADCとFPGAを同一チップに集積したRFSoC級デバイスが成熟し、 地上局の新設計はこの方向へ進んでいる。第1.5.3節で扱う時間インタリーブ技術が、 この構成を可能にした立役者である。

① スーパーヘテロダイン + IFサンプリング(地上局) LNA BPF ミキサ×1,2 IF BPF ADC(実) DDC IQ完全直交・設備共用/段数多 ② ゼロIF(小型SDRデバイス) LNA 直交ミキサLO = fc LPF×2 ADC×2(IQ) 小型・安価・広帯域/IQ不平衡・DCオフセット ③ 直接RFサンプリング(RFSoC世代) LNA BPF ADC 数GSPS DDC(FPGA) ミキサレス・完全ソフト定義/ジッタ・電力・DR 共通の終着点: 複素ベースバンド z[n](ゆっくり・狭帯域・IQ)→ 第III部の同期・復調へ アーキテクチャの違い=「そこへ至る道」と「道中で拾う障害」の違い
図2.2-1 受信機アーキテクチャ3類型。どれを選んでも最後は複素ベースバンドに行き着く。 選択は障害(イメージ/DC/ジッタ)とコスト・柔軟性のトレードである。

2.2.5 従来無線機との対応 — RF・IF・ベースバンドはどこへ行ったか

◇ 直観でつかむ — 「周波数」が3つの意味を持つ
従来の無線機では、周波数と言えば必ず「電線やケーブルの上に実在する振動の速さ」だった。 SDRではそれが3層に分かれる。①アンテナから見た本物の周波数(8.4 GHz)、 ②数列の中での位置(この標本列の中で信号は+25 kHzにある)、 ③比としての周波数(f_s の何分の1か)。 混乱の原因はほぼ全部、いま自分がどの層の話をしているか見失うことである。 逆に3層を意識して読み分けられれば、SDRの設定値はすべて素直に理解できる。

従来のスーパーヘテロダイン受信機を思い出そう。信号は RF(例: 8.4 GHz)→ 第1IF(例: 300 MHz)→ 第2IF(例: 70 MHz)→ ベースバンド と段階的に周波数を下げられ、各段に物理的な発振器・ミキサ・フィルタが実在していた。 「IF 70 MHz、帯域 2 MHz」と言えば、その帯域のフィルタが基板上に部品として載っていた。

SDRでもこの階段は消えていない。変わったのは階段のどこから下がソフトウェアになるかだけである。 ADCより上は従来と同じ物理の世界、ADCより下は数列の世界になる。 両者の対応を表にする。この表が本節の要点である。

従来の無線機SDRでの対応物設定する場所
RF搬送波周波数同じもの。SDRで唯一の絶対周波数USRPの set_center_freq()(第4.5.3節)
局部発振器(LO)の周波数アナログLO(残っている場合)+NCOの設定値 M·f_s/2^Wハード側は tune_request、ディジタル側は Xlating FIR の center_freq
ミキサ複素乗算(第2.3.1節)—(DDCの内部)
IF周波数2種類に分かれる(下記)
IFフィルタの帯域デシメーションフィルタの cutofffirdes.low_pass() の引数
受信機の帯域(IF段の通過幅)f_s と cutoff の組。f_s/2 が物理的な上限USRPの set_samp_rate() と各フィルタ
検波(ベースバンドへ)DDCで0 Hzへ移動(第2.3章)NCO周波数の設定
ビット同期回路・PLL回路同期ループ。パラメータは正規化値loop_bw など(第3.1.2節)

いちばん混乱を招くのが「IF」である。SDRではIFが2種類ある。 この区別がつけば、本書の周波数の話はほぼ整理できる。

(a) アナログIF——ADCに入る直前の、実在する物理的な周波数である。 IFサンプリング構成(第2.2.1節)で「IF 140 MHzを100 MSPSで食う」と言うときの140 MHzがこれ。 物理的に存在するので、アンチエイリアシングフィルタの設計とクロックのジッタ要求を決める (第1.2.5節・第1.4.1節)。ゼロIF構成ではこれが0 Hzになり、存在しないとも言える。

(b) ディジタルIF——標本化された後の数列の中で、信号が0 Hzから何Hzずれた位置にあるかである。 第4.5.3節で「搬送波を+25 kHzに置く」と言うときの25 kHzがこれ。 物理的な振動ではなく数列の中の位置にすぎないが、 ゼロIFデバイスのDC汚れを避けるという実務上の理由から意図的に設ける(第2.1.5節)。 アナログIFが「アンテナ側の事情で決まる周波数」なのに対し、 ディジタルIFは「設計者が好きに決められる周波数」である。

3つの座標系についても整理しておく。同じ「1 kHz」が文脈で3通りの意味を持つ。

座標系表し方この単位で指定するもの
RF絶対周波数Hz(例: 2.265 GHz)USRPの center_freq のみ。ここで指定した周波数が数列の0 Hzに対応する
ベースバンド周波数
(数列内の位置)
Hz。ただしf_s とセットでのみ意味を持つSignal Source の frequency、Xlating FIR の center_freq、firdes の cutoff・transition
正規化周波数f/f_s(cycles/sample、全世界が±0.5)
または 2πf/f_s(rad/sample)
同期ブロックのパラメータ: PLL の max_freq/min_freq(rad/sample)、各ループの loop_bw

換算は f_s で割るだけである。ただしその f_s が「フローグラフのどの地点の値か」を 間違えないこと——これが次節(第2.4.6節)のレート連鎖の話につながる。

【例2.2-1】同じ信号を3つの座標系で言い換える
S帯 2.265 GHz の搬送波を、USRPを 2.264975 GHz にチューンして受信し、 f_s = 524.288 kSPS で標本化しているとする。この搬送波は:
RF絶対では 2.265 GHz。ベースバンドでは +25 kHz(=2.265 GHz − 2.264975 GHz)。 正規化では 25000/524288 = 0.0477 cycles/sample、すなわち 0.300 rad/sample。
PLLの引き込み範囲を「±2 kHz」にしたければ、ブロックには 2π×2000/524288 = 0.024 を渡す。3つはすべて同じ物理的対象を指している。

2.2.6 選定の指針

用途推奨構成理由
深宇宙地上局(計測級)ヘテロダイン+IFサンプリング(→将来は直接RF)IQ完全直交・局基準クロックへの同期・既存設備との整合。
開発・教育・アマチュア局ゼロIF小型SDR数千円〜数万円で第IV部の全実験ができる。障害は周波数プランで回避。
探査機搭載ヘテロダイン+低IF/IFサンプリング耐放射線ADCの速度制約下で帯域通過標本化が武器(第1.5.6節・第5.1章)。
広帯域監視・記録直接RFサンプリング周波数計画の自由度が最大。帯域ごと記録して後処理(第5.2章)。
Q. RTL-SDRはどの類型か?

ゼロIF(チューナICによってはローIF)である。もともとテレビ受信用チューナ+8ビットADCを 流用したもので、IQ不平衡もDCスパイクも教材として観察できる。本書の実験には十分だが、 クロックがフリーラン(第1.4.5節)なので計測には使えない——TCXO換装版が人気なのはこのためである。

Q. 探査機のトランスポンダはなぜゼロIFにしないのか?

コヒーレント・ターンアラウンド(姉妹編第2.3.6節)のため受信搬送波の位相を 精密に追う必要があり、DCオフセットやフリッカ雑音が乗る0 Hz付近に搬送波を置く構成は不利だから。 加えて宇宙用の集積IQトランシーバの選択肢が乏しく、実績あるヘテロダイン+ディジタルIF処理が選ばれてきた。

■ まとめ
  • 類型は「ADCの位置」で決まる: ヘテロダイン+IFサンプリング(計測級・IQ完全直交)、ゼロIF(小型安価・IQ障害)、ローIF(DC回避の折衷)、直接RF(ミキサレス・将来主流)。
  • どの構成も終着点は複素ベースバンド。違いは道中の障害とコスト。
  • 地上局はIFサンプリング→直接RFへ、小型SDRはゼロIF、搭載は帯域通過標本化併用のヘテロダイン、が現在の相場。

第2.3章ディジタルダウンコンバージョン(DDC)

■ この章で学ぶこと
ADCの出力(速い実数列)を復調器の入力(遅い複素列)へ変える三点セット—— NCO・複素ミキサ・デシメーションフィルタ——を設計できるようになる。 NCOの周波数分解能とスプリアス、CICフィルタの原理と補償、段構成の組み方まで。
◇ 直観でつかむ — 「引き寄せて」「間引く」
ADCから出てくるのは、広い周波数範囲を高速で写した大量の数列である。 復調したいのはその中のごく狭い一部分。そこでやることは2つだけ:
①引き寄せる——狙った周波数の信号を0 Hz付近へ平行移動する(スペクトルを横にスライドさせる)。 実現方法は「回る点を逆向きに回す数を掛ける」だけ。ラジオのダイヤルを合わせる操作のディジタル版である。
②間引く——欲しい帯域の外を捨てて(フィルタ)、標本の数を減らす(デシメーション)。 100万個/秒だった数列が2万個/秒になれば、以降の処理は50倍楽になる。
この「引き寄せて間引く」装置がDDCで、アナログ受信機のミキサ+IFフィルタと同じ役目を果たす。 GNU Radioでは Frequency Xlating FIR Filter 1個がこれをやってくれる。

2.3.1 DDCの全体像

DDC(Digital Down-Converter, ディジタルダウンコンバータ)は、 アナログ受信機の「ミキサ+IFフィルタ」をそのままディジタルに置き換えた装置である。 構成は3段で、それぞれの役目は次のとおりである。

第1段: NCO(Numerically Controlled Oscillator, 数値制御発振器)。 複素指数 e^{−j2πf₀n·T_s}、つまり「毎標本ごとに一定角度ずつ回る点」の数列を作る発振器である。 アナログのLO(局部発振器)に相当するが、実体は数値計算なので 周波数を自由・瞬時・正確に設定できる(2.3.2節)。

第2段: 複素乗算器。入力信号にNCOの出力を掛ける。 掛け算は周波数の平行移動に相当するので、これによって 狙った周波数 f₀ にあった信号が0 Hz付近へ移動してくる。 アナログのミキサと同じ働きだが、こちらは数値の乗算なので歪みもイメージも生じない。

第3段: デシメーションフィルタ。必要な帯域の外を落とし(フィルタ)、 標本化周波数を 1/R に間引く(デシメーション)。 これで後段の処理量が R 分の1に減る。順序が重要で、 必ずフィルタしてから間引く(理由は第2.4.1節)。

入力が実信号(IFサンプリング構成)でも複素信号(ゼロIF構成)でも、 この3段という骨格は変わらない。以下の節で各段を詳しく見ていく。

ADCfₛ = 100 MSPS × NCOe^(−j2πf₀nTₛ) CIC ↓R₁粗い間引き 補償FIR ↓2droop補正+整形 HB/FIR ↓2ⁿ最終帯域整形 復調器へ〜数百kSPS 複素 周波数シフト → 段階的に「濾しては間引く」
図2.3-1 DDCの標準構成。速い側は単純なフィルタ(CIC)、遅い側は上等なフィルタ(FIR)—— 計算量を速度で按分するのが多段設計の思想である(第2.4章)。

2.3.2 NCO — 位相アキュムレータの機械

NCOの作り方を理解しておくと、後の章(特にドップラ補償と搬送波同期)の 設計の自由度がどこから来るのかが見えるようになる。

心臓部は位相アキュムレータと呼ぶ、ただの加算器付きレジスタである。 Wビットのレジスタを用意し、標本ごとに一定値 M を足していく。 レジスタは W ビットなので 2^W で桁があふれて0に戻る—— このあふれによる巡回が、位相が2πを超えて1周することに対応する。 レジスタの値を「0から2πまでの位相」と読み替え、 その位相に対する sin と cos の値を表(ルックアップテーブル)から引くか、 CORDICという回転演算アルゴリズムで計算すれば、複素正弦波の数列ができる。

1周に必要な標本数は 2^W/M なので、出力周波数と、設定できる周波数の細かさ(分解能)は次になる。

f_{NCO} = \frac{M}{2^{W}} f_{s},\, Δf = \frac{f_{s}}{2^{W}}

数字を入れてみよう。W = 32ビット、f_s = 100 MSPS のとき、 分解能は 100×10⁶/2³² = 0.023 Hz である。 アナログのシンセサイザでこの細かさを実現することは容易ではない。 さらに重要なのは即応性で、加算値 M を書き換えれば 次の標本からもう新しい周波数で回っている。 この「細かく・瞬時に・正確に周波数を動かせる」という性質が、 第3.4章のドップラ追尾をあれほど簡単にしている源である。

実装上の留意点を2つ挙げる。

①位相の切り捨てがスプリアスを生む。 Wビットの位相をそのままテーブルの添字にはできないので、 上位Pビットに丸めて(切り捨てて)使う。この丸め誤差が周期的なパターンを作り、 おおよそ −6.02P dBc の高さのスプリアスが出る。 P = 16 ビットなら −96 dBc であり、通常はこれで十分。 足りなければ位相にディザ(第1.3.7節と同じ発想)を加えて砕く。

②NCOの周波数確度はクロックの確度そのものである。 式に f_s が入っていることに注目してほしい。NCOは 入力クロックを正確な分数倍する機械にすぎず、クロックがずれていれば 出力も同じ比率でずれる。「ディジタルだから正確」ではないので、 周波数を測る用途では第1.4章の基準クロックの議論に必ず戻ることになる。

2.3.3 CICフィルタ — 乗算器のいらない間引き機

DDCの第3段(フィルタと間引き)には固有の困難がある。 この段の入口では f_s がまだ最も速く、そこで多数のタップ(係数)の掛け算を行う 通常のFIRフィルタは、FPGAの乗算器を大量に消費して高価につく。

そこで使われるのが CIC(Cascaded Integrator–Comb)フィルタである。 構造は驚くほど単純で、掛け算を1個も使わない。 前半に積分器(前の値に今の値を足し続ける回路)をN段並べ、 間引きを行った後、後半に微分器(コム, 差分を取る回路)をN段並べるだけである。 加算と減算しかないので、速いレートでも安価に実装できる。 周波数特性は sinc 関数のN乗という形のローパスフィルタになる。

実装上の注意が1つある。積分器は値を足し続けるので内部の数値が大きく育つ。 間引き比を R、微分器の遅延を M(通常1)とすると利得は (RM)^N になるため、 内部演算のビット幅を N·log₂(RM) だけ余分に確保しておかないと桁あふれで壊れる (具体的な計算は演習2.3-2で行う)。出力側で適切に割り戻して後段に渡す。

CICには弱点もある。通過域が平坦ではなく、 周波数が上がるにつれて緩やかに減衰するドループ(垂れ下がり)が生じる。 信号帯域の端で振幅が下がってしまうと復調性能に影響するので、 CICの後段に補償FIR——通過域でCICの逆の傾きを持つ短いフィルタ——を置いて平坦に戻す。

この「CICで粗く速く間引き、短い補償FIRで整える」という組み合わせは、 FPGAのDDC、ΣΔ型ADCの内部デシメータ、民生SDRチップの中——あらゆる場所で使われている定番である。 安い部品で粗く削り、良い部品で仕上げる、という考え方は次節でさらに一般化される。

2.3.4 段構成の設計

ADCの出力レートから復調器が欲しいレートまで、たとえば 100 MSPS から 200 kSPS へ 落とすとする。総デシメーション比は R_total = 500 である。 これを1段で行うのは最悪の設計である。 1段でやるということは、100 MSPSの速さで、200 kSPS用の急峻なフィルタ (遷移域が極端に狭い=タップ数が莫大なフィルタ)を回すことを意味する。

定石は段階的に落とすことである。典型的な構成は次の並びになる。 CIC(R = 8〜64 の粗い間引き)→ 補償FIR(↓2、CICのドループを直しつつ間引く)→ ハーフバンドフィルタ(↓2 を必要な回数。係数の半分がゼロで計算が軽い)→ 最終整形FIR(↓1〜2、ここだけ丁寧に作る)。

なぜ分けると得なのか。各段が担う仕事は「その段の出力レートのナイキスト周波数より上を落とす」 ことだけであり、まだレートが速い段では要求される切れ味が緩い。 緩いフィルタはタップ数が少なく、速いレートでも安く回せる。 切れ味が必要な仕事は、レートが十分に落ちて標本数が減った奥の段に回す。 結果として合計の計算量が桁で減る(定量的な比較は第2.4.3節の例で行う)。

深宇宙受信ならではの注意を1つ添える。最終段のフィルタの品質は復調性能に直結する。 通過域のリプル(振幅のうねり)や群遅延の変化は、シンボル間の干渉(ISI, 姉妹編第2.4.2節) を生んで実装損失になる。中間段は雑に、しかし最後の1段だけは直線位相のFIRで丁寧に—— これが設計の勘所である。

【例2.3-1】100 MSPS→200 kSPSのDDC
R_total = 500。構成例: CIC 5段 ↓25 → 補償FIR ↓2 → HB ↓2 → 最終RRC整形 ↓5 (25×2×2×5 = 500)。NCOはIF 40 MHz(第1.2章の帯域通過標本化例の折り返し先)に置く。 最終段出力 200 kSPSは、100 kbaudのBPSKに対し2標本/シンボル——第3.2章のシンボル同期が 要求する標本化レートにちょうど接続する。

2.3.5 実入力DDCの小技 — fs/4ミキサ

設計の自由度を使い切る例を1つ紹介する。搭載機器のように資源が厳しい環境で常用される技法である。

IFサンプリングにおいて、信号が第1ゾーンのちょうど中央、すなわち f_s/4 の位置に 折り返すように f_s を選んだとしよう(第1.2.5節の不等式の範囲内でこうした値を狙える)。 すると必要なNCOの周波数は f_s/4 であり、その出力は e^{−jπn/2} = 1, −j, −1, +j, 1, −j, … という4つの値の繰り返しになる。

この4値はどれも、掛け算が「そのまま」「符号反転」「実部と虚部の入れ替え」で済む。 つまり乗算器を1個も使わずに複素ミキシングが実現できる。 あとはローパスフィルタと2分の1間引きを続ければ複素化が完了する。

これは第1.2.6節で述べた「f_s の選定は後段の資源まで決める」という主張の、 もっとも鮮やかな実例である。標本化周波数という1つの決断が、 FPGAの乗算器の個数を左右する——SDR設計が階層をまたいで結びついていることの好例として記憶してほしい。

Q. DDCはどこまでFPGAで、どこからCPUでやるべきか?

経験則は「f_s が速い区間=単純で規則的な処理=FPGA、レートが落ちた区間=複雑で 分岐の多い処理=CPU」。DDCはまさに前者で、市販SDR(USRP等)もDDC/DUCはFPGA内蔵、 ホストには間引き後の複素標本だけが流れる(第2.5章)。GNU Radioで書くDDC(Frequency Xlating FIR)は 学習と試作には最適だが、100 MSPS級の実時間処理はCPUでは苦しいことを知っておく。

Q. NCOの周波数を動かすと位相は飛ばないのか?

飛ばない。位相アキュムレータは連続に回り続け、Mの変更は「回転速度」だけを変える。 この位相連続性がドップラ追尾・掃引捕捉(第3.1・3.4章)でNCOが使える本質的理由である。 位相そのものを書き換えない限り、周波数をどう動かしても搬送波位相の連続性は保たれる。

▶ GNU Radioで試す — DDCを1ブロックで
GNU Radioの Frequency Xlating FIR Filter はNCO+複素ミキサ+FIR+デシメーションを 1ブロックに束ねたDDCそのものである。File Source(第4.5章で録るIQファイル)または Signal Source+Noise Source を入力に、 taps = firdes.low_pass(1, samp_rate, 25e3, 10e3)、center_freq を QT GUI Range で±100 kHz可変にして、スペクトル上の任意の信号を 「掴んで0 Hzへ引き寄せ、間引く」感覚を体験する。これが第4.3章の受信機の最初の1段になる。

章末演習

【演習 2.3-1】NCOの設計
f_s = 125 MSPS、位相アキュムレータ32ビットのNCOで 21.4 MHz を出したい。 増分Mの値と、実際に出る周波数の誤差を求めよ。
解答
M = round(21.4×10⁶ × 2³²/125×10⁶) = round(735,204,565.8…) = 735,204,566。 実周波数 = M·f_s/2³² = 21.400000006 MHz、誤差は約6 mHz(分解能 f_s/2³² = 0.029 Hzの範囲内)。 この残差は搬送波同期ループ(第3.1章)が吸収する。
【演習 2.3-2】CICのビット成長
入力14ビット、5段CIC、間引き比R = 32(M = 1)のとき、内部演算に必要なビット幅はいくらか。
解答
成長 = N·log₂(RM) = 5×5 = 25ビット。必要幅 = 14 + 25 = 39ビット。 FPGAでは39ビットのアキュムレータを5本並べる。出力では下位を丸めて後段のFIRに渡す (丸め位置ごとの量子化雑音は第1.3章の理屈で評価できる)。
■ まとめ
  • DDC = NCO+複素乗算+デシメーションフィルタ。アナログの「ミキサ+IFフィルタ」の完全な置き換え。
  • NCOは位相アキュムレータ: f = M·f_s/2^W、分解能mHz級・位相連続・即応。位相切り捨てで−6P dBcのスプリアス。
  • 初段はCIC(加減算のみ、sinc^Nドループを補償FIRで平坦化)、終段は直線位相FIRで丁寧に。
  • fs/4ミキサ・多段分解などの定石は「f_s 選定が後段の資源を決める」ことの現れ。

第2.4章マルチレート信号処理

■ この章で学ぶこと
デシメーション・補間・分数比再標本化の規則と、ポリフェーズ分解がもたらす計算量の劇的削減。 「どのレートで計算するか」はSDR設計の中心的な自由度であり、DDC(前章)とシンボル同期(第3.2章)を つなぐ幹線道路である。後半(2.4.6節)では、標本化周波数・シンボルレート・ビットレート・ スループット・占有帯域という5つの量を1本の連鎖として結び、 実装で迷わないための追跡方法を確立する——ここが本書でもっとも実務直結の節である。
◇ 直観でつかむ — 急な仕事は「遅い場所」でやる
フィルタの計算量は「1秒あたり何個の標本を処理するか」×「フィルタの長さ」で決まる。 そしてキレの良い(急峻な)フィルタは長い。だから、高速な入口で急峻なフィルタを回すのは最も高くつく。 賢い作り方は、入口では甘いフィルタで大ざっぱに削って間引き、標本が減って暇になった奥で キレのよい仕上げをする。同じ結果が計算量2桁減で得られることも珍しくない。 工場のライン設計と同じで、混んでいる工程には簡単な作業を、空いた工程に難しい作業を回す—— これがマルチレート信号処理の思想である。

2.4.1 デシメーションと補間の規則

標本化周波数を変える操作は2つある。用語と、絶対に守るべき順序を確認する。

デシメーション(間引き、↓R と書く)は、R個の標本のうち1つだけを残して 標本化周波数を 1/R にする操作である。ここで思い出してほしいのは、 標本化周波数が下がればナイキスト周波数も下がるという事実である。 間引いた後のナイキスト周波数は f_s/2R でしかないので、 それより高い成分が残っていればそのまま折り返してくる(第1.2.2節のエイリアシング)。 したがって間引く前に、必ずフィルタで f_s/2R 以上を落としておく。 この目的のフィルタをデシメーションフィルタと呼ぶ。

補間(↑L と書く)は逆の操作で、標本の間に L−1 個のゼロを挿入して 標本化周波数を L 倍にする。ゼロを挿入した時点では波形がギザギザで、 スペクトルには不要な複製(イメージ)が L−1 組現れている。 したがって挿入した後に、必ずフィルタでイメージを潰す。 これを補間フィルタと呼び、この処理が実質的に「点と点の間を滑らかに埋める」役目を果たす。

まとめると「デシメーションはフィルタが先、補間はフィルタが後」である。 当たり前に見えるが、この順序を破った実装は現実に頻出する。 症状はエイリアシングやイメージという形で現れ、スペクトルを見るまで気づかないことが多い。 自作ブロックを書くときは、まずこの順序を確認する習慣をつけてほしい。

2.4.2 ポリフェーズ分解 — 捨てる標本は計算しない

前節の規則に素直に従うと、大きな無駄が生じる。 「f_s の速さでフィルタを全部計算してから、R個に1個だけ残して他を捨てる」—— 捨てる標本のために行った計算、つまり全体の (R−1)/R が無駄になっている。 R = 100 なら計算の99%を捨てていることになる。

この無駄を完全に除く実装がポリフェーズ分解である。 考え方は「捨てる標本を最初から計算しない」ことに尽きる。 フィルタの係数列を R 本の部分列(ポリフェーズ成分)に分け、 それぞれを間引き後の遅いレートで回すように組み替えると、 出力に必要な標本だけが計算される。数学的には元のフィルタと完全に等価で、 計算量だけが 1/R になる。補間の場合も同様に 1/L になる。 具体的には、Nタップのフィルタで R 分の1に間引く処理の乗算回数が、 毎秒 N·f_s 回から毎秒 N·f_s/R 回へ減る。

GNU Radioの Decimating FIR FilterPolyphase Arbitrary Resampler は内部でこれを行っている。 したがってこの節を学ぶ実務上の意義は、自分で実装することよりも、 処理が重いときに原因を切り分けられるようになることにある。 重さの原因はブロックの実装効率ではなく、たいてい自分が指定した 「タップ数 × レート」という設計値の側にある。

2.4.3 多段化の算術 — なぜ分けると安いのか

第2.3.4節で「段階的に間引くと計算量が桁で減る」と述べた。その根拠を計算できるようにしておく。

FIRフィルタに必要なタップ数は、次の経験式で見積もれる。

N ≈ \frac{f_{s}}{Δf} · \frac{A_{dB}}{22}

ここで Δf は遷移帯域の幅(通過域端から阻止域端までの周波数差)、 A_dB は要求する阻止減衰量[dB]である。式の意味を読み取ろう。 分母に Δf があるので、切れ味を良くする(遷移域を狭くする)ほどタップが増える。 そして分子に f_s があるので、同じ切れ味でも、レートが速い場所で実現するほどタップが増える

後者が多段化の根拠である。急峻なフィルタが必要な仕事は、 間引いてレートが落ちた後で行えば安く済む。 逆にレートが速い入口では、切れ味を要求しない仕事—— 緩く落として間引くだけ——に留め、CICフィルタ(第2.3.3節)や ハーフバンドフィルタ(係数のちょうど半分がゼロになる特別なローパスフィルタで、 2分の1間引き専用。ゼロの係数は計算しなくてよいので計算量が半分で済む)に任せる。 第2.3.4節で示した段構成は、この算術から導かれた結論だったのである。 次の例で、その差が実際にどれほどかを確認してほしい。

【例2.4-1】1段 vs 多段
10 MSPS→100 kSPS(R = 100)、最終遷移域 10 kHz・阻止60 dBとする。 1段なら N ≈ (10⁷/10⁴)×(60/22) ≈ 2700タップを10 MSPSで回す=毎秒270億乗算(ポリフェーズでも2.7億)。 多段(HB↓2×2段 → CIC↓5 → 最終FIR↓5)なら合計は毎秒数百万〜千万乗算のオーダーに落ちる。 2桁の差はFPGAの規模、CPUの実時間性、搭載機器の消費電力に直結する。

2.4.4 分数比再標本化 — レートの違う世界をつなぐ

これまでは整数倍・整数分の1の変換を扱ってきた。しかし現実には 整数比にならない変換が必要になる。理由は2つある。

第一に、ADCの標本化周波数は装置の都合(クロックの整数分の1、第4.5.1節)で決まり、 シンボルレートは通信規格で決まるので、両者の比が整数になる保証はない。 第二に、ドップラによってシンボルレート自体がわずかに伸び縮みする(第3.4.5節)。 つまり必要な比は整数どころか、時間とともに変化する実数である。

比が L/M という有理数(分数)で表せる場合は、原理的には 「↑L で増やす → フィルタ → ↓M で間引く」の組み合わせで作れる。 GNU Radioの Rational Resampler がこれである。

任意の実数比、あるいは時間変化する比に対応するにはポリフェーズ補間器を使う。 仕組みはこうである。まず「標本と標本の間を32等分した各位置の値を計算するフィルタ」を 32本用意しておく(これらは互いに少しずつ遅延の異なるフィルタである)。 値が欲しい時刻が標本間のどの位置にあたるかを計算し、 その位置に対応するフィルタを選んで適用する。 32分割では足りない精度が必要なら、隣り合う2本の結果を線形補間する。 こうして標本の存在しない任意の時刻の値を合成できる

この機構を覚えておいてほしい。第3.2章で扱うシンボル同期器の心臓部は、 まさにこのポリフェーズ補間器である。そしてタイミング同期ループとは、 「どの位置のフィルタを選ぶか」を誤差信号にしたがって連続的に動かす仕組みにほかならない。 再標本化の技術と同期の技術は、実装レベルでは同じものなのである。

2.4.5 フィルタ設計の実務 — なぜSDRのフィルタはFIRばかりなのか

本章でここまで扱ったフィルタはすべてFIR(Finite Impulse Response, 有限インパルス応答)だった。 ディジタルフィルタにはもう一方の系統であるIIR(Infinite Impulse Response, 無限インパルス応答)が あるのに、なぜSDRの信号経路にはFIRしか出てこないのか。ここを押さえておくと、 フィルタの選択で迷わなくなる。

2つの違いは帰還があるかどうかである。FIRは過去の入力だけに係数を掛けて足す (y[n] = Σ b_k·x[n−k])。IIRはそれに加えて過去の出力を足し戻す (y[n] = Σ b_k·x[n−k] − Σ a_k·y[n−k])。 アナログ回路のRCフィルタやLCフィルタは、動作としてはIIRに対応する。

IIRの強みは効率である。帰還によって過去の情報が減衰しながら永久に残るため、 同じ切れ味(選択度)を数分の1から数十分の1の係数数で実現できる。 アナログ的な発想からすれば、IIRを使わない理由はないように見える。 しかしSDRの信号経路では、次の4つの理由でFIRが選ばれる。

理由1: FIRは位相を完全に直線にできる(IIRは原理的にできない)。 係数を左右対称に取ったFIRは、すべての周波数に対して群遅延が ちょうど (N−1)/2 標本で一定になる。これを直線位相と呼ぶ。 群遅延が一定ということは、波形が遅れるだけで形が崩れないことを意味する。 IIRでは群遅延が周波数によって変わるため、パルスの形が歪み、 シンボル間干渉(ISI)となって復調性能を直接損なう。 復調直前の整形フィルタにIIRを使わないのは、この一点だけで決まる。

理由2: FIRは常に安定である。帰還がないので発振しようがない。 IIRは係数を有限ビットに丸めた瞬間に極が単位円の外へ出て発振する危険があり、 特にFPGAの固定小数点実装では設計時の検証が要る。 さらに帰還路の丸め誤差が自己維持するリミットサイクル(入力がゼロなのに出力が振動し続ける現象)も IIR固有の厄介事である。

理由3: FIRはポリフェーズ分解できる(IIRはできない)。 第2.4.2節で見たとおり、FIRは「捨てる標本を計算しない」形に組み替えられ、 デシメーション時に計算量が 1/R になる。 ところがIIRは各出力が前の出力に依存するため、間引く標本も計算しないと次が計算できない。 マルチレート処理——すなわちSDRの信号経路の骨格——と本質的に相性が悪い。

理由4: FIRは並列化・パイプライン化しやすい。 FIRの各タップは独立に計算できるので、FPGAで乗算器を並べて1クロックで処理できる。 IIRは帰還があるため「前の出力が出るまで次が始められず」、 パイプライン段数を増やせない。結果として動作クロックの上限が帰還路の遅延で決まってしまう。 高いレートで回す入口側のフィルタにIIRが使えない理由がこれである。

ではIIRはSDRのどこにいるのか。実は消えたわけではなく、 「波形を通すフィルタ」ではなく「量を平滑する仕組み」として随所で使われている。 AGCの電力推定(第3.3.2節の p_est = (1−α)·p_est + α·|z|² は1次IIRである)、 ロック検出量の平滑(第3.1.7節)、DCオフセットの除去、SNR推定の移動平均などである。 これらは通過波形の位相を問わない用途なので、IIRの効率が素直に活きる。

そしてもっとも重要な事実を挙げる。第3.1章のPLLのループフィルタ自体がIIRである。 積分器 v += g2 * e は過去の出力を足し戻す帰還であり、定義上IIRにほかならない。 つまり「SDRの信号経路はFIR、制御と推定はIIR」という住み分けになっている。 IIRの安定性の議論(極の位置)が、そのままループの安定性の議論(第3.1.3節の B_n·T_s < 0.01 という制約)に対応していることも、いま見た理由2からうなずけるはずである。

以上を踏まえ、FIRの設計法の選択肢を整理する。

設計法特徴使いどころ
窓関数法(firdes)簡単・頑健。仕様ぴったりにはならないチャネル選択・とりあえずのLPF。GNU Radioのfirdes.low_pass()
等リプル(Parks–McClellan / remez)同じ仕様を最少タップで満たす資源が厳しいFPGA・搭載機器の最終整形。
RRC(ルートレイズドコサイン)整合フィルタ+ISIゼロ(姉妹編第2.4.1節)復調直前の整形はこれ一択。firdes.root_raised_cosine()
ハーフバンド係数半分がゼロ、↓2専用で計算量最小多段デシメーションの中間段。
CIC乗算ゼロ・ドループあり(第2.3.3節)最速レートの初段。

仕様の置き方にも定石がある。通過域リプルは復調ISIとして実装損失に効くので0.1 dB級に抑える。 阻止減衰は「折り返してくる雑音・妨害の許容量」から決める(60〜80 dBが相場)。 群遅延は直線位相FIRなら一定で(N−1)/2標本——同期ループの中に入るフィルタの遅延はループの 安定余裕を食う(第3.1章)ので、ループ内は短く、ループ外で贅沢に、が原則である。

Q. 「まず最高レートで全部フィルタしてから最後に一気に間引く」のはなぜ駄目か?

結果は同じでも計算量が桁違いだから(例2.4-1)。マルチレート設計とは 「同じ伝達関数をどの順序・どのレートで計算するか」の最適化であり、 正しさではなく資源の問題である。逆に言えば、資源が余る試作段階では1段でも構わない—— GNU Radioでの試作→FPGA化の際に多段へ再分解する、が現実的な開発順序である。

2.4.6 レート連鎖 — 各アローで3つの数を言えるようにする

◇ 直観でつかむ — 「レート」も3つある
通信の教科書では「レート」は毎秒何ビット送るか(ビットレート)を指す。 SDRではこれに2つ加わる。標本化周波数(毎秒何個の数値が流れるか)と、 スループット(毎秒何バイトがUSBやEthernetを通るか)である。 3つは互いに換算できるが、桁も単位も違う——4096 bps の信号が 524288 SPS の標本流に乗り、4.2 MB/s としてPCに届く、というように。 この節では3者を1本の連鎖として結ぶ。

SDRで最初に身につけるべき規律を1つ挙げるなら、これである。 フローグラフのすべての線(アロー)について、3つの数を即座に言えるようにする。 ①その地点の標本化周波数 f_s、②その地点で信号が占めている帯域幅、 ③下流のブロックに渡した samp_rate の値。 この3つが言えれば、フィルタのcutoffもspsもループ帯域も機械的に決まる。 言えなければ、どこかで必ず破綻する。

なぜ意識しないと分からなくなるのか。第1.2章で述べたとおり、 ブロックの間を流れているのは裸の数列だけで、 「これは毎秒何標本のデータです」という情報は付いていない。 GRCで定義する samp_rate という変数も、 設計者がHzと正規化値を換算するために使う約束事にすぎず、 実際のデータ流と自動で一致するわけではない(第4.1.1節で再度扱う)。 レートを追跡するのは人間の仕事なのである。

追跡そのものは簡単で、掛け算と割り算だけである。 f_s が確定するのは起点(ハードウェア、または Throttle)であり、 そこから下流は各ブロックの interpolation と decimation の比だけで決まる。

f_{s}(その地点) = f_{s}(起点) × \frac{Π\, interp_{i}}{Π\, decim_{i}}

第4.3章で作るPCM/PSK/PM受信機について、実際に書き出してみる。 設計時にこの表を作り、コードのコメントに残しておくのが本書の流儀である。

USRP Source 524288 SPS complex 占有帯域 ±74 kHz → Xlating FIR (decim=1) 524288 SPS ← レート不変・周波数だけ −25 kHz 平行移動 → AGC → PLL → C→Arg 524288 SPS ← レート不変(型が complex→float に変化) → Xlating FIR fcc ↓16 32768 SPS complex 占有帯域 ±4 kHz → 移動平均8 → Symbol Sync 4096 sym/s ← ここで単位が「標本」から「シンボル」へ → Binary Slicer 4096 bit/s

ここで単位が2回変わっていることに注目してほしい。 complexからfloatへの型変化(位相復調)と、標本からシンボルへの意味の変化(シンボル同期)である。 後者を橋渡しするのが次の1本の式で、これがSDRの世界と通信の世界をつなぐ蝶番になる。

sps = \frac{f_{s}}{R_{s}}

sps(samples per symbol, 標本/シンボル)は、1つのシンボルの間に何個の標本があるかを表す。 R_s はシンボルレート[baud]である。そしてシンボルレートとビットレートの関係は

R_{b} = R_{s} × log_{2}M × r_{code} × η_{frame}

で結ばれる。M は変調の多値数(BPSKなら2で log₂M = 1、QPSKなら4で2)、 r_code は誤り訂正符号の符号化率(畳み込み(7,1/2)なら1/2)、 η_frame はフレームのオーバーヘッドを除いた効率である。

この式は逆向きに読むと設計上の意味を持つ。符号化を入れると、 同じ情報レートを送るためにチャネル側のシンボルレートが上がり、 占有帯域も必要な f_s も増える。畳み込み(7,1/2)なら2倍である。 「符号化はリンクバジェットを改善する」だけでなく「レート設計と帯域設計に波及する」 ——第5.3章のウォークスルーでこの効果を実際に扱う。

3番目のレート、スループットも忘れてはならない。これは変調とは無関係に、 標本化周波数とデータ型だけで決まる。

スループット [B/s] = f_{s} × 2 × (1成分のバイト数)

係数2はIQ(複素数1個=実数2個)である。 524288 SPS を complex64(float32×2 = 8バイト)で扱えば毎秒4.2 MB、 USRPとの線上で otw_format="sc16"(16ビット整数×2 = 4バイト)にすれば毎秒2.1 MBになる。 この数字がUSBやEthernetの実効帯域を超えていれば、 どれほど計算が速くても標本は落ちる(第2.5.2節)。

最後に、f_s の下限を決めるもう一方の量——占有帯域——の見積りをまとめておく。 変調方式ごとに次の値を使う。

方式占有帯域の実用的な見積り
NRZ矩形パルスのBPSK(整形なし)主ローブは ±R_s(第1ヌルまで)。実用上は ±2R_s を通す
RRC整形(ロールオフ α)(1+α)·R_s、すなわち ±(1+α)R_s/2
PCM/PSK/PM(副搬送波 f_sc)±(f_sc + 2R_b)。加えて 3f_sc の高調波を考慮

第4.3章の設計に当てはめると、f_sc = 65.536 kHz、R_b = 4096 bps なので 占有帯域は ±(65536 + 8192) = ±73.7 kHz、幅にして約148 kHz。 これに対し f_s = 524.288 kSPS は3.5倍であり、 AAFの遷移域とドップラによる移動分の余裕を含んだ選定になっている(第1.2.6節の選定表)。

各段で確認すべき不等式は、結局これ1本にまとまる。

占有帯域 ≤ 2 × cutoff ≤ f_{s}(その段の出力)

左の不等号が「信号を削っていないこと」、右が「折り返していないこと」を保証する。 レート連鎖の表を書き、各段でこの不等式を検算する—— これがSDR設計の日常的な作業である。

▶ GNU Radioで試す — 再標本化とイメージ
Rational Resampler(interpolation = 3, decimation = 2)で 48 kSPS の信号を 72 kSPSへ。taps を空欄(自動設計)にした場合と、わざと [1](フィルタなし)にした場合で QT GUI Frequency Sink を比較すると、補間イメージがフィルタの有無でどう変わるかが見える。 次に Polyphase Arbitrary Resampler で比を 1.0001 のような無理数近くに設定し、 トーンの周波数が正確に1.0001倍になることを確認する——これがドップラでレートの伸び縮みした 信号を扱う道具である(第3.4章)。

章末演習

【演習 2.4-1】タップ数の見積り
2 MSPSで動くチャネル選択フィルタに、遷移域 50 kHz・阻止減衰 66 dB を要求する。 概算タップ数と、↓4のポリフェーズ実装での毎秒乗算回数を求めよ。
解答
N ≈ (2×10⁶/5×10⁴)×(66/22) = 40×3 = 120タップ。 ポリフェーズ↓4なら実効 120×(2×10⁶)/4 = 毎秒6000万乗算。 現代のCPU1コアで余裕、FPGAならDSPスライス数個分である。
■ まとめ
  • 間引く前に濾す・挿入した後に濾す。順序を破るとエイリアシング/イメージが即発生。
  • ポリフェーズ分解で計算は出力レート側: デシメーションFIRの計算量は1/Rになる。
  • タップ数 ∝ f_s/Δf。急峻な仕事は遅いレートへ送る——多段構成で計算量は桁で減る。
  • 任意比・時変比の再標本化はポリフェーズ補間器。シンボル同期器の心臓部と同じ機械。
  • 通過域リプルは実装損失、ループ内の群遅延は安定余裕を食う。仕様は回線と同期から逆算する。
  • 信号経路はFIR(直線位相・常に安定・ポリフェーズ可・並列化可)、平滑と制御はIIR(PLLのループフィルタもIIR)。
  • レート連鎖: f_s は起点×Π(interp)/Π(decim)。全アローで f_s・占有帯域・渡した samp_rate の3つを言えるようにする。
  • 標本の世界と通信の世界の蝶番は sps = f_s/R_s。R_b = R_s·log₂M·r_code·η_frame で符号化がレートと帯域に波及する。
  • 第3のレートはスループット f_s×2×バイト幅。変調とは無関係に伝送路の限界を決める。
  • 各段の検算式は「占有帯域 ≤ 2×cutoff ≤ 出力 f_s」の1本。

第2.5章SDRプラットフォームの解剖

■ この章で学ぶこと
CPU・FPGA・ASIC・GPUへの仕事の割り振り(なぜそうなるかまで)、ホストへの伝送路とバッファリング、 オーバーフロー(標本落ち)というSDR特有の故障モード、タイムスタンプ機構。 アルゴリズムではなく「システムとしてのSDR」を設計する視点を得る。

2.5.1 処理の分担 — CPU / FPGA / ASIC / GPU

◇ 直観でつかむ — 「速い」の意味が2通りある
CPUは3 GHzで動き、FPGAは200 MHzでしか動かない。それでも 100 MSPSのフィルタはFPGAで動いてCPUでは動かない。矛盾しているように見えるのは、 「速い」に2つの意味があるからである。CPUは1つの命令を速く順番にこなす機械、 FPGAはたくさんの演算を同時にこなす機械である。 信号処理は「同じ計算を全標本に施す」仕事なので、後者の形に合っている。

SDRの処理をどこで実行するかは、アルゴリズムの正しさとは別の、 しかし同じくらい重要な設計判断である。選択肢は4つあり、 「時間で分けるか、空間で分けるか」という軸で理解できる。

CPUは1つ(あるいは数個)の高速な演算器を、命令列に従って時間で使い回す。 クロックは3 GHz級と高いが、1クロックで実行できる乗算はSIMD命令を使っても十数個程度である。 仮に毎秒100×10⁶標本に120タップのフィルタを掛けるなら毎秒120億回の乗算が必要で、 これは汎用CPUの現実的な処理能力を超える。 一方でCPUは条件分岐・状態機械・可変長の処理・浮動小数点が自在であり、 プログラムを書き換えるだけで振る舞いを変えられる。

FPGA(Field-Programmable Gate Array)は、論理ブロックと乗算器(DSPスライス)と 配線を書き換え可能な形で敷き詰めたデバイスである。 クロックは100〜500 MHz程度でCPUより低いが、乗算器を数百〜数千個並べて空間的に同時に動かせる。 さらに各段の結果を次の段へ流し続けるパイプライン構成にできるので、 「毎クロック1標本を確実に処理し続ける」動作が保証される。 標本化周波数が高く、処理が固定的で規則的な区間——まさにDDCやCIC——はFPGAの領分である。 第2.4.5節で見たFIRの並列化しやすさが、ここで効いてくる。

ASIC(Application-Specific Integrated Circuit)は、 同じ回路を書き換え不能な専用チップとして焼き固めたものである。 FPGAの書き換え機構(配線スイッチや構成メモリ)が要らなくなるため、 同じ処理を数分の1の電力・面積で、より高いクロックで実行できる。 代償は柔軟性の喪失と、設計・製造の初期費用(NRE)が莫大なことである。 したがってASICが選ばれるのは「大量生産する」か「電力・面積が絶対制約」の場合に限られる。

ここでSDRの定義(第1.1.1節)と突き合わせてみてほしい。 信号処理をASICに焼き固めることは、SDRの利点そのものを捨てることに等しい。 打上げ後にプロトコルを更新できるという第1.1.3節の価値は、書き換え可能性から来ていたのである。 ところが現実のSDRはASICを大量に使っている——ただし使う場所が違う。 アナログフロントエンドの集積トランシーバIC、ADC/DAC、USBやEthernetのインタフェース、 そして携帯電話の基地局のように仕様が固まって数が出る用途の変復調部である。 「変わらない部分はASIC、変わる部分はFPGAとCPU」という切り分けが、 SDRという言葉の実体だと理解しておくとよい。

GPUはCPUとFPGAの中間にあり、同じ演算を大量のデータに一斉に適用する (データ並列)用途で圧倒的に速い。ただしホストとの間でデータを往復させる遅延が大きいので、 実時間の受信経路よりも、記録したデータの事後処理(第5.2.3節)や 大規模なFFT・相関に向く。

実行場所得意な処理SDRでの典型例
CPU(ホスト)可変・分岐・状態機械・浮動小数点。書き換えが即座同期ループ、復調、フレーム同期、復号、運用ロジック、GNU Radio全般
FPGA(デバイス内)高レート・固定・規則的・パイプライン化できる処理DDC/DUC、CIC/ハーフバンド、fs/4ミキサ、タイムスタンプ付与、搭載機の変復調
ASIC変わらない処理を最小電力・最小面積でRFトランシーバIC、ADC/DAC、通信インタフェース、量産機の変復調部
GPU大規模データ並列(遅延は大きい)広帯域チャネライザ、捕捉FFT、多チャネル相関(ΔDOR等)、記録データの事後処理

境界は固定ではなく、開発の段階によって動く。 研究開発期は「全部CPU(GNU Radio)」で正しさを確立し、 実時間性や電力が要求される段階でFPGAへ降ろし、 量産・究極の低電力が要るならASICへ——という順序が定石である。 この順序は第IV部の学び方の前提でもあり、第4.4.1節(Pythonで正しく→測って→遅い所だけC++) および第5.1.5節(フライトはFPGA、検証はGNU Radio)で繰り返し現れる。 なお搭載機器では、この選択にもう1つの軸——放射線への耐性——が加わる。 FPGAの型式(SRAM型・フラッシュ型・アンチヒューズ型)ごとに事情が違うので、第5.1.2節で扱う。

2.5.2 伝送路の算術 — 帯域は足りるか

デバイス→ホストのデータレートは f_{s} × 2(IQ) × B_{bytes}。 複素16ビット(4バイト/標本)なら、10 MSPSで40 MB/s、100 MSPSで400 MB/s。 USB 2.0(実効〜35 MB/s)、USB 3.0(実効〜300 MB/s)、1 GbE(〜110 MB/s)、10 GbE(〜1.1 GB/s)と 並べれば、「ホストへ何MSPS持って来られるか」はインタフェースで決まっていることがわかる。 持って来られない分はFPGA内のDDCで間引いてから送る——市販SDRの「最大帯域」の数字は ADCではなく伝送路の数字であることが多い。

2.5.3 バッファとオーバーフロー — SDRの故障モード

SDR特有の故障モードを1つ、名前と症状と対策で覚えてほしい。実機を触ると必ず出会う。

ホスト側の処理は汎用OS上のプログラムなので、他のプロセスに割り込まれたり、 メモリ確保に時間がかかったりして一瞬もたつくことがある。 その間もADCは止まらず標本を送り続けるので、受信バッファが溢れる。 溢れた標本は黙って捨てられる——これがオーバーフローで、 GNU RadioとUHD(USRPのドライバ)の組み合わせでは端末に「O」の文字が表示される。

深刻さは用途で大きく違う。テレメトリ受信なら、落ちた区間のビットが読めないだけで 一時的なBER劣化として済むこともある。しかしドップラ計測・測距・ΔDORでは致命的である。 これらは位相を連続的に積み上げて測る技術なので、 標本が1回落ちただけで位相の連続性が切れ、その測定は無効になる

対策は4つある。①十分に間引く——伝送路と処理量に余裕を持たせる(前節の算術)。 ②実行環境を整える——プロセスの優先度を上げ、CPUコアを固定する。 ③バッファを深くする——一時的なもたつきを吸収させる。 ④まず記録し、後で処理する——実時間処理を諦め、ディスクに書き切ってから オフラインで解析する。④は敗北ではなくSDRの正当な戦術であり、 深宇宙の重要イベントではむしろ標準手段である(第5.2章のオープンループ記録)。

送信側では逆の現象が起きる。ホストが波形を供給しきれないと 送るデータがなくなり、送信波形が途切れる。これをアンダーフローと呼び、 端末には「U」が表示される。

2.5.4 タイムスタンプと同期 — 「いつの標本か」を運ぶ

研究用SDR(USRP等)は標本流に標本番号と時刻のメタデータを添付する機構を持つ。 内部カウンタを1PPS+10 MHz基準(第1.4.6節)に同期させれば、 「標本#123456789 = UTC 12:00:00.000000」という対応が得られ、 指定時刻に送信を開始する(time_spec付きバースト送信)・複数デバイスの標本を時刻で揃える (多局受信・干渉計)ことができる。GNU Radioではこのメタデータがストリームタグとして ブロック間を流れる(第4.4章)。計測用SDRシステムの設計とは、信号経路と同じ真剣さで 「時刻の経路」を設計することである。

2.5.5 代表的プラットフォーム

クラス特徴本書での位置づけ
入門受信専用RTL-SDR8ビット・〜2.4 MSPS・USB2.0・数千円第IV部の実験の最低装備。受信のみ。
入門送受信ADALM-Pluto12ビット・ゼロIF・〜61.44 MSPS(USB帯域に注意)ループバック実験(第4.5章)に好適。
中級送受信LimeSDR, HackRF等広帯域・送受信・数万円同上+広帯域実験。
研究・計測級USRP(N/X/B系)GPSDO・タイムスタンプ・10 GbE・多チャネル局試作・計測実験(第5.2・5.3章)。
統合SoCRFSoC搭載ボードGSPS級ADC/DAC+FPGA+CPU一体直接RF受信機・搭載機器プロトタイプ。
Q. レイテンシはどのくらい見込むべきか?

USB系で数ms〜数十ms、ネットワーク系で1ms前後、FPGA内で完結すればμs以下が相場。 テレメトリ受信は片道なのでレイテンシは実質無害だが、送受を結ぶループ——コヒーレント・ ターンアラウンド、閉ループの試験治具、TDMA的な時刻厳守の送信——では設計制約になる。 「どこまでの経路がレイテンシに敏感か」を最初に仕分けるのがシステム設計の第一歩である。

Q. ホストPCの性能はどれだけ要るか?

処理量の主部はフィルタ(タップ数×レート、第2.4章)とFFT。1 MSPS級の復調なら ラップトップで余裕、数十MSPSの多チャネル処理からコア数・メモリ帯域・リアルタイム設定が 効いてくる。見積りの出発点は「毎秒乗算回数」を数えること——例2.4-1の算術がそのまま使える。

▶ GNU Radioで試す — オーバーフローを起こしてみる
RTL-SDR/Plutoを繋ぎ(第4.5章)、Sink側に重い処理(巨大タップのFIRや高レートのGUI表示)を わざと置いて標本落ち(端末の「O」表示)を観察する。次に間引きを増やす・GUI更新率を下げる・ File Sinkへの記録に切り替える、の3手でそれぞれ「O」が消えることを確認する。 故障モードを一度自分で起こしておくと、本番で「O」を見た瞬間に原因の当たりがつくようになる。
■ まとめ
  • CPUは演算器を時間で使い回す(分岐と可変処理に強い)、FPGAは空間に並べる(高レートの固定処理に強い)。速く規則的=FPGA、遅く複雑=CPU、大規模並列=GPU。
  • ASICは「変わらない処理」を最小電力で。信号処理をASICに焼くのはSDRの利点を捨てること——変わらない部分(RFトランシーバ・ADC/DAC・IF)はASIC、変わる部分はFPGAとCPU。
  • 開発は全部CPU→実時間が要ればFPGA→量産・極低電力ならASIC、の順に降ろす。
  • ホストに来る帯域は伝送路が決める: f_s×2×バイト幅をUSB/GbEの実効値と比べる。
  • オーバーフロー(標本落ち)はSDR特有の故障モード。計測では1回で致命傷——間引き・優先度・記録戦術で守る。
  • 計測級SDRは1PPS/10 MHz同期のタイムスタンプ機構を持つ。時刻の経路も設計対象。
第 III 部 同期の実装 — ループをソフトウェアにする
姉妹編第2.3・2.4章で学んだPLL・シンボル同期の理論を、そのまま書ける差分方程式とゲイン設計式に翻訳する。ここでの1行1行がGNU Radioブロックのパラメータに1対1で対応する——第IV部でPCM/PSK/PM受信機を組むとき、すべての数値はこの部の式から出てくる。

第3.1章ディジタルPLLと搬送波同期

■ この章で学ぶこと
ディジタルPLLの標準形(位相検出器+PIフィルタ+NCO)を差分方程式で書き下し、 雑音帯域幅 B_n と減衰係数 ζ からループゲイン g₁, g₂ を決める設計式を導く。 この式はGNU Radioの loop_bw パラメータに直結する。 残留搬送波PLL・Costasループ・FLLの実装形、捕捉(FFT粗推定と掃引)、ロック検出まで、 PCM/PSK/PM受信機の搬送波系を完全に設計できるようにする。
◇ 直観でつかむ — PLLは「並走する車」
受信した搬送波は、送信側の発振器の都合とドップラで、こちらの想定とわずかに違う速さで回っている。 PLLは自分の中で回る点(NCO)を用意し、相手との角度差を見ながら回転速度を微調整して、 ぴったり並走させる装置である。高速道路で隣の車と速度を合わせる操作と同じで、 ①相手とのズレを見る(位相検出)→②アクセルを少し踏む/緩める(ループフィルタ)→ ③速度が変わる(NCO)、の3ステップを毎瞬繰り返す。
調整の強さ(ループ帯域 B_n)が本章の主役である。強く反応させれば相手の加速に素早く追いつくが、 路面のガタガタ(雑音)にも反応して車が揺れる。弱くすれば乗り心地は良いが加速に置いていかれる。 この綱引きを数字で決めるのが同期設計であり、決めた数字がGNU Radioの loop_bw という1つのパラメータに落ちる。

3.1.1 標準形 — 3つの部品と4行の差分方程式

まず「なぜ搬送波同期が必要か」を確認しておく。 受信した信号の位相を読むには、比較の基準となる「自分の側の位相」が必要である。 ところが送信側の発振器と受信側の発振器は独立に動いており、 さらにドップラで周波数がずれている。 基準がずれていれば、複素平面上で信号はぐるぐる回り続けて読み取れない。 そこで受信機の中に、相手の搬送波に位相を合わせ続ける発振器を持つ。それがPLLである。

ディジタルPLLは3つの部品でできている。

①位相検出器(PD, Phase Detector)。入力信号と自分のNCOとの位相差 e[n] を測る。 「どれだけずれているか」の測定器である。測り方は変調方式によって変わる(後述の表)。

②ループフィルタ。測った誤差 e[n] から、NCOの周波数をどう修正するかを決める。 比例(Proportional)と積分(Integral)の2経路を持つのでPI型と呼ぶ。 比例路は「いま生じているずれを即座に打ち消す」働き、 積分路は「ずれが続いているなら周波数そのものが違うのだと判断して覚え込む」働きをする。

③NCO(第2.3.2節)。ループフィルタの指示に従って回転速度を変える発振器。

実装は驚くほど短い。1標本ごとの処理は次の4行に尽きる。 この4行が本書で最も重要なコードである。

# z[n]: 入力複素標本, theta: NCO位相, v: 積分器, g1, g2: ループゲイン
y      = z[n] * np.exp(-1j * theta)      # NCOで逆回転(位相を剥がす)
e      = phase_detector(y)               # 位相誤差の推定(PDは方式で異なる)
v     += g2 * e                          # 積分路: 周波数誤差を記憶する
theta += g1 * e + v                      # 比例路 + 積分路 → NCOを進める

4行の意味を1行ずつ確認しよう。1行目は、入力にNCOの複素共役を掛けている。 第2.1.4節の周波数シフトで、これは「NCOの回転を打ち消す」操作である。 ロックしていればこの出力 y は回転が止まって静止した点になる。 2行目で、その静止具合(ずれ)を測る。 3行目で誤差を積分器 v に少しずつ溜め込み、 4行目でNCOの位相を「比例路の即時修正 + 積分路が覚えた周波数」の分だけ進める。

アナログPLL(姉妹編第2.3.1節)と比べると、VCOがNCOに、 抵抗とコンデンサで作ったループフィルタがPIの2行に置き換わっただけで、 サーボ機構としての本質は同一である。だからアナログPLLの理論がそのまま使える。

ここで実務上とても重要な副産物に注目してほしい。 積分器 v の値は、周波数誤差の推定値そのものである。 ドップラによる周波数ずれは v が追いかけ、瞬間的な位相の揺らぎは比例路が処理する。 ということは、v を読み出せばそれがドップラ計測値になる。 アナログ時代は周波数を測るために別の測定器が必要だったが、 SDRでは同期ループの内部状態がそのまま計測データになる。 探査機の速度を測るという第3.4章・第5.2章の話は、この1つの変数から始まる。

残った部品は位相検出器である。これは変調方式によって変わるが、 どれも第2.1.4節の複素演算の組み合わせにすぎない。

対象位相検出器 e =特徴
残留搬送波(CW・PM)arg(y) または Im(y)/|y|argは±πまで線形。Imは小誤差近似で低演算。
BPSK(抑圧搬送波)sgn(Re(y))·Im(y)Costas型。データ変調を判定で剥がす。±πの2値曖昧性。
QPSKsgn(Re)·Im − sgn(Im)·Re4相Costas。±π/2の4値曖昧性。

3.1.2 ゲイン設計式 — B_n と ζ から g₁, g₂ へ

前節の4行のうち、決めていないのは g₁ と g₂ という2つの数だけである。 この2つが「ループをどれだけ強く反応させるか」を決める。 本節ではこれを回線設計から導出する方法を確立する。ここが本書の実装の要である。

直接 g₁, g₂ を決めるのではなく、まず物理的に意味のある2つの量を決める。

雑音帯域幅 B_n [Hz]。ループが「反応する周波数の幅」を表す量である。 B_n が広いほど素早く追従できるが、その幅に入る雑音を全部取り込んでしまう。 B_n の選び方が3.1.3節の主題で、回線のC/N₀から決まる。

減衰係数 ζ。過渡応答の形(行き過ぎて振動するか、なめらかに収束するか)を決める無次元量。 制御工学の標準的な選択である ζ = 1/√2 ≈ 0.707 を使えばよく、 これは「わずかに行き過ぎるが最も速く収束する」バランス点である。

この2つから g₁, g₂ を計算する式が次である。アナログの2次ループ理論を 離散時間に写像して得られるもので、導出は付録Cの文献(Rice)に譲る。

θ_{n} = \frac{B_{n} T_{s}}{ζ + \frac{1}{4ζ}},\, g_{1} = \frac{4 ζ θ_{n}}{1 + 2ζθ_{n} + θ_{n}^{2}},\, g_{2} = \frac{4 θ_{n}^{2}}{1 + 2ζθ_{n} + θ_{n}^{2}}

使い方を説明する。まず θ_n を計算する。ここで T_s は ループを回すレートの標本周期である(DDCで間引いた後のレートでループを回すなら、 そのレートの逆数を使う。ADCのレートではない点に注意)。 B_n·T_s は「1標本の間にループが何周期分反応するか」を表す無次元量で、 それを ζ で決まる係数で割ったものが θ_n、すなわち正規化されたループ帯域である。 θ_n が求まれば、残りの2式に代入するだけで g₁ と g₂ が出る。

暗算用の近似も覚えておくと便利である。ζ = 0.707 なら ζ + 1/(4ζ) = 1.061 なので

θ_{n} ≈ 0.94 · B_{n} T_{s}

であり、さらに θ_n は通常 1 よりずっと小さいので、g₁, g₂ の式の分母はほぼ1になる。 したがって g₁ ≈ 2.83·θ_n、g₂ ≈ 4·θ_n² と概算できる。 設計値の桁を確認するのに使うとよい。

【例3.1-1】設計例 — 残留搬送波PLL
レート f_s = 500 kSPS でループを回し、雑音帯域幅 B_n = 100 Hz が欲しい(回線設計から ループSNR ρ = P_c/(N₀·2B_n) ≧ 17 dB を確保できる値として決めた——姉妹編第2.3.2節)。 θ_n = 100/(500×10³×1.061) = 1.89×10⁻⁴、 g₁ = 4×0.707×θ_n/(1+…) ≈ 5.33×10⁻⁴、g₂ = 4θ_n² ≈ 1.42×10⁻⁷。 分母の補正項は θ_n ≪ 1 ではほぼ1で、暗算では g₁ ≈ 2.83θ_n、g₂ ≈ 4θ_n² と覚えてよい。

そしてここがGNU Radioとの接続点である。 Costas LoopPLL Carrier TrackingSymbol Sync といった 同期ブロックは、内部に共通の制御ループ実装(control_loopクラス)を持ち、 パラメータ loop_bw を受け取って上とまったく同じ式で内部ゲインを計算している (ζ は既定値0.707が使われる)。つまり

loop\_bw = θ_{n} ≈ 0.94 · B_{n} T_{s}

である。ネット上には「loop_bw は 2π/100 くらいにしておけばよい」といった経験則が流布しているが、 本書の読者はそれをしない。回線のC/N₀から必要な B_n を決め、 上の式で loop_bw を計算する。この手順を踏めば、 なぜその値なのかを設計審査で説明でき、条件が変わったときに正しく再計算できる。 第4.3章の受信機では、すべてのループのパラメータをこの方法で決める。

3.1.3 ループ帯域の選定 — 追従と雑音の綱引き

では B_n はどう決めるのか。基本の綱引きはアナログ時代と同じで、 3つの要素が競合する(詳細は姉妹編第2.3.2節)。

B_n を広くすると: ①ドップラの変化や発振器の位相雑音に素早く追従できる。 しかし②その帯域幅に入る熱雑音を全部取り込むので、 追尾している位相自体が雑音でぶれる(位相ジッタ σ²_φ = 1/ρ。 ρ はループSNRで、ρ = P_c/(N₀·2B_n) と計算される)。 さらに③位相のぶれが大きくなると、ある瞬間に1周期分ずれてしまう サイクルスリップが起き、その確率は ρ に対して指数的に悪化する。

したがって設計は「追従に必要な最小の B_n を選ぶ」ことになる。 深宇宙では追従すべきドップラの変化が予測で先に消せる(第3.4章)ので、 B_n を極めて狭く(数Hz〜数百Hz)取れる。これが微弱信号を掴める理由である。

SDR固有の考慮が2つ加わる。ここは実装で必ず問題になる箇所である。

考慮1: ループを回すレートも設計変数である。 B_n·T_s(1標本あたりのループ反応量)が大きすぎると、 離散化の影響でアナログの設計式から実際の挙動がずれていき、 0.1 に近づくとループは不安定化して発振する。 目安として B_n·T_s < 0.01 を守る。 一方でレートを無駄に高くすると計算資源を食うだけなので、 DDCで「ちょうどよい遅さ」まで間引いてからループを回すのが定石である。

考慮2: ループの中に遅延を入れると余裕を失う。 ディジタル実装では、ループの経路にフィルタの群遅延やパイプライン遅延が入り込む。 遅延が D 標本あると、位相余裕(安定性の余裕)を おおよそ 2π·B_n·T_s·D に相当する分だけ食われる。 B_n·T_s·D < 0.02 程度に収める。 第2.4.5節で「ループ内のフィルタは短く、ループ外で贅沢に」と述べたのは、この制約のことである。

3.1.4 残留搬送波PLL — PCM/PSK/PMの第1ループ

ここで本書の実装目標であるPCM/PSK/PM(第4.3章)に話を接続する。 この方式の受信は3つのループを縦に連ねた構造になる。 第1が搬送波PLL(本節)、第2が副搬送波のループ(第4.3章で実装)、 第3がシンボル同期(第3.2章)である。信号が3重に包まれているので、 外側から順に開けていくことになる(第4.3章冒頭の「三重の入れ物」の話)。

第1ループの相手は残留搬送波である。PCM/PSK/PMは位相変調だが、 変調指数 m を控えめにすると搬送波成分が消えずに残る。 残る割合は J₀²(m) というBessel関数で決まり(第4.3.1節)、 この「残った線」にPLLをロックさせる。振幅も位相も既知の純粋な正弦波なので、 位相検出器は最も単純な arg(y) で足りる(3.1.1節の表の1行目)。

設計上の要点は1つ、B_n を副搬送波周波数 f_sc よりずっと狭く取ることである。 理由を考えてみよう。搬送波PLLから見ると、±f_sc の位置にあるデータの側波帯は 「非常に速く振動する外乱」である。ループの反応帯域 B_n がそれよりずっと狭ければ、 速い外乱は平均されてループには見えない。 具体的には f_sc = 65.536 kHz に対して B_n = 30〜300 Hz を選べば、 2〜3桁の分離があり、データがPLLを乱すことはない。 周波数の分離によって、3つのループが互いに干渉せず共存できる—— これがPCM/PSK/PMという方式の設計思想である。

GNU Radioで使うブロックは PLL Carrier Tracking である。 このブロックは便利な出力を持っており、入力をNCOで逆回転した複素信号 (つまり3.1.1節の4行の1行目の結果)をそのまま出してくれる。 搬送波の回転が取り除かれた信号が得られるので、 あとは第2.1.4節の arg() を掛ければ位相変調の中身が読める。 設定すべきパラメータは loop_bw(=θ_n、3.1.2節)と max_freqmin_freq で、後者は周波数の引き込み範囲を rad/sample という単位で与える(Hzから換算するには 2π/f_s を掛ける)。 この範囲はドップラ予測の残差の大きさに合わせる(第3.4章)。

3.1.5 CostasループとFLL — 抑圧搬送波の系

前節は「搬送波の線が残っている」場合だった。 高レートのBPSK/QPSK(抑圧搬送波方式、姉妹編第2.1.5節)では 電力をすべてデータに使うため搬送波の線が存在しない。 追いかける目印がないのに、どうやって位相を合わせるのか。

答えがCostasループである。発想は「データによる位相の反転を、 判定して取り除いてから位相差を測る」ことにある。 BPSKなら信号は0°か180°のどちらかにあるので、 実部の符号を見て「たぶん今は180°側だ」と判定し、その分を打ち消せば、 あたかも搬送波が残っているかのように位相誤差が測れる。 これが3.1.1節の表にあった sgn(Re(y))·Im(y) という式の意味である。 ゲイン設計は3.1.2節とまったく同じ式が使える。

代償が2つある。第一に、判定を含む位相検出器は低SNRで判定を誤るため、 実効的なループSNRが理論値より下がる。この劣化を二乗損失と呼ぶ(姉妹編第2.3.10節)。 第二に、位相の絶対的な基準がないので、180°反転した状態でもロックしてしまう (BPSKなら2通り、QPSKなら4通りの曖昧性がある)。 これはフレーム同期の段階で解決する——第4.3.5節のデフレーマが 「反転したASMも探す」実装になっているのはこのためである。

もう1つ、PLL全般の弱点にも触れておく。PLLの引き込み範囲は狭い (おおよそ B_n の数倍)。初期の周波数誤差がこれを超えていると、 ループは永久にロックしない。対処は2つある。

対処A: FFTで粗く探す(3.1.6節)。周波数軸上でピークを探し、 NCOの初期値をそこに置いてからループを起動する。

対処B: FLLを前置する。FLL(Frequency Locked Loop)は位相ではなく 周波数の差そのものを検出するループで、引き込み範囲がPLLよりずっと広い。 GNU Radioの FLL Band-Edge は、整形フィルタの帯域の左端と右端の エネルギーを比べ、どちらに偏っているかから周波数のずれを推定する実装で、 シンボルレートの数%程度のずれまで引き込める。

実務では「FLLで周波数を数百Hz以内に詰め、そこからPLL/Costasで位相を掴む」 という2段構えにする。担当する範囲を重ねておくのが設計の要点で、 この考え方は第3.4.3節でさらに3段に拡張される。

3.1.6 捕捉 — FFT粗推定と掃引

深宇宙運用の捕捉(姉妹編第2.3.4節)はSDRでは2通りに実装できる。

(a) FFT捕捉。N点のFFTを取ると、周波数軸が f_s/N の幅の「ビン」に分割される。 残留搬送波方式なら電力スペクトルにピークが立つので、 その位置を探せば周波数が f_s/N の精度で即座にわかる。 Nを大きくすれば(=長く積分すれば)分解能が上がり、 より微弱な搬送波も雑音から浮き上がってくる。

ただし積分長には上限がある。ドップラで周波数が動いていると、 積分中にピークが複数のビンにまたがって滲んでしまうからである。 条件は「ドップラレート × 積分時間 < ビン幅」であり、 これを超えると長く積分しても感度は上がらない(演習3.1-2で実際に計算する)。

抑圧搬送波(BPSK)の場合はピークがないが、 信号を2乗してからFFTを取ると 2f₀ の位置に線が立つ(2乗法)。 位相反転が2乗によって打ち消されるためである。

実装はごく短い。記録した複素標本をNumPyで読み、np.fft.fft を掛けて np.argmax でピーク位置を求め、その周波数をNCOの初期値に設定するだけである。 専用ハードウェアの時代には考えられなかった捕捉戦略の自由度—— たとえば「見つからなければFFT長を倍にして再挑戦する」といった適応動作が 数行で書ける——がSDRの大きな価値である。

(b) 掃引: NCO周波数を予測中心から線形に掃く古典戦術。SDRではNCOに ランプを足すだけで実装でき、掃引レートの上限則 |df/dt| ≲ B_n²/π(ρが十分高いとき)も そのまま適用できる。地上局互換の運用(アップリンク掃引をトランスポンダが掴む—— 姉妹編第2.3.9節)を模擬する試験治具(第5.3章)では、この掃引プロファイル生成が ソフトウェアの仕事になる。

3.1.7 ロック検出とサイクルスリップ監視

受信機は「掴んでいるか、外れているか」を自分で判断して外に伝える必要がある。 運用者が画面を見て判断するためにも、自動化スクリプトが分岐するためにも、 そして計測データの品質を保証するためにも要る。

残留搬送波の場合、定石は次のロック検出量を計算することである。

L = \frac{⟨I^{2} − Q^{2}⟩}{⟨I^{2} + Q^{2}⟩}

考え方はこうである。PLLがロックしていれば、位相を剥がした後の信号は 実軸(I軸)上に寄るので I² が大きく Q² は小さく、L は1に近づく。 ロックしていなければ信号は複素平面上をぐるぐる回り、 I² と Q² の平均が等しくなって L は0に近づく。 ⟨·⟩ は時間平均を表し、実装では1次IIRフィルタ(時定数はループ時定数の数倍)で 平滑してから閾値と比べる。Costasループの場合は、 判定誤差の分散 ⟨|e|²⟩ が十分小さくなったことでロックを判定する。

もう1つ監視すべきものがサイクルスリップ(3.1.3節)である。 これは位相が1周期分飛ぶ現象で、積分器 v の不連続な跳びや、 位相を連続値に展開(unwrap)したときの 2π のジャンプとして検出できる。

ここで計測系としての作法を強調しておく。スリップが起きた区間の位相データは 使ってはならない。したがって計測データには必ず品質フラグを添えて出力する—— いつロックし、いつ外れ、いつスリップしたかを時系列で記録する。 値だけを並べたデータは、後から誰も信用できない(第5.2章・第5.3.7節)。

Q. ループのレートはどう選ぶのが正解か?

「B_n·T_s が 10⁻³〜10⁻² に入るレートまでデシメーションしてから回す」が答えである。 500 kSPSで B_n = 100 Hz なら B_n·T_s = 2×10⁻⁴ で問題なく動くが、資源を詰めるなら 50 kSPSまで落として回してもよい(2×10⁻³)。ただし落とし過ぎると引き込み範囲 (f_s に比例)と、ループ内フィルタの遅延の相対的な重みが悪化する。

Q. 2次ループで足りるのか?3次はいつ要るのか?

2次ループは周波数ステップ(ドップラの一定オフセット)を定常誤差ゼロで追えるが、 周波数ランプ(ドップラレート)には定常位相誤差 θ_e = (dω/dt)/ω_n² が残る(姉妹編第2.3.7節)。 X帯の地球自転ドップラレート(数十Hz/s)と B_n = 30 Hz 級の狭いループでは θ_e が 無視できないことがあり、その場合は③次化——積分器をもう1段——か、 予測ドップラのNCOフィードフォワード(第3.4章)で動特性を先に抜くのがSDR流である。 後者の方が安定設計が楽で、深宇宙では予測が高精度に手に入るため、実務はほぼ後者を選ぶ。

▶ GNU Radioで試す — PLLの過渡応答を観る
Signal Source(complex, 周波数 5 kHz, 振幅1)+ Noise Source(0.1)→ PLL Carrier Tracking(loop_bw = 例3.1-1の θ_n×(fs換算)、max_freq = ±0.2)→ 出力を Complex to ArgQT GUI Time Sink。 起動直後の周波数引き込み(位相ランプが折れて水平になる瞬間)が見える。 Signal Source の周波数を QT GUI Range で階段状に動かし、 loop_bw を10倍/1/10にして過渡の速さと定常ジッタのトレードを体感する。 これが「B_n を回線から決める」ことの意味である。

章末演習

【演習 3.1-1】ゲイン計算
f_s = 62.5 kSPS で回すCostasループに B_n = 500 Hz を与える。θ_n, g₁, g₂ を求めよ(ζ = 0.707)。
解答
θ_n = 500/(62500×1.061) = 7.54×10⁻³。分母 = 1+2×0.707×0.00754+0.00754² = 1.0107。 g₁ = 4×0.707×0.00754/1.0107 = 2.11×10⁻²、g₂ = 4×0.00754²/1.0107 = 2.25×10⁻⁴。 GNU Radioなら digital.costas_loop_cc(7.54e-3, 2) と書くことに相当する。
【演習 3.1-2】FFT捕捉の分解能と限界
f_s = 500 kSPS、N = 2²⁰点のFFTで残留搬送波を探す。周波数分解能と積分時間を求めよ。 またドップラレートが 50 Hz/s あるとき、この積分は成立するか。
解答
分解能 = 500×10³/2²⁰ = 0.48 Hz、積分時間 = 2²⁰/500×10³ = 2.1 s。 積分中の周波数移動 = 50×2.1 = 105 Hz ≫ 0.48 Hz なので成立しない(線が220ビンに滲む)。 対策は①予測レートでNCOを先に走らせて残差レートだけにする(第3.4章)、 ②Nを下げて分解能と滲みを釣り合わせる(最適は N ≈ f_s/√(df/dt) 付近)、 ③チャープ変換で滲みごと整合する。
■ まとめ
  • ディジタルPLLは4行: 逆回転→PD→積分→NCO更新。積分器の値がそのままドップラ計測値。
  • 設計式: θ_n = B_n·T_s/(ζ+1/4ζ)、g₁ = 4ζθ_n/d、g₂ = 4θ_n²/d。GNU Radioの loop_bw = θ_n。
  • PCM/PSK/PMは搬送波PLL→副搬送波→シンボルの三重ループ。B_n ≪ f_sc で層を分離する。
  • 捕捉はFFT粗推定(積分長はドップラレートと引き換え)+掃引の2本立て。ソフトウェア化で戦略自由度が激増。
  • ロック検出・スリップ監視を実装し、計測データに品質フラグを添えるのがSDR計測系の作法。

第3.2章シンボル同期と整合フィルタ

■ この章で学ぶこと
「どの瞬間の値を判定に使うか」を信号自身から推定するタイミングループを実装レベルで理解する。 タイミング誤差検出器(Gardner・M&M・早遅)、ポリフェーズ補間器、ループ設計、 そしてNRZ/整形パルスそれぞれの整合フィルタ。GNU Radioの Symbol Sync ブロックの 全パラメータに根拠を持って値を入れられるようになる。
◇ 直観でつかむ — 「いつ読むか」を信号自身に教えてもらう
ビットは一定間隔で並んでいるが、受信側はその区切りがどこにあるかを知らない (送信側の時計と受信側の時計は独立だから)。だから信号を見ながら 「たぶん今が1ビットの真ん中だ」という時刻を推定し続ける必要がある。 ちょうど、知らない曲を聴きながら手拍子のタイミングを合わせていく感覚に近い。
仕組みはPLL(前章)とまったく同じサーボで、追いかける対象が「位相」から 「読み取り時刻」に変わっただけである。誤差の測り方(TED)と、 標本の間の値を作る道具(補間器)の2つが新しく登場する。

3.2.1 問題の構造 — 位相ループと同型

解くべき問題を明確にしよう。ADCは f_s の等間隔で標本を取っているが、 その時刻はシンボルの中心とは無関係である。 判定に使いたいのは各シンボルの中央——雑音に対して最も余裕のある瞬間の値だが、 その瞬間がどこかは受信側には分からない。 送信側の時計と受信側の時計は独立で、しかもドップラでずれ続けるからである。 そこで信号自身から「いま何割の位置にいるか」を推定し続ける仕組みが必要になる。

朗報は、これが前章のPLLとまったく同じ構造の問題だという点である。 追いかける対象が搬送波の位相からサンプリング位相 τ に変わっただけで、 「誤差を測る → PIフィルタを通す → 制御対象を動かす」というサーボの形は同一で、 3.1.2節のゲイン設計式もそのまま使える。 新しく学ぶべきものは、誤差の測り方(TED、3.2.2節)と 制御対象である補間器(3.2.3節)の2つだけである。

ただし流儀の違いが2点あり、これを知らないと数値が合わない。

違い1: ループはシンボルレートで回る。 3.1.2節の設計式に出てくる T_s を、ここではシンボル周期 T_sym に読み替える。 GNU Radioの Symbol Syncloop_bw もシンボル正規化された値である。 常用域は B_n·T_sym = 0.01 前後で、たとえばよく見かける loop_bw = 0.045 という設定は B_n ≈ 0.048/T_sym を意味している (シンボルレートの約5%の帯域でループが反応する、ということ)。

違い2: TEDの感度で正規化が必要。 誤差検出器は方式ごとに「ずれ1単位あたり何ボルトの誤差を出すか」という感度 (S字カーブの傾き、K_ted と書く)が異なる。 感度が2倍違えば実効的なループ帯域も2倍ずれてしまうので、 ゲインを K_ted で割って揃える必要がある。 これが Symbol Syncted_gain パラメータである。 既定値1.0のまま使うと実効 B_n が設計値からずれるので、 精密な設計をするときは変調方式・TED・整形係数ごとの値を GNU Radioのドキュメント記載の表から引くこと。 実用上は、ずれても数倍以内なので動作はする—— ただし「なぜ収束が想定より速い/遅いのか」を説明できないときは、ここを疑う。

3.2.2 タイミング誤差検出器(TED)の実装比較

TED誤差式(1シンボルあたり)必要sps特徴
Gardnere = Re{ (x[k] − x[k−1]) · x*[k−1/2] }2判定不要・搬送波位相に無感。搬送波同期の前に置ける。BPSK/QPSK向けの実務標準。
Mueller & Müllere = Re{ â[k−1]·x[k] − â[k]·x[k−1] }1判定 â を使う。最少レートで動くが搬送波同期後に置く必要。低sps実装(FPGA)で有利。
早遅(Early–Late)e = |x[k+δ]| − |x[k−δ]|2〜直観的。包絡線の対称性を使う。性能はGardnerに一歩譲る。

PCM/PSK/PM受信機(第4.3章)では、副搬送波復調後のBPSKストリームにGardnerを使う。 副搬送波Costasの位相が多少ふらついてもタイミングが取れる(搬送波位相無感性)ため、 ループの立ち上げ順序に神経を使わなくて済むからである。

3.2.3 補間器 — 「標本の間」の値を作る

TEDが「読み取り時刻を τ だけずらせ」と言ってきたとしよう。 ところが標本は f_s の格子上にしか存在せず、その中間の時刻の値は手元にない。 存在しない時刻の値を作り出すのが補間器の仕事である。

実装は第2.4.4節で学んだポリフェーズ補間器そのものである。 標本間を n 等分した各位置に対応する分数遅延フィルタを用意しておき、 τ に対応する枝を選んで適用する。 タイミングの分解能は 1/n シンボルになるので、n = 128 なら シンボル周期の128分の1の精度で読み取り時刻を制御できる。

Symbol Sync ブロックでは補間器の方式を選べる。 既定はMMSE 8タップ補間器(8点から最小二乗誤差で中間値を推定する方式。手軽で高性能)、 もう1つがポリフェーズフィルタバンクn_filters 本の枝を持つ方式)である。

後者には大きな利点がある。整合フィルタ(RRC、3.2.4節)を補間器に兼務させられるのである。 考えてみれば、整合フィルタも補間器も分数遅延も、すべて「係数を掛けて足す」FIRフィルタである。 ならば1つのフィルタバンクに全部の役目を持たせればよい。 こうすると「波形整形+任意時刻の読み出し+シンボルレートへの間引き」が 1個の機構にまとまり、計算量も構造も最小になる。 信号処理の実装として非常に美しい設計で、fred harrisの教科書(付録C)が詳しい。

3.2.4 整合フィルタ — NRZは積分、整形パルスはRRC

読み取る時刻が決まっても、まだ最良の判定にはならない。 1点の瞬時値だけを見るのではなく、1シンボル区間の情報を全部使うほうが有利である。 雑音に対して最も有利な取り出し方は理論的に決まっており、 それが整合フィルタ(送信パルスと同じ形をテンプレートとして照合するフィルタ、 姉妹編第2.4.1節)である。形が波形によって変わるので、2つの代表例を押さえる。

ケース1: NRZ矩形パルス(PCM/PSK/PMの伝統的な選択)。 1シンボルの間ずっと同じ値を保つ矩形波なので、整合フィルタも矩形、 すなわちシンボル区間で値を足し合わせる(積分する)操作になる。 これを積分・ダンプ(integrate and dump: 1シンボル分積分して、読み出したらリセット)と呼ぶ。 ディジタル実装は極めて簡単で、「sps点の移動平均を取り、シンボル時刻で間引く」に等しい。 GNU Radioなら係数 [1/sps]*sps のFIRフィルタ1個で書ける。 実際の信号は帯域制限を受けて角が丸まっているが、それでも損失は0.2 dB級にとどまるため、 深宇宙の低レート回線では今も現役の構成である。

ケース2: RRC整形(抑圧搬送波の高レート系で使う)。 矩形パルスは帯域を無駄に広く使うので、高レートでは あらかじめ帯域を絞った滑らかな波形(レイズドコサイン特性)を使う。 その特性を送信側と受信側で分担して持つのが定石で、 それぞれが「ルート(平方根)」を担うのでRRC(Root Raised Cosine)と呼ぶ。 送信でRRC、受信でRRCを掛けると合わせてレイズドコサインになり、 判定時刻でのシンボル間干渉がゼロになる(姉妹編第2.4.2節)。

GNU Radioでは係数を firdes.root_raised_cosine(gain, samp_rate, sym_rate, alpha, ntaps) で生成する。 パラメータ選びの目安は2つ。ntaps(フィルタ長)はシンボル8〜11個分×sps ——短すぎると波形の裾を切り落としてしまい干渉が残り、長すぎると計算量と ループ内遅延(3.1.3節の考慮2)が増える。 α(ロールオフ係数、帯域と波形の滑らかさのトレード)は衛星系では0.25〜0.5が相場で、 CCSDSの整形規定に従う場合はその値を使う。

3.2.5 sps(標本/シンボル)の選び方

1シンボルあたり何標本(sps, samples per symbol)で処理すべきか。 直観では「多いほど正確」と思えるが、実際には必要なspsは意外に少ない。 Gardner TEDなら2、M&Mなら1で足りる。 余裕を見て4以上にするのは、多くの場合ただの計算の無駄である (波形を目で見て確認したいデバッグ時は別の話)。

さらに実務で重要な事実がある。spsは整数である必要がない。 前節の補間器は任意の実数位置の値を作れるので、 f_s とシンボルレートの比が半端な値でも——さらにドップラでその比が 時間変化していても——ループはそのまま追従する。 第4.3章の受信機や演習で「31.25 kSPS ÷ 4096 baud = sps 7.63」のような 半端な値を平気で使うのはこのためである。 装置側のレートの都合(第4.5.1節)を、同期器が吸収してくれる、と理解すればよい。

3.2.6 実装の落とし穴チェックリスト

症状原因と処方
コンスタレーションが円環状に回る搬送波残留。シンボルループでなく搬送波ループ(順序・帯域)を疑う。Gardnerなら回っていてもタイミングは取れているはず。
アイは開くが時々ドッと誤るサイクルスリップ(搬送波)かタイミングループの一時脱調。B_nを下げる/sps・ted_gainの整合を確認。
常時BERが理論より1〜2 dB悪い整合フィルタ不整合(α違い・taps打ち切り・二重に掛けている)、またはAGC暴れ(第3.3章)。
ロックまで異常に長い初期周波数誤差がTED引き込み外。FLL/FFT前置(第3.1.5節)を入れる。
Q. Symbol Syncの max_deviation はどう決める?

クロック周波数の相対誤差の想定上限(送受の基準精度+ドップラによるレート伸縮)で決める。 TCXO同士なら±数ppm、ドップラは v/c(X帯深宇宙でも10⁻⁴台)。合計を1.5倍して 例えば 1.5×10⁻⁴ シンボルのような値を入れる。大きすぎると雑音での迷走を許し、 小さすぎると真のずれを追い切れない。

▶ GNU Radioで試す — アイパターンとS字カーブ
乱数ビット→Constellation Modulator(BPSK, sps 4, α 0.35)→雑音付加→ Symbol Sync(Gardner, sps 4, loop_bw 0.045)→QT GUI Constellation Sink。 loop_bw を 0.002 にすると収束が目に見えて遅くなり、0.2 にすると点群が呼吸するように暴れる。 さらに Channel Model で timing offset(epsilon 1.0002)を入れ、 ループがゆっくり追従し続ける様子を Time Sink(error出力端子)で観察する。 「ループ帯域は追従と雑音の交換レート」を、搬送波(3.1章)とタイミングの両方で確認したことになる。

章末演習

【演習 3.2-1】積分・ダンプの実装損失
NRZ 4096 baud を 62.5 kSPS(sps = 15.26)で受け、taps 15点の移動平均を整合フィルタとして使った。 理想の積分・ダンプに対する損失の主因を2つ挙げよ。
解答
①スパン不整合: 15点は15.26点分のシンボルを覆い切れず、端の0.26標本分のエネルギーを 取り落とす(≈10log₁₀(15/15.26) = 0.07 dB)。②遷移またぎ: 移動平均が固定グリッドで 走るため、補間器と一体化しない実装ではシンボル境界をまたいだ平均が混ざる。 Symbol Sync のポリフェーズ整合フィルタ(taps = 矩形×n_filters本の分数遅延版)を 使えば両方とも解消される——「整合フィルタは補間器に兼務させる」(3.2.3節)の実利である。
■ まとめ
  • シンボル同期はτを追うPLL。ゲイン式は3.1.2節と同じ、ただしT_sはシンボル周期・ted_gainで正規化。
  • TEDはGardner(2sps・搬送波無感・実務標準)/M&M(1sps・判定つき)/早遅。PCM/PSK/PMはGardner。
  • 補間器はポリフェーズ分数遅延。整合フィルタを兼務させるのが定石。spsは非整数でよい。
  • NRZの整合フィルタは積分・ダンプ、整形系はRRC(αと taps 長に注意)。
  • 不調の切り分け: 回る→搬送波系、ドッと誤る→スリップ、常時劣化→フィルタ/AGC、掴まない→周波数誤差。

第3.3章AGCと信号レベル管理

■ この章で学ぶこと
SDRの利得は「アナログ(ADCを守る)」と「ディジタル(ループを守る)」の二層構造である。 それぞれの設計則、GNU RadioのAGCブロックの使い分け、そして「AGCが原因の不具合」の見抜き方。 地味だが、実機で最初に嵌るのはほぼここである。
◇ 直観でつかむ — 音量つまみは2つある
信号が小さすぎるとADCの目盛りの下に埋もれ、大きすぎると振り切れて(クリップ)波形が壊れる。 ちょうど良い大きさに保つのがAGC(自動利得制御)である。
SDRではつまみが2段階ある。アナログのつまみはADCに入る大きさを決めるもので、 一度合わせたら運用中は触らない。ディジタルのつまみは後段の同期ループが 「振幅1.0の信号が来る」前提で設計されているため、その前提を守るための正規化である。 前者は装置を守るため、後者は計算式の前提を守るため——目的が別なので両方必要になる。

3.3.1 二層のレベル管理

第一層(アナログ利得)の使命はADCのローディング(第1.3.5節)である。 入力の雑音+信号の実効値を −12 dBFS 級に置き、LSBを雑音が数カウント揺らす状態を作る。 USRPなら set_gain() で設定するRF/IF利得がこれで、動かすのは設定時だけ、 運用中は固定が計測系の作法である(利得を動かすと振幅計測の連続性と較正が壊れる)。 深宇宙受信は信号がフェージングで暴れる世界ではないので、これで十分成立する。

第二層(ディジタルAGC)の使命は後段アルゴリズムの動作点合わせである。 Costasループのゲインは入力振幅の2乗に、判定閾値は振幅に比例して変わるため、 振幅を基準値(普通1.0)に正規化してから同期ループ群に渡す。 これは情報を何も足さないが、ループゲインを設計値どおりに保つために必須である。 第3.1.2節のg₁, g₂は「入力振幅1」を前提に導いたことを思い出してほしい。

3.3.2 ディジタルAGCの差分方程式

# 参照電力 ref に向けて利得 g を指数追従させる(AGCループ)
p_est = (1 - alpha) * p_est + alpha * abs(z[n])**2   # 電力推定(1次IIR)
g     = g + mu * (ref - p_est * g**2)                # 誤差で利得を更新
out   = g * z[n]

時定数(alpha, mu)の選定則はループ一般と同じで、信号のどの変動を「追い」、 どれを「保存」するかで決める。搬送波・副搬送波・データの変調は保存すべき情報なので、 AGC帯域はシンボルレートよりずっと遅く(時定数で数百〜数千シンボル)、 一方で運用中の緩やかなレベル変動(仰角変化・降雨・指向誤差: 秒スケール)よりは速く取る。 深宇宙用なら時定数0.1〜1秒が定番である。

3.3.3 GNU RadioのAGCブロック使い分け

ブロック動作使いどころ
AGC単純な1ループ(rate, reference, gain, max_gain)まずこれ。rate = 10⁻⁴〜10⁻⁵(1/標本)で時定数を上式から見積る。
AGC2attack/decayの2レートバースト先頭に速く追従し、その後静かに保持したいとき。
AGC3ブロック平均で初期即応+以後IIR捕捉時間を詰めたいバースト系。
RMS AGC(gr-satellites)RMS推定で正規化。雑音支配でも安定微弱信号ではこれ。信号がノイズの下に居てもRMSが暴れない。衛星受信の実績多数。

深宇宙的な注意を1つ。C/N₀が低い信号では標本の電力はほぼ雑音で決まるため、 AGCは実質「雑音を1.0に正規化する装置」になる。これで問題ない—— 同期ループが見る信号振幅は C/N が決めるので、基準が雑音でも設計は成立する。 ただしBER較正(第5.3章)では「信号振幅」と「雑音振幅」を別々に知る必要があるので、 AGC後の値だけからE_b/N₀を出そうとしてはいけない(SNR推定器を別に置く)。

3.3.4 レベル起因の不具合パターン

症状正体
コンスタレーションが脈打つ・呼吸するAGCが速すぎて変調に反応している。rateを1〜2桁下げる。
強信号でスペクトルに突然「芝生」が生えるアナログ段どこかのクリップ(ADCとは限らない。USRPではRF利得過大)。第一層を下げる。
ロックはするがBERが数dB悪い基準値とブロック要求の不一致(Costas系は振幅1前提)。AGCのreferenceを確認。
信号を強くしたのにSNR推定が上がらない第一層が低すぎADC量子化/雑音床に当たっている(第1.3章)。ゲイン配分を前段へ。
▶ GNU Radioで試す — AGCの時定数と変調の保存
BPSK変調信号に QT GUI Range で振幅(0.01〜1.0)を掛け、AGC(reference = 1)を通して Time Sinkで出力振幅を見る。rate = 10⁻² だとBPSKの包絡線変動(整形後の谷)にまでAGCが 食いつき波形が歪む。10⁻⁵ に下げると振幅ステップへの追従は緩やかになるが波形は保存される。 「AGCは変調より遅く、運用変動より速く」を波形で確認する。
■ まとめ
  • 第一層(アナログ)はADCローディングを作り、運用中は固定。第二層(ディジタル)はループの動作点を1.0に保つ。
  • AGC帯域は「変調より遅く、運用変動より速く」。深宇宙は時定数0.1〜1 s。
  • 微弱信号はRMS AGC。AGC後の振幅からE_b/N₀は出せない——SNR推定は別系統で。
  • 症状からの逆引き(脈打つ=速すぎ、芝生=アナログクリップ…)を身体に入れる。

第3.4章ドップラ補償

■ この章で学ぶこと
深宇宙回線のドップラは大きく(X帯で±数百kHz)、速く動く(数十Hz/s)。 これをSDRでどう扱うか——予測ステアリング・広域捕捉・事後補正の3戦略を、 量の見積りとともに実装レベルで整理する。搬送波だけでなくシンボルレートも伸縮することへの 対処までがドップラ補償である。
◇ 直観でつかむ — 深宇宙のドップラは「大きいが予測できる」
救急車のサイレンが近づくと高く、遠ざかると低く聞こえる。同じことが電波にも起き、 X帯では数百kHzも周波数がずれる——受信帯域よりはるかに大きい量である。 ところが深宇宙の探査機は軌道力学に従って動くだけなので、 いつ・どれだけずれるかが事前に精密に計算できる。
そこで戦略はこうなる: 計算できる分は先に引き算しておき、ループには「計算しきれなかった残り」だけ 追わせる。おかげで狭くて雑音に強いループが使える。 決定論で消せるものは決定論で消し、確率的な残りだけをサーボに任せる—— 深宇宙通信の設計思想がもっとも素直に現れる場面である。

3.4.1 量の見積り — 敵の大きさを知る

ドップラシフトは f_d = (v/c)·f_c。X帯下り 8.45 GHz で主な寄与は、

要因視線速度f_dレート df_d/dt
地球自転(低仰角の局)±0.46 km/s max±13 kHz〜1 Hz/s(日周でゆっくり)
地球公転+探査機軌道±30 km/s級±850 kHzごく緩やか
惑星周回機の公転(例: 火星低軌道)±3 km/s級±85 kHz数十Hz/s(掩蔽前後で最大)
LEO衛星(参考: 地上局試験で使う場合)±7 km/s±200 kHz(2 GHz帯換算±47k)kHz/s級

絶対量は数百kHzに達するがレートは小さい、が深宇宙の特徴である (LEOはその逆で、レートが厳しい)。そして深宇宙では軌道決定により 予測(predicts)が数Hz〜数十Hzの精度で事前に手に入る。この非対称性が戦略を決める。

3.4.2 戦略1 — 予測ステアリング(深宇宙の本命)

基本のアイデアはこうである。予測できる分は受信機の側から先に引き算しておき、 同期ループには「予測しきれなかった残り」だけを追わせる。

具体的には、時刻ごとの予測ドップラ f_pred(t) の時系列を用意する。 入手方法は、局が発行する追尾予報(predicts)を使うか、 SPICE(NASAの軌道計算ライブラリ)やGMATなどで視線速度を自分で計算する。 この時系列でNCOの周波数を走らせれば、受信信号のドップラはほぼ打ち消される。

実装は3通りあり、精度と手軽さで選ぶ。

①USRPのハードウェア側で補正する。デバイス内蔵DDCの周波数を、 タイムスタンプ付きコマンドで逐次更新する(第4.5.4節)。 更新間隔ごとの階段状の補正になるが、ホスト側の処理は要らない。

②ホスト側のDDCで補正する。Frequency Xlating FIR Filter の center_freq をメッセージで更新する。細かく制御できる。

③専用の補正ブロックを使う。予測周波数の時系列を複素VCOに流し込んで乗算する。 gr-satellitesの Doppler Correction ブロックがこの型で、 時刻タグ付きの予測ファイルを読み、位相を連続に保ったまま補正してくれる。

どの方法でも本質的に効いているのは第2.3.2節の性質、 すなわちNCOは位相の連続性を保ったまま周波数を変えられることである。 アナログのシンセサイザで周波数を変えると位相が飛ぶが、 位相アキュムレータは回り続けるので飛ばない。だから計測に使える。

この方法の効果を確認しよう。補正後に残るのは、予測の誤差(軌道決定の精度)と 探査機側の発振器のずれだけであり、合わせて高々数百Hzである。 これなら B_n が数十Hzしかない極めて狭い計測用ループでも余裕で捉えられる。 決定論的に計算できる動きは決定論で消し、ループは確率的な残差の処理に徹させる—— これが2-wayコヒーレント運用によるドップラ計測の標準構成である。

3.4.3 戦略2 — 広域捕捉と自力追尾

予測が無い・信頼できない場面(初期捕捉直後、セーフモード探索、他機関支援)では、 ①FFTサーチ(第3.1.6節)で±数百kHzから搬送波を見つけ、 ②FLLで数百Hzまで詰め、③PLLに引き渡す、の3段ロケットを組む。 各段の受け持ち範囲が重なるように設計する(FFT分解能 ≪ FLL引き込み範囲、 FLL残差 ≪ PLL引き込み範囲)。全段ソフトウェアなので、 「見つからなければFFT長を倍にして感度を上げる」といった適応戦略も書ける。 これはハードウェア受信機に対するSDRの決定的な優位である。

3.4.4 戦略3 — 記録して事後補正

オープンループ記録(第5.2章)してから、後処理でドップラを剥がす。 事後なら軌道決定後の精密な再構成ドップラが使え、非因果処理(前後の標本を全部見る平滑化)も できるため、リアルタイム処理より常に高品質である。掩蔽・着陸のような 一発勝負のイベントで記録が標準運用になっている理由がこれである。 実装は「記録IQ → 予測位相 φ_pred(t) を掛けて exp(−jφ_pred) → 残差を狭帯域処理」。

3.4.5 忘れられがちな相棒 — レートドップラ

ドップラは搬送波だけでなくすべての時間軸を同率で伸縮させる。 シンボルレートも副搬送波周波数も v/c だけずれる(10⁻⁴なら4096 baudで0.4 baud)。 搬送波を完璧に補正してもタイミングは別途ずれ続けるので、 ①シンボルループのmax_deviationに織り込む(第3.2.6節)か、 ②予測レートで再標本化(Polyphase Arbitrary Resamplerの比を時変させる)してから 復調するか、を選ぶ。2-wayコヒーレント運用ではさらに上り掃引の転写 (ターンアラウンド比倍された上りドップラ)まで見込む——姉妹編第2.3.12節の周波数管理表を SDRのNCO設定表に翻訳する作業が、運用準備の実務になる。

Q. 予測ステアリングとループ3次化はどちらを選ぶべきか?

予測が手に入るなら常にステアリングが勝る。3次ループはレートを自力で推定する分だけ 雑音に弱く、安定設計も難しい。深宇宙の強みは「軌道力学が正確」なこと—— 決定論で消せる項は決定論で消し、ループには確率的な残差だけを任せるのが原則である。 予測が無いLEO試験受信などでは3次化や広めのB_nが現実解になる。

▶ GNU Radioで試す — ドップラプロファイルを合成して剥がす
送信側フローグラフで、Signal Source(三角波, 0.01 Hz, 振幅±5 kHz相当)を VCO (complex) の制御に入れ、BPSK信号に乗算——「往復するドップラ」の模擬信号を作る。 受信側では同じ三角波(=完全な予測に相当)を逆符号でVCOに入れて乗算し、 残差ゼロで復調できることを確認。次に予測を10%狂わせ、Costasの積分器(周波数出力)が 残差ランプを追う様子を観察する。第4.3章の受信機にこのVCO段を足せば、 ドップラ耐性の試験治具(第5.3章)になる。

章末演習

【演習 3.4-1】残差設計
X帯下り、予測精度±20 Hz、機上USO安定度による不確かさ±50 Hz、B_n = 30 HzのPLL (引き込み範囲をB_nの3倍とする)で予測ステアリング受信を組む。ロックは成立するか。 成立しない場合の最小の追加処置は何か。
解答
残差上限 = 20 + 50 = 70 Hz > 引き込み 90 Hz…実は 3×30 = 90 Hz なのでぎりぎり成立する。 ただしマージンが20 Hzしかなく、USOの経年ドリフトで破綻し得る。最小の処置は ロック前だけFFT粗推定(0.5 s積分で分解能2 Hz)を1回走らせ、NCO初期値を残差込みで置くこと。 定常運用は B_n = 30 Hz のまま統計性能を保てる。
■ まとめ
  • 深宇宙のドップラは「大きいが遅く、予測できる」。予測ステアリングで動特性を消し、ループは残差だけ追う。
  • 予測なしはFFT→FLL→PLLの3段。各段の受け持ちを重ねて設計する。
  • 一発勝負は記録+事後補正。非因果処理はリアルタイムに常に勝る。
  • 搬送波と同率でシンボルレートも伸縮する。タイミング側の補償(許容幅 or 再標本化)を忘れない。
第 IV 部 GNU Radio実装 — 理論を動く受信機にする
ここまでの理論を、JAXA RF通信標準(JERG-2-401系)のPCM/PSK/PM変復調として完全に実装する。GNU Radioの実行モデルとブロックの内部を解剖し、送信機・受信機の全コードを書き、自作ブロックで欠けている部品を補い、USRPでRF区間を張って閉じる。この部を終えたとき、読者の手元には研究にそのまま使える変復調系一式が残る。

第4.1章GNU Radioの実行モデル

■ この章で学ぶこと
フローグラフがどう実行されるのか——スケジューラ・バッファ・レートの決まり方、 ストリームタグとメッセージという2つの帯域外情報、GRCとPythonコードの関係。 表面的な使い方ではなく、不具合時に内部で何が起きているか推論できる水準の理解を作る。 環境構築の類は扱わない(公式のインストールガイドに譲る)。
◇ 直観でつかむ — 「工場のベルトコンベア」
GNU Radioのフローグラフは工場のラインである。ブロックが各工程の機械、 工程間のバッファがベルトコンベア。機械は「コンベアに材料が乗ってきたら動く」—— 時計ではなくデータが来たら動くのが基本ルールである。
ここから実務的な結論が出る。①どこか1つの機械が遅いとライン全体が詰まる (=ハードウェアからの標本が捨てられる「O」表示)。 ②材料(標本)自体には「毎秒何個」という情報は書かれておらず、 レートは設計者が各機械に教えてやる約束事にすぎない(samp_rate変数の正体)。 ③工程の間に「付箋」(タグ)や「別便のメモ」(メッセージ)を流す仕組みが別にある。

4.1.1 フローグラフ = ブロック + 円環バッファ

GNU Radioで作るアプリケーションをフローグラフと呼ぶ。 信号処理の部品であるブロックを、データが流れる向きに線でつないだものである。

実行時に何が起きているかを知っておくと、不具合の原因を推論できるようになる。 実体は2つの要素からできている。ブロックごとに1本のスレッド(並行して走る処理の単位)と、 ブロックの間をつなぐ円環バッファ(データを一時的に溜める領域)である。 各ブロックは次の3ステップを延々と繰り返す。 ①上流のバッファに未処理のデータが溜まるのを待つ。 ②スケジューラがそのブロックの work() 関数を呼ぶ。 ③処理結果を下流のバッファへ書く。

この仕組みから、実務で効く帰結が3つ出てくる。順に見ていこう。

帰結(1): データ駆動である。 ブロックは時計に従って「毎秒何回」動くのではなく、データが来たら動く。 ということはフローグラフ全体の速度を決めるのは、 ハードウェア(USRPなど)がつながっていればその標本化周波数、 つながっていなければCPUの全力である。 ファイルやシミュレーションだけのフローグラフを動かすとCPU使用率が100%に張り付くのは、 バグではなくこの仕様のためである。 その暴走を抑えるために、あえて速度を制限する Throttle ブロックがある。 逆に、ハードウェアがつながっているフローグラフにThrottleを入れてはならない。 速度を決める要素が2つになって競合し、標本落ちの原因になる。 「Throttleは1つのフローグラフに1個だけ、しかもハードがないときだけ」と覚える。

帰結(2): samp_rate はただの申し合わせである。 ブロックの間を流れているのは裸の数列だけで、 「これは毎秒何標本のデータです」という情報はどこにも付いていない。 GRCで定義する samp_rate という変数は、 各ブロックのパラメータ計算(フィルタの設計、表示の周波数軸)に 設計者が使うための約束事にすぎず、実際のデータ流と自動で一致するわけではない。

ここから初学者の定番バグが生まれる。デシメーションで実際のレートが4分の1になったのに、 下流のブロックに元の samp_rate を渡してしまう—— するとフィルタの設計周波数も表示のスケールも全部ずれる。 レート変換をしたら、その下流に渡す値を必ず検算する習慣をつけること。

帰結(3): 背圧(バックプレッシャ)で全体がつながる。 下流のブロックが遅いとバッファが埋まり、上流のブロックは 書き込み先が空くまで待たされる。この「詰まりが上流に伝わる」性質を背圧と呼ぶ。 ファイルを読んで処理する場合は、これで全体が自然に減速するだけなので何も問題ない (実時間の3倍重い処理でも、3倍の時間をかけて正しく完走する)。

しかしハードウェアのソースは待ってくれない。 詰まればバッファが溢れて標本が捨てられる——第2.5.3節のオーバーフロー「O」である。 「O」を見たときの読み方はこうである。どこかのブロックが実時間に間に合っていない。 犯人は多くの場合、①タップ数×レートが最大のフィルタ(第2.4.3節の算術で当たりを付ける)か、 ②描画が重いGUIブロックである。

4.1.2 ブロックの種類とレートの規約

基底クラス入出力関係
sync_block出力数 = 入力数(1:1)乗算・AGC・PLL系の大半
decimator出力 = 入力/N(固定比)Decimating FIR、Keep 1 in N
interpolator出力 = 入力×N(固定比)Interpolating FIR、Repeat
general(basic)可変比・自己申告Symbol Sync(1シンボル/可変標本)、Rational Resampler

この区別は自作ブロック(第4.4章)で必須になるほか、既製ブロックの挙動理解にも効く。 たとえば Symbol Sync は「タイミングループの現在値に応じて消費標本数が揺れる」 generalブロックなので、上流に固定長を仮定する処理を置いてはならない。

4.1.3 ストリームタグ — 標本に貼る付箋

前節までで扱ったのは「数列そのもの」の流れだった。 しかし実務では、数列と一緒に運びたい付加情報がある。 「この標本はUTC 12:00:00 に取られた」「ここからフレームが始まる」といった情報である。 振幅の値に埋め込むわけにはいかないので、別の仕組みが用意されている。

1つ目がストリームタグで、特定の標本に貼り付く付箋である。 中身は(絶対標本番号, キー, 値)の3つ組で、 貼られた標本と一緒に下流へ流れていく。 レート変換ブロックを通るときは標本番号が自動で換算されるので、 間引いても補間してもタグは正しい位置に留まる。

代表的な用途を挙げる。①USRPが受信開始の標本に貼る時刻タグ rx_time ——これが第2.5.4節・第1.4.6節で述べたタイムスタンプの実体である。 ②送信バーストの開始と終了を示す tx_sobtx_eob。 ③フレーム同期の相関器が「ここでASMを見つけた」と貼る位置情報。 ④パケット長 packet_len(可変長パケットを扱うブロック群が使う)。

「この標本は特別だ」という情報は、振幅に埋め込まずタグで運ぶ—— これがGNU Radio流の設計語法である。自作ブロック(第4.4.3節)でも同じ流儀に従う。

4.1.4 メッセージとPDU — 非同期の裏方

2つ目の仕組みがメッセージポートである。 タグが「標本にひも付いた情報」だったのに対し、メッセージは 標本の流れとは無関係に、任意のタイミングで送れる構造データである。 中身は辞書やベクトルなどを表現できるPMT(polymorphic type)という形式で運ばれる。

主な使い道は3つある。①フレームの受け渡し。 復調が終わってビット列になったら、それ以上「標本の流れ」として扱う意味がないので、 メタデータの辞書とバイト列を組にしたPDUという単位に変換して渡す。 ②制御。第3.4.2節の予測ドップラをNCOに送り込むような、動的なパラメータ変更。 ③外部連携。ソケット経由で他のプログラムとやり取りする。

設計の指針として覚えてほしいのは、標本の世界(ストリーム)で復調し、 ビットの世界(PDU)で解析するという分業である。 受信機の後半をPDU化しておけば、フレームの解析や統計処理を 普通のPythonコードとして自由に書ける(第4.4.4節でBER測定器を作る)。 2つの世界の橋渡しは Tagged Stream to PDUPDU to Tagged Stream といったブロックが担う。

4.1.5 GRCとPythonの関係 — 生成コードを読む

GRC(GNU Radio Companion)で描いたフローグラフは、実行時に1本のPythonファイルtop_blockクラス)に変換される。生成コードの骨格は次で、 本書のコード例もこの形式で書く——GRCで作ったものとPythonで書いたものは等価であり、 パラメータ掃引・自動試験・長時間運用のスクリプト化はPython直書きの方が楽だからである。

from gnuradio import gr, blocks, analog, digital, filter
from gnuradio.filter import firdes

class rx_top(gr.top_block):
    def __init__(self):
        gr.top_block.__init__(self, "PCM/PSK/PM RX")
        # --- 変数(GRCのVariableに相当) ---
        self.samp_rate = samp_rate = 524288
        # --- ブロック生成(GRCの各ブロックに相当) ---
        self.src  = blocks.file_source(gr.sizeof_gr_complex, "iq.bin", True)
        self.agc  = analog.agc_cc(1e-4, 1.0, 1.0)
        # --- 接続(GRCの矢印に相当) ---
        self.connect(self.src, self.agc)

tb = rx_top()
tb.start()      # 各ブロックのスレッドが走り出す
tb.wait()       # ソースが尽きるまで(無限ソースなら永久に)待つ

変数をGUIから動かすとき、GRCは set_変数名() のコールバック連鎖を生成し、 影響するブロックのセッタ(set_frequency() など)を呼ぶ。 どのパラメータが実行中に変更可能かはブロックごとに決まっており (フィルタのタップは可、デシメーション比は不可、など)、 変更不可のものを動かすにはフローグラフの stop→再構成→start が要る。

4.1.6 デバッグの道具箱

道具用途
QT GUI Frequency/Time/Constellation/Waterfall Sink信号の目視。各同期段の直後に1個ずつ置いて「どこまで健全か」を切り分けるのが定石。
ブロックの補助出力Costas/Symbol Syncは誤差・周波数・位相の診断端子を持つ(GRCで「Show Advanced」)。ループの内部状態を波形で見る——第3部の理論の実況中継である。
Tag Debug / Message Debugタグ・メッセージの中身を印字。フレーム同期の生死確認に。
File Sink(要所で録る)疑わしい区間の生データを保存し、NumPy(np.fromfile(f, np.complex64))で精査。「動くフローグラフ」と「解析スクリプト」の往復が研究の基本動作になる。
Probe系(Probe Avg Mag²等)数値をPython側から読み出しautomationに使う。
Q. GRCとPython直書き、どちらで開発すべきか?

探索はGRC、確定したらPythonへ、が能率的である。GRCは接続ミスが視覚的に 潰せて試行錯誤が速い。一方、パラメータを回線条件から計算で決める(本書の流儀)、 多数の条件で自動BER測定を回す、といった段階ではPythonファイルとして 持っている方が圧倒的に扱いやすい。GRCの生成コードを読める(本節)なら移行は機械的である。

Q. リアルタイムで動かない処理はどうするか?

録ってから流す。File SourceはCPUの許す速さで流れるので、 実時間の3倍重い処理でも3倍の時間をかけて正しく完走する。深宇宙の解析が オープンループ記録+事後処理(第3.4.4節・第5.2章)を好むのと同じ理屈が、 開発の日常にもそのまま現れる。

■ まとめ
  • フローグラフ=ブロック+円環バッファ。データ駆動・背圧で繋がり、速度はハードが律速(無ければThrottle)。
  • samp_rateは申し合わせにすぎない。レート変換後の値の引き回しを常に検算する。
  • 帯域外情報は2系統: 標本に貼るタグ(時刻・バースト・フレーム位置)と非同期メッセージ/PDU(フレーム・制御)。
  • GRCはPythonコード生成器。研究用途は最終的にPythonで持ち、掃引・自動試験を回す。
  • デバッグは「各同期段直後にSink」「診断端子」「録ってNumPy」の三種の神器。

第4.2章主要ブロックの解剖

■ この章で学ぶこと
第4.3章の受信機で使うブロックを1つずつ開け、パラメータの意味を本書前半の理論に接続する。 「このパラメータは第何章のどの記号か」が全部言えるようになれば、 ブロックはブラックボックスではなく理論の実行形式になる。

4.2.1 信号源と算術 — 素材のブロック

ブロック要点
Signal SourceNCOそのもの(第2.3.2節)。complex出力にすると解析信号 e^{j2πft}。位相連続で周波数変更可。
Noise SourceGR_GAUSSIANのamplitudeは実部・虚部それぞれの標準偏差。複素雑音電力は2×amplitude²——E_b/N₀較正(第4.3.8節)で間違えやすい急所。
VCO (complex)float入力→e^{jθ}出力、θ' = sensitivity×入力。ドップラプロファイル注入(第3.4章)の主役。
Multiply / Multiply Conjugate / Add第2.1.4節の複素四則。Multiply Conjugateは相関・周波数弁別の素。
Phase Modulatorout = exp(j·sensitivity·in)。PM送信機の心臓(第4.3.3節)。sensitivityが変調指数[rad](入力±1のとき)。
Delay整数標本の遅延。差動検波・自己相関に。分数遅延はポリフェーズ再標本化で(第2.4.4節)。

4.2.2 フィルタ系 — firdesと3つの実装形

フィルタ関連は「タップ設計(firdes)」と「実行形(FIR/FFT/Xlating)」を分けて理解する。

from gnuradio.filter import firdes
# LPF: (gain, samp_rate, cutoff, transition, window)  → 第2.4.5節の窓関数法
taps_lp  = firdes.low_pass(1.0, 524288, 6000, 6000, firdes.WIN_HAMMING)
# RRC: (gain, samp_rate, symbol_rate, alpha, ntaps)   → 第3.2.4節
taps_rrc = firdes.root_raised_cosine(1.0, 32768, 4096, 0.35, 8*11)
print(len(taps_lp))  # タップ数を必ず確認する習慣を(計算量=タップ数×レート)
実行形特徴・使いどころ
FIR Filter / Decimating FIRポリフェーズ実装(第2.4.2節)。デシメーション比は接続時固定。
FFT Filter重畳保存法。タップ数が数百を超えたらFIRより速い。長い整形・急峻なチャネルフィルタに。
Frequency Xlating FIR FilterDDCの1ブロック版(第2.3章): NCO+複素乗算+LPF+間引き。center_freqは実行中変更可=粗い同調・予測ステアリングの受け口。型に注意: 入力float/complex×タップreal/complexで6種ある(fcc型=実入力→複素出力は副搬送波復調で使う)。
Polyphase Arbitrary Resampler任意実数比の再標本化(第2.4.4節)。レートドップラ補正・装置間のレート接続に。
Rational ResamplerL/M有理比。taps省略時は自動設計(まずこれでよい)。

ここで実装上もっとも間違いやすい点を確定させる。 「firdes に渡す samp_rate は、どの地点のレートか」がブロックによって違う。 第2.4.6節のレート連鎖と併せて、次の3つの規則として覚えること。

規則1: デシメーションするFIRは、入力レートで設計し、出力ナイキストに収める。 GNU Radioのデシメーティングフィルタは入力レートでフィルタしてから間引くので、 taps は入力レートで設計する。ただし cutoff が満たすべき条件は出力側のナイキスト周波数である。

fs_in  = 524288
decim  = 16
fs_out = fs_in / decim          # = 32768 → ナイキストは 16384 Hz
# tapsは入力レート fs_in で設計するが…
taps = firdes.low_pass(1.0, fs_in, 6e3, 6e3)
# …cutoff + transition ≤ fs_out/2 を必ず自分で検算する: 6k + 6k = 12k ≤ 16384 ✓

この検算を怠ると、フィルタ自体は正常に設計されるのに、 間引いた瞬間に折り返す。firdes は cutoff が入力ナイキストを超えたときだけ例外を出し、 「出力ナイキストを超えている」ことは検出してくれない——ここは人間が守る箇所である。

規則2: 補間するFIRは、出力レートで設計し、gainに補間比を入れる。 デシメーションと逆で、taps は補間後(=出力)のレートで設計する。 さらにゼロ挿入によって振幅が 1/L に落ちるため、これを打ち消すよう gain に interpolation の値を入れる

interp = 4
taps = firdes.low_pass(interp, fs_in*interp, fs_in/2*0.9, fs_in/2*0.2)
#                      ↑gain=L    ↑出力レートで設計   ↑cutoffは元のナイキスト以下

gain を 1 のままにすると出力振幅が L 分の1になり、 「理由もなく信号が小さい」「AGCが妙な値に張り付く」という症状になる。

規則3: Xlating FIR の center_freq は「入力レートにおけるHz」である。 freq_xlating_fir_filter は center_freq に指定した周波数を0 Hzへ引き寄せる。 渡す値は入力レートの座標系におけるベースバンド周波数(第2.2.5節の第2の座標系)であり、 taps も入力レートで設計する(cutoffの条件は規則1と同じ)。 Rational Resampler は taps を空欄にすれば規則1と2を自動で満たすフィルタを設計するので、 迷ったらまずこれを使う。Polyphase Arbitrary Resampler の prototype filter は nfilts × f_s のレートで設計する(firdes.low_pass(nfilts, nfilts*fs, ...))。

最後に、フィルタを持たない間引き・補間ブロックの存在も知っておく。 Keep 1 in N は素の間引き(折り返す)、Repeat は素のゼロ次ホールド(イメージが残る)である。 通常は避けるべきだが、第4.3.3節の送信機では Repeat を意図的に使っている—— あそこで作りたいのはNRZ矩形パルスそのものなので、階段状の波形が正解なのである。 「フィルタなしの間引き・補間を使うときは、それが意図であると言えること」が使用条件になる。

レートと単位に起因する不具合は、症状から原因をほぼ一意に逆引きできる。 実装中に手元に置いておく表として掲げる。

症状原因
スペクトルの周波数軸が全体にずれるGUI Sinkに渡した samp_rate が実レートと不一致(レート連鎖の計算漏れ・第2.4.6節)
帯域端に折り返し成分が出るデシメーションの cutoff が出力ナイキストを超えている(規則1の検算漏れ)
補間後に振幅が 1/L になる補間FIRの gain に interp を入れていない(規則2)
firdes check failed の例外cutoff > samp_rate/2。渡した samp_rate がその地点の値かを確認
Symbol Sync がロックしないsps の値が実際の f_s/R_s と違う(レート連鎖の誤り)、または初期周波数誤差がTEDの引き込み外(第3.1.5節)
ループの収束が想定より速い/遅いloop_bw に Hz をそのまま渡している、または正規化の基準を間違えている(搬送波系は f_s、タイミング系は R_s が基準・第3.2.1節)
端末に「O」が出る実時間に間に合っていない。タップ数×レートが最大の段を疑う(第2.4.3節)
USB/Ethernetが飽和するスループット f_s×2×バイト幅が伝送路の実効値を超えている(第2.4.6節・第2.5.2節)

4.2.3 同期系 — 第III部の実行形式

PLL Carrier Trackinganalog.pll_carriertracking_cc(loop_bw, max_freq, min_freq)): 残留搬送波用PLL(第3.1.4節)。入力をNCO共役で回した複素信号を出力する= ロック後は搬送波が実軸DCに立ち、PM成分が位相に残る。loop_bw = θ_n(第3.1.2節)、 max/min_freqはrad/sample単位の引き込み限界(Hz×2π/f_sで換算)。 姉妹ブロックに、位相まで剥いだ搬送波レプリカを出す PLL Refout、 周波数推定値を出す PLL Freq Det がある。

Costas Loopdigital.costas_loop_cc(loop_bw, order)): 抑圧搬送波用(第3.1.5節)。order = 2がBPSK、4がQPSK。位相検出器は3.1.1節の表の判定型。 出力は位相補正済み複素ストリーム。診断端子(frequency/phase/error)を持ち、 frequency出力×f_s/2πが搬送波(本書の用法では副搬送波)残差周波数の実況値になる。

Symbol Syncdigital.symbol_sync_ff/cc(TED, sps, loop_bw, damping, ted_gain, max_dev, osps, ...)): タイミング同期の統合ブロック(第3.2章)。 TED_GARDNER/TED_MUELLER_AND_MULLER等を選び、補間器(既定MMSE 8タップ)と ループを内蔵する。spsは実数でよい。osps = 1で判定時刻の1点だけを出す。 loop_bwはシンボル正規化θ_n、max_devはクロック相対誤差の想定(第3.2.6節)。

FLL Band-Edgedigital.fll_band_edge_cc(sps, alpha, ntaps, loop_bw)): 整形済みBPSK/QPSKの周波数誤差をシンボルレート数%まで引き込む前置ループ(第3.1.5節)。 PCM/PSK/PM(残留搬送波が見えている)では不要だが、抑圧搬送波系では標準装備。

4.2.4 判定・ビット系 — 標本からビットへ

ブロック要点
Binary Slicerfloat符号→0/1バイト(1バイト1ビットの「unpacked」表現)。以降のビット処理はこの表現が基本。
Differential Decoder/EncoderNRZ-M/S(差動表現、姉妹編第2.1.7節)の変換。Costasの±π曖昧性を差動で吸収する構成にも使う。
Unpack K Bits / Pack K Bitsバイト⇄ビット表現の変換。MSBファースト指定に注意(CCSDS系は常にMSB first)。
Correlate Access Code - Tagビット列からASM(同期マーカ)を探し、発見位置にタグを貼る(姉妹編第2.4.5節)。閾値=許容ビット誤り数。
DescramblerCCSDSランダマイザ等の解除(多項式・初期値・自己同期/加算型の別を規格書で確認)。
Map0/1→任意値の写像。0/1→±1(NRZ-L化)は Map [-1,1] または char→float→2x−1 で。

4.2.5 gr-satellites — 車輪を再発明しない

衛星・宇宙機のテレメトリ受信に必要な部品——各種デフレーマ、CCSDS 畳み込み/RS/LDPC復号、リアルタイムのドップラ補正、RMS AGC——を集めた OOTモジュールが gr-satellites である。第4.3章では原理学習のため 同期系を素のブロックで組むが、フレーム層から先(ASM探索→復号→パケット出力)は gr-satellitesのコンポーネント(Sync and create packed PDUCCSDS deframer等)を使うのが実務的である。 自分のフレーム形式が既製と合わない部分だけ自作する(第4.4章)—— この「境界の見極め」自体が研究ツール開発の重要スキルである。

Q. 同名機能のブロックが複数あるとき(AGC/AGC2/AGC3など)の選び方は?

歴史的経緯で重複があるのがGNU Radioの実態である。選定基準は ①本書のような設計根拠に紐づくパラメータを持つか、②診断端子があるか、 ③最近のリリースで手が入っているか(Symbol SyncはClock Recovery MM/Polyphase Clock Syncの 後継として設計し直された統合版——新規設計はSymbol Syncを使う)。

Q. ブロックの中身はどこで確認できるか?

ソースを読む。gr-digital/lib/ 以下のC++実装が真実であり、 たとえばcostas_loop_cc_impl.ccを開けば位相検出器が3.1.1節の表そのままであることが 数十行で確認できる。「ドキュメントと論文とソースの三点照合」は SDR研究者の基本動作である。

■ まとめ
  • 素材(NCO・雑音・複素算術・Phase Modulator)→フィルタ(firdes設計+FIR/FFT/Xlating実行)→同期(PLL/Costas/Symbol Sync/FLL)→ビット(Slicer以降)の4層で覚える。
  • 各パラメータは理論の記号に1対1対応: loop_bw=θ_n、max_freq=引き込み[rad/sample]、sps=実数可、Noiseのamplitude=成分ごとのσ。
  • tapsの設計レートは3規則: デシメーションは入力レートで設計・出力ナイキストで検算、補間は出力レートで設計・gain=L、Xlatingのcenter_freqは入力レートのHz。
  • フィルタなしの間引き(Keep 1 in N)・補間(Repeat)は、意図であると言えるときだけ使う。
  • レート・単位起因の不具合は症状から一意に逆引きできる(4.2.2節末の表)。
  • 診断端子はループ内部状態の実況中継。開発時は常に表示する。
  • フレーム層はgr-satellitesを使い、足りない部品だけ自作する。

第4.3章PCM/PSK/PM変復調の完全実装

■ この章で学ぶこと
本書の中心章である。JAXAのRF通信標準(JERG-2-401系、CCSDS 401互換)が定める PCM/PSK/PM——NRZデータで正弦波副搬送波をBPSKし、それを残留搬送波に位相変調する方式——の 送信機と受信機を、設計パラメータの決定からGNU Radioの全コードまで通しで実装する。 すべての数値は第I〜III部の式から導出し、出所を明記する。 この章の成果物は、USRP(第4.5章)を繋げばそのまま実RFで動く変復調系である。
◇ 直観でつかむ — PCM/PSK/PMは「三重の入れ物」
名前が長くて怖いが、やっていることは入れ物を3回入れ替えるだけである。
①PCM: 送りたい情報をビット列(±1の連続、NRZ)にする。
②PSK: そのビットで副搬送波(例: 65.536 kHzの音のような正弦波)の位相を0/180°に切り替える。 ——ここまでで「65 kHzの正弦波を、ビットに応じて±反転させた信号」ができる。
③PM: それを本物の搬送波(例: 2.2 GHz)の位相の揺れとして乗せる。
受信はこの逆順に開けていく: 搬送波の位相を追って(PLL)位相の揺れを取り出し、 その中から65 kHzの成分を抜き出して(DDC)±反転を読み(Costas)、ビットの区切りを合わせる(Symbol Sync)。 3つの入れ物 = 3つの同期ループという対応が、この章の受信機の骨格である。
なぜこんな凝った方式かというと、搬送波を少しだけ残しておける(残留搬送波)から。 残った搬送波の線を追いかけることで、通信と同時に探査機の速度をドップラで精密計測できる—— 深宇宙通信が今もこの方式を使い続ける理由である。

4.3.1 規格の信号定義

JAXAの宇宙機RF通信設計標準(JERG-2-401、CCSDS 401勧告と整合)が定める テレメトリ変調の中核がPCM/PSK/PMである。まず信号の姿を数式で確認する。

s(t) = \sqrt{2P}\, cos\big( 2π f_{c} t + m · d(t) · sin(2π f_{sc} t) \big)

記号を1つずつ確認しよう。f_c は搬送波周波数(例: 2.2 GHz)。 d(t) は送りたいデータで、値は +1 か −1 のどちらか (ビット1を+1、0を−1に対応させるNRZ-Lというラインコードを使う)。 f_sc は副搬送波周波数(例: 65.536 kHz)で、正弦波である。 m変調指数で、位相をどれだけ大きく振るかをラジアンで表す。 cos の中身(位相)を見ると、搬送波の回転 2πf_c t に、 m·d(t)·sin(2πf_sc t) という揺れが足されている。 つまりデータで符号が反転する正弦波の分だけ、搬送波の位相が揺らされている—— これが「NRZデータで副搬送波をBPSKし、それで搬送波を位相変調する」という言葉の中身である。

この信号を第2.1.2節の複素包絡線で書き直すと、扱いやすい形になる。

z(t) = e^{\,j m · d(t) · sin(2π f_{sc} t)}

ここで重要な性質に気づいてほしい。指数関数の肩が純虚数なので、 |z| = 1、すなわち振幅が常に一定である(定包絡線と呼ぶ)。 振幅が変化しないということは、増幅器を飽和領域(最も効率の良い動作点)で 使っても波形が歪まないことを意味する。 電力が貴重な探査機にとってこれは決定的な利点であり、 PM系の変調が宇宙機で使われ続ける理由の1つである(姉妹編第2.1章)。

次に、送信電力がどう配分されるかを見る。位相変調された信号を Bessel関数で展開すると、搬送波成分とデータ成分の割合が次のように決まる。

\frac{P_{c}}{P_{T}} = J_{0}^{2}(m),\, \frac{P_{d}}{P_{T}} = 2 J_{1}^{2}(m)

P_T が全電力、P_c が搬送波(0 Hzに残る線)の電力、P_d がデータ側波帯の電力である。 J₀, J₁ は第1種Bessel関数で、m を与えれば数表や計算ライブラリから値が出る。 残りの電力は副搬送波の高調波(3f_sc, 5f_sc の位置に J₃², J₅² の割合で)に漏れる。

この式が意味するのは、変調指数 m という1つのつまみで、 搬送波(=計測に使う)とデータ(=通信に使う)への電力配分を決められるということである。 m を小さくすれば搬送波が強く残り計測が有利、大きくすればデータが有利になる。 m = 2.405 で J₀ がゼロになり搬送波が完全に消える——残留搬送波方式が成立する上限がここである。 この配分設計が4.3.2節の中心的な決断になる。

設計標準が課す主な制約を表にまとめる (数値は代表例である。実設計では対象ミッションのRF-ICDと規格原文に必ず拠ること)。

項目規定の形根拠
副搬送波波形正弦波(低レート系では方形波の系譜もある)高調波の帯域外放射を抑える。
f_sc とビットレートの比整数(2のべきが慣例。例: 16, 32, 64サイクル/ビット)副搬送波とシンボルの同期関係を保証し、復調器設計を単純化。
f_sc の選定データ主ローブが搬送波成分と重ならないよう Rb に対し十分高く(かつ必要以上に高くしない)搬送波PLLとデータの層分離(第3.1.4節)。
変調指数 m〜1.4 rad程度まで(測距等との同時変調時は配分設計)J₀(2.405) = 0で搬送波が消える。残留搬送波方式の成立条件。
ラインコードNRZ-L(副搬送波PSK時)遷移確保は擬似ランダム化(CCSDSランダマイザ)が担う。
符号化・フレームCCSDS TM(ASM 1ACFFC1D、畳み込み/RS/LDPC)姉妹編第2.2章。

4.3.2 設計パラメータの決定 — 数値に根拠を持たせる

ここからが実装である。ただしコードを書く前に必ず設計表を作る。 本節の2つの表——パラメータ表とループ表——が、次節以降のコードに現れる すべての定数の出所になる。逆順(とりあえず動かしてから値を調整する)で進めると、 なぜその値なのか誰も説明できない受信機ができあがり、条件が変わった時に破綻する。

実装例として次のリンクを想定する。小型技術実証機と大学局を意識した控えめな値だが、 比率の構造は深宇宙でもそのまま通用する。

項目決定根拠
ビットレート Rb4096 bps例として。CCSDSフレーム(次節)を毎秒2枚運べる。
副搬送波 f_sc65.536 kHz(正弦波)16サイクル/ビット(整数比の慣例)。搬送波から十分離隔。
変調指数 m1.2 radP_c/P_T = J₀²(1.2) = −3.5 dB、P_d/P_T = 2J₁²(1.2) = −3.0 dB。搬送波とデータにほぼ等分——搬送波計測とデータ伝送を両立する古典的な配分。
標本化周波数 f_s524.288 kSPS= 128標本/ビット = 8標本/副搬送波周期。全レートが2のべき比(第1.2.6節)。占有帯域(±74 kHz)の3.5倍でAAF/フィルタ余裕も充分。
想定回線 C/N₀55 dBHz回線計算(姉妹編第1.2章)から来る前提値。以下のループ設計の入力。

次に、この前提から3つのループ(第3.1.4節)のパラメータを決める。 手順は各ループについて共通で、次の4段階である。 ①そのループが使える電力を求める(電力配分の式から)。 ②必要な追従速度から B_n を仮に決める。 ③ループSNR ρ = P/(N₀·2B_n) を計算し、必要値(残留搬送波PLLなら17 dB程度が目安)を 満たしているか検算する。満たさなければ B_n を狭める。 ④第3.1.2節の式で loop_bw(=θ_n)に換算する。

ループ使える電力B_n の選定ループSNR ρloop_bw(第3.1.2節)
①搬送波PLL
(524.288 kSPSで回す)
P_c/N₀ = 55 − 3.5 = 51.5 dBHz100 Hz(ドップラ残差追従に充分・第3.4.2節の予測併用前提)51.5 − 10log(200) = 28.5 dB ≫ 17 dB ✓θ_n = 100/(524288×1.061) = 1.8×10⁻⁴
②副搬送波Costas
(32.768 kSPSで回す)
P_d/N₀ = 52.0 dBHz250 Hz(送受クロック差の追従には過剰なほど広い)52.0 − 10log(500) = 25.0 dB ✓θ_n = 250/(32768×1.061) = 7.2×10⁻³
③シンボル同期
(sps = 8)
E_s/N₀ = 52.0 − 36.1 = 15.9 dBB_n·T_sym ≈ 0.02(標準域・第3.2.1節)—(TED感度で決まる)loop_bw = 0.02

最後に、この設計で通信が成立するかを確認する。 データが受け取るエネルギーは、全電力のうちデータ配分の分を、ビットレートで割ったものである。 dBで積み上げると

E_{b}/N_{0} = C/N_{0} + 10log_{10}(2J_{1}^{2}(m)) − 10 log_{10}(R_{b})

すなわち 55 − 3.0 − 36.1 = 15.9 dB が得られる。 符号化なしのBPSKでビット誤り率 10⁻⁵ を達成するのに必要なのは 9.6 dB なので、 余裕は+6.3 dB。実装損失(第1.3.8節・第5.3.5節で積み上げる1 dB強)を 差し引いても十分に成立する。ここまで確認できたら、コードを書き始めてよい。

4.3.3 送信機の実装

送信機は4.3.1節の定義式をそのまま部品に置き換えるだけで作れる。 信号の流れは次のとおりである。 まずフレーム化されたビット列を用意し、それを ±1 のNRZ波形にする。 次にその波形と副搬送波 sin(2πf_sc t) を掛ける(これでBPSK変調された副搬送波ができる)。 最後にそれを位相変調器 e^{jm(·)} に通せば、複素包絡線 z(t) が完成する。 あとはUSRPに渡せば実際の電波になる。

[File Source frames.bin] → [Packed to Unpacked MSB] → [Map 0,1→−1,+1] → [Repeat ×128] → [Multiply × Signal Source sin 65.536k][Phase Modulator sens=1.2] → [×0.7] → [UHD Sink / File Sink]

まずフレームを作る補助スクリプト。CCSDS TMフレームの骨格(ASM + 一連番号入りペイロード)を 生成する。符号化(畳み込み・RS)を入れる場合はこの段に挿入する(4.3.6節)。

# make_frames.py — ASM付きテレメトリフレーム列を生成(試験用: 中身はカウンタ+PN)
import numpy as np
ASM   = bytes.fromhex("1ACFFC1D")          # CCSDS付加同期マーカ(姉妹編2.4.5節)
FLEN  = 223                                 # 情報部長[byte](RS(255,223)の情報長に合わせた例)
rng   = np.random.default_rng(2)
with open("frames.bin", "wb") as f:
    for i in range(2000):
        payload = bytearray(rng.integers(0, 256, FLEN, dtype=np.uint8))
        payload[0:2] = i.to_bytes(2, "big")   # 先頭2byteに一連番号(受信側で欠落検出)
        f.write(ASM + bytes(payload))
# 注: 実規格ではランダマイザ・誤り訂正符号をASMの後段に適用する。4.3.6節参照。

送信フローグラフ本体。1行ごとに「第何章のどの式か」を注記した——本書の流儀である。

# tx_pcm_psk_pm.py — PCM/PSK/PM送信機(GNU Radio 3.10)
from gnuradio import gr, blocks, analog, digital
import numpy as np

class tx_top(gr.top_block):
    def __init__(self, to_usrp=False):
        gr.top_block.__init__(self, "PCM/PSK/PM TX")
        # ---- 設計パラメータ(4.3.2節の表) ----
        self.samp_rate = fs   = 524288      # 128 samp/bit
        self.bitrate   = rb   = 4096
        self.f_sub     = fsc  = 65536       # 16 cycle/bit(整数比制約)
        self.mod_index = m    = 1.2         # J0²=−3.5dB / 2J1²=−3.0dB
        sps_bit = fs // rb                  # = 128

        # ---- ビット列 → NRZ-L ----
        self.src    = blocks.file_source(gr.sizeof_char, "frames.bin", True)  # repeat=True
        self.unpack = blocks.packed_to_unpacked_bb(1, gr.GR_MSB_FIRST)        # byte→bit(MSB先)
        self.nrz    = digital.chunks_to_symbols_bf([-1.0, +1.0])              # 0→−1, 1→+1
        self.rept   = blocks.repeat(gr.sizeof_float, sps_bit)                 # NRZ矩形パルス

        # ---- 副搬送波BPSK → 位相変調(4.3.1節の定義式そのまま) ----
        self.subc   = analog.sig_source_f(fs, analog.GR_SIN_WAVE, fsc, 1.0, 0.0)
        self.mult   = blocks.multiply_ff()                    # d(t)·sin(2πfsc t)
        self.pm     = analog.phase_modulator_fc(m)            # exp(j·m·x) ← 定包絡線
        self.scale  = blocks.multiply_const_cc(0.7)           # DACヘッドルーム(第1.5.4節)

        self.connect(self.src, self.unpack, self.nrz, self.rept, (self.mult, 0))
        self.connect(self.subc, (self.mult, 1))
        self.connect(self.mult, self.pm, self.scale)

        if to_usrp:                                           # 実RF送信(第4.5章)
            from gnuradio import uhd
            self.sink = uhd.usrp_sink(",".join(("", "")),
                uhd.stream_args(cpu_format="fc32", channels=[0]))
            self.sink.set_samp_rate(fs)
            self.sink.set_center_freq(uhd.tune_request(2265.0e6, 200e3))  # LOオフセット: 4.5.3節
            self.sink.set_gain(30)
            self.connect(self.scale, self.sink)
        else:                                                 # まずはファイルへ(IQ記録)
            self.sink = blocks.file_sink(gr.sizeof_gr_complex, "tx_iq.bin")
            self.head = blocks.head(gr.sizeof_gr_complex, fs * 30)  # 30秒分
            self.connect(self.scale, self.head, self.sink)

if __name__ == "__main__":
    tb = tx_top(to_usrp=False)
    tb.start(); tb.wait()

ここで生成した tx_iq.bin のスペクトルを確認すると、0 Hzの搬送波線、 ±65.536 kHzを中心とするデータ側波帯(sinc²形、幅±4.096 kHzの主ローブ)、 ±196.6 kHz(3f_sc)の弱い高調波が見えるはずである。実装の正しさをスペクトルの 理論形と照合するのが第一の検収であり、電力比を測れば J₀²/2J₁² の−3.5/−3.0 dBも検証できる。

4.3.4 受信機の設計 — レートとループの配管図

受信機は送信の逆順に「3重の入れ物」を開けていく。 コードを読む前に、信号がどんなレートでどの処理を通るかを図で把握しておこう。 各段のレートとループ帯域は、前節の設計表からすべて決まっている。

USRP Source524.288 kSPS Xlating FIR−25 kHz 戻しLPF ±80k AGC|z|→1(3.3節) ① PLL CarrierBn=100Hzloop_bw=1.8e-4 Complex→Arg位相復調 φ(t) Xlating FIR (fcc) ↓1665.536k→0, LPF 6k→ 32.768 kSPS 複素BPSK ② Costas (BPSK)Bn=250Hzloop_bw=7.2e-3 C→Reald(t)+雑音 移動平均 8整合フィルタ積分・ダンプ ③ Symbol SyncGardner, sps=8loop_bw=0.02 Slicer→ 0/1 ASMデフレーマ(自作)極性解決+PDU化(第4.4章の技法) 緑=同期ループ(第III部で設計した3つ)。各段直後にQT Sinkを挿して段階検収する(4.3.6節)
図4.3-1 PCM/PSK/PM受信機の全配管。レートは 524.288k →(↓16)→ 32.768k → シンボルレート4096。 ①が位相を剥がし、Complex→Argで位相波形(=副搬送波BPSK)を取り出し、②③は通常のBPSK受信になる。

図で確認しておきたい設計上の要点を3つ挙げる。

要点1: 位相の取り出しには atan2 を使う。 PLLで搬送波の回転を剥がした後、残っているのは位相の揺れ φ(t) = m·d(t)·sin(ω_sc t) である。 これを取り出すには、複素数の偏角を計算する Complex to Arg(内部でatan2)を使う。 「虚部を取れば位相の近似になる」という手もあるが、それは φ が小さいときだけ成り立つ近似で、 m = 1.2 rad(約69°)という本設計では成り立たない。 atan2 なら m がいくら大きくても厳密に位相が取り出せる(PLLがロックしている限り)。

要点2: DDCが2回登場する。1回目は入口で、周波数プランのずれを戻して帯域制限するため。 2回目は位相波形の中から副搬送波(65.536 kHz)の成分を抜き出して0 Hzへ降ろすためである。 同じ第2.3章の道具が、階層の違う2か所で使われている。

要点3: 2回目のDDCは「実数入力・複素出力」型を使う。 atan2の出力は実数(float)だが、副搬送波を抜き出した結果は複素数である必要がある。 GNU Radioの Frequency Xlating FIR Filter には入出力の型ごとに複数の版があり、 この用途では fcc型(float入力・complex出力)を選ぶ。 型の選択を間違えると接続できないので、フローグラフ作成時に注意する。

4.3.5 受信機の実装

# rx_pcm_psk_pm.py — PCM/PSK/PM受信機(GNU Radio 3.10)
from gnuradio import gr, blocks, analog, digital, filter as gr_filter
from gnuradio.filter import firdes
import numpy as np, pmt

# ---------- 自作: ASMデフレーマ(第4.4章で解剖する) ----------
class asm_deframer(gr.sync_block):
    """unpackedビット列からASMを探索、極性反転を解決し、フレームをPDUで出す"""
    def __init__(self, asm=0x1ACFFC1D, asm_len=32, frame_bits=223*8, thresh=3):
        gr.sync_block.__init__(self, "asm_deframer", [np.uint8], [])
        self.asm  = np.array([(asm >> (asm_len-1-i)) & 1 for i in range(asm_len)], np.uint8)
        self.n, self.fb, self.th = asm_len, frame_bits, thresh
        self.buf = np.zeros(0, np.uint8)
        self.message_port_register_out(pmt.intern("frames"))
    def work(self, input_items, output_items):
        self.buf = np.concatenate([self.buf, input_items[0]])
        i = 0
        while len(self.buf) - i >= self.n + self.fb:
            w    = self.buf[i:i+self.n]
            dist = int(np.sum(w != self.asm))          # ハミング距離
            if dist <= self.th or dist >= self.n - self.th:   # 反転ASMも許容
                inv  = dist >= self.n - self.th               # Costasのπ曖昧性(3.1.5節)
                bits = self.buf[i+self.n : i+self.n+self.fb] ^ (1 if inv else 0)
                data = np.packbits(bits)
                meta = pmt.dict_add(pmt.make_dict(), pmt.intern("inverted"), pmt.from_bool(bool(inv)))
                self.message_port_pub(pmt.intern("frames"),
                                      pmt.cons(meta, pmt.init_u8vector(len(data), data.tolist())))
                i += self.n + self.fb
            else:
                i += 1
        self.buf = self.buf[i:]
        return len(input_items[0])

class rx_top(gr.top_block):
    def __init__(self, from_usrp=False):
        gr.top_block.__init__(self, "PCM/PSK/PM RX")
        # ---- 4.3.2節の設計表がそのまま定数になる ----
        fs, rb, fsc  = 524288, 4096, 65536
        decim        = 16
        fs2          = fs // decim              # 32768 SPS
        sps          = fs2 / rb                 # = 8.0(実数でよい: 3.2.5節)
        bw_pll       = 100 / (fs  * 1.061)      # θn: 第3.1.2節の設計式
        bw_costas    = 250 / (fs2 * 1.061)
        bw_timing    = 0.02

        # ---- 信号源: 記録ファイル or USRP(第4.5章) ----
        if from_usrp:
            from gnuradio import uhd
            self.src = uhd.usrp_source(",".join(("", "")),
                uhd.stream_args(cpu_format="fc32", channels=[0]))
            self.src.set_samp_rate(fs)
            # 周波数プラン(4.5.3節): 搬送波を+25 kHzに置いてDC/LO漏れを回避
            self.src.set_center_freq(uhd.tune_request(2265.0e6 - 25e3, 200e3))
            self.src.set_gain(40)
        else:
            self.src = blocks.file_source(gr.sizeof_gr_complex, "tx_iq.bin", False)
            # 試験用に周波数誤差+雑音を注入(4.3.8節で較正計算)
            self.chan = blocks.multiply_cc()
            self.cfo  = analog.sig_source_c(fs, analog.GR_COS_WAVE, 25e3 + 137.0, 1.0)
            self.noise= analog.noise_source_c(analog.GR_GAUSSIAN, 0.917, 7)
            self.add  = blocks.add_cc()

        # ---- 前段: 周波数プラン戻し+帯域制限(第2.3章のDDC・1回目) ----
        taps_pre = firdes.low_pass(1.0, fs, 80e3, 40e3)
        self.pre = gr_filter.freq_xlating_fir_filter_ccc(1, taps_pre, 25e3, fs)
        self.agc = analog.agc_cc(1e-5, 1.0, 1.0)            # 第3.3節: 変調より遅く

        # ---- ① 搬送波PLL(残留搬送波・第3.1.4節) ----
        max_f = 2*np.pi*2e3/fs                              # 引き込み±2 kHz→rad/sample
        self.pll = analog.pll_carriertracking_cc(bw_pll, max_f, -max_f)
        self.arg = blocks.complex_to_arg()                  # φ(t)=m·d(t)·sin(ωsc·t)

        # ---- 副搬送波帯へのDDC(2回目・fcc型): 65.536kHz→0、↓16 ----
        taps_sub = firdes.low_pass(1.0, fs, 6e3, 6e3)
        self.sub = gr_filter.freq_xlating_fir_filter_fcc(decim, taps_sub, fsc, fs)

        # ---- ② 副搬送波Costas(BPSK・第3.1.5節) ----
        self.costas = digital.costas_loop_cc(bw_costas, 2, False)
        self.c2r    = blocks.complex_to_real()

        # ---- 整合フィルタ+③シンボル同期(第3.2章) ----
        self.mf   = gr_filter.fir_filter_fff(1, [1.0/8]*8)  # 積分・ダンプ相当(3.2.4節)
        self.sync = digital.symbol_sync_ff(
            digital.TED_GARDNER, sps, bw_timing, 1.0, 1.0,  # damping=1.0(やや過減衰)も常用
            1.5e-4, 1,                                      # max_dev: クロック相対誤差(3.2.6節)
            digital.constellation_bpsk().base(),
            digital.IR_MMSE_8TAP, 128, [])
        self.slicer = digital.binary_slicer_fb()

        # ---- フレーム同期→PDU ----
        self.deframe = asm_deframer()
        self.dbg     = blocks.message_debug()               # まずは印字で確認

        # ---- 接続 ----
        if from_usrp:
            self.connect(self.src, self.pre)
        else:
            self.connect(self.src, (self.chan,0)); self.connect(self.cfo, (self.chan,1))
            self.connect(self.chan, (self.add,0)); self.connect(self.noise, (self.add,1))
            self.connect(self.add, self.pre)
        self.connect(self.pre, self.agc, self.pll, self.arg, self.sub,
                     self.costas, self.c2r, self.mf, self.sync, self.slicer, self.deframe)
        self.msg_connect(self.deframe, "frames", self.dbg, "print_pdu")

if __name__ == "__main__":
    tb = rx_top(from_usrp=False)
    tb.start(); tb.wait()
全体で1画面強——「三重ループの受信機」がこの分量で書けること自体がSDRの含意である。 ファイルモードでは搬送波オフセット25 kHz + 137 Hz(USRPの周波数プランと予測残差の模擬)と 較正済み雑音(4.3.8節: σ=0.917はE_b/N₀ ≈ 9.6 dBに相当)を注入している。

4.3.6 立ち上げ手順 — 段階検収の作法

前節のコードを走らせて、いきなりフレームが取れることは期待しないほうがよい。 3つのループが縦に並んでいるので、上流のループがロックしていなければ 下流は永久に動かない。そして画面には「何も出ない」という同じ症状が出るだけで、 どこが悪いのかは分からない。

そこで信号の流れる順に、1段ずつ目で確認して蓋を閉じていく。 確認したい箇所に QT GUI Frequency SinkQT GUI Time Sink を仮に接続し、期待どおりの波形・スペクトルが 出ていることを確かめてから次へ進む(確認が済んだSinkは外してよい)。 この手順を踏めば、不具合の原因は必ず「最後に確認できた段の直後」に限定される。

下の表の「見るもの」の列が、各段での合格基準である。 自分の実装がここに書いた通りの見え方になるまで、次の段へ進まないこと。

#確認点見るものNG時の容疑者
1入力スペクトル+25 kHzに搬送波線、±65.5 kHz先に側波帯周波数プラン・レート値の引き回し(4.1.1節)
2PLLロックpll出力のComplex→Argが「搬送波の回転なし」=±m·sin波形だけ。Freq Sinkで搬送波線がDDCの0 Hzへloop_bw桁誤り・max_freq不足・AGC不調
3位相復調波形Time Sinkでφ(t)が±1.2 radの正弦波束に見えるPLL未ロックのまま進んでいる
4副搬送波DDC後0 Hz中心のBPSKスペクトル(幅±4 kHz主ローブ)fcc型のcenter符号・decim後のレート値
5Costas後コンスタレーションが実軸2点に凝縮loop_bw・order=2か・AGC基準値
6Symbol Sync後2点がさらに締まる(1標本/シンボル)。error端子が0近傍で細かく揺れるsps値・max_dev・整合フィルタ二重掛け
7デフレーマPDUが毎秒 Rb/フレーム長 ≈ 2.2枚、一連番号が連続ビット順(MSB/LSB)・極性・フレーム長不一致

この手順で「どの段まで健全か」を常に言えるようにしておくと、 実RF(第4.5章)で不調が出たときにアナログ起因かディジタル起因かを即座に切り分けられる。

4.3.7 上りコマンド回線 — 同じ骨格の別パラメータ

コマンド(アップリンク)もPCM/PSK/PM構造は同じで、パラメータ群が変わるだけである (代表値: 副搬送波 16 kHz正弦波、レート 7.8125×2^n bps系列、m ≈ 1.0 rad前後)。 送信機は4.3.3節のコードで fsc=16000, rb=2000, m=1.0 等に差し替えれば済む—— パラメータ化しておいた設計は方式ファミリ全体に使い回せる。 上り特有の追加要素はデータリンク層にある: コマンドビット列はBCH(63,56)で符号化され CLTU(開始系列EB90…+テール系列)に包まれ、変調オン→アイドル系列→CLTU…という PLOP手順で送られる(姉妹編第2.5章)。BCH/CLTU生成はビット演算なので Pythonで素直に書ける——第4.4章の自作ブロック例題として実装する。 なお実際に電波を出す前に、免許・周波数調整の確認と、终段をダミーロード/同軸直結にした 閉ループ試験(第4.5.6節)を必ず挟むこと

4.3.8 BER測定とE_b/N₀較正 — 「理論通り」を証明する

フレームが取れても、まだ「動いた」だけである。 実装が正しいことの証明は、ビット誤り率(BER)の曲線を理論値と重ねることで初めて得られる。 理論より2 dB悪い受信機は「動いてはいるが2 dB分のバグを抱えている」のであり、 その差の原因を説明できなければ設計は完成していない。

そのために必要なのがE_b/N₀の較正—— 「いま自分は何dBの条件で測っているのか」を正確に知ることである。 幸いディジタル領域では雑音も自分で作るので、全部計算できる。 較正は「式を正しく書くこと」に帰着する。

順に組み立てよう。送信信号は定包絡線なので |z| = 1、 すなわち全電力 P_T = 1 である。 雑音は Noise Source(GR_GAUSSIAN, amplitude = σ)で作るが、 ここに落とし穴がある。このσは実部・虚部それぞれの標準偏差なので、 複素雑音としての電力は 2σ² になる(第4.2.1節で急所として挙げた箇所)。 その電力が 0 から f_s に広がっているので、雑音電力密度は N₀ = 2σ²/f_s である。 一方、データが使える電力は全電力のうち 2J₁²(m) の割合。 1ビットあたりのエネルギーはそれをビットレートで割ったものなので、両者の比は次になる。

\frac{E_{b}}{N_{0}} = \frac{2 J_{1}^{2}(m) · P_{T} / R_{b}}{2σ^{2}/f_{s}} = \frac{J_{1}^{2}(m) · f_{s}}{σ^{2} R_{b}}
【例4.3-1】σの逆算と2経路検算
E_b/N₀ = 9.6 dB(= 9.12倍)を作りたい。上式から σ² = J₁²(1.2)·f_s/(9.12·R_b) = 0.2483×524288/(9.12×4096) = 3.49、σ = 1.87
検算をdB積み上げで: 2σ² = 6.97 → C/N₀ = 10log₁₀(524288/6.97) = 48.8 dBHz。 E_b/N₀ = 48.8 − 3.0(データ配分 2J₁²)− 36.1(10log R_b)= 9.7 dB ✓(丸め誤差内で一致)。 較正値は必ず2経路で検算するのが計測の作法である。 4.3.5節のコード中の σ = 0.917 は同じ式で E_b/N₀ ≈ 15.8 dB—— 4.3.2節の想定回線(C/N₀ = 55 dBHz相当)を模擬する値である。

BERカウンタは既知PN系列(または一連番号照合)で書く。フレームが取れているなら デフレーマのPDUを受けて誤りビットを数える数十行のPythonで足りる(第4.4.4節に掲載)。 測定は各E_b/N₀点で誤り100個以上集める(信頼区間±20%)。理論値 BER = ½erfc(√(E_b/N₀)) との差が実装損失の実測値であり、 0.5〜1.0 dB以内に収まれば本章の設計は合格である。内訳(整合フィルタ近似 0.1、 ループジッタ 0.2、量子化ほか 0.1…)は第1.3.8節・第5.3章の損失バジェットと突き合わせる。

Q. 副搬送波の復調に「もう1つPLL」を使う流儀もあると聞くが?

ある。方形波副搬送波の時代は専用の副搬送波トラッキングループ(Costasの変形)が 定番だった。正弦波副搬送波BPSKは「±f_scに現れる抑圧搬送波BPSK対」なので、 本章のように片側をDDCで抜き出してCostasに掛けるのが現代的で部品も少ない。 両側波帯を合成して3 dB稼ぐ精密実装(上下のDDC出力を共役合成)もあり、 これは読者への発展課題とする(演習4.3-2)。

Q. 畳み込み符号・RS符号はどこに入れるか?

送信はフレーム生成(make_frames.py)とNRZ化の間に符号化を挿す。 受信はデフレーマの手前がハード判定になっている本章の構成を、 Slicerを外して軟判定値のままViterbi復号器へ渡す構成に改造する(軟判定で約2 dB得)。 gr-satellitesのCCSDSデフレーマ(畳み込み+RS一式内蔵)に差し替えるのが早道で、 その接続例は第5.3章のウォークスルーで示す。

章末演習

【演習 4.3-1】パラメータ改造
同じコードベースで「f_sc = 32.768 kHz・Rb = 2048 bps・m = 1.0」の系を作るには、 どの定数をどう変えればよいか。ループ帯域の再計算まで含めて列挙せよ。
解答
fsc = 32768, rb = 2048(16サイクル/ビット維持)、m = 1.0(J₀² = −2.3 dB, 2J₁² = −4.1 dB)。 f_s = 524288のままなら sps_bit = 256、decim = 16でfs2 = 32768、sps = 16。 ループ: P_c/N₀ = 52.7 dBHz → B_n = 100 HzでOK(ρ = 29.7 dB)。 Costas入力P_d/N₀ = 50.9 dBHz → B_n = 250 Hzでρ = 23.9 dB OK。 θ_n再計算: bw_pll不変、bw_costas不変(fs2同じ)、Symbol Syncはsps = 16に変更。 整合フィルタは[1/16]*16に。設計表→定数→検収の3点セットで完結することを確認してほしい。
【演習 4.3-2】両側波帯合成(発展)
±f_scの両側波帯をそれぞれDDCで取り出し、共役合成してからCostasに入れる改造を設計せよ。 得られる利得と、合成前に必要な位相条件を述べよ。
解答
上側 z₊(+f_scをDDC)と下側 z₋(−f_scをDDC)はデータ成分が複素共役の関係にあるので、 z₊ + z₋* で電圧加算=信号電力4倍・雑音電力2倍で+3 dB(片側のみに対し)。 条件は2経路のDDCフィルタが同一特性・同一群遅延であること(同じtapsを使えば自動的に満たす)。 本章の片側実装はデータ電力の半分しか使っていない——4.3.8節のBER実測が理論より 3 dB劣って見えた読者は、ここに気づけたかを振り返ること(E_b定義を片側で取れば整合する)。
■ まとめ
  • PCM/PSK/PM = 残留搬送波PM×正弦波副搬送波BPSK。z = exp(jm·d·sin ω_sc t)、配分はJ₀²/2J₁²。
  • 実装の順序は 設計表(レート・電力配分・3ループのB_nとθ_n)→ コード → 段階検収。
  • 送信はPhase Modulator1個が核。受信はDDC×2回+PLL/Costas/SymbolSyncの三重ループ+自作デフレーマ。
  • atan2位相復調でm大でも厳密。副搬送波は片側DDC+Costasが現代的(両側合成で+3 dB)。
  • 検収の頂点はBER曲線と理論の重ね合わせ。E_b/N₀はディジタル較正(N₀ = 2σ²/f_s)で正確に作れる。

第4.4章自作ブロックとOOTモジュール

■ この章で学ぶこと
既製ブロックで足りない部品——規格特有のフレーマ、計測ロジック、独自アルゴリズム——を自作する技術。 Pythonブロックの完全な作法(work関数・タグ・メッセージ)、実用例としてBERカウンタと CCSDS TC系のBCH(63,56)+CLTUエンコーダを実装し、C++/OOT化と単体試験まで。 研究の独自性は必ずここに宿る——既製品の組み合わせで済む研究は既に誰かがやっている。

4.4.1 拡張の3段階 — どこに書くか

手段特徴使いどころ
Embedded Python Block(GRC内蔵)GRCのブロックとしてその場に書ける。ファイル管理不要試作・1回きりの計測ロジック。第4.3章のデフレーマ級まで。
Python OOTモジュールgr_modtoolで独立パッケージ化。GRCメニューに載り、再利用・配布可研究室の共通部品。フレーマ・計測器・規格実装。
C++ OOTモジュール本気の性能。VOLK(SIMD)も使える高レートの実時間経路。Pythonで検証してから移植する。

鉄則は「Pythonで正しく→測って→遅い所だけC++」。 NumPyでベクトル化されたPythonブロックは意外に速く(次節)、 本書の受信機規模(数百kSPS)なら全段Pythonでも実時間に収まることが多い。

4.4.2 ブロックの解剖 — work関数の契約

ブロックの本体は「入力配列を受け、出力配列を書き、処理した個数を返す」workメソッドである。 基底クラス(第4.1.2節)ごとに契約が異なる。

import numpy as np
from gnuradio import gr

class my_block(gr.sync_block):                      # 1:1レートならsync_block
    def __init__(self, gain=1.0):
        gr.sync_block.__init__(self,
            name="my_block",
            in_sig=[np.complex64],                  # 入力ポートの型リスト
            out_sig=[np.complex64])                 # ([]にすればシンク/ソース)
        self.gain = gain                            # パラメータは属性に。GRCから
                                                    # set可にするならセッタを書く
    def work(self, input_items, output_items):
        inp = input_items[0]                        # NumPy配列(長さは可変!)
        output_items[0][:] = self.gain * inp        # ★必ずベクトル演算で書く
        return len(output_items[0])                 # 生産した標本数を申告

要点は3つ。(1) 長さは毎回違う。スケジューラの都合で数百〜数万標本が来る。 呼び出し間で状態を持つ処理(フィルタ・ループ・デフレーマ)は、 端数を自分でバッファリングする(第4.3.5節のデフレーマの self.buf がその実例)。 (2) ベクトル化は義務。Pythonのforループで1標本ずつ回すと100倍単位で遅くなり、 実時間経路では即オーバーフローする。NumPyの配列演算・np.convolve・ ブールマスクで書き切る。ループが本質的に逐次な処理(PLL)はPython試作までとし、実時間はC++へ。 (3) レート比が固定でないならgeneralgr.basic_block を継承し general_work()consume()/生産数を自己申告する (デフレーマ類は入力を消費しつつ出力はPDUなのでsync_block+メッセージで足りることも多い)。

4.4.3 タグとメッセージのAPI

    # --- タグを読む(work内・入力0番の今回ウィンドウ分) ---
    n0 = self.nitems_read(0)
    tags = self.get_tags_in_window(0, 0, len(input_items[0]), pmt.intern("rx_time"))
    for t in tags:
        offset_in_win = t.offset - n0               # 絶対標本番号→今回配列内の位置
        value = pmt.to_python(t.value)

    # --- タグを打つ(出力0番のk番目の標本に) ---
    self.add_item_tag(0, self.nitems_written(0) + k,
                      pmt.intern("frame_start"), pmt.from_long(fn))

    # --- メッセージポート(__init__で登録、ハンドラで受ける) ---
    self.message_port_register_in(pmt.intern("in"))
    self.set_msg_handler(pmt.intern("in"), self.handle)   # 任意時刻に呼ばれる
    self.message_port_register_out(pmt.intern("out"))
    self.message_port_pub(pmt.intern("out"), pmt.cons(meta, data))  # PDU送出

タグは標本に紐づく情報(時刻・フレーム位置)、メッセージは標本と独立な情報(制御・フレーム) ——第4.1.3〜4.1.4節の設計語法をそのままAPIで書いているだけである。

4.4.4 実用例1 — フレームBERカウンタ

第4.3章の受信機のPDUを受け、送信に使った frames.bin と突き合わせて BER・フレーム欠落を数える計測ブロック。ストリームを持たない「メッセージだけのブロック」の 見本でもある。

class frame_ber(gr.sync_block):
    """PDUを既知フレームと照合しBER/欠落を集計(4.3.8節の測定器)"""
    def __init__(self, ref_file="frames.bin", flen=223):
        gr.sync_block.__init__(self, "frame_ber", [], [])   # ストリームなし
        raw = open(ref_file, "rb").read()
        step = 4 + flen                                     # ASM+payload
        self.ref = {}                                       # 一連番号→ビット配列
        for i in range(0, len(raw), step):
            p = np.frombuffer(raw[i+4:i+step], np.uint8)
            self.ref[int.from_bytes(p[:2], "big")] = np.unpackbits(p)
        self.bits = self.errs = self.frames = 0
        self.last_seq = None
        self.message_port_register_in(pmt.intern("pdus"))
        self.set_msg_handler(pmt.intern("pdus"), self.handle)
    def handle(self, msg):
        p   = np.array(pmt.u8vector_elements(pmt.cdr(msg)), np.uint8)
        seq = int.from_bytes(p[:2].tobytes(), "big")
        if seq in self.ref:
            e = int(np.sum(np.unpackbits(p) != self.ref[seq]))
            self.frames += 1; self.bits += len(p)*8; self.errs += e
            if self.last_seq is not None:
                lost = (seq - self.last_seq - 1) % 2000
                if lost: print(f"[gap] {lost} frame(s) lost")
            self.last_seq = seq
            if self.frames % 100 == 0:
                print(f"frames={self.frames}  BER={self.errs/max(self.bits,1):.2e}")
    def work(self, input_items, output_items):
        return 0
受信機側は self.msg_connect(self.deframe, "frames", self.ber, "pdus") と 1行つなぐだけ。誤り100個集まるまで回す(第4.3.8節の統計則)。

4.4.5 実用例2 — BCH(63,56)+CLTUエンコーダ(コマンド上り)

第4.3.7節のコマンド回線に必要な、TCフレーム→CLTUの変換器。CCSDS TC同期・符号化層 (JERG-2-401が参照する構造)のBCH(63,56)は、56情報ビットに7パリティ(生成多項式 g(x) = x⁷+x⁶+x²+1、パリティは反転して付加)+フィラービット0で64ビットのコードブロックを作る。

START_SEQ = bytes.fromhex("EB90")
TAIL_SEQ  = bytes.fromhex("C5C5C5C5C5C5C579")     # 復号器を確実に脱同期させる終端

def bch_codeblock(info56):                         # info56: 56ビットのnumpy配列(0/1)
    reg = np.zeros(7, np.uint8)                    # シフトレジスタ実装
    for b in info56:                               # g(x)=x^7+x^6+x^2+1
        fb = b ^ reg[6]
        reg[1:] = reg[:-1]                         # シフト
        reg[0] = fb
        reg[2] ^= fb
        reg[6] ^= fb
    parity = reg[::-1] ^ 1                         # 反転パリティ(規格)
    return np.concatenate([info56, parity, [0]])   # +フィラー → 64ビット

def make_cltu(tc_frame: bytes) -> bytes:
    bits = np.unpackbits(np.frombuffer(tc_frame, np.uint8))
    pad  = (-len(bits)) % 56                       # 56の倍数へ充填(規格の充填則に従う)
    bits = np.concatenate([bits, np.zeros(pad, np.uint8)])
    blocks_ = [bch_codeblock(bits[i:i+56]) for i in range(0, len(bits), 56)]
    body = np.packbits(np.concatenate(blocks_)).tobytes()
    return START_SEQ + body + TAIL_SEQ
これをPDU入出力のブロック(4.4.4節と同型)に包めば、 「TCフレームPDU → CLTU PDU → PDU to Tagged Stream → 4.3.3節の送信機」で コマンド送信系が閉じる。シフトレジスタ符号器はビット逐次だが、コマンドは低レートなので Pythonで十分間に合う——「どこまでPythonでよいか」の判断(4.4.1節)の実例である。 検証は規格書の試験ベクトル(既知フレーム→既知CLTU)との照合で行うこと。

4.4.6 OOT化と単体試験

再利用する部品は gr_modtool でOOT(Out-Of-Tree)モジュールに昇格させる。 gr_modtool newmod deepspacegr_modtool add -t sync -l python asm_deframer で 雛形(実装・GRC用YAML・試験ファイル)が生成され、実装を移植してビルドすれば GRCのブロック一覧に現れる。C++版(-l cpp)はwork関数をC++で書き、 内側のホットループにVOLKカーネル(SIMD最適化済み演算集)を使う。

昇格の対価として単体試験を書く。GNU Radioの流儀は「小さなフローグラフを組んで流す」:

from gnuradio import gr, gr_unittest, blocks
class qa_asm_deframer(gr_unittest.TestCase):
    def test_finds_inverted_frame(self):
        tb   = gr.top_block()
        bits = make_test_bits(invert=True, nerr=3)      # 反転+3ビット誤りでも取れるか
        src  = blocks.vector_source_b(bits)
        dut  = asm_deframer(thresh=3)
        sink = blocks.message_debug()
        tb.connect(src, dut); tb.msg_connect(dut, "frames", sink, "store")
        tb.run()
        self.assertEqual(sink.num_messages(), 1)        # 境界条件を試験で固定する

同期器・フレーマの類は「誤り0で通る」だけでなく閾値の境界・反転・端数バッファまたぎで 試験する。研究コードの信頼性は、論文の再現性そのものである。

Q. Embedded Python Blockのコードはどこに保存されるのか?

GRCファイル(.grc)の中に文字列として埋め込まれる。便利だが版管理・再利用に不向きなので、 育ってきたブロックは早めに.pyファイル→OOTへ移すこと。「.grcの中にしか存在しない重要コード」は 研究室の技術負債の典型である。

Q. PLLのような逐次ループはPythonでは書けないのか?

書けるが遅い(1標本ずつのforになるため)。オフライン解析なら問題ない—— 記録IQをNumPyで読み、本書第3.1.1節の4行ループを回して位相を抜くのは研究の常套手段である。 実時間で必要なら既製ブロック(C++実装)を使うか、自作をC++化する。 「オフラインはPython、実時間はC++」と役割を分ければ大半の研究はPythonで完結する。

■ まとめ
  • Embedded→Python OOT→C++の3段階。Pythonで正しく、測って、遅い所だけC++。
  • work契約: 可変長・状態は自前バッファ・ベクトル化義務。レート可変ならgeneral_work。
  • タグ=標本の付箋、メッセージ/PDU=非同期データ。APIはnitems_read/add_item_tag/msg_handler。
  • BERカウンタ・BCH/CLTUエンコーダ程度は数十行のPythonで書ける——規格実装を自分の手に。
  • OOT化したら単体試験(境界・反転・端数)を書く。再現性は研究の生命線。

第4.5章USRPでRF区間を張る

■ この章で学ぶこと
第4.3章の変復調系を実RFに接続する。UHDドライバの設定体系(レート・同調・利得・クロック)、 残留搬送波方式ならではの周波数プラン、外部基準とタイムスタンプ、 そして送受を同軸で閉じるループバック試験の完全な手順。 「ファイルで動く」と「電波で動く」の間にある溝を、すべて名前を付けて埋める。
◇ 直観でつかむ — USRPは「アンテナとPCの間の変換器」
USRPがやることは2つだけである: 電波をIQの数列に変えてPCへ送る(受信)、 PCから来たIQの数列を電波にする(送信)。中身は本書第I・II部そのもの—— 増幅器・ミキサ・ADC/DAC・FPGA内のDDC/DUCが箱に収まっている。 GNU Radioから見れば UHD SourceUHD Sink という 「ファイル入出力の代わりに空とつながっている口」に見える。
実機で新しく気にすることは3つに集約される: ①レートは自由に選べない(内部クロックの整数分の1)、 ②0 Hz付近が汚れているので信号をそこに置かない、③外部の正確なクロックを繋ぐと 通信機が計測器になる。本章はこの3点の具体策である。

4.5.1 レートの決め方 — マスタクロックとの整合

実機で最初にぶつかる壁がこれである。 USRPの標本化周波数は、望んだ値を自由に設定できない。

理由は装置の構造にある。USRPの中でADCとDACを駆動しているのは マスタクロック(MCR, master clock rate)と呼ばれる1つの発振源であり、 ホストに渡す標本化周波数は、そのMCRを内部のDDC/DUCで整数分の1に間引いて作られる。 したがってMCRの整数分の1にあたる値しか正確には出ない。 それ以外の値を要求すると、UHDドライバは最も近い実現可能な値に丸め、 警告メッセージを出す(見落としやすいので必ず読むこと)。

ここで規格側との衝突が起きる。通信規格のレート体系は 4096 bps のように 2のべき乗を基本とするのに対し、装置のクロック体系は 100 MHz のように 10の倍数系で作られていることが多い。両者は整数比で結ばれない。

系列MCRf_s = 524.288 kSPSを作るには
B200/B210可変(〜61.44 MHz)デバイス引数 master_clock_rate=16.777216e6 を指定 → ÷32で厳密に524.288k。可変MCRは2のべき系レートと相性が良い
N210100 MHz固定100M/524288は非整数→作れない。500 kSPS(÷200)で受け、sps = 7.63の非整数で復調する(第3.2.5節: Symbol Syncは実数spsを追える)か、ホストでPolyphase Resampler(第2.4.4節)を挟む。
X310/N310系200 MHz等同上の考え方。計測級は外部基準前提(4.5.4節)。

表のとおり、解は2つしかない。①MCRを規格側に合わせて設定する (B200系のようにMCRが可変な機種で可能。2のべき系のMCRを選べば厳密に一致する)か、 ②非整数比のまま同期器に吸収させる(第3.2.5節の通り、 Symbol Sync は実数のspsを扱えるので原理的に問題ない)か。

どちらでも動作するが、どちらを選んだかを設計書に明記すること。 ②を選んだ場合、シンボル同期の許容偏差(max_deviation)の設定に その分の余裕が必要になるので、後から見て判断できるようにしておく必要がある。

4.5.2 Source/Sinkの設定項目を総なめする

from gnuradio import uhd
src = uhd.usrp_source(
    "type=b200,master_clock_rate=16.777216e6",      # デバイス引数
    uhd.stream_args(cpu_format="fc32",              # ホスト側の型: fc32=complex64
                    otw_format="sc16",              # 線上の型: 16bit整数(帯域半減)
                    channels=[0]))
src.set_samp_rate(524288)
print(src.get_samp_rate())                          # ★実際に設定された値を必ず読み戻す
src.set_center_freq(uhd.tune_request(2265.0e6 - 25e3, 200e3))   # 4.5.3節
src.set_gain(40)                                    # 第一層利得(第3.3.1節: 運用中固定)
src.set_antenna("RX2")
src.set_bandwidth(400e3)                            # アナログAAF帯域(第1.2.3節の実物)

読み戻し確認(get_*)を習慣にする。丸め・上限クリップは黙って起きるからである。 otw_format=sc16 は伝送量を半分にする(第2.5.2節)が、8ビット(sc8)まで落とすときは 第1.3章のダイナミックレンジ議論に立ち戻って判断する。利得は較正試験(4.5.6節)で 「雑音床がADC量子化床より10〜15 dB上」に来る値を決め、以後固定する。

4.5.3 周波数プラン — 残留搬送波をDCの汚れから守る

本章でもっとも実害の大きい落とし穴がこれである。知らずに組むとまず動かない。

USRPのB2xx系はゼロIF構成(第2.2.2節)である。 第2.1.5節で学んだとおり、ゼロIFのベースバンド0 Hz付近には DCオフセット・LO漏れ・フリッカ雑音という3つの汚れが住んでいる。 ところがPCM/PSK/PMで真っ先に掴まねばならないのは、 スペクトルの中心にぽつんと立つ残留搬送波の細い線である。 素直に「搬送波の周波数にチューンする」と、その線を いちばん汚い場所に置くことになる

さらに悪いことに、UHDには自動DC除去機能(set_auto_dc_offset)があり、 これは0 Hzにノッチ(切り欠き)を掘って直流成分を消す。 搬送波を0 Hzに置いていると、この自動較正が自分の搬送波を削り取ってしまう。 「PLLがロックしない」「搬送波が見えたはずなのに消えた」という症状の典型的な原因である。

処方は第2.1.5節で予告した周波数プランである。次の3点セットで組む。

設定値(4.3章の受信機)意図
チューン中心f_c − 25 kHz搬送波がベースバンドの+25 kHzに現れ、DC汚染帯(±数kHz)から退避。
lo_offset+200 kHzLO実体をさらに外へ。LO漏れは+200 kHz付近に現れ、信号帯(+25k±74k)の外。
ホストDDCXlating FIRで−25 kHzディジタルで厳密に0 Hzへ戻す(第2.3章)。数値NCOなので汚れは持ち込まない。

この3点セット(機体側チューン・LO退避・ホスト戻し)が、 ゼロIFデバイスで狭帯域の残留搬送波方式を扱う定石の周波数プランである。 IFサンプリング構成の地上局(第2.2.1節)ではこの問題自体が存在しない—— アーキテクチャ選定が運用の面倒を先に消している例として対比しておきたい。

4.5.4 クロック・時刻・確度 — 通信と計測の分水嶺

ここが「通信機として使う」と「計測器として使う」の分かれ目である。

まず現実を数字で見る。USRPに内蔵されているTCXO(温度補償水晶発振器)の 周波数確度は±2 ppm程度である。搬送波2.2 GHzに対して2 ppmは ±4.4 kHz——第4.3.5節の受信機で設定したPLLの引き込み範囲±2 kHzを 軽く超えてしまう大きさである。 つまり内蔵クロックのままでは、そもそもロックしない可能性がある。 対策は3つ: ①FFTによる粗推定を前置する(第3.1.6節)、 ②引き込み範囲を広げる(雑音耐性を犠牲にする)、 ③外部基準を接続する。

そして周波数・位相・時刻を測る用途(ドップラ計測、オープンループ記録)では、 ③が必須である。第1.4.4節で述べた「純度の鎖」の出発点を、 USRPの内蔵発振器から局の基準に差し替える操作にあたる。設定は次の数行で済む。

src.set_clock_source("external")     # 10 MHz基準(局標準/GPSDO/ルビジウム)
src.set_time_source("external")      # 1PPS
src.set_time_unknown_pps(uhd.time_spec(0.0))   # 次のPPS立ち上がりでt=0に揃える
# 受信ストリーム先頭にはタグ rx_time=(整数秒, 小数秒) が付く(第2.5.4節)
# 時刻指定コマンド: 指定時刻に同調を実行(掃引・周波数切替の決定論化)
src.set_command_time(uhd.time_spec(t_next))
src.set_center_freq(uhd.tune_request(f_next))
src.clear_command_time()

外部10 MHzに繋ぐと搬送波確度は基準並み(GPSDOで10⁻¹¹級)になり、 ドップラ計測・オープンループ記録(第5.2章)・複数USRPの位相コヒーレント運用が視野に入る。 「同じUSRPが、基準を繋いだ瞬間に通信機から計測器に変わる」—— 第1.4章のクロック論はこの1行のためにあった。

4.5.5 送受同時運用 — 試験治具としてのUSRP

B210/X310は全二重なので、1台で「地上局送信+機上受信(またはその逆)」の 対向試験が組める。第4.3章のTX/RXフローグラフを同一プロセスに同居させ、 TXポート→(減衰器)→RXポートを同軸で結べば、変復調系一式の閉ループ試験環境になる。 応用として、受信搬送波に定数比を掛けて送り返す簡易ターンアラウンド模擬 (姉妹編第2.3.6節のコヒーレント動作の教材版)も、受信PLLの周波数出力をTX側NCOに メッセージで渡すことで実装できる——ただしホスト経由のループはレイテンシが大きく (第2.5.5節)、位相コヒーレンスの厳密な模擬はFPGA実装の領分であることは弁えておく。

4.5.6 ループバック試験 — 手順書

安全と法規が先: アンテナを繋いだ送信は免許・実験局手続きの世界である。 開発はすべて同軸ケーブル+減衰器で閉じる。USRPのTX最大出力(+10 dBm級)を RX許容入力(歪みなく受けられるのは−20〜−30 dBm程度から下)に合わせ、 30〜40 dBの固定減衰器を必ず挟む(直結はフロントエンドを痛め得る)。

手順やること合格判定
1. 物理結線TX/RX→40 dB減衰器→RX2。基準10 MHz/1PPSを分配(あれば)
2. トーン試験TXから無変調搬送波、RXはFrequency Sinkのみ+25 kHz(プラン通り)にトーン。周波数誤差が基準の有無と整合(±数Hz/±数kHz)
3. レベル調整TX利得・RX利得を掃引RX信号−30 dBFS前後、雑音床が量子化床+10 dB以上(第1.3.5節)、「O」なし
4. 変調オン4.3.3節TX起動スペクトルが4.3.3節の理論形(搬送波+±65.5k側波帯+3次高調波)
5. 復調4.3.5節RX起動、段階検収表4.3.6を上から全7段クリア、フレーム連続受信
6. 性能測定TX利得を下げてE_b/N₀を振り、frame_ber(4.4.4節)でBER測定理論曲線+実装損失1 dB以内。これで初めて「実装完了」と言える

手順6の実RF版E_b/N₀較正は、ディジタル較正(第4.3.8節)と違い雑音がフロントエンド由来なので、 SNR推定(信号断で雑音電力、信号ありで信号+雑音電力を測る断続法)で実測する。 ディジタル注入で作ったBER曲線と実RFのBER曲線を重ねれば、 RF区間そのものの劣化寄与が分離できる——研究データとして最も価値のある1枚になる。

4.5.7 実運用の落とし穴表

症状正体と処方
端末に「O」オーバーフロー(第2.5.3節)。レート・GUI・タップ数を疑う。USBなら給電・ハブ・ケーブルも。
端末に「U」「L」送信アンダーフロー/タイムスタンプ遅刻(time_specが過去)。送信バッファ・時刻設定を確認。
再同調のたび位相が飛ぶLO再ロックによる正常挙動。位相連続が要る計測はホストNCO側で周波数を動かす(第3.4.2節)。
起動直後だけ波形が暴れるDC較正・AGC・PLLの過渡。冒頭数秒を捨てる(記録解析でも同じ作法)。
スペクトルに謎の櫛・スパイクUSB由来のスプリアス・LO漏れ・イメージ(第2.1.5節)。周波数プランの再点検とフェライト・電源分離。
2台のUSRPで周波数が微妙に合わないそれが±2 ppmの現実(4.5.4節)。外部基準を分配するか、受信側の捕捉範囲に織り込む。
Q. X帯やS帯の実周波数で試験したいが、USRPの上限を超える場合は?

トランスバータ(外部のアップ/ダウンコンバータ)でUSRPのカバー範囲と 目的帯を橋渡しするのが定石である。このときの周波数変換・位相雑音・利得配分の設計は 姉妹編第4.4章(給電系とRFフロントエンド)の領分で、本書のディジタル設計とは LNA/ミキサ込みの雑音温度とIF周波数プランの2点で接続する。

Q. 実衛星・実探査機の電波で検証するには?

受信だけなら免許不要である。学習順として、①強力で常時居るGEO衛星のビーコン、 ②アマチュア衛星のテレメトリ(gr-satellitesに多数の既製デコーダ)、 ③深宇宙機の下り(大口径が要るが、強い機体をアマチュア深宇宙受信の実績局が捉えている)と 段階を踏むのがよい。本章のループバックで較正した受信機をそのまま空に向ける—— その瞬間に本書の全章が1本につながる。

■ まとめ
  • f_sはMCRの整数分の1しか出ない。MCRを合わせるか、非整数spsを同期器に飲ませる。設定は必ず読み戻す。
  • ゼロIFの定石プラン: チューンをずらして搬送波を+25 kHzへ、LOはlo_offsetでさらに外へ、ホストDDCで戻す。自動DC除去のノッチに搬送波を食わせない。
  • 外部10 MHz+1PPSで通信機が計測器になる。時刻指定コマンドで運用が決定論化する。
  • 試験は同軸+30〜40 dB減衰器で閉じ、トーン→レベル→変調→復調→BERの6段手順で進める。
  • 実RFのBER曲線とディジタル較正曲線の差分がRF区間の劣化——最重要の研究データ。
第 V 部 宇宙システムへの展開
実験室で完成した変復調系を、探査機に載せ、局に据え、ミッションの設計プロセスに組み込む。放射線とFPGA、オープンループ記録という深宇宙の切り札、そして回線設計からBER実測までを一気通貫でやり切る設計ウォークスルー。

第5.1章機上SDR — 探査機に載せる

■ この章で学ぶこと
地上で自由に組めたSDRを宇宙機に載せるとき、何が変わるのか。放射線環境とFPGAの対策、 耐放射線部品の制約下での設計術、飛行実績のあるSDRトランスポンダの構成、 そして「書き換えられる無線機」の運用・品質保証上の意味を学ぶ。

5.1.1 何が地上と違うのか

搭載SDRの設計制約は4つの軸で地上と異なる。①放射線(次節)、 ②電力・熱(トランスポンダに割ける電力は数W〜十数W。GSPS級ADCやGPUは論外)、 ③部品選択(宇宙用実績のあるデバイスのみ。第1.5.6節の通り民生比1〜2世代遅れ)、 ④修理不能(打上げ後はソフトウェア更新だけが唯一の介入手段——これがSDR化の動機でもある)。 結果として搭載SDRは「控えめなf_s・少ないビット・FPGA中心・帯域通過標本化を多用」という、 第I部の理論を限界まで使う設計になる。

5.1.2 放射線とディジタル回路 — 故障モードの語彙

効果機構SDRへの現れ方対策
TID(トータルドーズ)累積電離損傷で閾値電圧がドリフトADCのENOB劣化・リーク増・最終的な機能喪失耐性部品の選定・遮蔽・寿命末期性能での回線設計
SEU(シングルイベントアップセット)荷電粒子1発でビット反転FPGAコンフィギュレーションRAMの化け=回路そのものが変形する。レジスタ・メモリの化けスクラビング(構成メモリの巡回再書込み)、TMR(三重化多数決)、EDAC付きメモリ
SEL(ラッチアップ)寄生サイリスタ点弧で過電流デバイス焼損の恐れ耐SEL部品・電流監視と高速遮断
SEFI(機能割込み)制御ロジックの一時故障ADC/PLL等の設定飛び・出力停止ウォッチドッグと再初期化シーケンス

表のうちSEUが搭載SDRにとって最も厄介である。理由を説明する。 FPGAは「どの回路をどう配線するか」という情報を内部のメモリ(構成メモリ)に持っており、 そのメモリが放射線でビット反転すると、回路そのものが別のものに変わってしまう。 計算結果が1つ狂うのではなく、装置の設計図が書き換わるのである。

そのためFPGAの種類選定が信頼性設計の核心になる。3種類の性質を押さえてほしい。

アンチヒューズ型は、製造時に配線を物理的に焼き切って固定する方式である。 配線が物理構造なので放射線で化けることがなく、最も堅牢。 ただし一度焼いたら変更できないので、SDRの利点である書き換えができない

フラッシュ型は構成情報を不揮発メモリに持つ方式で、SEUに強く、書き換えも可能。 中規模の搭載SDRの定番である。

SRAM型(宇宙用グレード品)は最大の規模と性能が得られるが、 構成メモリが揮発性のSRAMなので化ける。そのため スクラビング(構成メモリを定期的に読み直し、正しい内容を書き戻す巡回処理)と TMR(Triple Modular Redundancy: 同じ回路を3個作って多数決を取る)を 前提とした設計・運用が必須になる。

ミッションの規模、必要な処理能力、信頼性要求の兼ね合いで選ぶ—— ここは通信系の設計者が単独で決められる事項ではなく、 信頼性・部品・熱の各担当との協議事項になる。

5.1.3 搭載SDRトランスポンダの構成

典型構成は「アナログでIFへ→中速ADCで帯域通過標本化→FPGAでDDC・変復調・符号—— 本書第I〜III部の教科書通り」である。コヒーレント・ターンアラウンド(姉妹編第2.3.6節)も ディジタルで実現される: 受信搬送波を追うPLL(第3.1章)の周波数語(NCOの積分器!)に ターンアラウンド比 880/749 を数値で乗じて送信NCOを駆動する。 アナログ時代に逓倍器の連鎖で作った位相コヒーレンスが、レジスタ演算1つに置き換わる—— ただし数値精度(第2.3.2節の周波数分解能)と処理遅延の一定性が計測品質を決めるため、 この経路だけはFPGA内で完結させ、ソフトウェア(CPU)を経由させないのが鉄則である。

飛行実績の例を挙げる。Electra(JPL): 火星周回機搭載のUHF中継SDR。 着陸機ごとに異なるプロトコルへ軌道上でファームウェア更新により対応してきた、 「書き換えられる価値」の実証例(第1.1.3節)。Iris(JPL): 超小型機向け深宇宙トランスポンダ。 X帯送受・DSN互換の計測(コヒーレントドップラ・測距)を約1リットル級で実現し、 MarCO(火星フライバイの6Uキューブサット)で深宇宙飛行実証。 いずれも「1つのハードウェア設計+ミッション別ソフトウェア」という搭載SDRの標準形を確立した。 JAXA系でも小型機・深宇宙機のトランスポンダはディジタル化が進んでおり、 設計標準(JERG-2-401系)への適合を機上ソフトウェアで実現する流れは同じである。

5.1.4 「書き換えられる」ことの品質保証

SDRの柔軟性は、品質保証の問いを裏返す: 「何を書き換えてよいか」を設計時に決めておく 必要がある。実務では①パラメータ更新(レート・変調指数・ループ帯域——検証済み範囲内の数値変更)、 ②テーブル更新(符号・フレーム定義)、③ロジック更新(FPGAビットストリーム)の3階級に分け、 階級ごとに検証プロセスと運用手順を定める。③はリスクが桁違いに大きく、 地上の同一品(エンジニアリングモデル)での全数回帰試験+二重化(旧イメージへの復帰手段の常時確保)が 前提になる。第4.4.6節で「研究コードにも単体試験を」と説いたのと同じ思想の、これが最終形である。

Q. 搭載SDRでもGNU Radioは使えるのか?

フライト品の実時間経路には使わない(汎用OS+動的メモリの塊は搭載品質にならない)。 しかし開発では大活躍する: アルゴリズム検証・地上支援装置(EGSE)・対向試験治具は GNU Radioで組むのが速く、FPGA実装の照合基準(ゴールデンモデル)として 本書第4.3章の受信機がそのまま使える。「フライトはFPGA、検証はGNU Radio」が現代の分業である。

■ まとめ
  • 搭載SDRは電力・部品・放射線・修理不能の制約下で、少ビット×帯域通過標本化×FPGAの設計になる。
  • 放射線の語彙: TID(劣化)・SEU(ビット化け→スクラビング/TMR)・SEL(焼損)・SEFI(機能飛び)。FPGAの型式で対策思想が変わる。
  • コヒーレント・ターンアラウンドはNCO周波数語の数値演算。FPGA内で完結させる。
  • Electra・Irisが確立した「共通ハード+ミッション別ソフト」が標準形。
  • 書き換え可能性には階級別の品質保証(パラメータ/テーブル/ロジック)を設計時に定義する。

第5.2章地上局のSDR化とオープンループ記録

■ この章で学ぶこと
現代の深宇宙地上局の受信系がどうSDR化されているか、そして深宇宙ならではの切り札 オープンループ記録——復調せずIQのまま録る——の技術と使いどころ。 大学・研究室スケールでUSRPを使って同じ構造を作る方法まで。

5.2.1 局のディジタル受信系 — クローズドループとオープンループ

深宇宙地上局の受信系は、目的の異なる2種類の受信機からできている。 名前と役割を対比して覚えてほしい。

クローズドループ受信機は、本書第4.3章で作ったものの業務用版である。 「クローズドループ」とは同期ループを閉じて動かすという意味で、 リアルタイムに搬送波とシンボルに同期し、テレメトリのビット列と 計測データ(ドップラ・測距値)を出力する。日常の運用はこちらが担う。

オープンループ受信機は、同期を一切行わない。 予測周波数を中心に必要な帯域を切り出し、IQサンプルをそのままディスクに記録するだけである。 ループを閉じないから「オープンループ」と呼ぶ。 復調は後から、何度でも、別のアルゴリズムでやり直せる。

両者はアンテナ・低雑音増幅器・IFへの周波数変換までを共用し、 IFをディジタル化した後で分岐する。 つまり現代の局における「受信機」の実体は、 1つの共通ディジタイザの出力を、複数のDDC(第2.3章)が並列に食う構造である。 1本のIF信号から、テレメトリ復調用のDDC、計測用のDDC、記録用のDDCが同時に走る。 本書第II部で学んだSDRアーキテクチャが、そのまま局のブロック図になっている姿と言える。

5.2.2 オープンループ記録の技術要素

要素設計上の要点本書の該当章
帯域と量子化予測±不確かさ+信号帯域で帯域を決め、雑音支配なら2〜8ビットで十分(2ビットで損失0.55 dB)第1.3.6節
時刻局の水素メーザ/基準系に位相同期したクロックと、標本番号への時刻タグ。これが無いと計測に使えない第1.4.6節・第2.5.4節
周波数プラン記録中心周波数と予測ドップラの履歴をメタデータに残す(無いと後処理で位相が再構成できない)第3.4.4節
データ量f_s×ビット幅×時間。演習1.3-2の算術。ディスク書き切り優先で「O」を出さない設計第2.5.3節
フォーマットメタデータ標準: SigMF(SDR界の標準。JSONメタ+生IQ)、VDIF(VLBI系の標準)。自己流バイナリは数年後の自分が読めない

使いどころは「一発勝負」と「後から別の問いを立てたい場面」である: 着陸・軌道投入などのクリティカルイベント(失敗しても波形が残り原因解析できる)、 電波科学(掩蔽で大気を測る——受信位相そのものがデータ)、ΔDOR(複数局の記録を相関処理)、 微弱信号の探索(セーフモード機体の捜索)。「復調は後からいくらでもやり直せる。 記録は今しかできない」——この非対称性がオープンループの思想である。

5.2.3 事後処理のパイプライン

記録IQの解析は本書の技術の総集編になる。典型パイプラインは: ①予測位相を掛けてドップラを剥がす(第3.4.4節)→②狭帯域化(DDC・第2.3章)→ ③FFTウォーターフォールで信号を目視確認→④目的別処理——テレメトリなら第4.3章の受信機に File Sourceから流す、計測なら位相抽出(第3.1.1節のPLLをNumPyで回すか、 FFTピークの位相追跡)。すべて非実時間なので、ループ帯域を後知恵で最適化したり、 複数パラメータで再処理して比較したりできる。研究データとしてのIQ記録は、 観測装置の生データと同格に扱い、メタデータと処理スクリプトごと保存すること。

5.2.4 研究室スケールの実装 — USRPで局の相似形を作る

大学局・研究室でも同じ構造が組める。USRP+GPSDO(10 MHz/1PPS)を基準同期し(第4.5.4節)、 ①クローズドループ系: 第4.3章の受信機をリアルタイム実行、 ②オープンループ系: File Sink(またはSigMF Sink)で並列記録、を 同一フローグラフ内で分岐させるだけである。記録帯域を欲張らないこと(第2.5.2節の伝送路算術)、 冒頭に較正区間(無信号の雑音のみ数十秒——雑音電力の基準になる)を録ること、 メタデータ(中心周波数・f_s・利得・時刻・アンテナ)を必ず添えること。 この作法で録った1本のIQファイルが、変復調研究・同期アルゴリズム研究・計測研究の 共通試料になる。

Q. オープンループ記録があればクローズドループ受信機は不要では?

リアルタイム性が要る仕事(コマンド応答の確認、異常の即時検知、測距のような 送受連携)は記録では代替できない。また記録は帯域×時間でデータ量が線形に増えるので、 長時間の定常運用はクローズドループで、クリティカルな瞬間だけ記録を重ねる、が実務の解である。

■ まとめ
  • 局の受信系=共通ディジタイザ+並列DDC群。クローズドループ(実時間復調・計測)とオープンループ(IQ記録)の2系統。
  • 記録の技術要素は帯域・少ビット量子化・基準同期時刻・周波数メタデータ・標準フォーマット(SigMF/VDIF)。
  • 「復調はやり直せる、記録は今だけ」。一発勝負と電波科学・ΔDOR・捜索が主戦場。
  • USRP+GPSDOで研究室に局の相似形が組める。較正区間とメタデータが研究試料の価値を決める。

第5.3章設計ウォークスルー — PCM/PSK/PM地上系をゼロから

■ この章で学ぶこと
仕上げとして、架空だが現実的なミッションを題材に、要求→回線→変調パラメータ→受信機設計→ 実装→検証→運用準備までを通しでやる。各ステップで「どの章の式を使ったか」を明記する。 これは読者が自分のミッションで繰り返すべき手順書のひな型である。

5.3.1 題材と要求

題材: 小型技術実証機。S帯下りテレメトリをJERG-2-401系のPCM/PSK/PMで送る。 地上は3 mクラスの大学局+USRP。要求は「定常テレメトリ 4 kbps をBER 10⁻⁵以下で、 仰角20°以上の可視時間中に受信する」とする。

5.3.2 Step 1 — 回線計算でC/N₀を確定する

回線計算そのものは姉妹編(第1.2章・第6.2章)の手順で行い、ここでは結果だけ使う: 最悪条件(最大距離・仰角20°・マージン込み)でC/N₀ = 55 dBHzが確保できたとする。 SDR設計への入力はこの1つの数字である——以降のすべての帯域・損失・閾値がここから流れる。

5.3.3 Step 2 — 変調パラメータ(規格との対話)

決定根拠
方式PCM/PSK/PM・正弦波副搬送波・NRZ-L規格の標準構成(第4.3.1節)。残留搬送波でドップラ計測も兼ねる。
R_b4096 bps要求4 kbps+フレームオーバーヘッド。
f_sc65.536 kHz16サイクル/ビット(整数比制約)。搬送波PLLとの層分離1600倍(第3.1.4節)。
m1.2 rad搬送波−3.5 dB/データ−3.0 dBの等分配。計測と伝送の両立(第4.3.2節)。
符号化畳み込み(7,1/2)+RS(255,223)CCSDS標準連接(姉妹編第2.2章)。所要E_b/N₀が9.6→約2.7 dBへ。

符号化後の所要E_b/N₀ 2.7 dB+実装損失予算1.5 dB=4.2 dBに対し、 供給E_b/N₀ = 55 − 3.0 − 36.1 = 15.9 dB。マージン+11.7 dB——余裕が大きいのは 低仰角・雨・指向誤差をC/N₀側で既に見込んだ上での話であり、 余剰は将来のレート増(16 kbpsまで+6 dB)に取っておく、と設計書に書く。

5.3.4 Step 3 — 受信機アーキテクチャとレート設計

項目決定根拠章
構成USRP B210(ゼロIF)+GPSDO外部基準第2.2.2節・第4.5.4節
MCR / f_s16.777216 MHz / 524.288 kSPS第4.5.1節(2のべき整合)
周波数プラン搬送波を+25 kHzへ退避、lo_offset 200 kHz、ホストDDCで戻す第4.5.3節
レート階段524.288k →(↓16)→ 32.768k → sps 8第2.3.4節・第4.3.4節
ループ帯域PLL 100 Hz/Costas 250 Hz/タイミング0.02(正規化)第4.3.2節の表(ρ検算済み)
ドップラTLE/軌道予報から予測ステアリング(±50 kHz級)、残差はPLL第3.4.2節

5.3.5 Step 4 — 実装損失バジェット

回線計算書の「実装損失1.5 dB」の内訳を、本書の各章で定量化した項目で埋める。 この表が書けることが、SDR設計者が回線設計に対して負う説明責任である。

項目予算根拠
量子化・クリップ(12ビット・−12 dBFS運用)0.1 dB第1.3.5・1.3.8節
ジッタ(内蔵クロック+外部基準)0.05 dB第1.4.2節(ベースバンド近傍なので軽い)
フィルタ帯域内リプル・打ち切りISI0.2 dB第2.4.5節
搬送波位相ジッタ(ρ=28.5 dB)0.1 dB第3.1.3節・姉妹編2.3.2節
副搬送波・タイミングジッタ0.2 dB第3.1〜3.2章
整合フィルタ近似(移動平均)0.1 dB演習3.2-1
AGC・利得配分の残り0.1 dB第3.3章
予備0.65 dB
合計1.5 dBBER実測(Step 5)で検証

5.3.6 Step 5 — 検証マトリクス

検証は3段階で積む。各段の合格基準を先に文書化してから実験する。

段階環境確認内容合格基準
V1: ディジタル閉ループファイルベース(第4.3章)E_b/N₀較正つきBER曲線理論+0.8 dB以内(RF起因を除く実装損失)
V2: RF閉ループUSRP+同軸+減衰器(第4.5.6節)実RFのBER曲線、周波数確度、長時間フレーム連続性V1+0.7 dB以内。1時間欠落ゼロ
V3: 実電波実衛星ビーコン/アマチュア衛星→本命機ドップラ追尾込みの実運用リハーサル予測ステアリング残差がPLL引込内。パス全域でロック維持

5.3.7 Step 6 — 運用準備

研究・運用としての完成度は、受信機の「周辺」で決まる。チェックリスト: ①設定の版管理——フローグラフ・パラメータ・較正値をgitで管理し、記録データに版番号を刻む。 ②監視量の記録——各ループの周波数・ロック検出・SNR推定を時系列でファイルに落とす (PLLの積分器=ドップラ曲線はそれ自体が成果物)。③品質フラグ——ロック断・「O」発生・ 再同調イベントをデータに併記(第3.1.7節)。④並列オープンループ記録——重要パスはIQも録る (第5.2.4節)。⑤手順書——第4.5.6節の6段手順をパス前点検として毎回回す。 ここまで揃えば、この地上系は「動くデモ」ではなく研究インフラである。

Q. このウォークスルーを深宇宙ミッションに拡張するには?

構造は同一で、数字が動く。C/N₀が数十dB下がる→R_bが下がりループ帯域も狭くなる (B_n数Hz級=ρ確保のため。掃引捕捉・予測精度の要求が上がる)。ドップラ予測は軌道決定と 結合し(第3.4.2節)、周波数基準は水素メーザ級へ(第1.4.4節)。アンテナと初段は 大口径・極低雑音の局設備(姉妹編第4.2章)に置き換わる。変わらないのは本章の手順そのもの—— C/N₀を確定し、規格と対話してパラメータを決め、ループを設計し、損失に説明責任を持ち、 3段階で検証する。これが本書の到達点である。

■ まとめ
  • 設計はC/N₀という1つの数字から流れ落ちる: 変調パラメータ→レート階段→ループ帯域→損失予算。
  • 実装損失1.5 dBの内訳を章の式で埋め、BER実測で検証する——説明責任の完成形。
  • 検証はV1ディジタル→V2 RF閉ループ→V3実電波。合格基準を先に書く。
  • 版管理・監視量・品質フラグ・並列記録・手順書が揃って初めて研究インフラになる。
付録
章をまたぐ総合演習、用語集、そして先へ進むための文献地図。

付録A総合演習 — 章をまたいで設計する

【総合演習1】別リンクの全パラメータ設計
C/N₀ = 48 dBHz のリンクで、R_b = 1024 bps・f_sc = 32.768 kHz・m = 1.0 rad の PCM/PSK/PM受信系を f_s = 262.144 kSPS で設計する。 (a) 電力配分、(b) データE_b/N₀、(c) 搬送波PLL(B_n = 30 Hz)とCostas(B_n = 100 Hz、 ↓16後の16.384 kSPSで駆動)のρとloop_bw、(d) sps、をすべて求めよ。
解答
(a) J₀²(1.0) = 0.585 → 搬送波−2.3 dB、2J₁²(1.0) = 0.387 → データ−4.1 dB。
(b) E_b/N₀ = 48 − 4.1 − 10log₁₀1024 = 48 − 4.1 − 30.1 = 13.8 dB
(c) PLL: P_c/N₀ = 45.7 dBHz、ρ = 45.7 − 10log(60) = 27.9 dB ✓。 loop_bw = 30/(262144×1.061) = 1.08×10⁻⁴。 Costas: P_d/N₀ = 43.9 dBHz、ρ = 43.9 − 10log(200) = 20.9 dB ✓。 loop_bw = 100/(16384×1.061) = 5.75×10⁻³
(d) sps = 16384/1024 = 16。整合フィルタは[1/16]×16。 ——第4.3章の設計表と同じ紙面が、別の数字で再現できれば本書の目的は達成である。
【総合演習2】IFディジタイザの設計
IF 140 MHz・帯域 10 MHz を、14ビット・f_s = 100 MSPS のADCで帯域通過標本化する 地上局ディジタイザを考える。(a) 信号は第何ナイキストゾーンか、反転するか。 (b) ジッタSNRを量子化SNR+6 dBにするための許容ジッタ。 (c) 2ビットでオープンループ記録する場合の8時間データ量と感度損失。
解答
(a) ゾーンは⌈2×140/100⌉ = 第3ゾーン(100〜150 MHz)、奇数なので反転なし、40 MHzに現れる。
(b) 量子化SNR = 6.02×14+1.76 = 86.0 dB → 目標92 dB。 σ_j = 1/(2π×1.4×10⁸×10^{92/20}) = 28 fs。極めて厳しく、 「多ビット×高IF」がクロック設計問題になる(第1.4.2節)ことの実感値である。
(c) 12.5 MSPS複素(10 MHz帯域)×2ビット×2(IQ) = 6.25 MB/s → 8時間で180 GB。 感度損失は0.55 dB(第1.3.6節)。
【総合演習3】方形波副搬送波への改造
第4.3章の系を方形波副搬送波(低レート系の系譜)に改造する。 (a) 電力配分の式はどう変わるか。(b) 送信機・受信機で変更が必要なブロックはどこか。
解答
(a) 方形波±1の位相変調では搬送波 cos²m・データ sin²m の2項配分になり(Bessel展開は不要)、 高調波はデータ側波帯が f_sc の奇数倍に(1/n)²で並ぶ形に変わる。
(b) 送信: sig_source_f を GR_SQR_WAVE(±1にオフセット調整)へ——1ブロック。 受信: 位相復調後の信号が「方形波×d(t)」なので、DDC+Costasの代わりに 方形波レプリカ(±1)を掛けて全高調波を一括で畳み込む復調が最適になる。 レプリカの位相を追う副搬送波ループが必要になり、片側DDC方式より部品が増える—— 正弦波副搬送波が現代の主流である実装上の理由も、この改造をやると身体でわかる。
【総合演習4】N210での非整数sps設計
N210(f_s = 500 kSPSしか選べない)で第4.3章の系を受ける。 (a) 各段のレートとsps。(b) Symbol Syncのmax_devに織り込むべきクロック要因を TCXO±2 ppmとドップラ±20 ppmとして見積れ。
解答
(a) ↓16で31.25 kSPS、sps = 31250/4096 = 7.629(非整数のままSymbol Syncへ——第3.2.5節)。 整合フィルタは8タップ近似(演習3.2-1の損失を再評価)か、ポリフェーズ整合フィルタ一体型に。
(b) 合計±22 ppm = 2.2×10⁻⁵。余裕1.5倍で max_dev ≈ 3.3×10⁻⁵(シンボル正規化)。 ——「デバイスの都合をどの層で吸収するか」を自分で決められれば、本書の同期理解は完成である。

付録B用語集

用語意味(初出章)
AAF(アンチエイリアシングフィルタ)標本化前に±f_s/2外を落とす宿命的アナログフィルタ(1.2)
ADC / DACアナログ⇄ディジタル変換器。SDRの性能上限を握る(1.1, 1.5)
AGC自動利得制御。アナログ層はADCローディング、ディジタル層はループ動作点の管理(3.3)
ASM(付加同期マーカ)フレーム先頭検出用の既知ビットパターン。CCSDS TMでは1ACFFC1D(4.3)
ASIC専用集積回路。書き換え不能な代わりに最小電力・最小面積。SDRでは「変わらない部分」(RFトランシーバ・ADC/DAC・IF)に使う(2.5)
CIC フィルタ乗算不要のsinc^N型デシメーションフィルタ。DDC初段の定番(2.3)
CLTUコマンドリンク伝送単位。開始系列+BCH符号化ブロック列+終端(4.4)
Costasループ変調を剥がしながら搬送波位相を追うPLL。BPSK/QPSK用(3.1)
DDC / DUCディジタルダウン/アップコンバータ。NCO+複素乗算+レート変換フィルタ(2.3)
ENOB実効ビット数 =(SINAD−1.76)/6.02。設計に使うのは公称ビットでなくこちら(1.3)
FIR / IIR帰還のない/ある離散フィルタ。SDRの信号経路はFIR(直線位相・常に安定・ポリフェーズ可)、平滑と制御はIIR(PLLのループフィルタもIIR)(2.4)
FLL周波数差を検出して引き込むループ。PLLの前置に(3.1)
FPGA書き換え可能な論理デバイス。乗算器を空間に並べて高レートの固定処理を担う。搭載では型式(SRAM/フラッシュ/アンチヒューズ)でSEU耐性が変わる(2.5, 5.1)
Gardner TED2標本/シンボルで動く搬送波位相無感のタイミング誤差検出器(3.2)
GPSDOGPS同期基準発振器。USRPを計測器に変える10 MHz/1PPS源(4.5)
IQ信号 / 複素包絡線搬送波を剥がした複素ベースバンド表現 z = I+jQ = Ae^{jφ}(2.1)
IRR(鏡像抑圧比)IQ不平衡による鏡像漏れの抑圧量 ≈10log(4/(ε²+δ²))(2.1)
JERG-2-401JAXAの宇宙機RF通信設計標準。CCSDS 401系と整合(4.3)
ローディングファクタADCフルスケールに対する信号実効値。−12 dBFSが定石(1.3)
ナイキストゾーン周波数軸のf_s/2幅の区画。標本化で全ゾーンが第1ゾーンへ折り重なる(1.2)
NCO数値制御発振器。位相アキュムレータ+波形テーブル。f = M·f_s/2^W(2.3)
オープンループ記録同期せずIQのまま記録し事後処理する受信形態(5.2)
オーバーフロー(O)ホストが実時間に間に合わず標本が落ちるSDR特有の故障(2.5)
PCM/PSK/PMNRZデータ→副搬送波BPSK→残留搬送波PM。z = exp(jm·d·sin ω_sc t)(4.3)
PDUメタデータ+バイト列のメッセージ。フレーム層以降の標準的な受け渡し形(4.1)
位相アキュムレータ毎クロック増分Mを足すレジスタ。NCOの心臓(2.3)
ポリフェーズ分解フィルタを部分位相に分けて低レート側で計算する技法。計算量1/R。FIRでのみ可能(2.4)
直線位相係数が左右対称なFIRの性質。群遅延が全周波数で一定=波形が歪まない。IIRでは実現できない(2.4)
プロセッシングゲインオーバーサンプリング比による実効SNR改善 10log(f_s/2B)(1.3)
帯域通過標本化2f_H/n ≤ f_s ≤ 2f_L/(n−1)で高いIFを低いf_sで直接食う技法(1.2)
θ_n(正規化ループ帯域)B_n·T_s/(ζ+1/4ζ)。GNU Radioのloop_bwに渡す値(3.1)
ディザ量子化誤差を白色化するため意図的に加える微小雑音(1.3)
SEU / TID / SEL放射線効果: ビット化け/累積劣化/ラッチアップ(5.1)
SFDRスプリアスフリーダイナミックレンジ。微弱信号検出の限界を決める(1.3)
SigMF / VDIFIQ記録のメタデータ標準(SDR系/VLBI系)(5.2)
sincロールオフDACのゼロ次ホールドに由来する高域減衰。inverse-sincで補償(1.5)
ストリームタグ特定標本に貼る(番号,キー,値)の帯域外情報(4.1)
Symbol SyncTED+ループ+ポリフェーズ補間器を統合したGNU Radioのシンボル同期ブロック(3.2, 4.2)
ターンアラウンド比コヒーレント動作の受送信周波数比(X帯880/749)。SDRではNCOの数値演算(5.1)
タイムスタンプ標本番号と絶対時刻の対応。1PPS+10 MHzで確立(1.4, 2.5, 4.5)
ゼロIF / ローIF / IFサンプリング / 直接RFADCの置き場所による受信機アーキテクチャ4類型(2.2)

付録C参考文献 — 深く知るための地図

C.1 ディジタル通信・同期の理論

M. Rice, Digital Communications: A Discrete-Time Approach — 本書第III部の設計式(θ_n・ループゲイン・TED)の出典系。離散時間で同期を設計する現代の標準教科書。
J. G. Proakis & M. Salehi, Digital Communications — 変復調・符号の網羅的正典。
U. Mengali & A. N. D'Andrea, Synchronization Techniques for Digital Receivers — 同期アルゴリズムの理論限界(CRB)まで踏み込む専門書。

C.2 DSP・マルチレート・SDR実務

R. G. Lyons, Understanding Digital Signal Processing — DSPの直観と実務の橋。第I・II部の背景に。
f. j. harris, Multirate Signal Processing for Communication Systems — ポリフェーズ・CIC・チャネライザの原典。第2.4章の世界を極めるならこれ。
T. Collins ほか, Software-Defined Radio for Engineers(Analog Devices, PDF無償公開) — ゼロIFトランシーバの実装障害(IQ不平衡・DC・較正)に詳しい。
PySDR(pysdr.org) — Python/NumPyでSDRの全域を体験できる無償オンライン教科書。本書の副読本に最適。

C.3 GNU Radio・エコシステム

GNU Radio公式チュートリアル・Wiki(wiki.gnuradio.org) — ブロックリファレンスとAPI。 第4.2章の「三点照合」の一角。
gr-satellites ドキュメント(D. Estévez) — 衛星デコーダ集の使い方とフレーム形式の宝庫。 同氏のブログ(destevez.net)は実信号解析の実例集として研究の手本になる。
GNU Radio Conference(GRCon)発表アーカイブ — 最新の実装事例。深宇宙受信の発表も毎年ある。

C.4 規格・宇宙機関文書

JERG-2-401(宇宙機設計標準: RF通信系) — JAXA設計標準。PCM/PSK/PMの規定・変調指数・ 周波数管理の一次資料(JAXAの設計標準公開ページから入手)。
CCSDS 401.0-B(RF and Modulation)131.0-B(TM Sync & Coding)231.0-B/232.0-B(TC Sync & Coding / Space Data Link) — 国際標準の原文。 Blue Book(規格)とGreen Book(根拠解説)をセットで読む。
DSN Telecommunications Link Design Handbook(810-005)JPL DESCANSOシリーズ — 深宇宙局の性能と設計根拠。オープンループ受信・電波科学の記述も。

読む順序の推奨: 本書→(実装で詰まったら)C.3→(理論の根に降りたいとき)C.1/C.2→ (数値の最終根拠が要るとき)C.4。姉妹編『深宇宙通信工学』の付録Cと合わせて、 理論・実装・規格の三面から引ける体制を作ってほしい。引用時は版・発行年を必ず添えること。

本書のコードはGNU Radio 3.10系のAPIに基づく教材である。ブロックの引数順・名称は バージョンで変わり得るため、実行時はGRCで同名ブロックを配置して生成コードと突き合わせること(第4.1.5節)。 規格値(副搬送波周波数・変調指数・符号化・CLTU構造等)の最終根拠は、対象ミッションのRF-ICDと JERG-2-401・CCSDS勧告の原文である。また電波の送信は免許を要する——開発は同軸で閉じ、 受信から空へ出ること。姉妹編『深宇宙通信工学』(SpaceCOM教科書)と併読されたい。