グレイ符号マッピングとは?多値変調のBERを下げる仕組み

スマートフォンが基地局と話すとき、電波の1回の「区切り」(シンボル)に載せているビットは1個ではありません。16QAMなら4ビット、64QAMなら6ビット、256QAMなら8ビットをまとめて1つの信号点として送ります。ここで少し不思議なことが起こります。送信電力もノイズも変調方式もまったく同じなのに、「どの信号点にどのビット列を割り当てるか」を変えるだけで、受信側のビット誤り率が変わってしまうのです。信号点の配置は1ミリも動かしていないのに、です。

なぜそんなことが起きるのでしょうか。鍵は「シンボルが1個間違うと、ビットは何個間違うのか」という問いにあります。16QAMのシンボルが1つ誤ったとき、壊れるビットは1個かもしれないし、4個全部かもしれません。どちらになるかを決めているのが、信号点とビット列の対応表 — すなわちマッピング(ラベリング)です。そして、隣り合う信号点のビット列がちょうど1ビットしか違わないように対応を組む方法がグレイ符号マッピング(Gray coded mapping)です。

グレイ符号マッピングと自然2進マッピングで、同じ1回のシンボル誤りから壊れるビット数が1個と2個に分かれる様子の模式図

この図が本記事の主張のすべてを1枚に凝縮したものです。左右どちらも「送った信号点の隣に誤って落ちた」というまったく同じ事故が起きていますが、グレイ側では 0111 → 1111 で違うのは先頭の1桁だけ、自然2進側では 0110 → 1010 で2桁が同時に壊れています。信号点の座標も送信電力も雑音の統計も一切変えていないのに、貼ったビット列の違いだけで被害が2倍になっている — この「タダで損をしている」状態を潰すのがグレイ符号マッピングです。

グレイ符号マッピングは、追加の電力も帯域も計算量も一切使わずにBERを下げられる、通信システム設計における数少ない「タダ飯」です。実際、次のような場面で必ず顔を出します。

  • 携帯電話・Wi-Fiの適応変調: LTE/5G NRやIEEE 802.11の変調方式(QPSK/16QAM/64QAM/256QAM/1024QAM)の信号点配置は、規格書のコンスタレーション表そのものがグレイマッピングで定義されています。伝搬状況に応じて多値数を切り替えても、常に隣接シンボル間は1ビット差です
  • 衛星放送・衛星通信: DVB-S2/S2XのAPSK変調では、リング状の信号点配置に対して「できるだけグレイに近い」ラベリングを設計する問題が規格策定の中心課題の一つでした
  • 誤り訂正符号との連携(BICM): LDPC符号やターボ符号と多値変調を組み合わせるとき、復号器に渡すビットごとの対数尤度比(LLR)の質はマッピングに直結します。グレイマッピングは各ビットのLLRを互いに独立に近づけ、軟判定復号の性能を引き出します
  • 光ファイバのコヒーレント伝送: 100G/400Gのコヒーレント光通信でも偏波多重16QAM/64QAMが使われ、DSPの内部で同じグレイマッピングが前提になっています

本記事の内容

  • シンボル誤り率(SER)とビット誤り率(BER)が別物である理由と、その橋渡しをする「平均ハミング距離」
  • 反射型グレイ符号の再帰的構成法と、閉じた式 $g = n \oplus (n \gg 1)$ の証明
  • 16QAM/64QAMの星座図にビット列を実際に貼り付け、隣接シンボルが必ず1ビット差になることの確認
  • 高SNR近似のもとで $\mathrm{BER} \approx \mathrm{SER}/\log_2 M$ が成り立つ理由の導出
  • 16QAMグレイマッピングの厳密なBER式 $\frac{1}{4}\left[3Q(z) + 2Q(3z) – Q(5z)\right]$ の完全導出
  • PythonによるAWGN上のモンテカルロ実験 — グレイ/自然2進/最悪マッピングの比較

前提知識

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

シンボルが1個誤ると、ビットは何個誤るのか

「1回の失敗」の重さは一定ではない

まず、シンボル誤りとビット誤りが別物であることを、数式抜きで納得しておきましょう。

4桁の暗証番号を思い浮かべてください。あなたが「3721」と伝えたのに、相手が「3722」と聞き間違えたなら、間違っているのは1桁だけです。ところが「3721」が「8496」と伝わってしまったら、4桁すべてが間違いです。どちらも「暗証番号を1回間違えた」という点では同じ1回の失敗ですが、壊れた桁数はまったく違います。

ディジタル変調でも事情はそっくり同じです。16QAMでは16個の信号点それぞれに4ビットのラベルが貼られています。受信機は雑音で揺らいだ受信点を見て、最も近い信号点を選びます(最尤判定=最近接判定)。このとき送った点と違う点を選んでしまえば「シンボル誤り」1回ですが、そこから取り出される4ビットのうち何ビットが反転するかは、送った点のラベルと選ばれた点のラベルのハミング距離で決まります。

つまり、

$$ \text{ビット誤り数} = d_H(\text{送信シンボルのラベル},\ \text{判定シンボルのラベル}) $$

です。$d_H$ はハミング距離、すなわち2つのビット列で値が異なる位置の個数を表します。

誤りは「隣」に落ちる

ここで、AWGN通信路が持つきわめて重要な性質が効いてきます。高いSNRでは、シンボル誤りはほとんどすべて「最も近い信号点への誤り」になる、という性質です。

理由はガウス雑音の裾の落ち方にあります。雑音が距離 $\delta$ 以上ずれる確率はおおよそ $Q(\delta/\sigma)$ で、$Q$ 関数は $Q(x) \approx e^{-x^2/2}/(x\sqrt{2\pi})$ と指数の二乗で落ちます。最近接点までの距離を $d_{\min}$、その2倍離れた点までの距離を $2 d_{\min}$ とすると、誤って飛び込む確率の比はおよそ

$$ \frac{Q(2d_{\min}/2\sigma)}{Q(d_{\min}/2\sigma)} \sim \exp\left(-\frac{3}{2}\left(\frac{d_{\min}}{2\sigma}\right)^2\right) $$

となり、SNRが上がるほど猛烈な勢いで無視できるようになります。後で数値で確かめますが、$E_b/N_0 = 10$ dBの16QAMではこの比はすでに $10^{-6}$ のオーダー($Q(2z)/Q(z) = 3.3\times10^{-6}$)です。

最近接点・斜め方向の点・2つ先の点への誤り確率をEb/N0に対して片対数で比較したグラフ

3本の曲線は距離が $d_{\min}$、$\sqrt{2}d_{\min}$、$2d_{\min}$ の相手へ誤り込む確率です。$E_b/N_0 = 10$ dB の縦線上で読むと、最近接への誤りが $2.34\times10^{-3}$ なのに対し、斜め方向は $3.17\times10^{-5}$(約1.4%)、2つ先は $7.7\times10^{-9}$(約 $3\times10^{-6}$)まで落ちています。SNRを上げるほど3本の間隔は開く一方なので、「誤り=隣への誤り」という近似は高SNRでは実質的に厳密です。だからこそ、隣とのラベル差だけを最適化すれば十分なのです。

この2つの事実を合わせると、設計指針が自動的に見えてきます。誤りはほぼ必ず隣の点に落ちる。ならば、隣の点とのラベルの差を最小にしておけばよい。 隣同士のハミング距離を1にできれば、シンボルが1回誤っても壊れるビットはたったの1個で済みます。これがグレイ符号マッピングの発想のすべてです。

では、そんな都合のよいビット列の並べ方は本当に作れるのでしょうか。次の節で、その構成法を見ていきましょう。

グレイ符号とは — 隣接語のハミング距離を1に保つ並べ方

回転する軸を読み取るという実務的な悩み

グレイ符号は通信のために生まれたわけではありません。もともとは、回転する軸の角度を読み取るアブソリュート・ロータリーエンコーダの設計から来ています。

円盤に同心円状の明暗パターンを刻み、複数のセンサで一度に読み取って角度をディジタル値として得る、という装置を考えます。角度の目盛りに自然2進数(0000, 0001, 0010, …)をそのまま刻むとどうなるでしょうか。目盛り7(0111)と目盛り8(1000)の境界では、4本のセンサが同時に切り替わらなければなりません。現実には円盤の刻みにも取り付けにも誤差がありますから、切り替わりのタイミングは微妙にずれます。1本だけ先に切り替われば、一瞬 1111(=15)という、まったく見当違いの値が読み出されてしまいます。7と8のあいだで15が出るのは、制御系にとって悪夢です。

この問題を消し去るには、隣の目盛りに移るとき変化するビットを常に1本だけにすればよい。1本しか変わらないなら、そのビットが切り替わる前後どちらの値が読めても、隣り合う正しい目盛りのどちらかになります。誤差は最大でも1目盛りです。この性質を持つ符号がグレイ符号(Gray code)で、1947年にベル研究所のFrank Grayが特許で提示したことから名前がついています。

自然2進とグレイ符号のエンコーダ円盤の明暗トラックを並べ、7から8の境界で切り替わるビット本数を比較した図

黒が1、白が0のトラックで、横方向が角度の目盛り番号です。左の自然2進では目盛り7と8の境界(太い縦線)で4本のトラックが一斉に反転しているのが一目でわかります。右のグレイ符号では、この境界に限らずどの目盛り境界を見ても色が変わっているトラックは1本だけです。この「1本しか変わらない」という性質が、そのまま多値変調の「1ビットしか壊れない」に対応します。

定義

$m$ ビットの符号語の列 $g_0, g_1, \dots, g_{2^m-1}$ がグレイ符号であるとは、次の2条件を満たすことをいいます。

$$ \begin{equation} \{g_0, g_1, \dots, g_{2^m-1}\} = \{0,1\}^m \end{equation} $$

すなわち $2^m$ 通りのビット列を1回ずつ過不足なく使い切る、ということです。そのうえで、

$$ \begin{equation} d_H(g_k,\ g_{k+1}) = 1 \quad (k = 0, 1, \dots, 2^m – 2) \end{equation} $$

を要求します。列の中で隣り合う符号語は、必ずどこか1桁だけが違う、という条件です。さらに $d_H(g_{2^m-1}, g_0) = 1$ も満たすものを巡回グレイ符号(cyclic Gray code)と呼びます。後で見る反射型グレイ符号は、この巡回性も満たします。

条件(2)は、「$m$ 次元超立方体の頂点を、辺をたどって一筆書きで全部訪問する」ことと同じです。ビット列を超立方体の頂点、1ビットだけ違う関係を辺と見なすと、グレイ符号とは超立方体のハミルトン路にほかなりません。巡回グレイ符号ならハミルトン閉路です。

3ビットグレイ符号を立方体上のハミルトン閉路として描いた3D図

立方体の8頂点が3ビットの符号語、辺が「1ビットだけ違う」関係です。青い太線が $000 \to 001 \to 011 \to 010 \to 110 \to 111 \to 101 \to 100$ という訪問順で、すべての頂点をちょうど1回ずつ、必ず辺の上だけを通って回っています。橙の破線は末尾 $100$ から先頭 $000$ へ戻る辺で、これも1ビット差なので閉路になっている(=巡回グレイ符号である)ことが見て取れます。グレイ符号を探す問題が、実は超立方体上の経路探索問題だったわけです。

反射型グレイ符号の再帰的構成

グレイ符号の作り方はいくつもありますが、最も基本的かつ実用上ほぼ唯一使われるのが反射型グレイ符号(reflected binary code, RBC)です。作り方は驚くほど簡単で、次の再帰で定義されます。

ステップ1(初期値): 1ビットのグレイ符号は自明に

$$ G_1 = (0,\ 1) $$

ステップ2(反射と拡張): $(m-1)$ ビットのグレイ符号 $G_{m-1} = (g_0, g_1, \dots, g_{2^{m-1}-1})$ が得られているとき、$m$ ビットのグレイ符号 $G_m$ を次で作ります。

$$ \begin{equation} G_m = \bigl(\underbrace{0g_0,\ 0g_1,\ \dots,\ 0g_{2^{m-1}-1}}_{\text{そのまま、先頭に }0},\ \underbrace{1g_{2^{m-1}-1},\ \dots,\ 1g_1,\ 1g_0}_{\text{順序を反転、先頭に }1}\bigr) \end{equation} $$

言葉にすると、「前半は $G_{m-1}$ をそのまま並べて先頭に0を付け、後半は $G_{m-1}$ を鏡像反転(reflect)して並べ先頭に1を付ける」となります。「反射型」という名前はこの鏡像反転から来ています。

実際に手を動かしてみましょう。$G_1 = (0, 1)$ から始めます。前半は $0$ を付けて $(00, 01)$、後半は $G_1$ を反転した $(1, 0)$ に $1$ を付けて $(11, 10)$。つなげて

$$ G_2 = (00,\ 01,\ 11,\ 10) $$

同じ操作をもう一度。前半は $(000, 001, 011, 010)$、後半は $G_2$ の反転 $(10, 11, 01, 00)$ に1を付けて $(110, 111, 101, 100)$。したがって

$$ G_3 = (000,\ 001,\ 011,\ 010,\ 110,\ 111,\ 101,\ 100) $$

G1からG2、G2からG3への反射型グレイ符号の再帰構成を矢印で示した図

青い実線の矢印が「前半:順序そのまま+先頭に0」、橙の破線の矢印が「後半:順序を反転+先頭に1」に対応します。破線が交差しているのは、まさに順序をひっくり返しているからです。注目すべきは赤で示した継ぎ目で、$G_3$ の前半末尾 $010$ と後半先頭 $110$ が下位2ビットを共有し、先頭ビットだけが $0 \to 1$ に変わっています。反射を入れずに $G_2$ をそのまま並べていたら継ぎ目は $010$ と $100$ になり、2ビット差になってしまいます。

もう一度回せば4ビット版が得られます。

$$ G_4 = (0000, 0001, 0011, 0010, 0110, 0111, 0101, 0100, 1100, 1101, 1111, 1110, 1010, 1011, 1001, 1000) $$

構成法が正しいことの証明

再帰構成(3)が本当にグレイ符号を作ることを、$m$ に関する帰納法で確かめます。$G_{m-1}$ がグレイ符号(かつ巡回グレイ符号)だと仮定します。$G_m$ の隣接ペアは3種類に分類できます。

(a) 前半の内部: $0g_k$ と $0g_{k+1}$ は、先頭ビットが共通で残りが $g_k, g_{k+1}$ です。帰納法の仮定から $d_H(g_k, g_{k+1}) = 1$ なので、$d_H(0g_k, 0g_{k+1}) = 1$ です。

(b) 後半の内部: 後半は $G_{m-1}$ を逆順に並べただけですから、隣接関係の集合は前半と同じです。先頭ビットもすべて1で共通なので、やはりハミング距離は1になります。

(c) 前半と後半の継ぎ目: 前半の最後の要素は $0g_{2^{m-1}-1}$、後半の最初の要素は $1g_{2^{m-1}-1}$ です。後ろの $(m-1)$ ビットが完全に一致し、先頭ビットだけが $0 \to 1$ と変わっています。したがってハミング距離はちょうど1です。ここが反射(鏡像反転)を入れた理由で、もし反転せずに $G_{m-1}$ をそのまま並べていたら、継ぎ目は $0g_{2^{m-1}-1}$ と $1g_0$ になり、$d_H$ が1になる保証はありません。

以上(a)(b)(c)から $G_m$ もグレイ符号です。巡回性も同様に確かめられます。$G_m$ の最後の要素は $1g_0$、最初の要素は $0g_0$ で、これも先頭ビットだけが違うのでハミング距離1です。$m=1$ で明らかに成立していますから、帰納法によりすべての $m \ge 1$ で成立します。

なお、要素数についても確認しておきましょう。$|G_m| = 2|G_{m-1}| = 2 \cdot 2^{m-1} = 2^m$ であり、前半と後半で先頭ビットが異なるため重複はありません。よって $\{0,1\}^m$ を過不足なく1回ずつ並べたものになっています。

閉じた式 — XORひとつでグレイ符号が作れる

再帰構成は美しいのですが、実装では「整数 $n$ に対応するグレイ符号語を直接計算したい」場面が多くあります。実は、反射型グレイ符号には次の驚くほど簡潔な閉形式があります。

$$ \begin{equation} g(n) = n \oplus (n \gg 1) \end{equation} $$

ここで $\oplus$ はビットごとの排他的論理和(XOR)、$\gg$ は右シフトです。ビット単位で書けば、$n$ の2進表現を $b_{m-1} b_{m-2} \cdots b_0$ として

$$ g_i = b_i \oplus b_{i+1} \quad (i = 0, 1, \dots, m-1,\ \ b_m \equiv 0) $$

となります。つまり「隣り合う2ビットのXORを取る」だけです。

nの2進表現、1ビット右シフト、そのXORであるグレイ語を4ビット16通り分並べ、隣とのハミング距離が全て1であることを示した表

上段が $n$、中段が $n \gg 1$、下段がそのXORです。下段を左から読むと $0000, 0001, 0011, 0010, 0110, \dots$ となり、先ほど再帰で作った $G_4$ と完全に一致しています。さらに下段の隣り合う列を見比べると、変わっているのは常にちょうど1桁で、青い「1」がその確認です。$n=7 \to 8$ のように2進表現では4桁が同時に変わる箇所でも、XORを通すと1桁差に化けるところがこの式の妙味です。

この式が式(2)の条件を満たすこと、すなわち $d_H(g(n), g(n+1)) = 1$ を直接示しましょう。まずXORの性質から

$$ g(n) \oplus g(n+1) = \bigl(n \oplus (n \gg 1)\bigr) \oplus \bigl((n+1) \oplus ((n+1) \gg 1)\bigr) $$

XORは可換かつ結合的なので、項を並べ替えて2つのグループにまとめられます。

$$ g(n) \oplus g(n+1) = \bigl(n \oplus (n+1)\bigr) \oplus \bigl((n \gg 1) \oplus ((n+1) \gg 1)\bigr) $$

ここで、$n$ の下位ビットがちょうど $t$ 個連続する1で終わっているとしましょう。すなわち $A$ を適当な非負整数として

$$ n = A \cdot 2^{t+1} + \underbrace{(2^t – 1)}_{\text{下位 }t\text{ ビットが }1}, \qquad n + 1 = A \cdot 2^{t+1} + 2^t $$

と書けます(位置 $t$ のビットは0、位置 $0 \sim t-1$ のビットが1)。$n$ に1を足すと下位の $t$ 個の1がすべて0に変わり、位置 $t$ に繰り上がりが乗ります。したがって第1グループは

$$ n \oplus (n+1) = 2^{t+1} – 1 \quad (\text{下位 } t+1 \text{ ビットがすべて1}) $$

次に第2グループを計算します。$t \ge 1$ のとき、右シフトすると

$$ n \gg 1 = A \cdot 2^{t} + (2^{t-1} – 1), \qquad (n+1) \gg 1 = A \cdot 2^{t} + 2^{t-1} $$

上位の $A \cdot 2^t$ が共通なのでXORで消え、残るのは $(2^{t-1}-1) \oplus 2^{t-1} = 2^t – 1$ です。よって

$$ (n \gg 1) \oplus ((n+1) \gg 1) = 2^t – 1 $$

2つのグループのXORを取ると、下位 $t$ ビットが打ち消し合って

$$ g(n) \oplus g(n+1) = (2^{t+1} – 1) \oplus (2^{t} – 1) = 2^t $$

$2^t$ は1ビットだけが立った数ですから、$d_H(g(n), g(n+1)) = 1$ が示されました。$t = 0$($n$ が偶数)の場合も別に確認しておくと、$n \oplus (n+1) = 1$、右シフトすると $n \gg 1 = (n+1) \gg 1$ なので第2グループは0となり、$g(n) \oplus g(n+1) = 1 = 2^0$ でやはり1ビットです。

逆変換も押さえておきましょう。$g_i = b_i \oplus b_{i+1}$ を $b$ について解くと、上位から順に

$$ b_{m-1} = g_{m-1}, \qquad b_i = b_{i+1} \oplus g_i \quad (i = m-2, \dots, 0) $$

すなわち $b_i = g_{m-1} \oplus g_{m-2} \oplus \cdots \oplus g_i$(上位からの累積XOR)です。受信側でグレイラベルから元のビット列を戻すときに使います。

グレイ符号という「1次元の並べ方」が手に入りました。次は、これを2次元の星座図(コンスタレーション)にどう貼り付けるかを見ていきます。

方形QAMへのグレイマッピング

I軸とQ軸に分けて考える

$M = 2^m$ 点の方形QAM($M$ が偶数乗のとき、$\sqrt{M} \times \sqrt{M}$ の格子)は、実は「2つの独立な $\sqrt{M}$ 値PAM」に完全に分解できます。同相成分(I)と直交成分(Q)は直交する2つの基底関数に載っているので、AWGNの雑音成分も互いに独立です。受信側の最近接判定も、I軸の判定とQ軸の判定に分離できます。

この分解を利用すれば、2次元のグレイラベリングは1次元の問題2つに帰着します。手順はこうです。

  1. $m$ ビットのラベルを前半 $m/2$ ビット(I用)と後半 $m/2$ ビット(Q用)に分ける
  2. I軸の $\sqrt{M}$ 個の振幅レベルを小さい順に並べ、$k$ 番目のレベルに $m/2$ ビットのグレイ符号語 $g(k)$ を割り当てる
  3. Q軸にもまったく同じことをする

これで完成です。この構成が2次元でもグレイ性を持つ理由は明快です。格子上で隣接する2点(I方向またはQ方向に1ステップ)を考えると、片方の軸のインデックスだけが1変化し、もう片方の軸は不変です。変化した軸のラベルはグレイ符号の性質から1ビットだけ変わり、変化しない軸のラベルは完全に同じままです。したがって全体のハミング距離はちょうど1になります。

$$ d_H\bigl((g(k_I),\, g(k_Q)),\ (g(k_I \pm 1),\, g(k_Q))\bigr) = d_H(g(k_I), g(k_I\pm1)) + 0 = 1 $$

16QAMのラベル表

具体的に16QAM($m = 4$、I/Qそれぞれ2ビット、4値PAM×2)を書き下しましょう。振幅レベルは $\{-3, -1, +1, +3\}$(正規化前)、対応するインデックスは $k = 0,1,2,3$ です。2ビットグレイ符号は $G_2 = (00, 01, 11, 10)$ なので、

レベル $-3$ $-1$ $+1$ $+3$
インデックス $k$ 0 1 2 3
グレイラベル $g(k)$ 00 01 11 10
自然2進ラベル 00 01 10 11

これをI・Q両軸に適用し、シンボルのビット列を $b_3 b_2 b_1 b_0$(上位2ビットがI、下位2ビットがQ)とすると、星座図は次のようになります。行が上から $Q = +3, +1, -1, -3$、列が左から $I = -3, -1, +1, +3$ です。

グレイマッピング

Q=+3 |  0010   0110   1110   1010
Q=+1 |  0011   0111   1111   1011
Q=-1 |  0001   0101   1101   1001
Q=-3 |  0000   0100   1100   1000
       I=-3   I=-1   I=+1   I=+3

自然2進マッピング(比較用)

Q=+3 |  0011   0111   1011   1111
Q=+1 |  0010   0110   1010   1110
Q=-1 |  0001   0101   1001   1101
Q=-3 |  0000   0100   1000   1100
       I=-3   I=-1   I=+1   I=+3

グレイの表で、どの隣り合う2マス(上下・左右)を取っても違うビットがちょうど1個であることを、いくつか確かめてみてください。たとえば $0111$ の左は $0011$($b_2$ だけ違う)、右は $1111$($b_3$ だけ違う)、上は $0110$($b_0$ だけ違う)、下は $0101$($b_1$ だけ違う)です。

一方、自然2進の表では危険な場所があります。$I = -1$ の $0110$ とその右隣 $I = +1$ の $1010$ は、$b_3$ と $b_2$ の2ビットが違います。これは4値PAMの $01 \to 10$ という繰り上がりがそのまま2次元に持ち込まれた結果です。中央の縦線と横線をまたぐたびに2ビットが同時に壊れます。

16QAM星座図にグレイと自然2進のビット割当を貼り、隣接ペアのハミング距離を辺の色で示した比較図

左右で信号点の座標はまったく同じで、貼られたラベルだけが違います。左のグレイでは辺がすべて灰色(1ビット差)で、赤い辺は1本もありません。右の自然2進では中央の縦線と横線に沿って赤い太線が並び、そこだけ2ビットが同時に壊れることが可視化されています。この赤い辺の存在が平均ハミング距離を $1.0000$ から $1.3333$ へ押し上げ、そのままBERの劣化として現れます。

斜め方向の隣はどうなるか

「隣接」という言葉には注意が必要です。格子上で斜めに位置する点(たとえば $0111$ と $1011$)は、距離が $\sqrt{2}\, d_{\min}$ 離れており、グレイマッピングではハミング距離が2になります(I側で1ビット、Q側で1ビット)。

これは欠陥ではありません。誤り確率は $Q(\sqrt{2} \cdot d_{\min}/2\sigma)$ のオーダーで、真の最近接点への誤り $Q(d_{\min}/2\sigma)$ より指数的に小さいからです。実際、$E_b/N_0 = 10$ dBの16QAMでは前者は後者の $1.4\times10^{-2}$ 程度($3.17\times10^{-5}$ 対 $2.34\times10^{-3}$)にすぎません。高SNR域では「上下左右の4近傍」だけを考えれば十分、というのが実務的な整理です。

なお、方形QAMのラベリングでは「すべての隣接ペアのハミング距離を1にする」ことは常に達成可能ですが、平均ハミング距離を1未満にすることは原理的に不可能です。隣接ペアは必ず異なるラベルを持つので、ハミング距離は最低でも1だからです。つまりグレイマッピングは、この意味で最適です。

64QAMへの拡張

64QAM($m = 6$、I/Qそれぞれ3ビット、8値PAM×2)でもまったく同じ手続きで構成できます。3ビットグレイ符号は

$$ G_3 = (000,\ 001,\ 011,\ 010,\ 110,\ 111,\ 101,\ 100) $$

なので、振幅レベル $-7, -5, -3, -1, +1, +3, +5, +7$ に上から順にこれを割り当てます。後のPython実験で、64QAMの全隣接ペア($64 \times 3.5 = 224$ 組の順序対)のハミング距離が例外なく1になることを数え上げで確認します。

対して自然2進の8値PAMでは、隣接ペアのハミング距離は $1, 2, 1, 3, 1, 2, 1$ と大きくばらつきます。特に中央の $011 \to 100$ は3ビット同時に反転します。多値数を上げるほど、自然2進の「繰り上がり」の被害は深刻になっていくわけです。

64QAM星座図にグレイと自然2進の6ビットラベルを貼り、隣接ペアのハミング距離を辺の色で示した比較図

64点に増えても構図は変わりません。左のグレイは64点すべての隣接ペアが灰色(1ビット差)で埋め尽くされ、平均ハミング距離はきっちり $1.0000$ です。右の自然2進では橙(2ビット差)と赤(3ビット差)の辺が格子状に走り、平均は $1.5714 = 11/7$ に悪化しています。赤い辺が図全体を貫く十字状に並んでいるのは、3ビット差になるのが8値PAMの $011 \to 100$($3 \to 4$)という1箇所だけで、その繰り上がり線をI方向・Q方向それぞれ8本の行・列すべてが横切るためです。橙の2ビット差は $1 \to 2$ と $5 \to 6$ の2箇所で起き、こちらは中央から離れた位置に対称に現れます。

ここまでで、グレイマッピングが「隣接ハミング距離1」を実現することがわかりました。次は、この性質がBERという最終的な性能指標にどう効くのかを、式で結びつけていきます。

SERからBERへ — $\mathrm{BER} \approx \mathrm{SER}/\log_2 M$ の導出

厳密な出発点

まず近似を一切使わない関係式から出発します。$M = 2^m$ 点のコンスタレーションで、シンボル $s$ を送って $\hat{s}$ と判定される確率を $P(\hat{s} \mid s)$、シンボルの事前確率を $P(s) = 1/M$(等確率)とします。1シンボルあたり $m$ ビットを運ぶので、ビット誤り率は「誤ったビット数の期待値 ÷ 総ビット数」として

$$ \begin{equation} \mathrm{BER} = \frac{1}{m} \sum_{s} P(s) \sum_{\hat{s} \neq s} P(\hat{s} \mid s)\, d_H(s, \hat{s}) \end{equation} $$

と書けます。$1/m$ で割っているのは、1シンボルあたり $m$ ビットあるためです。一方、シンボル誤り率は単にハミング距離の重みを外したもの、すなわち

$$ \begin{equation} \mathrm{SER} = \sum_{s} P(s) \sum_{\hat{s} \neq s} P(\hat{s} \mid s) \end{equation} $$

です。ここで式(5)と式(6)を見比べると、両者の違いが「誤り事象に $d_H$ という重みを付けるかどうか」だけであることがはっきりします。そこで、誤りが起きたという条件のもとでの平均ハミング距離を導入しましょう。

$$ \begin{equation} \bar{d}_H \equiv \frac{\sum_{s} P(s) \sum_{\hat{s} \neq s} P(\hat{s}\mid s)\, d_H(s,\hat{s})}{\sum_{s} P(s)\sum_{\hat{s}\neq s} P(\hat{s}\mid s)} = \mathbb{E}\left[d_H \mid \text{シンボル誤り}\right] \end{equation} $$

定義から、式(5)(6)(7)は次の厳密な関係で結ばれます。

$$ \begin{equation} \mathrm{BER} = \frac{\bar{d}_H}{m}\ \mathrm{SER} \end{equation} $$

この式(8)は近似ではありません。あらゆるSNR、あらゆるマッピングで成り立ちます。マッピングの良し悪しは、すべて $\bar{d}_H$ という1つのスカラーに凝縮されているわけです。

高SNR極限で $\bar{d}_H$ が何になるか

問題は $\bar{d}_H$ の評価です。ここで最初の節で確認した「誤りは隣に落ちる」という性質を使います。

高SNRでは、$P(\hat{s}\mid s)$ が実質的にゼロでないのは $\hat{s}$ が $s$ の最近接点(距離 $d_{\min}$)である場合だけです。しかも各最近接点への誤り確率はすべて同じ $\approx Q(d_{\min}/2\sigma)$ になります(判定境界までの距離が等しいため)。したがって式(7)の分子・分母の和は最近接ペアだけを走り、重みも共通の $Q(d_{\min}/2\sigma)$ で約分されて、

$$ \begin{equation} \bar{d}_H \xrightarrow[\text{高SNR}]{} \bar{d}_H^{\mathrm{NN}} \equiv \frac{\displaystyle\sum_{(s,\hat{s}) \in \mathcal{E}} d_H(s,\hat{s})}{|\mathcal{E}|} \end{equation} $$

となります。ここで $\mathcal{E}$ は最近接な順序対($s$ から $\hat{s}$ への「辺」)全体の集合です。要するに $\bar{d}_H^{\mathrm{NN}}$ は、星座図の隣接グラフの辺に沿って測ったハミング距離の平均値という、純粋に組合せ的な量です。

グレイマッピングでは、定義からすべての辺で $d_H = 1$ ですから

$$ \bar{d}_H^{\mathrm{NN}} = 1 \quad \Longrightarrow \quad \boxed{\ \mathrm{BER} \approx \frac{\mathrm{SER}}{m} = \frac{\mathrm{SER}}{\log_2 M}\ } $$

が得られます。これが本記事のタイトルにある関係式です。「シンボル誤りが1回起きても壊れるビットは1個、そのビットは $m$ ビット中の1個だから、ビット誤り率はシンボル誤り率の $1/m$」という、きわめて素直な理屈でした。

上限と下限 — 悪いマッピングはどこまで悪くなれるか

式(8)は同時に、マッピングの善し悪しの範囲も教えてくれます。隣接する2点のラベルは必ず異なるので $d_H \ge 1$、また $m$ ビットしかないので $d_H \le m$ です。したがって

$$ 1 \le \bar{d}_H^{\mathrm{NN}} \le m \quad \Longrightarrow \quad \frac{\mathrm{SER}}{m} \le \mathrm{BER} \lesssim \mathrm{SER} $$

つまり、グレイマッピングは達成可能な下限を実現しており、最悪のマッピングでもBERの劣化は高々 $\log_2 M$ 倍にとどまります。16QAMなら最大4倍、64QAMなら最大6倍です。

ただし、この上限 $\bar{d}_H^{\mathrm{NN}} = m$ は方形QAMでは達成できません。仮に達成できたとすると、すべての隣接ペアでラベルが全ビット反転、すなわち $f(\hat{s})$ が $f(s)$ のビット反転になっていなければなりません。ところが格子上に3点の道 $u – v – w$($u \neq w$)を取ると、$f(w)$ は $f(v)$ の反転、$f(v)$ は $f(u)$ の反転なので $f(w) = f(u)$ となり、ラベルが1対1であることに矛盾します。$4\times4$ 格子には当然そのような道が存在するので、$\bar{d}_H^{\mathrm{NN}} < m$ です。後の実験では、局所探索で見つかる最悪級のラベリングが $\bar{d}_H^{\mathrm{NN}} = 10/3 \approx 3.33$ になることを確かめます(上限4には届かないが、かなり近い)。

参考までに、ラベルを完全にランダムに振った場合も計算しておきましょう。この場合、誤り先のラベルは送信ラベルと無関係な一様乱数と見なせるので、各ビットが独立に確率 $1/2$ で反転し $\bar{d}_H \approx m/2$、すなわち $\mathrm{BER} \approx \mathrm{SER}/2$ となります。$m$ が大きいほど「ランダムマッピングはグレイの $m/2$ 倍悪い」ことになり、256QAM($m=8$)なら4倍です。

自然2進マッピングの $\bar{d}_H^{\mathrm{NN}}$ を手計算する

「グレイの反対」としてよく比較される自然2進マッピングは、実は上限の $m$ よりずっと1に近い値を取ります。手で数えてみましょう。

16QAMを考えます。まず辺の総数です。$4\times4$ 格子で、水平方向の隣接ペアは各行に3組、4行あるので12組。垂直方向も同じく12組。無向で24組、順序対にすると $|\mathcal{E}| = 48$ です(1点あたり平均 $48/16 = 3$ 近傍。方形QAMの一般式 $4(1 – 1/\sqrt{M}) = 4(1 – 1/4) = 3$ と一致します)。

次にハミング距離の総和です。自然2進の4値PAMラベルは $00, 01, 10, 11$ なので、軸方向の隣接ペアの距離は

$$ d_H(00,01) = 1, \qquad d_H(01,10) = 2, \qquad d_H(10,11) = 1 $$

I方向の辺では、Q側のラベルは変化しないので、上の3値がそのまま距離になります。各行(Q固定)につき順序対は $2 \times 3 = 6$ 組、その距離の和は $2(1 + 2 + 1) = 8$。4行あるので $32$。Q方向も対称に $32$。合計 $64$ です。したがって

$$ \bar{d}_H^{\mathrm{NN}} = \frac{64}{48} = \frac{4}{3} \approx 1.333 $$

16QAMの自然2進マッピングは、グレイに対してBERが $4/3$ 倍になる、という予測が立ちました。上限の4倍よりずっと穏やかです。理由は、自然2進の4値PAMでも3つの隣接ペアのうち2つは1ビット差で、2ビット差になるのは中央の1組だけだからです。

64QAMも同様に計算できます。自然2進の8値PAMの隣接ペアの距離は $(1, 2, 1, 3, 1, 2, 1)$ で、平均は $11/7 \approx 1.571$。方形QAMではこの1次元の平均がそのまま2次元の $\bar{d}_H^{\mathrm{NN}}$ になります(I方向・Q方向どちらの辺も、片軸のPAM隣接ペアの距離そのものだから)。よって64QAMでは約1.57倍の劣化です。多値数が上がるほどじわじわ悪化していきますが、$\log_2 M = 6$ 倍にはほど遠い値です。

この事実は重要です。「グレイでないと $\log_2 M$ 倍悪くなる」というのはあくまで最悪ケースの上界であって、自然2進という自然な代替案に対する実際の差は $4/3$ 倍(16QAM)程度です。後のシミュレーションでこの $4/3$ をきっちり実測します。

16QAMと64QAMそれぞれについてグレイと自然2進の平均ハミング距離を並べた棒グラフ

4本の棒が、これまで手計算してきた $\bar{d}_H^{\mathrm{NN}}$ です。グレイは16QAM・64QAMのどちらでも破線(下限1)にぴたりと乗っており、これ以上下げようがないことを意味します。自然2進は16QAMで $1.3333 = 4/3$、64QAMで $1.5714 = 11/7$ と、多値数が上がるほど下限から離れていきます。式(8)により、この棒の高さの比がそのままBERの比になるので、以降のシミュレーションではこの数字が答え合わせの基準になります。

$\bar{d}_H$ という組合せ量でBERの比が決まることがわかりました。次に、$Q$ 関数を使った具体的なBER式を最後まで導出して、数値で確かめられる形にしましょう。

16QAMのBERを最後まで導出する

正規化と $Q$ 関数の引数

方形QAMの振幅レベルを $\pm1, \pm3, \dots, \pm(\sqrt{M}-1)$(間隔2)とすると、平均シンボルエネルギーは

$$ E_s^{\text{raw}} = 2 \cdot \frac{1}{\sqrt{M}}\sum_{k=1}^{\sqrt{M}/2} (2k-1)^2 = \frac{2(M-1)}{3} $$

です。16QAMなら $2\cdot15/3 = 10$、64QAMなら $2\cdot63/3 = 42$ になります。$E_s = 1$ に正規化するには全体を $\sqrt{2(M-1)/3}$ で割ればよく、正規化後の最小距離は

$$ d_{\min} = \frac{2}{\sqrt{2(M-1)/3}} = \sqrt{\frac{6}{M-1}} $$

AWGNの雑音は複素ベースバンドで各実次元あたり分散 $N_0/2$ なので、判定境界(隣接点との中点、距離 $d_{\min}/2$)を越える確率は $Q\left(\frac{d_{\min}/2}{\sqrt{N_0/2}}\right)$ です。中身を整理すると

$$ \frac{d_{\min}/2}{\sqrt{N_0/2}} = \frac{1}{2}\sqrt{\frac{6}{M-1}} \cdot \sqrt{\frac{2}{N_0}} = \sqrt{\frac{3}{(M-1)N_0}} = \sqrt{\frac{3}{M-1}\cdot\frac{E_s}{N_0}} $$

さらに $E_s/N_0 = m\,E_b/N_0$(1シンボル $m$ ビット)を代入すると、$M = 16$、$m = 4$ の場合は

$$ \begin{equation} z \equiv \sqrt{\frac{3 \cdot 4}{15}\cdot \frac{E_b}{N_0}} = \sqrt{0.8\,\frac{E_b}{N_0}} \end{equation} $$

という、覚えやすい形になります。以下ではこの $z$ を使います。

4値PAMに分解して各ビットの誤り確率を求める

16QAMは独立な2つの4値PAMなので、I側の2ビット($b_3 b_2$)だけを考えれば十分です。レベルは $-3a, -a, +a, +3a$($a = d_{\min}/2$、$Q(a/\sigma) = Q(z)$)、判定境界は $-2a, 0, +2a$ にあります。ここで便利な記法として

$$ Q(z),\quad Q(3z),\quad Q(5z) $$

を用意します。$Q(3z)$ は「3レベル分(距離 $3a$)を飛び越える確率」、$Q(5z)$ は「5レベル分を飛び越える確率」に対応します。

4値PAMの4レベルに対しグレイの上位ビット・下位ビットと自然2進の下位ビットがどう0/1に分かれるかを3段で示した図

紺が0、橙が1です。上段のグレイ上位ビット $b_3$ は左2つが0・右2つが1という単純な符号ビットで、誤るのは原点をまたいだときだけ。中段のグレイ下位ビット $b_2$ は外側2つが0・内側2つが1という「内外ビット」で、0と1の領域がそれぞれ連続した1つの塊になっています。ところが下段の自然2進 $b_2$ は $0,1,0,1$ と交互で、0の領域が2つに分断されているのがわかります。この分断のせいで誤りの経路が増え、次に計算するように誤り確率が大きくなります。

上位ビット $b_3$(グレイでも自然2進でも同じ)

グレイラベルは左から $00, 01, 11, 10$ なので、$b_3$ は $\{-3a, -a\}$ で0、$\{+a, +3a\}$ で1、つまり符号ビットです。$b_3$ が誤るのは判定結果が原点の反対側に来たときです。

  • 送信が $-a$ のとき: $r > 0$ となる確率、すなわち雑音が $+a$ を超える確率 $Q(z)$
  • 送信が $-3a$ のとき: $r > 0$ となる確率、雑音が $+3a$ を超える確率 $Q(3z)$

4レベル等確率で、$+a, +3a$ は対称なので

$$ P_{b_3} = \frac{1}{2}\bigl[Q(z) + Q(3z)\bigr] $$

下位ビット $b_2$(グレイの場合)

グレイラベル $00, 01, 11, 10$ を見ると、$b_2$ は外側の2レベル($\pm3a$)で0、内側の2レベル($\pm a$)で1です。つまり $b_2$ は「内側か外側か」を表すビットです。$b_2$ が誤るのは、内外の別が入れ替わったときです。

  • 送信が $-a$(内側)のとき: 誤るのは判定が $-3a$ か $+3a$ になる場合。$r < -2a$(雑音が $-a$ 未満)または $r > 2a$(雑音が $+3a$ 超)なので、確率は $Q(z) + Q(3z)$
  • 送信が $-3a$(外側)のとき: 誤るのは判定が $-a$ か $+a$ になる場合、つまり $-2a < r < 2a$。雑音でいえば $a < n < 5a$ なので、確率は $Q(z) - Q(5z)$

対称性から

$$ P_{b_2} = \frac{1}{2}\bigl[\bigl(Q(z)+Q(3z)\bigr) + \bigl(Q(z)-Q(5z)\bigr)\bigr] = \frac{1}{2}\bigl[2Q(z) + Q(3z) – Q(5z)\bigr] $$

平均してBERへ

I側2ビットの平均を取り、Q側も同じ値になるので、16QAMグレイマッピングのBERは

$$ \begin{equation} \mathrm{BER}_{\text{Gray}} = \frac{P_{b_3} + P_{b_2}}{2} = \frac{1}{4}\bigl[3Q(z) + 2Q(3z) – Q(5z)\bigr], \qquad z = \sqrt{0.8\,\frac{E_b}{N_0}} \end{equation} $$

が得られました。高SNRでは $Q(3z), Q(5z)$ が急速に消えるので

$$ \mathrm{BER}_{\text{Gray}} \approx \frac{3}{4}Q(z) $$

という有名な近似式に落ち着きます。この $3/4$ は $\frac{1}{m}\cdot N_{\mathrm{NN}} = \frac{1}{4}\cdot 3$、すなわち「平均近傍数3を4ビットで割った」ものにほかならず、式(8)の $\mathrm{BER} = \mathrm{SER}/m$ と $\mathrm{SER} \approx 3Q(z)$ に完全に整合しています。

自然2進版も同じ手順で

自然2進の4値PAMラベルは $00, 01, 10, 11$ です。上位ビット $b_3$ は左2つで0、右2つで1なのでグレイと同じ符号ビットで、$P_{b_3}$ は変わりません。変わるのは下位ビット $b_2$ で、これは $0, 1, 0, 1$ と交互になります。

  • 送信が $-3a$($b_2 = 0$)のとき: 誤るのは判定が $-a$ か $+3a$ の場合。$-2a 2a$ の確率は $Q(5z)$。合計 $Q(z) – Q(3z) + Q(5z)$
  • 送信が $-a$($b_2 = 1$)のとき: 誤るのは判定が $-3a$ か $+a$ の場合。$r < -2a$ の確率は $Q(z)$、$0

平均して $P_{b_2}^{\text{nat}} = \frac{1}{2}\bigl[3Q(z) – 2Q(3z) + Q(5z)\bigr]$、したがって

$$ \begin{equation} \mathrm{BER}_{\text{natural}} = \frac{1}{4}\bigl[4Q(z) – Q(3z) + Q(5z)\bigr] \approx Q(z) \end{equation} $$

高SNR極限での比を取ると

$$ \frac{\mathrm{BER}_{\text{natural}}}{\mathrm{BER}_{\text{Gray}}} \to \frac{Q(z)}{\tfrac{3}{4}Q(z)} = \frac{4}{3} $$

となり、前節で組合せ的に数えた $\bar{d}_H^{\mathrm{NN}} = 4/3$ と独立な経路から完全に一致しました。理論の筋が通っていることの良い確認になります。

厳密式が手に入ったので、次は具体的な数値を入れて感触をつかみましょう。

具体例 — $E_b/N_0 = 10$ dBの16QAMで数を入れる

$E_b/N_0 = 10$ dBは真数で10です。式(9)から

$$ z = \sqrt{0.8 \times 10} = \sqrt{8} = 2.8284 $$

ここで $Q(x) = \frac{1}{2}\mathrm{erfc}(x/\sqrt{2})$ を使うと、$z/\sqrt{2} = 2$ ちょうどなので

$$ Q(z) = \tfrac{1}{2}\mathrm{erfc}(2) = 2.3389 \times 10^{-3} $$

という、きれいな値になります。同様に $Q(3z) = Q(8.485) \approx 1.1 \times 10^{-17}$、$Q(5z) = Q(14.14) \approx 10^{-45}$ で、どちらも $Q(z)$ に比べて完全に無視できます。「誤りは隣に落ちる」が数値としてどれほど強い主張かがよくわかります。

これらを式(10)(11)に入れると

$$ \mathrm{BER}_{\text{Gray}} = \tfrac{1}{4}\left[3 \times 2.3389\times10^{-3}\right] = 1.754\times10^{-3} $$

$$ \mathrm{BER}_{\text{natural}} = 2.339\times10^{-3} $$

シンボル誤り率は $\mathrm{SER} \approx 3Q(z) = 7.02\times10^{-3}$ です(厳密式 $1-\left[1-2(1-1/\sqrt{M})Q(\sqrt{3\gamma_s/(M-1)})\right]^2$ では $7.00\times10^{-3}$)。ここで検算すると

$$ \frac{\mathrm{SER}}{\log_2 16} = \frac{7.00\times10^{-3}}{4} = 1.75\times10^{-3} = \mathrm{BER}_{\text{Gray}} $$

となり、$\mathrm{BER} \approx \mathrm{SER}/\log_2 M$ が小数点以下3桁まで成立しています。

BER比は $2.339/1.754 = 1.333$ で、予測どおりの $4/3$ です。ではこれを「必要な送信電力」に翻訳するとどうなるでしょうか。目標BERを固定して必要な $E_b/N_0$ を逆算すると、次のようになります。

目標BER グレイ 自然2進 ペナルティ
$10^{-3}$ 10.52 dB 10.77 dB 0.25 dB
$10^{-4}$ 12.20 dB 12.38 dB 0.17 dB
$10^{-5}$ 13.43 dB 13.57 dB 0.13 dB
$10^{-6}$ 14.40 dB 14.51 dB 0.11 dB

BERで $4/3$ 倍という差は、dB換算では0.1〜0.25 dB程度にしかなりません。BER曲線が高SNRで非常に急峻(片対数プロットでほぼ垂直に落ちる)なので、縦方向に $4/3$ ずらしても横方向にはわずかしか動かないためです。

目標BERごとにグレイと自然2進の所要Eb/N0を水平線で結んだ図と、そのdB差を棒グラフにした図

左の図で、各目標BERの水平線上に打った丸(グレイ)と四角(自然2進)の横方向の隔たりが所要電力のペナルティです。2本の曲線は縦には確かに $4/3$ 倍離れているのに、横にはほとんど離れていないことが目で確認できます。右の棒グラフはそのdB差で、目標BERを $10^{-3}$ から $10^{-6}$ へ厳しくするほど 0.25 → 0.11 dB と減っていくのが面白いところです。曲線が急峻になるほど、同じ縦方向のずれを打ち消すのに必要な横方向の移動が小さくなるためです。

この0.1〜0.25 dBを「小さい」と見るか「大きい」と見るかが、通信システム設計の勘所です。 衛星リンクバジェットでは0.2 dBを削るためにアンテナ径や電力増幅器のバックオフを何度も見直します。しかもグレイマッピングのコストはゼロ(ラベル表を書き換えるだけ)です。タダで0.2 dB手に入るなら、使わない理由がありません。加えて、誤り訂正符号と組み合わせるBICM構成では、グレイマッピングによるビットLLRの独立性向上がこの差を上回る効果を生むこともあります。

ここまでは紙の上の計算でした。次に、実際にAWGN雑音を発生させてシミュレーションし、理論式が本当に正しいのかを確かめます。

Pythonでの実装

反射型グレイ符号の生成と検証

まず、再帰構成(式(3))と閉形式(式(4))が一致すること、そして隣接ハミング距離が1になることを確かめます。

import numpy as np

def gray_reflect(m):
    """反射型グレイ符号を再帰的に構成する(ビット文字列のリストを返す)"""
    if m == 1:
        return ['0', '1']
    prev = gray_reflect(m - 1)
    # 前半: そのまま並べて先頭に0 / 後半: 鏡像反転して先頭に1
    return ['0' + c for c in prev] + ['1' + c for c in prev[::-1]]

def gray_closed(n):
    """閉形式 g = n XOR (n >> 1)"""
    return n ^ (n >> 1)

for m in range(1, 5):
    seq = gray_reflect(m)
    rec = [int(c, 2) for c in seq]
    cls = [gray_closed(n) for n in range(2 ** m)]
    ham = [bin(rec[k] ^ rec[k + 1]).count('1') for k in range(len(rec) - 1)]
    wrap = bin(rec[0] ^ rec[-1]).count('1')
    print(f"m={m}: 再帰と閉形式が一致={rec == cls}, "
          f"隣接ハミング距離={set(ham)}, 巡回端={wrap}")

print("\n3ビットグレイ符号:", gray_reflect(3))
print("4ビットグレイ符号:", gray_reflect(4))

実行すると、$m = 1,2,3,4$ のすべてで「再帰と閉形式が一致=True」「隣接ハミング距離={1}」「巡回端=1」と表示されます。式(4)の証明で示したとおり、$n \oplus (n \gg 1)$ という1行の演算が反射型グレイ符号そのものを再現していること、そして先頭と末尾も1ビット差である(巡回グレイ符号である)ことが数値的に裏付けられました。3ビット版の ['000', '001', '011', '010', '110', '111', '101', '100'] を目で追うと、確かに毎回1桁ずつしか変わっていません。

16QAM星座図にラベルを貼る

次に、グレイ/自然2進の2つのマッピングで16QAMの信号点とラベルを作り、星座図として描きます。

import numpy as np
import matplotlib, matplotlib.pyplot as plt

for cand in ["Hiragino Sans", "Yu Gothic", "Noto Sans CJK JP", "IPAexGothic", "Meiryo"]:
    if any(cand == f.name for f in matplotlib.font_manager.fontManager.ttflist):
        plt.rcParams["font.family"] = cand
        break
plt.rcParams["axes.unicode_minus"] = False

def build_qam(m_bits, mapping='gray'):
    """方形QAMの信号点配列を返す(index=シンボル番号, 平均エネルギー1に正規化)"""
    M, L, mb = 2 ** m_bits, int(2 ** (m_bits / 2)), m_bits // 2
    levels = np.arange(-(L - 1), L, 2.0)          # 例: [-3,-1,1,3]
    if mapping == 'gray':
        label_of_index = [k ^ (k >> 1) for k in range(L)]   # k番目のレベル -> グレイ語
    else:
        label_of_index = list(range(L))                      # 自然2進
    index_of_label = {lab: i for i, lab in enumerate(label_of_index)}
    pts = np.zeros(M, dtype=complex)
    for s in range(M):
        bi, bq = s >> mb, s & (L - 1)             # 上位mbビット=I, 下位mbビット=Q
        pts[s] = levels[index_of_label[bi]] + 1j * levels[index_of_label[bq]]
    return pts / np.sqrt(np.mean(np.abs(pts) ** 2))

fig, axes = plt.subplots(1, 2, figsize=(12, 6))
for ax, mapping, name in zip(axes, ['gray', 'natural'], ['グレイ符号', '自然2進']):
    pts = build_qam(4, mapping)
    ax.scatter(pts.real, pts.imag, s=60, c='steelblue', zorder=3)
    for s, p in enumerate(pts):
        ax.annotate(format(s, '04b'), (p.real, p.imag),
                    textcoords="offset points", xytext=(0, 10), ha='center', fontsize=10)
    ax.set(title=f"16QAM 信号点とビット割当({name}マッピング)",
           xlabel="同相成分 I", ylabel="直交成分 Q")
    ax.grid(alpha=0.3); ax.set_aspect('equal'); ax.set_ylim(-1.35, 1.35)
plt.tight_layout(); plt.show()

2つの星座図を見比べると、信号点の位置はまったく同じで、貼られているラベルだけが違うことがわかります。グレイ側では上下左右に隣り合う点のラベルが必ず1文字しか違いません。自然2進側では、中央の縦線($I=-1$ と $I=+1$ のあいだ)と横線をまたぐと $0110 \to 1010$ のように2文字が同時に変わっています。この「中央をまたぐと2ビット壊れる」構造が、これから測るBER劣化の正体です。

隣接ハミング距離を数え上げる

理論で手計算した $\bar{d}_H^{\mathrm{NN}}$(グレイ=1、16QAM自然2進=4/3、64QAM自然2進=11/7)を、力任せの数え上げで検証します。

import numpy as np

def nn_hamming_stats(pts, m_bits):
    """最近接ペアに沿った平均ハミング距離と平均近傍数を数え上げる"""
    M = len(pts)
    d = np.abs(pts[:, None] - pts[None, :])
    dmin = d[d > 1e-9].min()
    tot_h = tot_pairs = 0
    for a in range(M):
        for b in range(M):
            if a != b and d[a, b] < dmin * 1.001:   # 最近接ペア(順序対)
                tot_pairs += 1
                tot_h += bin(a ^ b).count('1')
    return tot_h / tot_pairs, tot_pairs / M

for m_bits, name in [(4, '16QAM'), (6, '64QAM')]:
    for mapping in ['gray', 'natural']:
        pts = build_qam(m_bits, mapping)
        avg_h, avg_n = nn_hamming_stats(pts, m_bits)
        print(f"{name:6s} {mapping:8s}: 平均ハミング距離={avg_h:.6f}  平均近傍数={avg_n:.2f}")

出力は次のようになります。

16QAM  gray    : 平均ハミング距離=1.000000  平均近傍数=3.00
16QAM  natural : 平均ハミング距離=1.333333  平均近傍数=3.00
64QAM  gray    : 平均ハミング距離=1.000000  平均近傍数=3.50
64QAM  natural : 平均ハミング距離=1.571429  平均近傍数=3.50

グレイマッピングは16QAMでも64QAMでも例外なく1.000000、すなわちすべての隣接ペアがちょうど1ビット差であることが確認できました。自然2進は16QAMで $4/3 = 1.3333$、64QAMで $11/7 = 1.5714$ と、手計算の予測値に完全一致しています。平均近傍数も一般式 $4(1-1/\sqrt{M})$(16QAMで3、64QAMで3.5)と合っています。式(8)によれば、この表の数字がそのままBERの比になるはずです。

AWGN上のモンテカルロシミュレーション

いよいよ本番です。AWGN通信路に16QAMを流し、最近接判定で復調して、SERとBERを両方測ります。

import numpy as np

def simulate_qam(pts, m_bits, ebn0_db, n_sym=400000, seed=7):
    """AWGN上で方形QAMを送受信し (SER, BER) を返す"""
    rng = np.random.default_rng(seed)
    M = 2 ** m_bits
    ebn0 = 10 ** (ebn0_db / 10)
    N0 = 1.0 / (m_bits * ebn0)          # Es=1 なので Es/N0 = m * Eb/N0
    s = rng.integers(0, M, n_sym)       # 送信シンボル番号(等確率)
    noise = np.sqrt(N0 / 2) * (rng.standard_normal(n_sym)
                               + 1j * rng.standard_normal(n_sym))
    r = pts[s] + noise
    s_hat = np.argmin(np.abs(r[:, None] - pts[None, :]), axis=1)   # 最近接判定
    ser = np.mean(s_hat != s)
    xor = s ^ s_hat                      # 誤ったビットの位置がそのまま立つ
    n_bit_err = sum(((xor >> b) & 1) for b in range(m_bits))
    return ser, n_bit_err.sum() / (n_sym * m_bits)

pts_g, pts_n = build_qam(4, 'gray'), build_qam(4, 'natural')
print(" Eb/N0    SER      BER(グレイ)   BER(自然2進)  比    BER*4/SER")
for ebn0_db in [0, 2, 4, 6, 8, 10, 12]:
    ser_g, ber_g = simulate_qam(pts_g, 4, ebn0_db)
    ser_n, ber_n = simulate_qam(pts_n, 4, ebn0_db)
    print(f"{ebn0_db:5.1f} dB {ser_g:.3e}  {ber_g:.3e}   {ber_n:.3e}  "
          f"{ber_n/ber_g:5.3f}  {ber_g*4/ser_g:6.4f}")

実行結果は次のようになります(乱数seed固定、1点あたり40万シンボル)。

 Eb/N0    SER      BER(グレイ)   BER(自然2進)  比    BER*4/SER
  0.0 dB 4.789e-01  1.408e-01   1.845e-01  1.310  1.1759
  2.0 dB 3.519e-01  9.757e-02   1.297e-01  1.329  1.1090
  4.0 dB 2.215e-01  5.876e-02   7.832e-02  1.333  1.0610
  6.0 dB 1.090e-01  2.798e-02   3.718e-02  1.328  1.0274
  8.0 dB 3.698e-02  9.317e-03   1.242e-02  1.333  1.0078
 10.0 dB 7.085e-03  1.776e-03   2.336e-03  1.315  1.0025
 12.0 dB 5.850e-04  1.463e-04   1.975e-04  1.350  1.0000

この表から3つのことが読み取れます。第一に、最右列の $\mathrm{BER}\times 4/\mathrm{SER}$ が、SNRを上げるにつれて 1.176 → 1.109 → 1.061 → 1.027 → 1.008 → 1.003 → 1.000 と1へ単調に収束しています。これは式(8)で $\bar{d}_H \to 1$ となること、すなわち $\mathrm{BER} \approx \mathrm{SER}/\log_2 M$ が高SNR近似であることの直接的な実証です。低SNRで1より大きいのは、雑音が大きいと2つ先・3つ先の信号点への誤りも起き、ハミング距離2以上の誤りが混ざるためです。

第二に、自然2進とグレイのBER比が全域でおよそ 1.33、つまり手計算で求めた $4/3$ に貼り付いています。$E_b/N_0 = 10$ dBで1.315、12 dBで1.350とわずかに振れているのは、この領域ではビット誤りの総数が数百個以下まで減り、モンテカルロの統計誤差が乗るためです(試行数を増やせば $4/3$ に収束します)。

第三に、SERはマッピングによらず同一です(表には片方しか出していませんが、実行すると ser_g と ser_n はほぼ一致します)。マッピングは信号点の位置を変えないのでSERには一切影響せず、SERをBERに翻訳する「為替レート」だけを変えているという理論の主張がそのまま現れています。

グレイと自然2進についてBER×4/SERをEb/N0に対してプロットし、それぞれ1と4/3に収束する様子を示したグラフ

この図は表の最右列(に相当する量)を、自然2進についても計算してグラフ化したものです。縦軸は「シンボル誤り1回あたりに壊れるビット数の平均」$\bar{d}_H$ そのものになります。青(グレイ)は $E_b/N_0$ を上げるにつれ 1.18 から滑らかに下り、8 dB を過ぎるとほぼ 1.00 に張り付きます。赤(自然2進)も同様に下がりますが、行き着く先は 1 ではなく破線で示した $4/3$ です。低SNR側で両方とも上振れしているのは、雑音が大きく2つ先・斜めへの誤りが混ざってハミング距離2以上の事象が起きるためで、式(9)の「最近接ペアだけを数える」近似が崩れていることを意味します。

理論式との重ね合わせ

導出した厳密式(10)(11)とシミュレーションを同じ図に重ねて、BER曲線を描きます。

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import erfc

def Qfunc(x):
    return 0.5 * erfc(np.asarray(x, dtype=float) / np.sqrt(2))

def ber_theory(ebn0_db, mapping):
    """16QAMの厳密BER式(式10・式11)"""
    z = np.sqrt(0.8 * 10 ** (np.asarray(ebn0_db, dtype=float) / 10))
    if mapping == 'gray':
        return 0.25 * (3 * Qfunc(z) + 2 * Qfunc(3 * z) - Qfunc(5 * z))
    return 0.25 * (4 * Qfunc(z) - Qfunc(3 * z) + Qfunc(5 * z))

ebn0_list = np.arange(0, 15.1, 1.0)
ber_sim_g, ber_sim_n, ser_sim = [], [], []
for e in ebn0_list:
    sg, bg = simulate_qam(pts_g, 4, e, n_sym=1000000, seed=11)
    sn, bn = simulate_qam(pts_n, 4, e, n_sym=1000000, seed=11)
    ber_sim_g.append(bg); ber_sim_n.append(bn); ser_sim.append(sg)

plt.figure(figsize=(9, 6))
fine = np.linspace(0, 15, 200)
plt.semilogy(fine, ber_theory(fine, 'gray'), 'b-', label='理論BER(グレイ)')
plt.semilogy(fine, ber_theory(fine, 'natural'), 'r-', label='理論BER(自然2進)')
plt.semilogy(ebn0_list, ber_sim_g, 'bo', ms=6, label='実測BER(グレイ)')
plt.semilogy(ebn0_list, ber_sim_n, 'rs', ms=6, label='実測BER(自然2進)')
plt.semilogy(ebn0_list, np.array(ser_sim) / 4, 'k^--', ms=5, label='実測SER ÷ log2(16)')
plt.xlabel('$E_b/N_0$ [dB]'); plt.ylabel('ビット誤り率 BER')
plt.title('16QAM: グレイ符号マッピングと自然2進マッピングのBER比較')
plt.ylim(1e-6, 1); plt.grid(True, which='both', alpha=0.3); plt.legend()
plt.tight_layout(); plt.show()

16QAMのグレイと自然2進について理論BER曲線と実測BER、および実測SERを4で割った点を重ねた片対数グラフ

図から次のことが確認できます。理論曲線(実線)と実測点(マーカー)は全域でぴたりと重なり、式(10)(11)の導出が正しいことが裏付けられます。青(グレイ)と赤(自然2進)は片対数軸で平行に走り、その縦方向の間隔は $\log_{10}(4/3) = 0.125$ ディケード分で一定です。さらに、黒い三角で示した「実測SER ÷ 4」がグレイのBER曲線にほぼ完全に重なっており、$\mathrm{BER} \approx \mathrm{SER}/\log_2 M$ が実測レベルで成立していることが目で確認できます。低SNR側でわずかに三角が下にずれるのは、前述のとおり $\bar{d}_H > 1$ になるためです。

最悪のマッピングはどこまで悪くなるか

理論の節で「上限は $\log_2 M = 4$ 倍だが方形QAMでは達成不可能」と述べました。実際にどこまで悪くできるのか、局所探索(ランダム初期化+2点交換の山登り)で $\bar{d}_H^{\mathrm{NN}}$ を最大化するラベリングを探してみます。

import numpy as np, itertools, random

levels = np.array([-3., -1., 1., 3.])
coords = np.array([i + 1j * q for q in levels for i in levels])   # 格子点16個

def avg_hamming(perm):
    """perm[k] = 格子点kに割り当てるラベル。最近接ペアの平均ハミング距離"""
    tot_h = tot_p = 0
    for a in range(16):
        for b in range(16):
            if a != b and abs(coords[a] - coords[b]) < 2.001:
                tot_p += 1; tot_h += bin(perm[a] ^ perm[b]).count('1')
    return tot_h / tot_p

random.seed(0); best = None
for _ in range(60):                       # 多点スタートの山登り
    perm = list(range(16)); random.shuffle(perm); cur = avg_hamming(perm)
    improved = True
    while improved:
        improved = False
        for a, b in itertools.combinations(range(16), 2):
            perm[a], perm[b] = perm[b], perm[a]
            v = avg_hamming(perm)
            if v > cur + 1e-12:
                cur = v; improved = True
            else:
                perm[a], perm[b] = perm[b], perm[a]
    if best is None or cur > best[0]:
        best = (cur, list(perm))

print(f"探索で見つかった最大の平均ハミング距離 = {best[0]:.4f}  (上限 log2M = 4)")
for r in range(3, -1, -1):
    print("   ", " ".join(format(best[1][r * 4 + c], '04b') for c in range(4)))

出力は次のとおりです。

探索で見つかった最大の平均ハミング距離 = 3.3333  (上限 log2M = 4)
    0000 1111 0001 1110
    1011 0100 1010 0101
    0110 1001 0111 1000
    1101 0010 1100 0011

局所探索で見つけた最悪級ラベリングの16QAM星座図と、各隣接ペアのハミング距離を辺に書き込んだ図

辺に書かれた数字が、その隣接ペアのハミング距離です。ほとんどの辺が3か4で埋まっており、1ビット差の辺は1本もありません。$0000$ と $1111$、$0100$ と $1011$ のように、隣同士を意図的に「全ビット反転」に近づけた結果です。ただし4の辺は横方向に限られ、縦方向はすべて3にとどまっています。これは前節で示した「3点の道では全ビット反転を連続させられない」という制約が効いているためで、平均は上限4ではなく $10/3$ で頭打ちになります。

$\bar{d}_H^{\mathrm{NN}} = 10/3 \approx 3.333$ という値が得られました。理論上の上限4には届いていませんが、これは前節で示した「隣接ペアがすべて全ビット反転になることは格子上では不可能」という論証と整合します。得られたラベリングを見ると、$0000$ の右隣が $1111$(4ビット差)のように、意図的に真逆のラベルが並べられているのがわかります。このマッピングを同じモンテカルロ(40万シンボル、seed=7)にかけると、$E_b/N_0 = 10$ dBでBERは $5.71\times10^{-3}$ となり、グレイの $1.78\times10^{-3}$ に対して約3.2倍です(試行数を100万に増やすと3.32倍まで上がり、理論値 $10/3$ に近づきます)。$\bar{d}_H^{\mathrm{NN}}$ の値がそのままBER比として現れており、式(8)の妥当性が最悪ケースでも確認できます。dB換算のペナルティは、目標BER $10^{-4}$ で約0.68 dB、$10^{-6}$ で約0.43 dBです。

グレイ・自然2進・最悪級ラベリングの3つの実測BER曲線と、グレイに対する倍率のグラフ

左の図は3つのマッピングの実測BERで、信号点の配置はすべて同一なのに3本の曲線がはっきり分離しています。右の図はグレイに対する倍率で、自然2進(赤)は全域で $4/3$ の破線に貼り付き、最悪級(紫)はSNRを上げるにつれ理論値 $3.333$ の破線へ下から近づいていきます。紫が低SNRで 2.5 程度と小さいのは、雑音が大きいと「隣以外への誤り」が増え、そちらのハミング距離が平均して $m/2 = 2$ 程度とマシなためです。高SNRになるほど隣への誤りが支配的になり、意図的に悪くした隣接ラベルの効果がフルに出ます。

まとめると、16QAMにおいてマッピングの選択でBERは最大3.3倍(約0.7 dB)動き、そのうち自然2進という常識的な選択でも1.33倍(約0.17 dB)の損をする、ということになります。ラベル表を書き換えるだけの無償の改善としては、十分に価値のある差です。

実験で理論が裏付けられました。最後に、実際のシステム設計でグレイマッピングを扱うときの注意点を整理しておきましょう。

実務上の注意点

軟判定復号(BICM)ではもっと効く

ここまでは硬判定(最近接シンボル判定)を前提にしてきましたが、現代の通信システムはほぼ例外なく誤り訂正符号と組み合わされ、復調器はビットごとの対数尤度比(LLR)を出力します。この構成をBICM(Bit-Interleaved Coded Modulation)と呼びます。

BICMでは、受信点 $r$ から各ビット $b_i$ のLLRを

$$ L(b_i) = \ln\frac{\sum_{s : b_i(s) = 0} \exp\left(-|r – s|^2 / N_0\right)}{\sum_{s : b_i(s) = 1} \exp\left(-|r – s|^2 / N_0\right)} $$

として計算し、LDPC符号などの軟判定復号器に渡します。グレイマッピングの利点はここでさらに強まります。グレイでは各ビットの「0を割り当てた領域」と「1を割り当てた領域」が空間的にきれいに分離するため、上式の分子・分母がそれぞれ1項に支配されやすく、LLRが素直で信頼できる値になります。逆に悪いマッピングでは、あるビットの0領域と1領域が市松模様のように入り組み、LLRの絶対値が小さくなって(=情報が減って)復号性能が落ちます。情報理論的には、BICM容量がグレイマッピングでほぼ最大化されることが知られています。

ただし例外もあります。反復復調(BICM-ID)を行う場合、グレイマッピングはフィードバックで得られる利得が小さく、あえて非グレイのラベリング(アンチグレイに近いもの)を使う方が最終性能が良くなることがあります。反復のたびに他ビットの事前情報が使えるため、ラベル間の「絡み合い」が逆に情報源になるからです。「グレイが常に最善」ではない、数少ない反例です。

方形でないコンステレーションでは完全なグレイは作れない

方形QAMなら $\sqrt{M}$ 値PAM×2の直積で必ず完全グレイが作れますが、そうでない配置では話が変わります。

  • 32QAM/128QAMのようなクロス型: $M$ が奇数乗のとき正方格子にならず、十字型に信号点を配置します。この場合、すべての隣接ペアを1ビット差にすることは一般に不可能で、いくつかの辺で2ビット差が残ります
  • APSK(振幅位相偏移変調): DVB-S2/S2Xの16APSK/32APSKは同心円上に信号点を並べます。リング間・リング内の隣接関係が複雑で、規格ではリング内は位相方向のグレイ、リング間はできるだけ差を小さくする、という妥協的な設計が採られています
  • 8PSK: 円周上の8点は巡回的に並ぶので、3ビット巡回グレイ符号 $G_3$ を素直に一周させれば完全グレイになります。円周が閉じているため、巡回性が本質的に効く好例です

一般のコンステレーションに対する最適ラベリング探索はNP困難な組合せ最適化問題で、本記事でやったような局所探索や、シミュレーテッドアニーリング、binary switching algorithmといった手法が使われます。

位相曖昧性と微分符号化

搬送波再生(キャリアリカバリ)が90度単位の位相回転を残したまま収束すると、星座図全体が回転してラベルがずれます。グレイマッピングは隣接誤りには強いものの、この種の「全体回転」には無力です。実務では、$b_3 b_2$ の上位2ビット(象限を表すビット)だけを微分符号化する、パイロット信号を挿入する、あるいは符号語の同期パターンで曖昧性を解消する、といった対策と併用されます。グレイマッピングが守ってくれるのは「雑音による最近接誤り」であって、同期の誤りではないという切り分けは押さえておきましょう。

まとめ

本記事では、グレイ符号マッピングが多値変調のBERを下げる仕組みを、構成法から性能式まで通して解説しました。

  • シンボル誤りとビット誤りは別物: 1シンボル誤ったときに壊れるビット数は、送信ラベルと判定ラベルのハミング距離で決まります。これを平均した $\bar{d}_H$ を使うと $\mathrm{BER} = (\bar{d}_H/m)\,\mathrm{SER}$ という厳密な関係が成り立ちます
  • 反射型グレイ符号: 「前半はそのまま先頭に0、後半は鏡像反転して先頭に1」という再帰で構成でき、閉形式は $g(n) = n \oplus (n \gg 1)$ です。隣接語のハミング距離が常に1になることを、$n$ の末尾の1の個数 $t$ に着目して証明しました
  • 方形QAMへの適用: I軸・Q軸それぞれに独立にPAMグレイラベルを貼るだけで、2次元でも完全なグレイマッピングになります。16QAM・64QAMの全隣接ペアで $d_H = 1$ を数え上げで確認しました
  • $\mathrm{BER} \approx \mathrm{SER}/\log_2 M$: 高SNRでは誤りが最近接シンボルに支配されるため $\bar{d}_H \to 1$ となり、この近似が成立します。実測では $E_b/N_0 = 12$ dBで $\mathrm{BER}\times4/\mathrm{SER} = 1.0000$ まで一致しました
  • 自然2進との差は $4/3$ 倍: 16QAMで1.33倍(約0.17 dB)、64QAMで約1.57倍。「最悪でも $\log_2 M$ 倍」という上界に対し、自然2進はかなりマシな部類です。局所探索で見つけた最悪級のラベリングでは3.33倍(約0.68 dB)に達しました
  • コストゼロの利得: 電力も帯域も計算量も増やさず、ラベル表を書き換えるだけで得られる改善です。BICM構成ではLLRの質向上という形でさらに効きます

グレイマッピングは、「シンボルの幾何配置」と「ビットの組合せ論」という別々の層をどう結びつけるかという設計問題の、最も美しい解答の一つです。この視点は、より高度な符号化変調(TCM、BICM、確率的振幅整形)を理解する土台になります。

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