MSK/GMSK変調 — 連続位相で帯域効率と一定包絡線を両立する

携帯電話の第2世代規格であるGSM、船舶が自分の位置や針路を周囲に知らせるAIS(船舶自動識別装置)、Bluetoothの基本レート — これらに共通して使われている変調方式が GMSK(Gaussian Minimum Shift Keying)です。そのおおもとにあるのが MSK(Minimum Shift Keying、最小偏移変調)という、一見地味ですが非常に巧妙な変調方式です。なぜ世界中で何十億台と使われた携帯電話が、QPSKでも16QAMでもなく、わざわざMSK系の方式を選んだのでしょうか。

その理由は2つの「都合のよい性質」にあります。1つは 一定包絡線(信号の振幅が時間によらず一定)であること。これにより、電力効率の高い非線形電力増幅器(飽和領域で動作するC級アンプなど)を使っても波形が歪まず、バッテリー駆動の携帯端末で電力を無駄にしません。もう1つは 連続位相 であること。位相が時間の連続関数として滑らかに変化するため、位相が飛ぶ通常のPSKに比べてスペクトルの裾(サイドローブ)が急速に減衰し、隣接チャネルへの漏れ込みが小さくなります。GMSKはこの連続位相をさらにガウスフィルタで滑らかにすることで、帯域占有を一段と絞り込みます。

MSK/GMSKを理解すると、次のような分野への見通しが格段に良くなります。

  • 移動体通信: GSM(2G携帯)のπ/2回転を伴うGMSK、その後のEDGE/LTEへの発展を理解する基礎になります
  • 海事・航空無線: AIS(船舶識別)やACARS系の一部はGMSK系で、限られた帯域を多数の局で共有するために連続位相が活きます
  • 衛星・近距離無線: 衛星搭載の電力制約の厳しい送信機や、Bluetooth/Zigbeeのような低消費電力無線で一定包絡線の利点が直接効きます
  • 連続位相変調(CPM)全般の入口: MSKはCPMという広い変調族の最も基本的な一例で、ここを押さえると部分応答CPMやマルチh変調へ進めます

本記事の内容

  • 周波数シフトキーイング(FSK)の復習と「連続位相」という発想
  • MSKを変調指数 $h = 0.5$ の連続位相FSKとして導出する
  • 位相が1シンボルあたり $\pm\pi/2$ ずつ進む「位相トレリス」の構造
  • MSKがOQPSK(オフセットQPSK)と等価であることの証明
  • 一定包絡線がなぜ非線形電力増幅に有利なのか
  • ガウスフィルタでデータを整形してから変調するGMSKの仕組み
  • BT積がスペクトル占有とシンボル間干渉(ISI)に与えるトレードオフ
  • Python実装: MSK/GMSK波形と位相軌跡、パワースペクトル比較、BTを変えた帯域とアイパターン

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

MSKとは — FSKに「連続位相」を課す

2値FSKの素朴な問題

ディジタル信号の0と1を2つの異なる周波数 $f_1$, $f_2$ に対応させて送るのが2値FSK(Frequency Shift Keying)です。たとえば「1」を高い周波数、「0」を低い周波数で送ります。受信側は周波数を判別すればよいので、振幅変動に強く、構成も単純です。

ところが、素朴なFSKには無駄があります。もし2つの周波数を独立した発振器で作り、ビットの境界でスイッチを切り替えると、切り替えの瞬間に位相が飛んでしまいます。位相が不連続にジャンプすると、信号の波形に角(かど)ができ、その角が高い周波数成分を生みます。フーリエ解析の言葉で言えば、波形に不連続があるとスペクトルの裾が $1/f^2$ 程度のゆっくりした速さでしか落ちず、隣のチャネルに漏れ込んでしまうのです。

ここで自然な発想が生まれます。「周波数を切り替えるとき、位相を飛ばさず連続につなげればよいのではないか」。これが 連続位相FSK(CPFSK: Continuous Phase FSK) で、MSKはそのなかでも特に都合のよい条件を満たした特別な場合です。

水道の蛇口をイメージすると分かりやすいかもしれません。急に全開・全閉するとパイプが「ウォーターハンマー」で衝撃を受けますが、ゆっくり開け閉めすれば衝撃は出ません。位相の不連続は信号にとってのウォーターハンマーであり、連続位相はそれを避ける工夫です。

変調指数という尺度

FSKで2つの周波数がどれだけ離れているかを表す無次元量が 変調指数 $h$ です。シンボル周期を $T$(1ビットを送る時間)、2つの周波数の差を $\Delta f = f_1 – f_0$ とすると、

$$ h = \Delta f \cdot T $$

と定義されます。$h$ は「1シンボルの間に2つの信号の位相差が何回転(何 $\times 2\pi$)するか」を表しています。$h$ が大きいほど周波数が大きく離れるので判別は楽になりますが、その分だけ帯域を広く使います。逆に $h$ を小さくすると帯域は狭くなりますが、2つの信号が近づきすぎると区別がつかなくなります。

ここで「2つの信号波形が直交する(内積がゼロになる)ための最小の $h$ はいくつか」という問いを立てると、答えは $h = 0.5$ になります。この 直交性を保ちつつ最小の周波数偏移 を実現する $h = 0.5$ のCPFSKこそが MSK(Minimum Shift Keying、最小偏移変調)です。「Minimum」という名前は、この「直交を保つ最小の偏移」という意味から来ています。

直交であることがなぜ嬉しいかというと、受信側が相関検波(マッチトフィルタ)で2つの信号を分離するとき、互いの干渉なしに最適に判別できるからです。$h = 0.5$ はその境界ぎりぎりを攻めた値であり、帯域効率と検波性能のバランスがよいスイートスポットになっています。

ここまでで「連続位相」と「変調指数 $h = 0.5$」という2つのキーワードが出そろいました。次節では、これらを数式で表現し、MSKの送信信号を具体的に書き下していきましょう。

MSKの数学的定義と位相の導出

連続位相FSKの一般形

まず連続位相FSKの送信信号を書き下します。搬送波の角周波数を $\omega_c = 2\pi f_c$ とし、第 $k$ 番目のシンボル区間 $kT \le t < (k+1)T$ における送信信号を次の形で表します。

$$ s(t) = A\cos\bigl(\omega_c t + \phi(t)\bigr) $$

ここで $A$ は一定の振幅(これが一定包絡線の出発点です)、$\phi(t)$ は情報を運ぶ 位相 です。素朴なFSKでは周波数そのものを切り替えましたが、CPFSKでは位相 $\phi(t)$ を時間の連続関数として扱う点が肝心です。

データビット列を $a_k \in \{+1, -1\}$(双極性で表現)とします。瞬時周波数は搬送波からのずれとして、$+1$ なら $+\Delta\omega/2$、$-1$ なら $-\Delta\omega/2$ だけ偏移させます。瞬時周波数(角周波数)は位相の時間微分なので、

$$ \frac{d\phi(t)}{dt} = a_k \cdot \frac{\Delta\omega}{2} = a_k \cdot \pi h \cdot \frac{1}{T} \quad (kT \le t < (k+1)T) $$

と書けます。ここで $\Delta\omega = 2\pi\Delta f = 2\pi h / T$ を使いました($h = \Delta f \cdot T$ より $\Delta f = h/T$)。この式は「データが $+1$ のときは位相が一定の割合で増え、$-1$ のときは一定の割合で減る」ことを表しています。

位相を積分で求める

位相 $\phi(t)$ は、瞬時周波数を時間積分すれば得られます。第 $k$ シンボル区間での位相は、区間の始まりまでの位相 $\phi(kT)$ に、その区間での増分を足したものです。

$$ \phi(t) = \phi(kT) + a_k \cdot \frac{\pi h}{T}(t – kT) \quad (kT \le t < (k+1)T) $$

この式の意味を確認しましょう。右辺第1項 $\phi(kT)$ は「これまでに積み上がった位相」、第2項は「今のシンボルが区間内で線形に加える位相」です。位相が区間ごとに線形に増減し、区間の境界で値が連続につながる(前の区間の終端 = 次の区間の始点)ため、$\phi(t)$ は折れ線状の連続関数になります。これが連続位相の正体です。

1シンボル区間(長さ $T$)で位相がどれだけ変化するかを計算してみます。$t = (k+1)T$ を代入すると、$t – kT = T$ なので、

$$ \phi((k+1)T) – \phi(kT) = a_k \cdot \frac{\pi h}{T} \cdot T = a_k \cdot \pi h $$

つまり、1シンボルごとに位相は $\pm\pi h$ だけ変化します。

$h = 0.5$ を代入する — MSKの誕生

ここで MSK の条件 $h = 0.5$ を代入します。$\pi h = \pi/2$ なので、1シンボルあたりの位相変化は、

$$ \Delta\phi = a_k \cdot \frac{\pi}{2} $$

となります。データが $+1$ なら位相は $+\pi/2$(90度)進み、$-1$ なら $-\pi/2$ 戻ります。MSKでは、1ビットごとに位相がちょうど直角ぶん回転する というのが最も重要な性質です。

瞬時周波数の偏移も具体的に書けます。$\Delta f = h/T = 1/(2T)$ なので、2つの周波数は、

$$ f_1 = f_c + \frac{1}{4T}, \qquad f_0 = f_c – \frac{1}{4T} $$

であり、周波数間隔は $f_1 – f_0 = 1/(2T)$、すなわちシンボルレート $R = 1/T$ の半分です。FSKとして見たときの周波数の離れ具合が「シンボルレートの半分」というのが、直交を保つ最小値だったわけです。

ここまでの導出で、MSKの送信信号は次のように完全に書き下せます。区間 $kT \le t < (k+1)T$ で、

$$ s(t) = A\cos\left(\omega_c t + a_k\frac{\pi}{2T}(t – kT) + \phi(kT)\right) $$

振幅 $A$ は常に一定で、情報はすべてコサインの引数(位相)に入っていることに注目してください。これが一定包絡線を保証します。

位相が1ビットごとに $\pm\pi/2$ だけ変わるという離散的な構造は、図に描くと「位相トレリス」と呼ばれる格子状のパターンになります。次節ではこのトレリスを詳しく見て、MSKの位相がどんな値しか取れないのかを調べましょう。

位相トレリス — 位相がたどる格子

位相の取りうる値

MSKの位相 $\phi(t)$ をシンボル境界 $t = kT$ で評価した値 $\phi_k = \phi(kT)$ を考えます。漸化式は、

$$ \phi_{k+1} = \phi_k + a_k\frac{\pi}{2} $$

です。初期位相を $\phi_0 = 0$ とすると、$\phi_k$ は $\pi/2$ の整数倍、すなわち $\{0, \pm\pi/2, \pm\pi, \dots\}$ のいずれかしか取れません。さらに位相を $2\pi$ の周期で考えると(位相は $2\pi$ 足しても同じ)、本質的に取りうる値は $\{0, \pi/2, \pi, 3\pi/2\}$ の4状態に集約されます。

ここに偶数番目・奇数番目のシンボルで取れる値が分かれるという面白い性質があります。$\phi_k$ が $\pi/2$ ずつ動くので、$k$ が偶数のとき $\phi_k$ は $\{0, \pi\}$($\pi$ の整数倍)、$k$ が奇数のとき $\{\pi/2, 3\pi/2\}$($\pi/2$ の奇数倍)に交互に現れます。横軸に時間(シンボル番号)、縦軸に位相を取り、各シンボル境界での到達可能な位相を点で結ぶと、菱形が連なった格子模様が描けます。これが 位相トレリス(phase trellis) です。

トレリスが教えてくれること

位相トレリスは、MSKの信号がたどれる「経路」をすべて図示したものです。各区間で位相は傾き $\pm\pi/(2T)$ の直線(上り坂か下り坂)で結ばれ、境界では必ず連続につながります。トレリス上の1本の経路が1つのビット列に対応します。

この描像が重要な理由は2つあります。1つは、受信側の検波がトレリス上の最尤経路探索(ビタビアルゴリズム)として定式化でき、シンボル単位の判定より良い性能(コヒーレントMSKでBPSK相当の $E_b/N_0$ 性能)が得られることです。もう1つは、位相が決して飛ばず、しかも限られた状態しか取らないという規則性そのものが、スペクトルをきれいに保つ源泉だということです。

位相が折れ線で連続につながるという描像は分かりましたが、実はMSKにはもう1つの全く異なる見方があります。それは「2つの直交した搬送波に、半正弦波で重み付けしたデータを載せたQPSKの変種」と見る方法です。次節でこの等価性を示します。これがMSKを実際に実装・復調するうえで決定的に重要になります。

MSKはOQPSKと等価である

コサインの加法定理で展開する

MSKの信号を、位相に情報を持つ形(CPFSK表現)から、同相成分(I)と直交成分(Q)に分解した形(直交変調表現)へ書き換えます。出発点は、

$$ s(t) = A\cos\bigl(\omega_c t + \phi(t)\bigr) $$

です。コサインの加法定理 $\cos(X+Y) = \cos X\cos Y – \sin X\sin Y$ を $X = \omega_c t$, $Y = \phi(t)$ に適用すると、

$$ s(t) = A\cos\phi(t)\cos\omega_c t – A\sin\phi(t)\sin\omega_c t $$

となります。ここで $I(t) = A\cos\phi(t)$ を同相成分、$Q(t) = A\sin\phi(t)$ を直交成分と呼びます。情報がすべて $\phi(t)$ に入っているので、$I$ と $Q$ の振る舞いを調べれば、MSKがどんな直交変調になっているかが分かります。

位相がたどる軌跡から I・Q の形を読む

前節で見たように、MSKの位相 $\phi(t)$ は各区間で傾き $\pm\pi/(2T)$ の直線です。区間 $kT \le t < (k+1)T$ で $\phi(t) = \phi_k + a_k\frac{\pi}{2T}(t - kT)$ と書けるので、これを $\cos$ と $\sin$ に入れたものが $I(t)$, $Q(t)$ になります。鍵となるのは、位相が $\pi/2$ の倍数の格子点を通るため、$\cos\phi$ と $\sin\phi$ が半周期 $2T$ の正弦波・余弦波になることです。

丁寧に計算すると、MSKの $I(t)$ と $Q(t)$ は次の形にまとまります。

$$ I(t) = d_I(t)\cos\left(\frac{\pi t}{2T}\right), \qquad Q(t) = d_Q(t)\sin\left(\frac{\pi t}{2T}\right) $$

ここで $d_I(t)$, $d_Q(t)$ は $\pm 1$ を取るデータ(元のビット列を偶数番目・奇数番目に振り分けたもの)で、$\cos(\pi t/2T)$ と $\sin(\pi t/2T)$ は周期 $4T$ の正弦波の半分、すなわち 半正弦波パルス です。

この式を最初の展開に戻すと、MSKの最終形が得られます。

$$ s(t) = A\, d_I(t)\cos\left(\frac{\pi t}{2T}\right)\cos\omega_c t – A\, d_Q(t)\sin\left(\frac{\pi t}{2T}\right)\sin\omega_c t $$

なぜこれがOQPSKなのか

この式の構造を読み解きます。第1項は「同相搬送波 $\cos\omega_c t$ に、半正弦波で整形されたデータ $d_I$ を載せたもの」、第2項は「直交搬送波 $\sin\omega_c t$ に、半正弦波で整形されたデータ $d_Q$ を載せたもの」です。これはまさに QPSK の構造(IとQの2チャネルにデータを分けて直交搬送波に載せる)そのものです。

ただし2つの重要な違いがあります。1つは、パルス整形が通常QPSKの矩形パルスではなく 半正弦波パルス $\cos(\pi t/2T)$, $\sin(\pi t/2T)$ になっていること。半正弦波はパルスの両端で滑らかにゼロに落ちるため、矩形パルスより帯域がコンパクトで、合成包絡線が一定になります。もう1つは、I チャネルと Q チャネルのタイミングが互いに $T$(1ビット)だけずれていること。これは $\cos(\pi t/2T)$ がゼロになる時刻と $\sin(\pi t/2T)$ がゼロになる時刻が $T$ ずれていることに対応します。

このようにIとQを半シンボルずらして変調する方式を OQPSK(Offset QPSK、オフセットQPSK) と呼びます。すなわち、MSKは半正弦波パルス整形を施したOQPSKと数学的に完全に等価 なのです。

このオフセットこそが一定包絡線の鍵です。通常のQPSKでは、IとQが同時に符号反転すると信号点が原点を通過し(位相が180度飛び)、包絡線がゼロまで落ちます。OQPSKではIとQの反転時刻がずれるので、一度に1チャネルしか反転せず、原点通過が起きません。さらに半正弦波整形により、合成された $\sqrt{I^2 + Q^2}$ がちょうど一定になります。これは次節で確認します。

MSKがOQPSKと等価だと分かったことで、実装上は「2つの直交チャネルを半正弦波で整形してオフセットを付ける」だけでよく、復調も普通の直交検波器が使えるという実用上の恩恵が見えてきました。次は、この構造がもたらす最大のご利益 — 一定包絡線 — がなぜ電力増幅に有利なのかを詳しく見ます。

一定包絡線がなぜ電力増幅に有利なのか

包絡線が一定であることの確認

包絡線とは信号の瞬時振幅、すなわち $\sqrt{I(t)^2 + Q(t)^2}$ です。MSKの $I$, $Q$ を代入すると、

$$ \sqrt{I^2 + Q^2} = A\sqrt{d_I^2\cos^2\!\left(\frac{\pi t}{2T}\right) + d_Q^2\sin^2\!\left(\frac{\pi t}{2T}\right)} $$

$d_I, d_Q \in \{+1, -1\}$ なので $d_I^2 = d_Q^2 = 1$ です。これを代入すると、

$$ \sqrt{I^2 + Q^2} = A\sqrt{\cos^2\!\left(\frac{\pi t}{2T}\right) + \sin^2\!\left(\frac{\pi t}{2T}\right)} = A $$

ピタゴラスの三角恒等式 $\cos^2\theta + \sin^2\theta = 1$ により、包絡線はデータや時刻によらず常に $A$ で一定です。複素平面(IQ平面)で見ると、MSKの信号点は半径 $A$ の円周上を滑らかに動き続け、決して原点に近づきません。

非線形増幅器の事情

なぜ一定包絡線がそんなに嬉しいのでしょうか。鍵は 電力増幅器(PA)の非線形性 です。送信機の最終段で信号を大電力に増幅するPAには、大きく分けて線形PA(A級・AB級など)と非線形PA(C級・D級・E級、飽和動作のスイッチング増幅器など)があります。非線形PAは出力を飽和近くまで使い切るため 電力効率が圧倒的に高い(C級で70%以上、線形A級だと理論上25%程度)のですが、入出力特性が非線形なので、振幅変動のある信号を入れると振幅情報が歪んでしまいます。

振幅が変動する信号(たとえば16QAMや、原点を通過するQPSK)を非線形PAで増幅すると、振幅の山が飽和で潰され、波形が歪みます。この非線形歪みはスペクトルの 再成長(spectral regrowth) を引き起こし、せっかくフィルタで絞った帯域が再び広がって隣接チャネルに漏れます。これを防ぐには、PAを飽和点よりずっと低い動作点(バックオフ)で使うしかなく、その分だけ電力効率が犠牲になります。

ところがMSK/GMSKは包絡線が一定なので、振幅情報が存在しません。情報はすべて位相に入っています。したがって、非線形PAで振幅を飽和させて目一杯増幅しても、位相情報は保たれ、波形は歪みません。バックオフ不要で最大効率のPAを使える というのが、バッテリー駆動の携帯端末や電力制約の厳しい衛星送信機にとって決定的な利点です。GSM端末が長時間通話できたのも、この一定包絡線のおかげと言ってよいでしょう。

定量的に言えば、一定包絡線方式は PA を飽和点近くで動作させられるため、PAの付加電力効率(PAE)を最大限引き出せます。仮に非線形PAで効率60%が出るとして、振幅変動信号で6dBのバックオフが必要なら実効効率は大幅に落ちますが、一定包絡線ならバックオフがほぼ不要です。

ここまでで、MSKの「連続位相」「一定包絡線」という2大特長がなぜ重要かを理解しました。しかし、MSKのスペクトルにはまだ改善の余地があります。半正弦波パルスは矩形よりは良いものの、サイドローブがまだそれなりに残ります。これをさらに抑え込むのがGMSKです。次節でその仕組みを見ましょう。

GMSK — ガウスフィルタで帯域を絞る

MSKのスペクトルの弱点

MSKのパワースペクトルは、メインローブ(中心の山)がQPSKより少し広い一方で、サイドローブ(裾)は $f^{-4}$ で急速に減衰します。これは半正弦波パルスが滑らかな(連続な)形をしているおかげです。しかし、最初のサイドローブのレベルはまだメインローブから約 $-23$ dB 程度で、隣接チャネル間隔が非常に狭いシステム(GSMの200 kHz間隔など)では、この裾でも干渉源になりえます。

スペクトルの裾をさらに落とすには、位相の変化を「もっと滑らかに」すればよいというのが基本方針です。MSKでは位相が折れ線(区間ごとに直線、境界で傾きが急に変わる)でした。傾きが不連続だと、その2階微分にインパルスが現れ、スペクトルにある程度の裾を残します。そこで、位相の傾き(=瞬時周波数)そのものを滑らかに変化させれば、もっと裾が落ちるはずです。

ガウスフィルタによる事前整形

GMSK(Gaussian MSK)のアイデアは単純です。変調する前のデータパルス(矩形のNRZ波形)を、ガウス型の低域通過フィルタ(LPF)に通して滑らかにしてから、MSKと同じように周波数変調する というものです。矩形パルスの角を丸めることで、瞬時周波数の急変がなくなり、位相軌跡が一段と滑らかになります。

ガウスフィルタのインパルス応答 $h(t)$ は、3 dB帯域幅 $B$ を使って次のように書けます。

$$ h(t) = \frac{1}{\sqrt{2\pi}\,\sigma T}\exp\left(-\frac{t^2}{2\sigma^2 T^2}\right), \qquad \sigma = \frac{\sqrt{\ln 2}}{2\pi BT} $$

ここで $B$ はフィルタの3 dB遮断周波数、$T$ はシンボル周期です。重要なのは、フィルタの特性が $B$ と $T$ の積 $BT$(BT積) という1つの無次元パラメータだけで決まることです。GSMでは $BT = 0.3$、衛星系やAISなどでは $BT = 0.5$ や $0.25$ がよく使われます。

GMSKの送信信号は、矩形データパルス $g(t)$(幅 $T$、振幅1)をガウスフィルタで畳み込んだ整形パルス $q(t) = (g * h)(t)$ を、位相パルスとして使います。位相は、

$$ \phi(t) = \frac{\pi}{2}\sum_k a_k \, q(t – kT) $$

と表されます。$BT \to \infty$(フィルタの帯域を無限に広げる)の極限では、ガウスフィルタは何もしない(インパルス応答がデルタ関数になる)ため、$q(t)$ は矩形パルスのまま、すなわちGMSKはMSKに一致します。逆に $BT$ を小さくするほどフィルタが強くかかり、パルスが時間的に広がります。

部分応答 — パルスが複数シンボルにまたがる

ガウスフィルタでパルスを広げると、1つのビットの影響が前後のシンボル区間にはみ出します。$BT = 0.3$ では、1ビットの位相パルスがおよそ前後3シンボル分に広がります。つまり、ある時刻の位相は1つのビットだけでなく、近傍の複数ビットの重ね合わせで決まります。これを 部分応答信号(partial response signaling) と呼びます。

部分応答であることは、1つのシンボルが隣のシンボルの判定に影響を及ぼす シンボル間干渉(ISI: Inter-Symbol Interference) が意図的に導入されることを意味します。これは一見すると悪いことのように思えますが、GMSKでは「帯域をきつく絞る対価として、制御されたISIを受け入れる」というトレードオフを積極的に選んでいるのです。受信側は、このISIを既知のものとして扱い、ビタビ等化器などで補償できます。

ここでBT積の役割が明確になります。$BT$ を小さくすると帯域はぐっと狭くなりますが、ISIが増えて符号誤り率が悪化します。$BT$ を大きくするとISIは減りますが帯域が広がります。この スペクトル占有とISIのトレードオフを1パラメータで調整できる のがGMSKの設計の妙です。次節では具体的な値を入れて、このトレードオフを定量的に確認しましょう。

具体例 — GSMのGMSKパラメータ

GSMを例に、これまでの量を具体的な数値で確認します。GSMのシンボルレートは $R = 1/T = 270.833$ kbit/s(チャネル間隔200 kHzに対応)、変調はBT積 $BT = 0.3$ のGMSKです。

まず、ガウスフィルタの3 dB帯域 $B$ を求めます。$BT = 0.3$ かつ $T = 1/270833 \approx 3.692\,\mu\mathrm{s}$ なので、

$$ B = \frac{0.3}{T} = 0.3 \times 270833 \approx 81.25\ \text{kHz} $$

シンボルレート270.833 kHzに対し、ガウスフィルタの帯域はその約30%という、かなりきつい整形です。これにより矩形パルスは大きくなまされ、位相軌跡は滑らかになります。

次に、$\sigma$(ガウス分布の標準偏差に相当する量)を計算します。

$$ \sigma = \frac{\sqrt{\ln 2}}{2\pi BT} = \frac{\sqrt{0.693}}{2\pi \times 0.3} = \frac{0.8326}{1.885} \approx 0.442 $$

この $\sigma \approx 0.442$(シンボル周期 $T$ で規格化した単位)は、ガウスパルスの広がりが1シンボル幅の半分弱であることを意味します。フィルタ後のパルス $q(t)$ は前後数シンボルに裾を引き、結果として約3シンボルにわたる部分応答になります。

MSKと比べてGMSK($BT=0.3$)がどれだけ帯域を絞るかは、占有帯域幅(全電力の99%が入る帯域)で比較すると明瞭です。おおよそ次のような関係になります(規格化帯域 $B_{99}\cdot T$ の目安)。

方式 99%電力帯域 $B_{99}T$ の目安 最初のサイドローブ
QPSK(矩形) 約8 $-13$ dB
MSK($BT=\infty$) 約1.2 $-23$ dB
GMSK $BT=0.5$ 約1.0 深く沈む
GMSK $BT=0.3$ 約0.9 さらに深く沈む

この表から、MSKはQPSKに比べて占有帯域を桁違いに狭くし、GMSKはそれをさらに絞り込むことが読み取れます。一方で、$BT$ を小さくすると次に述べるISIによる性能劣化が生じます。$BT=0.3$ のGMSKは、理想的なコヒーレント検波に対して約0.3 dB程度の $E_b/N_0$ 劣化(アイ開口の縮小に起因)で済むため、GSMはこの値を実用的な落としどころとして採用しました。

数値感覚がつかめたところで、いよいよPythonでMSK/GMSKの波形・位相軌跡・スペクトル・アイパターンを実際に描き、これまでの理論を目で確かめましょう。

Pythonでの実装

MSK信号の生成と位相軌跡

まず、ランダムなビット列からMSK信号を生成し、その位相軌跡(位相トレリス)を描きます。位相を瞬時周波数の積分として計算する、最も基本に忠実な方法で実装します。

import numpy as np
import matplotlib.pyplot as plt

# パラメータ
T = 1.0            # シンボル周期 [s](規格化)
sps = 64           # 1シンボルあたりサンプル数
fs = sps / T       # サンプリング周波数
N_sym = 16         # シンボル数

rng = np.random.default_rng(0)
bits = rng.integers(0, 2, N_sym)      # 0/1 のビット列
a = 2 * bits - 1                       # 双極性 ±1 に変換

# 各サンプル時刻でのデータ値(NRZ矩形)を作る
data_nrz = np.repeat(a, sps).astype(float)
t = np.arange(len(data_nrz)) / fs

# MSKの瞬時周波数偏移は ±1/(4T)、位相増分は積分
# dphi/dt = a_k * pi/(2T)  → 位相 = 累積積分
h_mod = 0.5  # 変調指数
dphi = data_nrz * np.pi * h_mod / T / fs   # 1サンプルあたりの位相増分
phase = np.cumsum(dphi)                     # 位相を積分で得る

ここでは瞬時周波数 $d\phi/dt = a_k\,\pi h/T$ を1サンプル分の時間 $1/f_s$ で離散積分(累積和)して位相を求めています。h_mod = 0.5 がMSKの条件です。この phase 配列が、折れ線状に増減する連続位相そのものになります。

続いて、得られた位相から実際のMSK波形(搬送波に載せたもの)と、ベースバンドのIQ成分を作り、位相軌跡とともに描画します。

fc = 4.0 / T   # 搬送波周波数(描画用に低めに設定)
s = np.cos(2 * np.pi * fc * t + phase)   # MSK送信信号(一定振幅)

I = np.cos(phase)   # 同相成分
Q = np.sin(phase)   # 直交成分

fig, ax = plt.subplots(3, 1, figsize=(11, 8))
ax[0].plot(t, phase / np.pi, lw=1.8)
ax[0].set_ylabel('phase / π')
ax[0].set_title('MSK phase trajectory (folded-line, continuous)')
ax[0].grid(alpha=0.3)
for k in range(N_sym + 1):
    ax[0].axvline(k * T, color='gray', ls=':', alpha=0.4)

ax[1].plot(t, s, lw=0.8)
ax[1].set_ylabel('s(t)')
ax[1].set_title('MSK passband waveform (constant envelope)')
ax[1].grid(alpha=0.3)

ax[2].plot(t, I, label='I = cos φ')
ax[2].plot(t, Q, label='Q = sin φ')
ax[2].set_xlabel('time / T'); ax[2].set_ylabel('amplitude')
ax[2].set_title('Baseband I/Q (half-sinusoid pulses)')
ax[2].legend(loc='upper right'); ax[2].grid(alpha=0.3)
plt.tight_layout()
plt.savefig('msk_phase_iq.png', dpi=140, bbox_inches='tight')
plt.show()

上の3つのグラフから、MSKの本質的な特徴が読み取れます。最上段の位相軌跡は、各シンボル区間で傾き $\pm\pi/(2T)$ の直線(上り坂・下り坂)が連続的につながった折れ線になっており、シンボル境界で必ず $\pi/2$ の整数倍に到達しています。これがまさに位相トレリスの1経路です。中段の搬送波波形は振幅が常に一定で、周波数だけがビットに応じて2値に切り替わっている(連続位相FSK)ことがわかります。最下段のI/Q成分は、それぞれ周期 $4T$ の正弦波の一部(半正弦波パルス)になっており、OQPSK等価表現で導いた $\cos(\pi t/2T)$, $\sin(\pi t/2T)$ の包絡線をなぞっていることが確認できます。

一定包絡線をIQ平面で確認する

次に、IQ平面(コンスタレーション軌跡)を描いて、MSKの信号点が本当に原点を避けて半径一定の円周上を動くことを確かめます。比較のため、原点を通過する通常QPSKの軌跡も並べて描きます。

import numpy as np
import matplotlib.pyplot as plt

# 前のセルの I, Q を使う(MSK)
env_msk = np.sqrt(I**2 + Q**2)

# 比較用:通常QPSK(矩形パルス、Iが2ビットごと、Qも2ビットごとに同時切替)
N2 = (N_sym // 2) * 2
aI = (2 * rng.integers(0, 2, N2 // 2) - 1)
aQ = (2 * rng.integers(0, 2, N2 // 2) - 1)
I_q = np.repeat(aI, 2 * sps).astype(float)
Q_q = np.repeat(aQ, 2 * sps).astype(float)
# 簡易なRC的丸め(移動平均)で帯域制限し、原点通過を見やすく
win = np.hanning(sps); win /= win.sum()
I_q = np.convolve(I_q, win, 'same')
Q_q = np.convolve(Q_q, win, 'same')

fig, ax = plt.subplots(1, 2, figsize=(11, 5))
ax[0].plot(I, Q, lw=1.0)
th = np.linspace(0, 2*np.pi, 200)
ax[0].plot(np.cos(th), np.sin(th), 'r--', alpha=0.5, label='|s|=1 circle')
ax[0].set_title('MSK constellation locus (constant envelope)')
ax[0].set_xlabel('I'); ax[0].set_ylabel('Q')
ax[0].set_aspect('equal'); ax[0].legend(); ax[0].grid(alpha=0.3)

ax[1].plot(I_q, Q_q, lw=1.0, color='C1')
ax[1].plot(0, 0, 'kx', ms=10, label='origin crossing')
ax[1].set_title('Filtered QPSK locus (passes near origin)')
ax[1].set_xlabel('I'); ax[1].set_ylabel('Q')
ax[1].set_aspect('equal'); ax[1].legend(); ax[1].grid(alpha=0.3)
plt.tight_layout()
plt.savefig('msk_qpsk_locus.png', dpi=140, bbox_inches='tight')
plt.show()
print('MSK envelope: min=%.4f max=%.4f' % (env_msk.min(), env_msk.max()))

左のMSKの軌跡は、点線で示した半径1の円にぴったり張りついて動き、決して内側(原点側)に落ち込みません。出力される包絡線の最小値・最大値もともに1に極めて近く、一定包絡線が数値的に確認できます。一方、右の帯域制限したQPSKの軌跡は原点を何度も通過し、その瞬間に包絡線がゼロまで落ち込みます。この原点通過が、非線形増幅器でスペクトル再成長を引き起こす元凶です。MSKがこれを構造的に回避していることが、視覚的にはっきり分かります。

GMSKのガウス整形パルスを作る

ここからGMSKに進みます。まずガウスフィルタのインパルス応答を作り、矩形パルスと畳み込んで整形パルス $q(t)$ を生成します。BT積を変えて、パルスがどう広がるかを比較します。

import numpy as np
import matplotlib.pyplot as plt

def gaussian_pulse(BT, sps, span=4):
    """BT積を指定してGMSKの整形パルス(周波数パルス)を作る"""
    # ガウスフィルタのインパルス応答
    t = np.arange(-span*sps, span*sps + 1) / sps   # シンボル単位の時間
    sigma = np.sqrt(np.log(2)) / (2 * np.pi * BT)
    g = np.exp(-t**2 / (2 * sigma**2)) / (np.sqrt(2*np.pi) * sigma)
    g /= g.sum() / sps    # 面積を1シンボル分に正規化
    # 幅Tの矩形パルスと畳み込む
    rect = np.ones(sps)
    q = np.convolve(g, rect, 'same')
    q /= q.sum() / sps    # 周波数パルスの面積(=π/2の位相回転)を正規化
    return t, q

plt.figure(figsize=(10, 5))
for BT in [0.2, 0.3, 0.5, 1.0]:
    t, q = gaussian_pulse(BT, sps=64)
    plt.plot(t, q, label=f'BT = {BT}')
# 参考:MSK(矩形周波数パルス)
plt.plot([-0.5, -0.5, 0.5, 0.5], [0, 1, 1, 0], 'k--', lw=1, label='MSK (rect)')
plt.xlabel('time / T'); plt.ylabel('frequency pulse q(t)')
plt.title('GMSK frequency-shaping pulse for various BT')
plt.legend(); plt.grid(alpha=0.3); plt.xlim(-3, 3)
plt.tight_layout()
plt.savefig('gmsk_pulses.png', dpi=140, bbox_inches='tight')
plt.show()

このグラフは、MSKの矩形周波数パルス(黒破線、1シンボル幅でぴったり立ち上がる)と、各BT積のガウス整形パルスを比較しています。$BT=1.0$ ではパルスは矩形に近く、1シンボル幅にほぼ収まっています。$BT$ を小さくする(0.5→0.3→0.2)につれてパルスの山が低く幅広くなり、前後の複数シンボルに裾を引いていることが読み取れます。$BT=0.3$ では裾が前後およそ2〜3シンボルに広がっており、これが部分応答(ISIの導入)の正体です。

GMSK波形の生成とMSKとの比較

整形パルスを使って、実際にGMSK信号の位相と波形を生成します。位相は整形パルスを使ったデータの重ね合わせを積分して求めます。

import numpy as np
import matplotlib.pyplot as plt

def gmsk_phase(bits, BT, sps, span=4):
    """ビット列とBT積からGMSKの位相を生成"""
    a = 2 * bits - 1
    # 各ビットを整形パルス q(t) で表現し、重ね合わせて瞬時周波数を作る
    _, q = gaussian_pulse(BT, sps, span)
    # 周波数パルス列:各シンボル位置に a_k * q を配置して加算
    L = len(bits) * sps + len(q)
    freq = np.zeros(L)
    for k, ak in enumerate(a):
        start = k * sps
        freq[start:start+len(q)] += ak * q
    # 位相 = (π/2) * 瞬時周波数の積分 / sps
    phase = (np.pi / 2) * np.cumsum(freq) / sps
    return phase

rng = np.random.default_rng(1)
bits = rng.integers(0, 2, 20)
sps = 64

plt.figure(figsize=(11, 4.5))
for BT, c in zip([0.3, 0.5, 1e3], ['C0', 'C1', 'k']):
    ph = gmsk_phase(bits, BT, sps)
    t = np.arange(len(ph)) / sps
    label = 'MSK (BT→∞)' if BT > 100 else f'GMSK BT={BT}'
    plt.plot(t, ph / np.pi, c, lw=1.4, label=label,
             ls='--' if BT > 100 else '-')
plt.xlabel('time / T'); plt.ylabel('phase / π')
plt.title('Phase trajectory: MSK vs GMSK')
plt.legend(); plt.grid(alpha=0.3); plt.xlim(0, 20)
plt.tight_layout()
plt.savefig('gmsk_phase_compare.png', dpi=140, bbox_inches='tight')
plt.show()

このグラフは、同じビット列に対するMSK(黒破線)とGMSK($BT=0.5$, $0.3$)の位相軌跡を重ねたものです。MSKの位相は鋭い折れ線で、シンボル境界で傾きが急に変わっています。一方GMSKの位相はその折れ線を滑らかになぞった曲線になっており、$BT$ が小さいほど(0.3が最も)角が取れて緩やかに変化していることが分かります。傾き(瞬時周波数)が連続的に変化するこの滑らかさが、後で見るスペクトルの裾の急速な減衰を生みます。

パワースペクトルの比較

理論の核心であるスペクトルを比較します。MSK、GMSK(複数のBT)、参考にQPSKのパワースペクトル密度(PSD)を同じ図に重ねます。

import numpy as np
import matplotlib.pyplot as plt

def gen_passband(phase, sps, fc_norm=8.0):
    """位相からパスバンド信号を生成(PSD計算用)"""
    t = np.arange(len(phase)) / sps
    return np.cos(2*np.pi*fc_norm*t + phase)

def psd_db(x, sps):
    """周波数(シンボルレート規格化)とPSD[dB]を返す"""
    X = np.fft.fftshift(np.fft.fft(x * np.hanning(len(x))))
    f = np.fft.fftshift(np.fft.fftfreq(len(x), d=1/sps))
    P = 20*np.log10(np.abs(X) + 1e-12)
    P -= P.max()
    return f, P

rng = np.random.default_rng(2)
bits = rng.integers(0, 2, 4000)
sps = 16

plt.figure(figsize=(10, 6))
for BT, label in [(1e3, 'MSK'), (0.5, 'GMSK BT=0.5'), (0.3, 'GMSK BT=0.3')]:
    ph = gmsk_phase(bits, BT, sps)
    s = gen_passband(ph, sps)
    f, P = psd_db(s, sps)
    plt.plot(f - 8.0, P, lw=1.0, label=label)   # 搬送波を0にシフト

plt.xlabel('normalized frequency (f - fc) / R')
plt.ylabel('PSD [dB]')
plt.title('Power spectral density: MSK vs GMSK')
plt.xlim(-2.5, 2.5); plt.ylim(-80, 5)
plt.legend(); plt.grid(alpha=0.3)
plt.tight_layout()
plt.savefig('gmsk_psd.png', dpi=140, bbox_inches='tight')
plt.show()

このスペクトル比較は、本記事の理論がすべて凝縮された最重要の図です。3つの方式とも中心(搬送波)付近のメインローブは似ていますが、裾の落ち方が劇的に異なります。MSKはサイドローブが規則的に並び $f^{-4}$ で減衰しますが、最初のサイドローブは $-23$ dB付近に残っています。GMSK $BT=0.5$ になるとサイドローブが大きく沈み、$BT=0.3$ ではさらに深く(数十dB下まで)落ち込んで、隣接チャネルへの漏れがほぼ無視できるレベルになります。BT積を小さくするほど帯域がコンパクトになるという、GMSKの設計原理がそのまま見て取れます。

BT積とアイパターン — ISIのトレードオフ

最後に、帯域を絞る対価であるISIを アイパターン で可視化します。アイパターンは、復調後のベースバンド信号をシンボル周期ごとに重ね描きしたもので、「目(アイ)」の開き具合が判定マージン(ノイズ耐性)を表します。

import numpy as np
import matplotlib.pyplot as plt

def gmsk_baseband_I(bits, BT, sps, span=4):
    """GMSKのI成分(cos φ)をベースバンドで返す"""
    ph = gmsk_phase(bits, BT, sps, span)
    return np.cos(ph)

rng = np.random.default_rng(3)
bits = rng.integers(0, 2, 400)
sps = 32

fig, ax = plt.subplots(1, 3, figsize=(13, 4))
for j, BT in enumerate([1e3, 0.5, 0.3]):
    I = gmsk_baseband_I(bits, BT, sps)
    # 2シンボル分を1区画として重ね描き
    span_samp = 2 * sps
    n_trace = (len(I) - span_samp) // sps
    for k in range(n_trace):
        seg = I[k*sps : k*sps + span_samp]
        ax[j].plot(np.arange(span_samp)/sps, seg, 'C0', alpha=0.15)
    title = 'MSK' if BT > 100 else f'GMSK BT={BT}'
    ax[j].set_title(f'Eye pattern: {title}')
    ax[j].set_xlabel('time / T'); ax[j].set_ylabel('I = cos φ')
    ax[j].grid(alpha=0.3)
plt.tight_layout()
plt.savefig('gmsk_eye.png', dpi=140, bbox_inches='tight')
plt.show()

3つのアイパターンを比べると、帯域とISIのトレードオフが一目瞭然です。MSK(左)のアイは大きく開いており、判定時刻での上下のマージンが十分に取れています。GMSK $BT=0.5$(中)ではアイがやや狭まり、$BT=0.3$(右)になると軌跡のばらつきが増えてアイの開口が明確に縮小しています。これは部分応答により近傍シンボルが互いに干渉している(ISIが増えた)ことの直接の現れです。アイが狭いほど、同じ雑音でも誤判定しやすくなるため、$BT$ を下げると符号誤り率がわずかに悪化します。GSMが $BT=0.3$ を選んだのは、スペクトルの優秀さ(この程度のアイ狭まりで済む)と性能劣化(約0.3 dB)が許容できるバランス点だったからです。

これらの可視化を通じて、「連続位相による帯域の良さ」「一定包絡線による増幅の有利さ」「ガウス整形によるさらなる帯域圧縮とISIの代償」という、MSK/GMSKの全体像が定量的に確認できました。

まとめ

本記事では、MSK/GMSK変調を連続位相変調(CPM)の観点から導出し、Pythonで可視化しました。要点を整理します。

  • MSKは変調指数 $h=0.5$ の連続位相FSK であり、1ビットごとに位相がちょうど $\pm\pi/2$ だけ回転する。$h=0.5$ は2信号が直交を保つ最小の周波数偏移であり、これが「Minimum」の由来である
  • 位相トレリス は、位相が $\pi/2$ の格子点を通る折れ線として信号の取りうる経路を表し、最尤(ビタビ)検波の基盤になる
  • MSKは半正弦波パルス整形を施したOQPSKと数学的に等価 であり、IとQのオフセットと半正弦波整形が一定包絡線を生む
  • 一定包絡線 により、原点通過がなく振幅情報を持たないため、電力効率の高い非線形PAをバックオフなしで使え、携帯端末や衛星送信機の電力効率を最大化できる
  • GMSK は変調前のデータをガウスLPFで整形してから周波数変調することで、位相軌跡をさらに滑らかにし、スペクトルの裾を劇的に抑える
  • BT積 がスペクトル占有とISIのトレードオフを1パラメータで決め、GSMは $BT=0.3$ を採用した。$BT$ を下げると帯域は狭まるが部分応答によるISIが増え、アイが狭まる

MSK/GMSKは、連続位相変調(CPM)という広い変調族の最も基本的な入口です。ここを押さえれば、より一般の部分応答CPMや、複数の変調指数を切り替えるマルチh変調、さらにはターボ符号と組み合わせた連接符号化変調へと自然に発展できます。

次のステップとして、以下の記事も参考にしてください。