パルス圧縮(チャープ信号)の理論と実装を解説

パルスレーダーにおいて、距離分解能と探知距離は本質的にトレードオフの関係にあります。距離分解能を上げるにはパルス幅を短くする必要がありますが、短パルスでは送信エネルギーが低下して探知距離が短くなります。このジレンマを解決するのがパルス圧縮(Pulse Compression)技術であり、その中核をなすのがチャープ信号(線形FM変調信号)です。

パルス圧縮は、広い帯域幅を持つ長パルスを送信し、受信時にマッチドフィルタ処理を行うことで、あたかも短パルスを送信したかのような高い距離分解能を実現します。本記事では、パルスレーダーのジレンマから出発し、チャープ信号の数学的定義、マッチドフィルタの理論(SNR最大化の証明)、パルス圧縮の原理と距離分解能 $\Delta R = c/(2B)$ の導出、サイドローブ抑圧まで丁寧に解説し、Pythonで実装・可視化します。

本記事の内容

  • パルスレーダーのジレンマ(距離分解能 vs 探知距離)
  • チャープ信号(線形FM波形)の定義と瞬時周波数
  • マッチドフィルタの理論とSNR最大化の証明
  • パルス圧縮の原理と距離分解能 $\Delta R = c/(2B)$ の導出
  • 時間-帯域幅積 $TB$ とパルス圧縮比
  • サイドローブ抑圧(ウィンドウイング)
  • Pythonでの実装と可視化

前提知識

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

パルスレーダーのジレンマ

距離分解能

パルスレーダーの距離分解能(Range Resolution)とは、レンジ方向に近接する2つの目標を区別できる最小距離です。パルス幅 $\tau$ の単純パルスを送信する場合、距離分解能は次のように与えられます。

$$ \Delta R = \frac{c\tau}{2} $$

ここで $c$ は光速($3 \times 10^8 \, \mathrm{m/s}$)です。分母の2は電波の往復を考慮するためです。2つの目標の距離差がこの値より小さいと、反射信号が時間的に重なり、区別ができなくなります。

探知距離とエネルギー

一方、レーダーの探知距離はレーダー方程式により送信エネルギー $E$ に依存します。単純パルスの場合、送信エネルギーは次の通りです。

$$ E = P_t \cdot \tau $$

ここで $P_t$ は送信ピーク電力です。距離分解能を上げるためにパルス幅 $\tau$ を短くすると、同じピーク電力では送信エネルギー $E$ が低下し、探知距離が短くなります。

ジレンマの定量的理解

具体的な数値で確認しましょう。距離分解能 $\Delta R = 1 \, \mathrm{m}$ を得るために必要なパルス幅は次の通りです。

$$ \tau = \frac{2\Delta R}{c} = \frac{2 \times 1}{3 \times 10^8} = 6.67 \, \mathrm{ns} $$

ピーク電力 $P_t = 1 \, \mathrm{kW}$ とすると、送信エネルギーは次のようになります。

$$ E = 1000 \times 6.67 \times 10^{-9} = 6.67 \, \mu\mathrm{J} $$

逆に、十分な探知距離のために $\tau = 10 \, \mu\mathrm{s}$ のパルスを送信する場合のエネルギーは次の通りです。

$$ E = 1000 \times 10 \times 10^{-6} = 10 \, \mathrm{mJ} $$

しかしこのときの距離分解能は次のようになります。

$$ \Delta R = \frac{3 \times 10^8 \times 10 \times 10^{-6}}{2} = 1{,}500 \, \mathrm{m} $$

このように、単純パルスでは距離分解能と探知距離を同時に改善することができません。これがパルスレーダーのジレンマです。

チャープ信号(線形FM波形)

定義

パルス圧縮の鍵となるチャープ信号(Chirp Signal)は、パルス内で周波数が線形に変化する信号です。数学的には次のように定義されます。

$$ s(t) = \mathrm{rect}\!\left(\frac{t}{T}\right) \exp\!\left(j\pi K t^2\right) $$

ここで、$T$ はパルス幅、$K = B/T$ はチャープレート(周波数変化率, $\mathrm{Hz/s}$)、$B$ は周波数掃引幅(帯域幅)です。$\mathrm{rect}(t/T)$ は幅 $T$ の矩形窓関数であり、$|t| \leq T/2$ で1、それ以外で0です。

搬送波を含めた実信号は次のようになります。

$$ s_{\mathrm{RF}}(t) = \mathrm{rect}\!\left(\frac{t}{T}\right) \cos\!\left(2\pi f_c t + \pi K t^2\right) $$

瞬時周波数

チャープ信号の位相は次の通りです。

$$ \phi(t) = \pi K t^2 $$

瞬時周波数(Instantaneous Frequency)は、位相の時間微分の $1/(2\pi)$ 倍です。

$$ \begin{align} f_i(t) &= \frac{1}{2\pi} \frac{d\phi(t)}{dt} \\ &= \frac{1}{2\pi} \cdot 2\pi K t \\ &= Kt \end{align} $$

$t = -T/2$ のとき $f_i = -B/2$、$t = T/2$ のとき $f_i = B/2$ となり、パルス内で周波数が $-B/2$ から $B/2$ まで線形に増加します。$K > 0$ の場合をアップチャープ、$K < 0$ の場合をダウンチャープと呼びます。

周波数スペクトル

チャープ信号のフーリエ変換を求めましょう。定常位相近似(Stationary Phase Approximation)を用いると、$TB \gg 1$ のとき次のように近似できます。

$$ S(f) = \int_{-T/2}^{T/2} \exp\!\left(j\pi K t^2\right) \exp\!\left(-j2\pi ft\right) dt $$

被積分関数の位相 $\Phi(t) = \pi K t^2 – 2\pi ft$ の停留点は $d\Phi/dt = 0$ より $t_0 = f/K$ です。

定常位相近似を適用すると次のようになります。

$$ \begin{align} S(f) &\approx \sqrt{\frac{1}{|K|}} \cdot \mathrm{rect}\!\left(\frac{f}{B}\right) \cdot \exp\!\left(-j\frac{\pi f^2}{K}\right) \cdot \exp\!\left(j\frac{\pi}{4}\right) \end{align} $$

振幅スペクトルはおおむね帯域幅 $B$ の範囲で一定であり、チャープ信号は実効的に帯域幅 $B$ の信号であることが確認できます。

マッチドフィルタの理論

問題設定

雑音中の既知信号を検出する問題を考えます。受信信号は次のように表されます。

$$ r(t) = s(t – t_0) + n(t) $$

ここで $s(t)$ は送信信号、$t_0$ は遅延時間、$n(t)$ は白色ガウス雑音(電力スペクトル密度 $N_0/2$)です。

線形フィルタ $h(t)$(伝達関数 $H(f)$)を通過させた出力は次の通りです。

$$ y(t) = \int_{-\infty}^{\infty} h(\tau) r(t – \tau) d\tau $$

SNRの定式化

フィルタ出力の信号成分のピーク値を $|y_s(t_0)|^2$、雑音の平均電力を $E[|y_n(t)|^2]$ とすると、出力SNRは次のように定義されます。

$$ \mathrm{SNR} = \frac{|y_s(t_0)|^2}{E[|y_n(t)|^2]} $$

信号成分のピーク値は、周波数領域で次のように書けます。

$$ y_s(t_0) = \int_{-\infty}^{\infty} H(f) S(f) \exp\!\left(j2\pi f t_0\right) df $$

ここで $S(f)$ は $s(t)$ のフーリエ変換です(遅延 $t_0$ による位相は $\exp(-j2\pi f t_0)$ ですが、$t = t_0$ で評価するため相殺されます)。

$$ |y_s(t_0)|^2 = \left|\int_{-\infty}^{\infty} H(f) S(f) df \right|^2 $$

雑音の平均電力は次の通りです。

$$ E[|y_n(t)|^2] = \frac{N_0}{2} \int_{-\infty}^{\infty} |H(f)|^2 df $$

したがってSNRは次のようになります。

$$ \mathrm{SNR} = \frac{\left|\int_{-\infty}^{\infty} H(f) S(f) df \right|^2}{\frac{N_0}{2} \int_{-\infty}^{\infty} |H(f)|^2 df} $$

コーシー=シュワルツの不等式によるSNR最大化

コーシー=シュワルツの不等式を適用します。

$$ \left|\int_{-\infty}^{\infty} H(f) S(f) df \right|^2 \leq \int_{-\infty}^{\infty} |H(f)|^2 df \cdot \int_{-\infty}^{\infty} |S(f)|^2 df $$

等号は $H(f) = k \cdot S^*(f)$ のとき成立します($k$ は任意の定数)。これをSNRの式に代入すると次のようになります。

$$ \begin{align} \mathrm{SNR}_{\max} &= \frac{\int_{-\infty}^{\infty} |S(f)|^2 df \cdot \int_{-\infty}^{\infty} |S(f)|^2 df}{\frac{N_0}{2} \int_{-\infty}^{\infty} |S(f)|^2 df} \\ &= \frac{\int_{-\infty}^{\infty} |S(f)|^2 df}{\frac{N_0}{2}} \\ &= \frac{2E}{N_0} \end{align} $$

最後の等号では、パーセバルの定理 $\int |S(f)|^2 df = \int |s(t)|^2 dt = E$ を用いました。ここで $E$ は信号のエネルギーです。

マッチドフィルタの定義

$$ \boxed{H_{\mathrm{MF}}(f) = S^*(f) \exp(-j2\pi f t_0)} $$

時間領域では次のようになります。

$$ h_{\mathrm{MF}}(t) = s^*(t_0 – t) $$

これは送信信号を時間反転し複素共役をとったものです。つまり、マッチドフィルタは受信信号と送信波形の相互相関を計算しているのです。

重要な結果をまとめます。

$$ \boxed{\mathrm{SNR}_{\max} = \frac{2E}{N_0}} $$

最大出力SNRは送信信号の波形には依存せず、信号エネルギー $E$ と雑音の片側電力スペクトル密度 $N_0/2$ の比で決まります。これは非常に深い結果です。

パルス圧縮の原理

チャープ信号のマッチドフィルタ出力

チャープ信号 $s(t) = \mathrm{rect}(t/T) \exp(j\pi K t^2)$ のマッチドフィルタ出力を計算しましょう。

マッチドフィルタの出力は、入力信号とフィルタのインパルス応答の畳み込みです。遅延 $\tau$ の信号に対する出力は次の通りです。

$$ y(\tau) = \int_{-\infty}^{\infty} s(t) s^*(t – \tau) dt $$

これは $s(t)$ の自己相関関数です。チャープ信号を代入します。

$$ y(\tau) = \int_{-\infty}^{\infty} \mathrm{rect}\!\left(\frac{t}{T}\right) \exp\!\left(j\pi K t^2\right) \cdot \mathrm{rect}\!\left(\frac{t-\tau}{T}\right) \exp\!\left(-j\pi K (t-\tau)^2\right) dt $$

指数部を展開します。

$$ \begin{align} j\pi K t^2 – j\pi K(t-\tau)^2 &= j\pi K \left[t^2 – (t^2 – 2t\tau + \tau^2)\right] \\ &= j\pi K (2t\tau – \tau^2) \\ &= j2\pi K \tau t – j\pi K \tau^2 \end{align} $$

$\tau$ に依存する定数項 $\exp(-j\pi K \tau^2)$ を積分の外に出すと次のようになります。

$$ y(\tau) = \exp(-j\pi K \tau^2) \int_{-\infty}^{\infty} \mathrm{rect}\!\left(\frac{t}{T}\right) \mathrm{rect}\!\left(\frac{t-\tau}{T}\right) \exp\!\left(j2\pi K\tau t\right) dt $$

矩形窓の重なり区間の長さは $T – |\tau|$($|\tau| \leq T$ のとき)です。$|\tau| \ll T$(パルス圧縮後の主ローブ幅がパルス幅よりずっと短い場合)では、矩形窓の重なりをおよそ $T$ とみなせます。このとき積分は次のようになります。

$$ \begin{align} y(\tau) &\approx \exp(-j\pi K \tau^2) \int_{-T/2}^{T/2} \exp(j2\pi K\tau t) dt \\ &= \exp(-j\pi K \tau^2) \cdot T \cdot \mathrm{sinc}(K\tau T) \\ &= \exp(-j\pi K \tau^2) \cdot T \cdot \mathrm{sinc}(B\tau) \end{align} $$

ここで $\mathrm{sinc}(x) = \sin(\pi x) / (\pi x)$ であり、$KT = B$ を用いました。

圧縮後の時間幅

マッチドフィルタ出力 $|y(\tau)|$ の主ローブ幅は $\mathrm{sinc}(B\tau)$ の最初のゼロ点で決まります。

$$ B\tau_0 = 1 \quad \Rightarrow \quad \tau_0 = \frac{1}{B} $$

圧縮後のパルス幅(-3 dB幅)は約 $\tau_c \approx 1/B$ です。元のパルス幅 $T$ から $1/B$ に圧縮されたことから、圧縮比は次の通りです。

$$ \text{圧縮比} = \frac{T}{\tau_c} = \frac{T}{1/B} = TB $$

この $TB$ を時間-帯域幅積(Time-Bandwidth Product)と呼びます。

距離分解能の導出

圧縮後のパルス幅 $\tau_c = 1/B$ に対応する距離分解能は次の通りです。

$$ \begin{align} \Delta R &= \frac{c \tau_c}{2} \\ &= \frac{c}{2B} \end{align} $$

$$ \boxed{\Delta R = \frac{c}{2B}} $$

この結果の重要な点は、距離分解能が帯域幅 $B$ のみで決まり、パルス幅 $T$ には依存しないことです。長いパルス(高エネルギー)を送信しつつ、帯域幅を広くとることで高い距離分解能が得られます。

パルス圧縮の利得

パルス圧縮によるSNR改善量(パルス圧縮利得, Processing Gain)は、圧縮比に等しく次のようになります。

$$ G_{\mathrm{PC}} = TB $$

これはデシベルで表すと次の通りです。

$$ G_{\mathrm{PC}} \, [\mathrm{dB}] = 10 \log_{10}(TB) $$

例えば $T = 10 \, \mu\mathrm{s}$, $B = 10 \, \mathrm{MHz}$ の場合、$TB = 100$(20 dB)の圧縮利得が得られます。

時間-帯域幅積の意味

時間-帯域幅積 $TB$ はパルス圧縮の性能を決定する最も重要なパラメータです。

パラメータ 効果
パルス幅 $T$ 大きい 送信エネルギー大 → 探知距離向上
帯域幅 $B$ 大きい 距離分解能向上 ($\Delta R = c/(2B)$)
$TB$ 大きい 圧縮利得大、分解能と探知距離を同時に向上

チャープ信号の強みは、$T$ と $B$ を独立に設計できる点にあります。単純パルスでは $B \approx 1/T$ の制約がありますが、チャープ信号では $T$ を長くして $B$ も広くとることで、$TB \gg 1$ を実現できます。

実用的なレーダーでは $TB$ は100〜1000程度(20〜30 dB)が一般的です。

サイドローブ抑圧

サイドローブの問題

チャープ信号のマッチドフィルタ出力は $\mathrm{sinc}$ 関数の形をしますが、$\mathrm{sinc}$ 関数の最初のサイドローブレベルは主ローブから約 $-13.3 \, \mathrm{dB}$ しか低くありません。

$$ 20\log_{10}\!\left(\frac{1}{3\pi/2}\right) \approx -13.3 \, \mathrm{dB} $$

これは、弱い目標が強い目標のサイドローブに埋もれてしまうことを意味します。

ウィンドウイングによる抑圧

サイドローブを抑圧するために、マッチドフィルタの周波数応答にウィンドウ関数(窓関数)を乗算します。代表的な窓関数とサイドローブレベルを示します。

窓関数 サイドローブレベル 主ローブ幅の拡大
矩形窓(なし) -13.3 dB 1.0倍(基準)
ハミング窓 -42.7 dB 1.50倍
ハニング窓 -31.5 dB 1.44倍
テイラー窓(-40 dB) -40 dB 1.38倍

ウィンドウイングの代償は、主ローブ幅の拡大、すなわち距離分解能の劣化です。例えばハミング窓を適用すると、距離分解能は約1.5倍に劣化しますが、サイドローブは約30 dB改善します。

ウィンドウ関数を $W(f)$ とすると、修正マッチドフィルタの伝達関数は次の通りです。

$$ H_{\mathrm{WMF}}(f) = W(f) \cdot S^*(f) $$

Pythonでの実装と可視化

チャープ信号の生成と表示

import numpy as np
import matplotlib.pyplot as plt

# --- パラメータ設定 ---
T = 10e-6         # パルス幅 [s]
B = 5e6           # 帯域幅 [Hz]
K = B / T         # チャープレート [Hz/s]
fs = 4 * B        # サンプリング周波数 [Hz]
c = 3e8           # 光速 [m/s]

# 時間軸
N = int(T * fs)
t = np.linspace(-T/2, T/2, N)

# チャープ信号の生成(ベースバンド)
chirp = np.exp(1j * np.pi * K * t**2)

# 瞬時周波数
f_inst = K * t

# --- チャープ信号の可視化 ---
fig, axes = plt.subplots(3, 1, figsize=(12, 10))

# 実部
axes[0].plot(t * 1e6, np.real(chirp), 'b-', linewidth=0.5)
axes[0].set_xlabel('Time [us]')
axes[0].set_ylabel('Amplitude')
axes[0].set_title('Chirp Signal - Real Part')
axes[0].grid(True, alpha=0.3)

# 瞬時周波数
axes[1].plot(t * 1e6, f_inst / 1e6, 'r-', linewidth=2)
axes[1].set_xlabel('Time [us]')
axes[1].set_ylabel('Frequency [MHz]')
axes[1].set_title('Instantaneous Frequency')
axes[1].grid(True, alpha=0.3)

# スペクトログラム(周波数vs時間)
# 短時間フーリエ変換で表示
axes[2].specgram(np.real(chirp * np.exp(1j * 2 * np.pi * B * t)),
                 NFFT=64, Fs=fs/1e6, noverlap=60, cmap='jet')
axes[2].set_xlabel('Time [us]')
axes[2].set_ylabel('Frequency [MHz]')
axes[2].set_title('Spectrogram')

plt.tight_layout()
plt.show()

print(f"パルス幅 T = {T*1e6:.1f} us")
print(f"帯域幅 B = {B/1e6:.1f} MHz")
print(f"チャープレート K = {K/1e12:.2f} THz/s")
print(f"時間-帯域幅積 TB = {T*B:.0f}")

マッチドフィルタによるパルス圧縮

import numpy as np
import matplotlib.pyplot as plt

# --- パラメータ設定 ---
T = 10e-6         # パルス幅 [s]
B = 5e6           # 帯域幅 [Hz]
K = B / T         # チャープレート [Hz/s]
fs = 4 * B        # サンプリング周波数 [Hz]
c = 3e8           # 光速 [m/s]

# 時間軸(十分な長さを確保)
N_total = 4096
t_total = np.arange(N_total) / fs - N_total / (2 * fs)

# チャープ信号の生成
t_chirp = np.arange(int(T * fs)) / fs - T / 2
chirp = np.exp(1j * np.pi * K * t_chirp**2)

# --- 複数目標のエコー信号生成 ---
# 目標の距離と振幅(相対値)
targets = [
    {'range': 1500, 'amplitude': 1.0},    # 目標1: 1500 m, 強
    {'range': 1510, 'amplitude': 0.5},    # 目標2: 1510 m, 中
    {'range': 1600, 'amplitude': 0.3},    # 目標3: 1600 m, 弱
]

# 受信信号の初期化
rx_signal = np.zeros(N_total, dtype=complex)

# 各目標からのエコーを生成
for tgt in targets:
    delay = 2 * tgt['range'] / c  # 往復遅延
    delay_samples = int(delay * fs)
    # エコー信号を適切な位置に加算
    start = N_total // 2 + delay_samples - len(chirp) // 2
    end = start + len(chirp)
    if 0 <= start and end <= N_total:
        rx_signal[start:end] += tgt['amplitude'] * chirp

# 雑音の追加(SNR設定)
noise_power = 0.1
noise = np.sqrt(noise_power / 2) * (np.random.randn(N_total) + 1j * np.random.randn(N_total))
rx_signal_noisy = rx_signal + noise

# --- マッチドフィルタ処理(パルス圧縮) ---
# 参照チャープ信号(ゼロパディング)
ref = np.zeros(N_total, dtype=complex)
ref[:len(chirp)] = chirp

# 周波数領域でのマッチドフィルタ
Rx = np.fft.fft(rx_signal_noisy)
Ref = np.fft.fft(ref)
compressed = np.fft.ifft(Rx * np.conj(Ref))
compressed = np.fft.fftshift(compressed)

# --- 距離軸の生成 ---
range_axis = t_total * c / 2

# --- 可視化 ---
fig, axes = plt.subplots(3, 1, figsize=(12, 10))

# 受信信号(雑音あり)
axes[0].plot(range_axis, np.abs(rx_signal_noisy), 'b-', linewidth=0.5)
axes[0].set_xlabel('Range [m]')
axes[0].set_ylabel('Amplitude')
axes[0].set_title('Received Signal (with noise)')
axes[0].set_xlim([1400, 1700])
axes[0].grid(True, alpha=0.3)

# パルス圧縮後
axes[1].plot(range_axis, np.abs(compressed) / np.max(np.abs(compressed)), 'r-', linewidth=1)
axes[1].set_xlabel('Range [m]')
axes[1].set_ylabel('Normalized Amplitude')
axes[1].set_title('After Pulse Compression (Linear Scale)')
axes[1].set_xlim([1400, 1700])
axes[1].grid(True, alpha=0.3)
for tgt in targets:
    axes[1].axvline(x=tgt['range'], color='gray', linestyle='--', alpha=0.5)

# パルス圧縮後(dBスケール)
compressed_dB = 20 * np.log10(np.abs(compressed) / np.max(np.abs(compressed)) + 1e-10)
axes[2].plot(range_axis, compressed_dB, 'r-', linewidth=1)
axes[2].set_xlabel('Range [m]')
axes[2].set_ylabel('Amplitude [dB]')
axes[2].set_title('After Pulse Compression (dB Scale)')
axes[2].set_xlim([1400, 1700])
axes[2].set_ylim([-60, 5])
axes[2].axhline(y=-13.3, color='green', linestyle='--', label='-13.3 dB (sinc sidelobe)')
axes[2].legend()
axes[2].grid(True, alpha=0.3)
for tgt in targets:
    axes[2].axvline(x=tgt['range'], color='gray', linestyle='--', alpha=0.5)

plt.tight_layout()
plt.show()

# 理論値の表示
delta_R = c / (2 * B)
print(f"\n--- パルス圧縮の結果 ---")
print(f"距離分解能 (理論値): ΔR = c/(2B) = {delta_R:.1f} m")
print(f"圧縮比: TB = {T*B:.0f}")
print(f"圧縮利得: {10*np.log10(T*B):.1f} dB")

ウィンドウイングによるサイドローブ抑圧の比較

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import windows

# --- パラメータ設定 ---
T = 10e-6         # パルス幅 [s]
B = 10e6          # 帯域幅 [Hz]
K = B / T         # チャープレート [Hz/s]
fs = 4 * B        # サンプリング周波数 [Hz]
c = 3e8           # 光速 [m/s]

N_chirp = int(T * fs)
t_chirp = np.linspace(-T/2, T/2, N_chirp)
chirp = np.exp(1j * np.pi * K * t_chirp**2)

# 受信信号(単一目標)
N_total = 8192
rx = np.zeros(N_total, dtype=complex)
center = N_total // 2
rx[center - N_chirp//2 : center - N_chirp//2 + N_chirp] = chirp

# 参照信号
ref = np.zeros(N_total, dtype=complex)
ref[:N_chirp] = chirp

# 周波数領域
Rx = np.fft.fft(rx)
Ref = np.fft.fft(ref)

# --- 各種ウィンドウでのパルス圧縮 ---
window_names = ['Rectangular', 'Hamming', 'Hanning', 'Blackman']
window_funcs = [
    np.ones(N_total),
    np.fft.fftshift(windows.hamming(N_total)),
    np.fft.fftshift(windows.hann(N_total)),
    np.fft.fftshift(windows.blackman(N_total)),
]
colors = ['blue', 'red', 'green', 'orange']

fig, ax = plt.subplots(figsize=(14, 7))

for name, win, color in zip(window_names, window_funcs, colors):
    # ウィンドウ適用したマッチドフィルタ
    compressed = np.fft.ifft(Rx * np.conj(Ref) * np.fft.fftshift(win))
    compressed = np.fft.fftshift(compressed)
    # 正規化
    comp_norm = np.abs(compressed) / np.max(np.abs(compressed))
    comp_dB = 20 * np.log10(comp_norm + 1e-10)
    # 距離軸
    t_axis = np.arange(N_total) / fs - N_total / (2 * fs)
    range_axis = t_axis * c / 2
    # プロット(主ローブ周辺のみ)
    ax.plot(range_axis, comp_dB, color=color, linewidth=1.5, label=name)

ax.set_xlabel('Range [m]', fontsize=12)
ax.set_ylabel('Amplitude [dB]', fontsize=12)
ax.set_title('Pulse Compression with Different Windows', fontsize=14)
ax.set_xlim([-100, 100])
ax.set_ylim([-80, 5])
ax.axhline(y=-13.3, color='gray', linestyle=':', alpha=0.5, label='-13.3 dB')
ax.axhline(y=-3, color='gray', linestyle='--', alpha=0.5, label='-3 dB')
ax.legend(fontsize=11)
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print(f"距離分解能 (矩形窓): {c/(2*B):.1f} m")
print(f"時間-帯域幅積 TB = {T*B:.0f}")

上記のコードを実行すると、チャープ信号の実部・瞬時周波数・スペクトログラムの可視化、マッチドフィルタによるパルス圧縮の効果、そして各種窓関数によるサイドローブ抑圧の比較が得られます。パルス圧縮により、長いチャープパルスが鋭いピークに圧縮され、複数の近接目標が分離される様子を確認できます。

まとめ

本記事では、パルス圧縮(チャープ信号)の理論を数式で丁寧に導出しました。

  • パルスレーダーのジレンマ: 単純パルスでは距離分解能 $\Delta R = c\tau/2$ と探知距離(送信エネルギー $E = P_t\tau$)がトレードオフ
  • チャープ信号 $s(t) = \mathrm{rect}(t/T)\exp(j\pi Kt^2)$ は周波数が線形に変化する信号であり、パルス幅 $T$ と帯域幅 $B$ を独立に設計可能
  • マッチドフィルタ $H(f) = S^*(f)$ は出力SNRを最大化するフィルタであり、最大SNRは $2E/N_0$ で波形に依存しない
  • パルス圧縮後の距離分解能は $\Delta R = c/(2B)$ となり、パルス幅に依存しない
  • 時間-帯域幅積 $TB$ が圧縮比(Processing Gain)を決定する
  • ウィンドウイングでサイドローブを抑圧できるが、主ローブ幅の拡大が代償となる

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