パルス整形とナイキストフィルタ — ルートレイズドコサインで符号間干渉をなくす

衛星通信や光ファイバ、Wi-Fi、4G/5Gといったあらゆるディジタル通信は、「0」と「1」の連なり(シンボル列)を電波や光に乗せて運んでいます。ここで素朴に考えると、シンボルごとに「方形パルス」をポンポンと並べて送れば良さそうに思えます。しかし方形パルスを使うと、ある深刻な問題が起こります。方形パルスの周波数スペクトルは無限に裾を引き、限られた帯域に押し込もうとすると波形が滲み、隣のシンボルの判定タイミングに前後のシンボルの尾が漏れ込んでしまうのです。これが符号間干渉(ISI: Inter-Symbol Interference)で、ビット誤りの最大の原因の一つになります。

では「帯域を狭く制限しながら、しかも隣のシンボルへの干渉をゼロにする」ことは両立できるのでしょうか。一見矛盾するこの二つの要求を、見事に同時に満たす設計原理がナイキストの第一基準であり、それを実装する代表的なフィルタがレイズドコサインフィルタルートレイズドコサイン(RRC)フィルタです。これらは「パルス整形(pulse shaping)」と呼ばれる処理の心臓部であり、現代のほぼ全てのディジタル変調器・復調器に組み込まれています。

この記事を理解すると、次のような実務に直結する力が身につきます。第一に、衛星通信の帯域設計です。DVB-S2XやCCSDSのテレメトリ送信機では、ロールオフ係数 $\beta$ を 0.05〜0.35 のように選んで占有帯域を決めますが、その数字が何を意味するのかが腑に落ちます。第二に、復調器のタイミング同期設計です。なぜ送信と受信でフィルタを「半分ずつ」分けるのか、なぜサンプリングタイミングが少しずれるとビット誤り率が急激に悪化するのか、その理由を波形レベルで説明できるようになります。

本記事の内容

  • ナイキストの第一基準(標本化点でゼロISIになる条件)の直感と厳密な導出
  • レイズドコサインフィルタのスペクトルと時間波形、ロールオフ係数 $\beta$ の役割
  • RRCを送信・受信で分割する理由(整合フィルタと全体でのレイズドコサイン特性)
  • タイミング誤差に対する感度と過渡応答(サイドローブ)の意味
  • Pythonによる RRC インパルス応答の生成、シンボル列の整形・アップサンプル、アイパターン描画、$\beta$ ごとの帯域・ISI 比較

前提知識

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

特に、フィルタの周波数応答と畳み込み、そして信号の周波数スペクトルの考え方を押さえておくと、本記事のナイキスト条件の導出がスムーズに読めます。

パルス整形とは — なぜ方形パルスではダメなのか

ディジタル通信では、シンボル間隔 $T$ ごとに 1 個のシンボル $a_k$(例えば $\pm 1$)を送ります。送信波形 $s(t)$ は、各シンボルに「波形の型紙」$g(t)$ をかけて時間方向に並べたものです。

$$ s(t) = \sum_{k} a_k \, g(t – kT) $$

ここで $g(t)$ を送信パルス(transmit pulse)と呼びます。$g(t)$ を方形パルス(幅 $T$ の矩形)にすると、時間波形はきれいに区切れますが、周波数領域で見ると $\mathrm{sinc}$ 関数の形になり、スペクトルが $f = 1/T$ の何倍にもわたって裾を引いてしまいます。衛星のように使える帯域が厳密に決まっている系では、この裾は隣のチャネルへの妨害になり許されません。

逆に、帯域を厳しく制限するために $g(t)$ のスペクトルを箱型(理想低域通過)にすると、時間波形は $\mathrm{sinc}(t/T)$ になります。$\mathrm{sinc}$ 関数は実は非常に都合の良い性質を持っていて、$t = 0$ で $1$、$t = \pm T, \pm 2T, \dots$ でちょうど $0$ になります。つまり「自分のシンボルを判定する瞬間 $t = kT$ では、他のシンボルの波形がすべてゼロになる」のです。これがゼロISIの本質です。

ところが理想 $\mathrm{sinc}$ にも難点があります。第一に、裾の減衰が $1/t$ と非常に遅く、波形が長く尾を引きます。第二に、判定タイミングが少しでもずれると、ゆっくり減衰する尾が一斉に効いてきて干渉が爆発的に増えます。実用上は「ある程度の余分な帯域を許す代わりに、尾を速く減衰させ、タイミング誤差に強くする」という妥協が必要です。この妥協を最適に行うのがレイズドコサインフィルタなのですが、その前にまず「ゼロISIを保証する条件」を数式で厳密に書き下しておきましょう。

ナイキストの第一基準 — ゼロISIの条件

直感: 判定の瞬間に「自分以外がゼロ」

受信側では、整形された波形を $t = mT$($m$ は整数)でサンプリングして $a_m$ を読み取ります。送受信フィルタを通したあとの全体パルスを $p(t)$ と書くと、受信サンプルは

$$ y(mT) = \sum_k a_k \, p(mT – kT) = \sum_k a_k \, p\big((m-k)T\big) $$

です。ここで読み取りたいのは $a_m$ だけです。もし $p\big((m-k)T\big)$ が $m = k$ のとき $1$、$m \neq k$ のとき $0$ になってくれれば、和は $a_m$ ただ一つになり、他のシンボルの寄与(=ISI)は完全に消えます。つまりゼロISIの条件は、整形パルス $p(t)$ が

$$ p(nT) = \begin{cases} 1 & n = 0 \\ 0 & n = \pm 1, \pm 2, \dots \end{cases} $$

という「標本化点で間引くとデルタになる」性質を持つことです。この性質を満たすパルスをナイキストパルスと呼びます。

周波数領域での条件式の導出

この時間領域の条件を、設計に使いやすい周波数領域の条件に翻訳しましょう。ゴールは「$p(t)$ のフーリエ変換 $P(f)$ が満たすべき条件式」を導くことです。

出発点は、連続信号 $p(t)$ を周期 $T$ でサンプリングする操作です。サンプリングは時間領域でインパルス列 $\sum_n \delta(t – nT)$ を掛けることに相当し、周波数領域ではスペクトルが $1/T$ おきに繰り返される(折り返される)操作になります。サンプリング定理の標準的な結果として、サンプル列 $p(nT)$ の離散時間フーリエ変換は、元のスペクトル $P(f)$ を $1/T$ おきにずらして足し合わせた畳み込み(エイリアシング和)で書けます。

$$ \sum_{n=-\infty}^{\infty} p(nT) \, e^{-j 2\pi f n T} = \frac{1}{T} \sum_{m=-\infty}^{\infty} P\!\left(f – \frac{m}{T}\right) $$

ここで右辺は、$P(f)$ のコピーをシンボルレート $1/T$ おきに並べて重ね合わせたものです。

次に、左辺にゼロISI条件 $p(nT) = \delta_{n,0}$ を代入します。和のうち生き残るのは $n = 0$ の項だけで、その値は $p(0) = 1$ ですから、左辺はすべての $f$ に対して定数 $1$ になります。

$$ \sum_{n} p(nT) \, e^{-j 2\pi f n T} = p(0) \cdot e^{0} = 1 $$

両辺を等しいと置くと、ナイキストの第一基準の周波数領域表現が得られます。

$$ \frac{1}{T} \sum_{m=-\infty}^{\infty} P\!\left(f – \frac{m}{T}\right) = 1 \qquad \text{(すべての } f \text{ で)} $$

整理すると、次の式がナイキストの第一基準です。

$$ \begin{equation} \sum_{m=-\infty}^{\infty} P\!\left(f – \frac{m}{T}\right) = T \qquad (\text{const.}) \end{equation} $$

この式の意味するところは非常に幾何学的です。「$P(f)$ を $1/T$ 間隔でずらしたコピーをすべて足し合わせると、周波数によらず一定値 $T$ になる」――つまり、コピーが互いの隙間をぴったり埋め合って、平らな床になっていなければならない、ということです。

帯域の下限とロールオフの余地

この条件から重要な帰結が出ます。もし $P(f)$ がナイキスト周波数 $f_N = 1/(2T)$ より狭い帯域しか持たなければ、ずらしたコピーの間に隙間ができ、和が一定にはなりません。逆に帯域が広すぎると、隣り合うコピーが重なりすぎてやはり平らになりません。和が定数 $T$ になるためには、$f = f_N = 1/(2T)$ の点を中心に、スペクトルが奇対称(点対称)に減衰していく必要があります。$f_N$ より下で削れた分を、ちょうど $f_N$ より上で補う形です。

最小の帯域は、$P(f)$ が幅 $1/T$ の理想的な箱型(カットオフ $1/(2T)$)の場合で、これがまさに理想 $\mathrm{sinc}$ に対応します。この最小帯域 $1/(2T)$ をナイキスト帯域と呼びます。実用フィルタはこれより少しだけ広い帯域を使い、その「余分」を $f_N$ 周りのなだらかな遷移に充てます。この遷移の急峻さを表すのが、次に説明するロールオフ係数 $\beta$ です。

ここで一度、いま導いた条件式 (1) の意味をもう少し噛み砕いておきましょう。サンプリングという操作は、本来連続だったスペクトルを $1/T$ という「物差し」で折りたたみ、重ね合わせる行為でした。もし元のスペクトルがこの物差しより狭ければ、折りたたんだコピーどうしの間に隙間が空き、その隙間に当たる時刻のサンプル値(実際には標本点でのISI寄与)が中途半端に残ります。逆に物差しより広すぎれば、コピーが重なり合った部分で利得が盛り上がり、やはり床は平らになりません。「ちょうど隙間なく、しかし重なりすぎず、互いの肩を補い合って平らな床を作る」――この一点だけがゼロISIを保証するというのは、設計の自由度が思いのほか狭いことを物語っています。だからこそ、$f_N$ を中心とした奇対称という幾何学的な制約が決定的に効いてくるのです。

別の見方として、時間領域でこの条件を捉え直すこともできます。ナイキストパルス $p(t)$ を周期 $T$ のインパルス列でサンプリングしたものが「単一のデルタ」になる、ということは、$p(t)$ と $\sum_n \delta(t-nT)$ の積が $\delta(t)$ に等しいという意味でした。周波数領域でこの積は畳み込みになり、$P(f)$ と「$1/T$ 間隔のインパルス列のスペクトル(これも $1/T$ 間隔のインパルス列)」の畳み込みが定数になる、という式 (1) にそのまま対応します。時間と周波数の両側から同じ条件を眺めることで、ゼロISIが「サンプリングとスペクトルの折りたたみ」という普遍的な現象の一断面であることが見えてきます。ここまでで「平らな床を作る」という抽象条件が見えたので、それを具体的に実現する関数形を見ていきましょう。

レイズドコサインフィルタ

直感: 角を丸めて尾を速く落とす

理想箱型スペクトルの問題は、$f_N$ で値が崖のように $1$ から $0$ へ落ちることでした。崖(不連続)があると、その逆フーリエ変換である時間波形の尾が遅くしか減衰しません。そこで「崖の代わりに、コサインカーブで滑らかに $1$ から $0$ へ橋渡しする」というアイデアが生まれます。コサインで持ち上げた(raised cosine)形にすることで、$f_N$ を中心とした奇対称が自然に保たれ、ナイキスト条件 (1) を厳密に満たしたまま、遷移をなだらかにできるのです。なだらかな遷移は時間波形の尾を速く減衰させ、タイミング誤差への耐性を高めます。

スペクトルの定義

レイズドコサインフィルタの周波数特性 $P_{\mathrm{RC}}(f)$ は、ロールオフ係数 $\beta \in [0, 1]$ を用いて次のように定義されます。

$$ P_{\mathrm{RC}}(f) = \begin{cases} T & |f| \le \dfrac{1-\beta}{2T} \\[2mm] \dfrac{T}{2}\left[1 + \cos\!\left(\dfrac{\pi T}{\beta}\left(|f| – \dfrac{1-\beta}{2T}\right)\right)\right] & \dfrac{1-\beta}{2T} < |f| \le \dfrac{1+\beta}{2T} \\[2mm] 0 & |f| > \dfrac{1+\beta}{2T} \end{cases} $$

3 つの区間の意味を順に読み解きます。第一の区間(平坦部)は、ナイキスト周波数より十分内側で利得を一定 $T$ に保ちます。第二の区間(遷移部)が肝で、$|f| = (1-\beta)/(2T)$ から $|f| = (1+\beta)/(2T)$ にかけて、コサインの半周期を使って $T$ から $0$ へ滑らかに落とします。第三の区間(阻止部)では完全にゼロで、ここに帯域制限が効きます。

この遷移部が $f_N = 1/(2T)$ を中心に左右対称(値としては点対称)に配置されている点を確認してください。$f = (1-\beta)/(2T)$ での値は $T$、$f = (1+\beta)/(2T)$ での値は $0$、ちょうど中央 $f = 1/(2T)$ での値は $T/2$ です。$f_N$ より下で $T$ から $T/2$ まで削った分が、$f_N$ より上で $T/2$ から $0$ までの肩として現れ、ずらしたコピーと足すと床がきれいに $T$ で埋まります。

占有帯域とロールオフ係数

スペクトルがゼロになる周波数(占有帯域の片側端)は

$$ B = \frac{1+\beta}{2T} = (1+\beta) f_N $$

です。両側帯域(バンドパス信号としての占有帯域)は $2B = (1+\beta)/T = (1+\beta) R_s$($R_s = 1/T$ はシンボルレート)になります。ここから $\beta$ の物理的意味が明確になります。

  • $\beta = 0$: 理想箱型。占有帯域は最小の $R_s$(片側 $f_N$)。ただし尾が長く、タイミング誤差に極端に弱い。
  • $\beta = 1$: 占有帯域は $2 R_s$ と最小の 2 倍。その代わり遷移が最もなだらかで、尾が速く減衰しタイミング誤差に強い。
  • $0 < \beta < 1$: その中間。衛星では $\beta = 0.2 \sim 0.35$、超狭帯域用途では $0.05 \sim 0.1$ がよく使われる。

つまり $\beta$ は「余分にどれだけ帯域を使う代わりに、波形をどれだけ扱いやすくするか」を決める一つのつまみなのです。$\beta$ を $30\%$ にすれば、最小帯域より $30\%$ 広い帯域を使う、と直接読めます。

この $\beta$ の選び方は、通信システム設計のなかでも特に判断が分かれるポイントです。たとえば軌道上の中継器がいくつものキャリアを限られた帯域に詰め込みたい衛星通信では、1 キャリアあたりの占有帯域を少しでも削るために $\beta$ を小さく取りたくなります。実際、DVB-S2X では $\beta = 0.05$ や $0.10$ といった非常に小さいロールオフが規定されており、ナイキスト最小帯域にぎりぎりまで近づけて周波数利用効率を絞り出しています。しかし $\beta$ を小さくすると波形のピーク・トゥ・アベレージ電力比(PAPR)が上がり、増幅器を線形領域で余裕を持って使わなければならなくなります。さらに後で見るようにタイミング同期の精度要求も厳しくなります。逆に地上の安価な機器や、同期に余裕を持たせたい用途では $\beta = 0.35$ 程度を選び、波形を扱いやすくする代わりに帯域を犠牲にします。このように $\beta$ は単なる数学的パラメータではなく、増幅器・同期回路・周波数計画のすべてに波及するシステム設計の要なのです。

時間波形(インパルス応答)の導出

スペクトル $P_{\mathrm{RC}}(f)$ を逆フーリエ変換すると、時間波形 $p_{\mathrm{RC}}(t)$ が得られます。導出は積分が少し長いので結果を示します。$\beta \neq 0$ のとき

$$ \begin{equation} p_{\mathrm{RC}}(t) = \mathrm{sinc}\!\left(\frac{t}{T}\right) \cdot \frac{\cos\!\left(\dfrac{\pi \beta t}{T}\right)}{1 – \left(\dfrac{2\beta t}{T}\right)^2} \end{equation} $$

ここで $\mathrm{sinc}(x) = \sin(\pi x)/(\pi x)$ です。式の構造を読み取りましょう。第一因子 $\mathrm{sinc}(t/T)$ は、理想箱型と同じく $t = nT$($n \neq 0$)でゼロになる「ナイキスト性」を担っています。これがゼロISIを保証する骨格です。第二因子 $\cos(\pi\beta t/T)/[1-(2\beta t/T)^2]$ は、$\beta$ が大きいほど $t$ が大きいところで急速に小さくなる「重み」で、尾を抑え込む役割を果たします。分母が $1/t^2$ で増えるおかげで、レイズドコサインの尾は理想 $\mathrm{sinc}$ の $1/t$ よりずっと速い $1/t^3$ で減衰します。

なお、分母が $0$ になる $t = \pm T/(2\beta)$ では式が $0/0$ になりますが、極限を取ると有限値($\frac{\pi}{4}\mathrm{sinc}(1/(2\beta))$)に収束するので、実装では特異点を別扱いします。後ほどコードで丁寧に処理します。

ここで、尾の減衰の速さが $1/t^3$ になることの意味を強調しておきます。理想 $\mathrm{sinc}$($\beta = 0$)の尾は $1/t$ でしか減衰せず、$n$ 番目に離れたシンボルからのISI寄与は $1/n$ のオーダーで効きます。これらを多数のシンボルにわたって足し合わせると、調和級数 $\sum 1/n$ が発散することからも分かるように、わずかなタイミングずれで干渉が際限なく積み上がる危険があります。一方レイズドコサインの $1/t^3$ 減衰なら、$\sum 1/n^3$ は速やかに収束し、遠くのシンボルからの寄与は事実上無視できます。「角(不連続)を丸める」というたった一つの工夫が、級数の収束性という形で波形の頑健さに直結しているわけです。スペクトル上の滑らかさ(微分可能性)と時間波形の減衰速度がフーリエ変換を通じて結びついている、という普遍的な事実の好例でもあります。ここまでで「全体パルス $p(t)$ がレイズドコサインなら良い」ことが分かりました。しかし実際の送受信機では、このフィルタを送信側と受信側に「半分ずつ」分けて持たせます。その理由を次に説明します。

ルートレイズドコサイン(RRC) — 送受で分割する理由

なぜ分割するのか: 整合フィルタとの両立

受信機では、雑音に埋もれたシンボルをできるだけ確実に検出したいので、整合フィルタ(matched filter)を使います。整合フィルタの理論は「受信フィルタのインパルス応答を送信パルスの時間反転にすると、サンプリング点での信号対雑音比(SNR)が最大化される」というものです。送信フィルタを $H_T(f)$、受信フィルタを $H_R(f)$ とすると、整合フィルタ条件は $H_R(f) = H_T^*(f)$(実数係数なら $H_R(f) = H_T(f)$)です。

一方で、ゼロISIのためには「送受信を通した全体のパルス」がレイズドコサインでなければなりません。

$$ P_{\mathrm{RC}}(f) = H_T(f) \, H_R(f) $$

なぜ整合フィルタがSNRを最大にするのかも、直感的に押さえておきましょう。受信信号には所望のパルス波形と、それに加算される白色雑音が含まれています。受信フィルタの形を所望パルスの形に「揃える」と、フィルタは所望パルスのエネルギーを判定タイミングに集中させて取り出す一方、ランダムな雑音はフィルタの各タップでばらばらの符号を持つため打ち消し合います。結果として、信号成分は同位相で積み上がり、雑音成分は平均化されて相対的に小さくなる――これが整合フィルタが「波形を知っている分だけ得をする」仕組みです。逆に言えば、整合フィルタを使わずに受信側で別の特性のフィルタを掛けてしまうと、せっかく送信側で作り込んだ波形のエネルギーを取りこぼし、SNRが劣化します。だからこそ受信フィルタは送信パルスに整合させたい――この強い動機が、次のフィルタ分割の発想につながります。

この二つの要求、すなわち「$H_R = H_T$(整合)」かつ「$H_T H_R = P_{\mathrm{RC}}$(ゼロISI)」を同時に満たすには、各フィルタを

$$ \begin{equation} H_T(f) = H_R(f) = \sqrt{P_{\mathrm{RC}}(f)} \end{equation} $$

とすればよい、と直ちに分かります。$\sqrt{P_{\mathrm{RC}}(f)}$ がレイズドコサインの「平方根」であることから、このフィルタをルートレイズドコサイン(Root Raised Cosine, RRC)フィルタと呼びます。送信で $\sqrt{P_{\mathrm{RC}}}$、受信でも $\sqrt{P_{\mathrm{RC}}}$ を掛けると、その積はちょうど $P_{\mathrm{RC}}$ になり、ゼロISIが達成されると同時に、受信フィルタが整合フィルタになっているので雑音耐性も最良になります。これがRRCを送受で分割する理由です。

重要な注意: RRC単体はナイキストパルスではない

ここで初学者が必ず引っかかる点を明確にしておきます。RRCフィルタ単体のインパルス応答は、$t = nT$ でゼロになりません。ナイキスト性(ゼロISI)を満たすのはあくまで送受を通した全体 $P_{\mathrm{RC}} = H_T H_R$ であって、$\sqrt{P_{\mathrm{RC}}}$ 単体ではありません。なぜなら、レイズドコサインスペクトル $P_{\mathrm{RC}}(f)$ は $f_N$ を中心とした奇対称という条件 (1) を満たしますが、その平方根 $\sqrt{P_{\mathrm{RC}}(f)}$ は一般にこの奇対称を満たさないからです。平方根を取ると遷移部の形が変わってしまい、ずらしたコピーを足しても床が平らになりません。したがって、送信波形だけをサンプリングしてアイパターンを描くと、見かけ上は閉じ気味に見えます。正しくゼロISIの「開いたアイ」を確認するには、必ず受信RRCを通してからサンプリングする必要があります。これは後のシミュレーションで実際に確かめます。

実務では、この性質はテストや測定のときにしばしば誤解を生みます。たとえば送信機の出力を測定器に取り込み、そのままアイパターンを表示すると目が十分に開いていないように見え、「フィルタ設計を間違えたのか」と慌てることがあります。しかし測定器側で整合RRCを掛けてから(あるいはリファレンスレシーバ機能を使って)観測すれば、きれいに開いたアイが現れます。送信波形そのものは「半分だけ整形された中間状態」であり、ゼロISIという最終的な性質は受信処理と組み合わせて初めて完成する――この役割分担を理解しておくことが、送受信機の検証では欠かせません。

RRCの時間波形

$\sqrt{P_{\mathrm{RC}}(f)}$ を逆フーリエ変換すると、RRCのインパルス応答が得られます。よく使われる閉形式は次の通りです($\beta \neq 0$、特異点を除く)。

$$ \begin{equation} h_{\mathrm{RRC}}(t) = \frac{1}{\sqrt{T}} \cdot \frac{\sin\!\left(\pi \dfrac{t}{T}(1-\beta)\right) + 4\beta \dfrac{t}{T}\cos\!\left(\pi \dfrac{t}{T}(1+\beta)\right)}{\pi \dfrac{t}{T}\left(1 – \left(4\beta \dfrac{t}{T}\right)^2\right)} \end{equation} $$

この式も二つの特異点を持ちます。$t = 0$ と $t = \pm T/(4\beta)$ です。それぞれ極限を取ると

$$ h_{\mathrm{RRC}}(0) = \frac{1}{\sqrt{T}}\left(1 + \beta\left(\frac{4}{\pi} – 1\right)\right) $$

$$ h_{\mathrm{RRC}}\!\left(\pm\frac{T}{4\beta}\right) = \frac{\beta}{\sqrt{2T}}\left[\left(1+\frac{2}{\pi}\right)\sin\!\left(\frac{\pi}{4\beta}\right) + \left(1-\frac{2}{\pi}\right)\cos\!\left(\frac{\pi}{4\beta}\right)\right] $$

という有限値に収束します。実装ではこれらの点を明示的に代入して NaN を回避します。

この閉形式の式は一見複雑ですが、構造を追えば自然な形をしています。分子の第一項 $\sin(\pi(t/T)(1-\beta))$ は、ロールオフによって少し縮んだ「有効ナイキスト帯域」に対応する振動成分で、$\beta = 0$ のときは $\sin(\pi t/T)$ となり、分母の $\pi t/T$ と合わせてちょうど $\mathrm{sinc}(t/T)$ に戻ります。つまり $\beta \to 0$ の極限でRRCは $\mathrm{sinc}$(理想低域通過の平方根もまた理想低域通過)に一致し、矛盾なく連続的につながっています。第二項 $4\beta(t/T)\cos(\pi(t/T)(1+\beta))$ は $\beta$ に比例する補正で、遷移帯域のコサイン肩から生じる成分です。これがレイズドコサインとは異なる、RRC固有の「やや非対称な」波形を作り出します。式を丸暗記する必要はありませんが、各項がスペクトルのどの部分に対応するかを意識しておくと、実装でバグを見つけたときに原因を切り分けやすくなります。次の節では、この式をそのままコード化して波形とスペクトルを確かめます。

Pythonでの実装

RRCインパルス応答の生成

まず、式 (5) と特異点処理を素直に関数化します。FIRフィルタとして使うため、シンボルあたりのサンプル数 sps(samples per symbol、オーバーサンプリング率)と、片側のシンボル長 span でタップ長を決めます。

import numpy as np
import matplotlib.pyplot as plt

def rrc_filter(beta, sps, span):
    """ルートレイズドコサイン(RRC)フィルタのインパルス応答を生成する。

    beta : ロールオフ係数 (0 <= beta <= 1)
    sps  : 1シンボルあたりのサンプル数 (oversampling factor)
    span : フィルタの片側長 [シンボル単位] (全長は 2*span シンボル)
    戻り値 : (t, h) 時刻配列とインパルス応答(エネルギー正規化済み)
    """
    # T=1 (シンボル間隔)とし、サンプル間隔は 1/sps
    N = 2 * span * sps          # タップ数(偶数)
    t = (np.arange(N + 1) - N / 2) / sps   # 時刻 [シンボル単位], 中心0で対称
    h = np.zeros_like(t)

    for i, ti in enumerate(t):
        if np.isclose(ti, 0.0):
            # t=0 の特異点
            h[i] = 1.0 + beta * (4.0 / np.pi - 1.0)
        elif beta > 0 and np.isclose(abs(ti), 1.0 / (4.0 * beta)):
            # t = ±T/(4β) の特異点
            h[i] = (beta / np.sqrt(2.0)) * (
                (1 + 2 / np.pi) * np.sin(np.pi / (4 * beta))
                + (1 - 2 / np.pi) * np.cos(np.pi / (4 * beta))
            )
        else:
            # 一般項 (式5, T=1)
            num = (np.sin(np.pi * ti * (1 - beta))
                   + 4 * beta * ti * np.cos(np.pi * ti * (1 + beta)))
            den = np.pi * ti * (1 - (4 * beta * ti) ** 2)
            h[i] = num / den

    h /= np.sqrt(np.sum(h ** 2))   # エネルギーを1に正規化
    return t, h

rrc_filter は特異点 $t=0$ と $t=\pm 1/(4\beta)$ を np.isclose で検出し、極限値を直接代入しています。最後にエネルギーで正規化しているのは、後で送受2段重ねたときの利得を扱いやすくするためです。これで安全にRRC係数が得られます。

次に、$\beta$ を変えてインパルス応答を描いてみます。

import numpy as np
import matplotlib.pyplot as plt

sps, span = 8, 8
betas = [0.0, 0.25, 0.5, 1.0]

plt.figure(figsize=(9, 5))
for beta in betas:
    t, h = rrc_filter(beta, sps, span)
    plt.plot(t, h, label=f"β = {beta}")
plt.axhline(0, color="gray", lw=0.5)
# シンボル標本点に縦線
for n in range(-span, span + 1):
    plt.axvline(n, color="lightgray", lw=0.5, zorder=0)
plt.xlabel("Time t / T  (symbol periods)")
plt.ylabel("Amplitude")
plt.title("RRC Impulse Response for various roll-off β")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("rrc_impulse.png", dpi=150, bbox_inches="tight")
plt.show()

このグラフから二つのことが読み取れます。第一に、$\beta = 0$(理想 $\mathrm{sinc}$ に対応)では波形の尾が長く、グラフの端まで振動が続いています。一方 $\beta = 1$ では中央のローブの周りに尾がほとんど残らず、数シンボル分で急速に減衰しています。これが「$\beta$ を大きくすると尾が速く落ちる」という先の議論の可視化です。第二に、注意点として、RRC単体の波形は $t = \pm 1, \pm 2, \dots$ の標本点(薄い縦線)でゼロを通っていません。これはRRC単体がナイキストパルスではないことの直接的な証拠です。

全体パルスがレイズドコサインになることの確認

送信RRCと受信RRCを畳み込むと、全体パルスがレイズドコサインになり、標本点でゼロISIになるはずです。実際に畳み込んで確かめます。

import numpy as np
import matplotlib.pyplot as plt

sps, span, beta = 8, 8, 0.25
t, h = rrc_filter(beta, sps, span)

# 送受でRRCを2回通す = h と h の畳み込み = 全体パルス(レイズドコサイン)
p = np.convolve(h, h)
p /= np.max(p)                       # ピークを1に正規化
tp = (np.arange(len(p)) - (len(p) - 1) / 2) / sps  # 時刻[シンボル単位]

plt.figure(figsize=(9, 5))
plt.plot(tp, p, label="RRC ⊛ RRC = Raised Cosine (full pulse)")
plt.plot(t, h / np.max(h), "--", alpha=0.6, label="RRC alone (Tx only)")
# 標本点を強調
for n in range(-2 * span, 2 * span + 1):
    plt.axvline(n, color="lightgray", lw=0.5, zorder=0)
plt.scatter(np.arange(-3, 4),
            [p[np.argmin(np.abs(tp - n))] for n in range(-3, 4)],
            color="red", zorder=5, label="sample points")
plt.xlim(-8, 8)
plt.xlabel("Time t / T")
plt.ylabel("Normalized amplitude")
plt.title("Full pulse (RC) is zero at all non-zero sample points")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("rrc_cascade.png", dpi=150, bbox_inches="tight")
plt.show()

赤い点に注目してください。全体パルス(実線)は $t = 0$ でちょうど $1$、$t = \pm 1, \pm 2, \dots$ ではすべて $0$ を通っています。これがまさにナイキスト性、ゼロISIの実現です。対照的に破線のRRC単体は標本点でゼロを通らず、両者の違いが一目で分かります。送受を通して初めてゼロISIになる、という設計思想がこの図に凝縮されています。

スペクトルとロールオフ係数の関係

次に周波数領域で、$\beta$ が占有帯域をどう変えるかを確認します。RRC単体のスペクトル($\sqrt{P_{\mathrm{RC}}}$)と全体のレイズドコサインスペクトル($P_{\mathrm{RC}}$)を重ねます。

import numpy as np
import matplotlib.pyplot as plt

sps, span = 8, 16
NFFT = 4096

plt.figure(figsize=(9, 5))
for beta in [0.0, 0.25, 0.5, 1.0]:
    t, h = rrc_filter(beta, sps, span)
    H = np.fft.fftshift(np.fft.fft(h, NFFT))
    f = np.fft.fftshift(np.fft.fftfreq(NFFT, d=1.0 / sps))  # 周波数 [1/T 単位]
    H_db = 20 * np.log10(np.abs(H) / np.max(np.abs(H)) + 1e-12)
    plt.plot(f, H_db, label=f"RRC, β = {beta}")

plt.axvline(0.5, color="red", ls="--", alpha=0.6, label="Nyquist freq 1/2T")
plt.xlim(0, 1.2)
plt.ylim(-60, 5)
plt.xlabel("Frequency  f·T  (normalized to symbol rate)")
plt.ylabel("Magnitude [dB]")
plt.title("RRC spectra: larger β occupies wider band")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("rrc_spectrum.png", dpi=150, bbox_inches="tight")
plt.show()

このスペクトル図から、$\beta$ の役割がはっきり読み取れます。すべての曲線は $f \approx 1/(2T)$(ナイキスト周波数、赤破線)で $-3\,\mathrm{dB}$ 付近を通り、そこから $\beta$ に応じた幅で落ちていきます。$\beta = 0$ ではナイキスト周波数で垂直に切り立ち、占有帯域は最小ですが立ち上がりが急峻です。$\beta = 1$ では $f = 1/T$ までなだらかに広がり、占有帯域は最小の 2 倍になっています。つまり片側占有帯域は $(1+\beta)/(2T)$ という理論式どおりに広がっており、$\beta$ が「余分な帯域」を直接コントロールしていることが確認できます。

ここまでで周波数領域の振る舞いが分かりました。次に、実際にシンボル列を整形して送り、受信側で復元し、ISIが本当に消えるかをアイパターンで確かめます。

シンボル列の整形とアップサンプル

ランダムなBPSKシンボル列($\pm 1$)を生成し、シンボル間にゼロを挿入してアップサンプルしてからRRCで整形します。アップサンプル+フィルタという操作が、まさに先述の $s(t) = \sum_k a_k g(t-kT)$ をディジタルで実現したものです。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(0)
sps, span, beta = 8, 8, 0.25
n_sym = 200

# BPSKシンボル (+1 / -1)
symbols = np.random.choice([-1.0, 1.0], size=n_sym)

# アップサンプル: 各シンボルの間に sps-1 個のゼロを挿入
up = np.zeros(n_sym * sps)
up[::sps] = symbols

# 送信RRCで整形
_, h = rrc_filter(beta, sps, span)
tx = np.convolve(up, h, mode="same")

# 受信RRC(整合フィルタ)を通す
rx = np.convolve(tx, h, mode="same")
rx /= np.max(np.abs(rx))   # 表示用に正規化

plt.figure(figsize=(10, 4))
plt.plot(tx / np.max(np.abs(tx)), label="Tx (RRC shaped)", alpha=0.8)
plt.plot(rx, label="Rx (after matched filter)", alpha=0.8)
plt.xlim(0, 30 * sps)
plt.xlabel("Sample index")
plt.ylabel("Normalized amplitude")
plt.title("Pulse-shaped transmit and matched-filtered receive waveform")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("rrc_waveform.png", dpi=150, bbox_inches="tight")
plt.show()

送信波形(Tx)は、もとの $\pm 1$ のシンボル列が滑らかな連続波形に整形されている様子を示しています。受信波形(Rx)は整合フィルタを通したあとのもので、シンボルの中心($sps$ サンプルおき)で $\pm 1$ に対応するレベルへきれいに収束しているのが分かります。この「中心で値が定まる」ことが、サンプリングしたときにゼロISIになることの時間波形版です。

アイパターンによるISI評価

アイパターンは、受信波形を 1〜2 シンボル区間ごとに切り出して重ね描きしたものです。判定タイミングで「目(アイ)」が大きく開いていればISIが小さく、雑音やタイミング誤差に強いことを意味します。

import numpy as np
import matplotlib.pyplot as plt

def plot_eye(ax, sig, sps, n_traces=200, title=""):
    """2シンボル幅でトレースを重ねてアイパターンを描く。"""
    span_samples = 2 * sps
    start = 4 * sps                      # 過渡部をスキップ
    tau = np.linspace(-1, 1, span_samples)  # -T..+T [シンボル単位]
    for k in range(n_traces):
        s = start + k * sps
        seg = sig[s:s + span_samples]
        if len(seg) == span_samples:
            ax.plot(tau, seg, color="steelblue", alpha=0.25, lw=0.8)
    ax.axvline(0, color="red", ls="--", alpha=0.7)  # 判定タイミング
    ax.set_xlabel("Time within symbol  (t/T)")
    ax.set_ylabel("Amplitude")
    ax.set_title(title)
    ax.grid(True, alpha=0.3)

np.random.seed(1)
sps, span = 8, 8
n_sym = 2000
symbols = np.random.choice([-1.0, 1.0], size=n_sym)
up = np.zeros(n_sym * sps)
up[::sps] = symbols

fig, axes = plt.subplots(1, 2, figsize=(12, 4.5))
for ax, beta in zip(axes, [0.25, 1.0]):
    _, h = rrc_filter(beta, sps, span)
    tx = np.convolve(up, h, mode="same")
    rx = np.convolve(tx, h, mode="same")
    rx /= np.max(np.abs(rx))
    plot_eye(ax, rx, sps, title=f"Eye diagram (β = {beta}, after MF)")
plt.tight_layout()
plt.savefig("rrc_eye.png", dpi=150, bbox_inches="tight")
plt.show()

二つのアイパターンを比べると、判定タイミング(赤破線、$t/T = 0$)で多数のトレースが上下 2 つの細い帯に集中し、中央に大きく開いた「目」ができています。これはゼロISIが達成され、$+1$ と $-1$ がはっきり分離していることを意味します。$\beta = 1$ のほうが $\beta = 0.25$ より目が左右に広く開いているのが見て取れますが、これは尾が速く減衰するため、判定タイミングが多少ずれてもアイが閉じにくいことを表しています。逆に $\beta = 0.25$ は目の横幅が狭く、タイミング誤差に敏感です。帯域とタイミング耐性のトレードオフがアイの形に現れているのです。

送信のみ(整合フィルタなし)でアイが閉じる様子

RRC単体がナイキストパルスでないことを、アイパターンで直接確かめます。受信RRCを通さず、送信波形だけでアイを描きます。

import numpy as np
import matplotlib.pyplot as plt

np.random.seed(2)
sps, span, beta = 8, 8, 0.25
n_sym = 2000
symbols = np.random.choice([-1.0, 1.0], size=n_sym)
up = np.zeros(n_sym * sps)
up[::sps] = symbols
_, h = rrc_filter(beta, sps, span)
tx = np.convolve(up, h, mode="same")
tx /= np.max(np.abs(tx))

fig, ax = plt.subplots(figsize=(7, 4.5))
plot_eye(ax, tx, sps, title="Eye of Tx-only RRC (no matched filter): ISI present")
plt.tight_layout()
plt.savefig("rrc_eye_txonly.png", dpi=150, bbox_inches="tight")
plt.show()

このアイパターンでは、判定タイミングでトレースが上下 2 本の細い帯に収束せず、ばらついて目が部分的に潰れています。これがRRC単体に残るISIです。先ほどの「送受を通したアイ」(きれいに開いていた)と比較すると、整合フィルタを通して初めてゼロISIになるという事実が、波形のレベルで明確に確認できます。設計者がうっかり片側だけRRCにすると性能が出ない、という実務上の落とし穴がここに可視化されています。

タイミング誤差に対する感度

最後に、サンプリングタイミングを意図的にずらして、残留ISIがどれだけ増えるかを定量化します。$\beta$ ごとに、タイミング誤差 $\tau$(シンボル周期に対する割合)に対する最悪ISIを計算します。

import numpy as np
import matplotlib.pyplot as plt

def peak_isi_db(beta, sps, span, offset_frac):
    """全体パルス(RC)の標本点ずれ offset に対するピークISIを計算[dB]。"""
    _, h = rrc_filter(beta, sps, span)
    p = np.convolve(h, h)
    p /= np.max(p)                       # 主ローブピークを1に
    center = (len(p) - 1) // 2
    off = int(round(offset_frac * sps))
    # 主シンボル以外の標本点(±1,±2,...)での値の絶対値合計
    isi = 0.0
    for n in range(-span, span + 1):
        if n == 0:
            continue
        idx = center + n * sps + off
        if 0 <= idx < len(p):
            isi += abs(p[idx])
    main = abs(p[center + off])
    return 20 * np.log10(isi / main + 1e-12)

sps, span = 16, 12
offsets = np.linspace(0, 0.3, 31)
plt.figure(figsize=(9, 5))
for beta in [0.1, 0.25, 0.5, 1.0]:
    vals = [peak_isi_db(beta, sps, span, o) for o in offsets]
    plt.plot(offsets, vals, label=f"β = {beta}")
plt.xlabel("Timing error  τ / T")
plt.ylabel("Peak ISI / main [dB]")
plt.title("Sensitivity of residual ISI to sampling timing error")
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig("rrc_timing.png", dpi=150, bbox_inches="tight")
plt.show()

この図は、設計上きわめて実務的な知見を与えてくれます。タイミング誤差 $\tau = 0$ では、どの $\beta$ でもISIは理論上 $-\infty$ dB(完全ゼロ)に近い深い谷になります。しかし $\tau$ が増えると残留ISIが急速に立ち上がり、その立ち上がりの急峻さは $\beta$ が小さいほど激しくなります。$\beta = 0.1$ ではわずか数 % のタイミング誤差でISIが $-20$ dB 以上に悪化するのに対し、$\beta = 1.0$ では同じ誤差でもISIがずっと低く抑えられます。これが「狭帯域(小さい $\beta$)はタイミング同期に厳しい要求を課す」という事実の定量的な裏付けです。衛星通信で $\beta$ を極端に小さくすると帯域は節約できますが、その分シンボルタイミング同期回路に高い精度が要求されるわけです。

この感度の違いは、波形の尾の減衰速度に立ち返ると腑に落ちます。$\beta$ が小さいパルスは中央ローブが鋭く尾が長いため、判定タイミングがずれると、まず急峻な傾きのせいで主シンボルの読み取り値そのものが変動し、同時に長い尾が近隣シンボルのゼロ点から外れて一斉に漏れ込みます。逆に $\beta$ が大きいパルスは、中央ローブがゆったりしてピーク付近が平坦に近く、少々タイミングがずれても主シンボル値が大きくは動かず、尾も短いので漏れ込みが限定的です。アイパターンで言えば、$\beta$ が大きいほど目が「横に広い」のは、この水平方向のタイミング余裕の大きさを反映しています。実機ではシンボルタイミング再生(Gardner法やMueller-Müller法などの早遅同期)でこのずれを追い込みますが、$\beta$ が小さいと許容できる残留ずれが小さく、ループ帯域や検出器の設計がよりシビアになります。したがって $\beta$ の選定は、占有帯域・PAPR・同期回路の難易度という三つの軸を同時ににらみながら決める、システム全体の最適化問題なのです。

まとめ

本記事では、ディジタル通信におけるパルス整形とナイキストフィルタについて、ゼロISIの原理からRRCの実装まで解説しました。要点を整理します。

  • 符号間干渉(ISI): 帯域制限で波形が滲み、判定タイミングに隣接シンボルの尾が漏れ込む現象。ビット誤りの主因の一つ。
  • ナイキストの第一基準: 整形パルスが標本点で $p(nT)=\delta_{n,0}$ を満たすこと。周波数領域では「$P(f)$ を $1/T$ おきにずらして足すと一定 $T$ になる($\sum_m P(f-m/T)=T$)」という条件で表される。
  • レイズドコサインフィルタ: ナイキスト周波数で崖を作らず、コサインで滑らかに遷移させることでナイキスト条件を満たしつつ尾を $1/t^3$ で速く減衰させる。占有帯域は片側 $(1+\beta)/(2T)$。
  • ロールオフ係数 $\beta$: 「余分な帯域 ($+\beta\times$最小帯域) と引き換えに、波形の尾の速さ・タイミング耐性を改善する」つまみ。
  • ルートレイズドコサイン(RRC): 整合フィルタ($H_R=H_T$)とゼロISI($H_T H_R = P_{\mathrm{RC}}$)を両立するため、各フィルタを $\sqrt{P_{\mathrm{RC}}}$ に分割。RRC単体はナイキストパルスではなく、送受を通して初めてゼロISIになる。
  • タイミング感度: $\beta$ が小さいほど残留ISIがタイミング誤差に敏感。狭帯域化は同期回路への要求を厳しくする。

パルス整形は、衛星通信・地上系を問わずあらゆる変調方式の土台です。ここで学んだRRCの考え方は、QAMやPSKのコンスタレーション設計、さらにはOFDMのサブキャリア設計やシンボルタイミング同期アルゴリズムの理解へと直結します。

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