レーダー信号のアンビギュイティ関数を導出して理解する

レーダーの波形設計において、ある波形が距離と速度をどの程度の精度で同時に測定できるかを評価するための最も強力なツールがアンビギュイティ関数(Ambiguity Function)です。アンビギュイティ関数は、遅延 $\tau$(距離に対応)とドップラー周波数シフト $f_d$(速度に対応)の2次元平面上でマッチドフィルタ出力を表現するものであり、波形の距離分解能と速度分解能の本質的なトレードオフを明らかにします。

1953年にWoodvillが定式化したこの関数は、レーダー波形の分解能・曖昧性・副ローブ特性を統一的に評価できる枠組みを提供します。本記事では、アンビギュイティ関数の定義と物理的意味を丁寧に解説し、主要な性質(最大値、体積保存、対称性)を証明し、矩形パルス・線形FMチャープ・パルス列の各波形についてアンビギュイティ関数を導出し、不確定性原理と波形設計への示唆を議論した上で、Pythonで3D可視化を実装します。

本記事の内容

  • アンビギュイティ関数の定義と物理的意味
  • アンビギュイティ関数の基本性質の証明
  • 矩形パルスのアンビギュイティ関数の導出
  • 線形FMチャープのアンビギュイティ関数の導出
  • パルス列のアンビギュイティ関数の導出
  • 不確定性原理(距離分解能と速度分解能のトレードオフ)
  • 波形設計への示唆(サムルームの理想)
  • Pythonでの各種波形のアンビギュイティ関数の3D可視化

前提知識

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

アンビギュイティ関数の定義

数学的定義

レーダー送信信号(ベースバンド複素包絡線)を $s(t)$ とします。アンビギュイティ関数 $\chi(\tau, f_d)$ は次のように定義されます。

$$ \boxed{\chi(\tau, f_d) = \left|\int_{-\infty}^{\infty} s(t) \, s^*(t – \tau) \, e^{j2\pi f_d t} \, dt\right|^2} $$

ここで、$\tau$ は遅延(距離に対応: $R = c\tau/2$)、$f_d$ はドップラー周波数シフト(速度に対応: $v = \lambda f_d/2$)です。

複素アンビギュイティ関数(位相情報も含む)を $A(\tau, f_d)$ と書くこともあります。

$$ A(\tau, f_d) = \int_{-\infty}^{\infty} s(t) \, s^*(t – \tau) \, e^{j2\pi f_d t} \, dt $$

$$ \chi(\tau, f_d) = |A(\tau, f_d)|^2 $$

物理的意味

アンビギュイティ関数の物理的意味を理解しましょう。

レーダーが信号 $s(t)$ を送信し、距離 $R$(遅延 $\tau_0 = 2R/c$)にある速度 $v$(ドップラーシフト $f_{d0} = 2v/\lambda$)の目標からの反射信号を受信するとします。受信信号は次の通りです。

$$ r(t) = A_0 \, s(t – \tau_0) \, e^{j2\pi f_{d0} t} $$

この受信信号をマッチドフィルタに通した出力を、遅延 $\tau$ とドップラー $f_d$ の関数として評価したものがアンビギュイティ関数です。

$$ y(\tau, f_d) = \int_{-\infty}^{\infty} r(t) \, s^*(t – \tau) \, e^{-j2\pi f_d t} \, dt $$

$(\tau, f_d) = (\tau_0, f_{d0})$ のときにフィルタ出力は最大になり、そこからずれるにつれて出力は減少します。アンビギュイティ関数は、この出力が遅延とドップラーの誤差に対してどのように減衰するかを特徴づけます。

大雑把に言えば、アンビギュイティ関数は「遅延-ドップラー平面上でのマッチドフィルタの応答特性マップ」です。原点 $(\tau, f_d) = (0, 0)$ でのピークが鋭いほど、距離と速度の分解能が高いことを意味します。

アンビギュイティ関数の基本性質

性質1: 最大値(原点で最大)

アンビギュイティ関数は $(\tau, f_d) = (0, 0)$ で最大値をとります。

$$ \chi(0, 0) = \left|\int_{-\infty}^{\infty} |s(t)|^2 dt\right|^2 = E^2 $$

ここで $E = \int |s(t)|^2 dt$ は信号のエネルギーです。

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

$$ \begin{align} |A(\tau, f_d)|^2 &= \left|\int s(t) \, s^*(t-\tau) \, e^{j2\pi f_d t} dt\right|^2 \\ &\leq \int |s(t)|^2 dt \cdot \int |s(t-\tau)|^2 dt \\ &= E \cdot E = E^2 \end{align} $$

等号は $s^*(t-\tau) e^{j2\pi f_d t} = c \cdot s(t)$(すなわち $\tau = 0, f_d = 0$)のとき成立します。

$$ A(0, 0) = \int |s(t)|^2 dt = E $$

よって $\chi(0, 0) = E^2 \geq \chi(\tau, f_d)$ が示されました。

性質2: 体積保存(レーダー不確定性原理)

アンビギュイティ関数の $(\tau, f_d)$ 平面上での体積は、波形に依存せず一定です。

$$ \boxed{\int_{-\infty}^{\infty}\int_{-\infty}^{\infty} \chi(\tau, f_d) \, d\tau \, df_d = E^2} $$

証明: $|A(\tau, f_d)|^2$ を展開します。

$$ \chi(\tau, f_d) = A(\tau, f_d) \cdot A^*(\tau, f_d) $$

$$ A(\tau, f_d) = \int s(t) s^*(t-\tau) e^{j2\pi f_d t} dt $$

$f_d$ に関する積分から行います。パーセバルの定理を $f_d$ について適用します。

まず $A(\tau, f_d)$ は、関数 $g_\tau(t) = s(t) s^*(t-\tau)$ のフーリエ変換($t \to f_d$)です。

$$ A(\tau, f_d) = \mathcal{F}\{g_\tau(t)\}(f_d) $$

パーセバルの定理より次が成り立ちます。

$$ \int_{-\infty}^{\infty} |A(\tau, f_d)|^2 df_d = \int_{-\infty}^{\infty} |g_\tau(t)|^2 dt = \int_{-\infty}^{\infty} |s(t)|^2 |s(t-\tau)|^2 dt $$

次に $\tau$ に関して積分します。

$$ \begin{align} \int\int \chi(\tau, f_d) \, d\tau \, df_d &= \int_{-\infty}^{\infty} \left(\int_{-\infty}^{\infty} |s(t)|^2 |s(t-\tau)|^2 dt\right) d\tau \end{align} $$

積分順序を交換し、$u = t – \tau$ と置換すると次のようになります。

$$ \begin{align} &= \int_{-\infty}^{\infty} |s(t)|^2 \left(\int_{-\infty}^{\infty} |s(t-\tau)|^2 d\tau\right) dt \\ &= \int_{-\infty}^{\infty} |s(t)|^2 dt \cdot \int_{-\infty}^{\infty} |s(u)|^2 du \\ &= E \cdot E = E^2 \end{align} $$

これで体積保存が証明されました。

この性質は非常に重要です。アンビギュイティ関数の体積は波形によらず一定($E^2$)であるため、ある領域でピークを鋭くする(分解能を上げる)と、別の領域で体積が押し出されてサイドローブが大きくなります。波形設計とは、この一定の体積をどのように配分するかの問題なのです。

性質3: 原点対称性

$$ \chi(\tau, f_d) = \chi(-\tau, -f_d) $$

証明: $A(-\tau, -f_d)$ を計算します。

$$ \begin{align} A(-\tau, -f_d) &= \int s(t) s^*(t+\tau) e^{-j2\pi f_d t} dt \end{align} $$

$t’ = t + \tau$ と置換すると次のようになります。

$$ \begin{align} &= \int s(t’-\tau) s^*(t’) e^{-j2\pi f_d (t’-\tau)} dt’ \\ &= e^{j2\pi f_d \tau} \int s^*(t’) s(t’-\tau) e^{-j2\pi f_d t’} dt’ \\ &= e^{j2\pi f_d \tau} \cdot A^*(\tau, f_d) \end{align} $$

したがって $|A(-\tau, -f_d)| = |A(\tau, f_d)|$ であり、$\chi(-\tau, -f_d) = \chi(\tau, f_d)$ が成り立ちます。

性質4: 軸上の値

遅延軸 ($f_d = 0$):

$$ \chi(\tau, 0) = \left|\int s(t) s^*(t-\tau) dt\right|^2 = |R_s(\tau)|^2 $$

これは信号の自己相関関数の2乗です。距離分解能を特徴づけます。

ドップラー軸 ($\tau = 0$):

$$ \chi(0, f_d) = \left|\int |s(t)|^2 e^{j2\pi f_d t} dt\right|^2 = |\mathcal{F}\{|s(t)|^2\}(f_d)|^2 $$

これは信号の瞬時電力のフーリエ変換の2乗です。速度分解能を特徴づけます。

矩形パルスのアンビギュイティ関数

波形の定義

幅 $T$、振幅 $1/\sqrt{T}$(単位エネルギー)の矩形パルスを考えます。

$$ s(t) = \frac{1}{\sqrt{T}} \, \mathrm{rect}\!\left(\frac{t}{T}\right) = \begin{cases} \frac{1}{\sqrt{T}} & |t| \leq T/2 \\ 0 & \text{otherwise} \end{cases} $$

導出

複素アンビギュイティ関数を計算します。

$$ A(\tau, f_d) = \frac{1}{T} \int_{-\infty}^{\infty} \mathrm{rect}\!\left(\frac{t}{T}\right) \mathrm{rect}\!\left(\frac{t-\tau}{T}\right) e^{j2\pi f_d t} \, dt $$

2つの矩形関数の重なり区間を求めます。$|\tau| \leq T$ のとき、重なり区間は次の通りです。

$$ \max\!\left(-\frac{T}{2}, \tau – \frac{T}{2}\right) \leq t \leq \min\!\left(\frac{T}{2}, \tau + \frac{T}{2}\right) $$

$0 \leq \tau \leq T$ の場合($\tau \geq 0$)、積分区間は $[\tau – T/2, T/2]$ となり、区間長は $T – \tau$ です。

$$ \begin{align} A(\tau, f_d) &= \frac{1}{T} \int_{\tau – T/2}^{T/2} e^{j2\pi f_d t} \, dt \\ &= \frac{1}{T} \cdot \frac{e^{j2\pi f_d T/2} – e^{j2\pi f_d (\tau – T/2)}}{j2\pi f_d} \\ &= \frac{1}{T} \cdot \frac{e^{j\pi f_d \tau} \left(e^{j\pi f_d(T-\tau)} – e^{-j\pi f_d(T-\tau)}\right)}{j2\pi f_d} \\ &= \frac{1}{T} \cdot e^{j\pi f_d \tau} \cdot \frac{\sin(\pi f_d(T – \tau))}{\pi f_d} \\ &= \frac{T – \tau}{T} \cdot e^{j\pi f_d \tau} \cdot \mathrm{sinc}(f_d(T – \tau)) \end{align} $$

対称性より $|\tau| \leq T$ で次のようになります。

$$ A(\tau, f_d) = \left(1 – \frac{|\tau|}{T}\right) e^{j\pi f_d \tau} \, \mathrm{sinc}\!\left(f_d(T – |\tau|)\right) $$

$$ \boxed{\chi_{\mathrm{rect}}(\tau, f_d) = \left(1 – \frac{|\tau|}{T}\right)^2 \mathrm{sinc}^2\!\left(f_d(T – |\tau|)\right), \quad |\tau| \leq T} $$

特性

遅延軸 ($f_d = 0$): $\chi(\tau, 0) = (1 – |\tau|/T)^2$(三角関数の2乗)。距離分解能はパルス幅 $T$ で決まり、$\Delta\tau \approx T$、すなわち $\Delta R \approx cT/2$ です。

ドップラー軸 ($\tau = 0$): $\chi(0, f_d) = \mathrm{sinc}^2(f_d T)$。速度分解能はパルス幅 $T$ の逆数で決まり、$\Delta f_d \approx 1/T$ です。

矩形パルスのアンビギュイティ関数は $(\tau, f_d)$ 平面上で対角方向に広がった形状を示します。パルス幅 $T$ を長くするとドップラー分解能は改善しますが、距離分解能は悪化します。

線形FMチャープのアンビギュイティ関数

波形の定義

帯域幅 $B$、パルス幅 $T$ の線形FMチャープ信号(単位エネルギー)を考えます。

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

ここで $K = B/T$ はチャープレートです。

導出

$$ A(\tau, f_d) = \frac{1}{T} \int \mathrm{rect}\!\left(\frac{t}{T}\right) \mathrm{rect}\!\left(\frac{t-\tau}{T}\right) \exp(j\pi K t^2) \exp(-j\pi K(t-\tau)^2) \exp(j2\pi f_d t) \, dt $$

指数部を整理します。

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

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

$$ A(\tau, f_d) = \frac{e^{-j\pi K\tau^2}}{T} \int \mathrm{rect}\!\left(\frac{t}{T}\right) \mathrm{rect}\!\left(\frac{t-\tau}{T}\right) \exp\!\left(j2\pi(f_d + K\tau)t\right) dt $$

この積分は矩形パルスの場合と同じ形であり、$f_d$ が $f_d + K\tau$ に置き換わっています。矩形パルスの結果を用いると次のようになります。

$$ A(\tau, f_d) = e^{-j\pi K\tau^2} \cdot e^{j\pi(f_d+K\tau)\tau} \cdot \left(1 – \frac{|\tau|}{T}\right) \mathrm{sinc}\!\left((f_d + K\tau)(T – |\tau|)\right) $$

$$ \boxed{\chi_{\mathrm{chirp}}(\tau, f_d) = \left(1 – \frac{|\tau|}{T}\right)^2 \mathrm{sinc}^2\!\left((f_d + K\tau)(T – |\tau|)\right), \quad |\tau| \leq T} $$

特性

矩形パルスとの比較で最も重要な違いは、$\mathrm{sinc}$ 関数の引数が $f_d T$ ではなく $(f_d + K\tau)T$ に変わったことです。これにより次のことがわかります。

  1. アンビギュイティ関数のピーク($\mathrm{sinc} = 1$ の条件)は $f_d = -K\tau$ の直線上にあります。つまり、$(\tau, f_d)$ 平面上でピークの稜線が傾いた楕円形状になります。

  2. 傾きは $df_d/d\tau = -K = -B/T$ であり、チャープレートに等しくなります。

  3. 遅延軸上 ($f_d = 0$) のカットでは $\mathrm{sinc}^2(K\tau \cdot T) = \mathrm{sinc}^2(B\tau)$ となり、距離分解能は $\Delta\tau \approx 1/B$($\Delta R = c/(2B)$)とパルス幅 $T$ ではなく帯域幅 $B$ で決まります。これがパルス圧縮の本質です。

  4. ドップラー軸上 ($\tau = 0$) のカットは矩形パルスと同じ $\mathrm{sinc}^2(f_d T)$ であり、速度分解能は変わりません。

チャープ信号のアンビギュイティ関数は、矩形パルスのそれを $f_d = -K\tau$ 方向にせん断(シアー)したものと解釈できます。

パルス列のアンビギュイティ関数

波形の定義

$M$ 個のパルスからなるコヒーレントパルス列を考えます。各パルスは幅 $T$ の矩形パルスで、パルス繰り返し間隔は $T_r$ です。

$$ s(t) = \frac{1}{\sqrt{MT}} \sum_{m=0}^{M-1} \mathrm{rect}\!\left(\frac{t – mT_r}{T}\right) $$

アンビギュイティ関数の構造

パルス列のアンビギュイティ関数は、単一パルスのアンビギュイティ関数と、パルス列の周期構造に対応するくし形パターンの積として理解できます。

詳細な導出は長くなりますが、結果は次のように表されます。

$$ \chi_{\mathrm{train}}(\tau, f_d) \approx \chi_{\mathrm{single}}(\tau, f_d) \cdot \left|\frac{\sin(\pi M f_d T_r)}{M \sin(\pi f_d T_r)}\right|^2 $$

ここで $\chi_{\mathrm{single}}$ は単一パルスのアンビギュイティ関数です。

第2因子はディリクレ核(Dirichlet kernel)であり、$f_d = k/T_r$($k$ は整数)でピークを持ちます。

特性

パルス列のアンビギュイティ関数は $(\tau, f_d)$ 平面上にくし形(ベッド・オブ・ネイルズ, bed-of-nails)パターンを形成します。

ドップラー方向: ドップラー分解能は $\Delta f_d \approx 1/(MT_r)$ と大幅に改善されますが、$f_d = k/T_r$ の間隔でドップラー曖昧性(速度の曖昧さ)が生じます。

遅延方向: 距離分解能は単一パルスと同じ $\Delta\tau = T$ ですが、$\tau = kT_r$ の間隔で距離の曖昧性が生じます。

ドップラー方向の曖昧性間隔 $1/T_r = \mathrm{PRF}$ は、パルスドップラーレーダーのドップラー曖昧性の原因です。この曖昧性のピークは、体積保存の性質によるものであり、避けることができません。

不確定性原理と波形設計

レーダーの不確定性原理

体積保存の性質から、アンビギュイティ関数のピークを遅延方向とドップラー方向の両方で同時に鋭くすることは原理的に不可能です。

$$ \Delta\tau \cdot \Delta f_d \geq \text{const} $$

これはレーダーにおける不確定性原理であり、量子力学の不確定性原理($\Delta x \cdot \Delta p \geq \hbar/2$)と数学的に同じ構造を持っています。

定量的には、遅延方向のRMS幅 $\beta_\tau$ とドップラー方向のRMS幅 $\beta_{f}$ の間に次の関係が成立します。

$$ \beta_\tau \cdot \beta_f \geq \frac{1}{4\pi} $$

主要波形のトレードオフ

各波形のアンビギュイティ関数の特性をまとめます。

波形 距離分解能 速度分解能 曖昧性 形状
矩形パルス(短い) 良好 ($\propto T$) 不良 ($\propto 1/T$) なし 対角方向に広がった楕円
矩形パルス(長い) 不良 良好 なし 対角方向に広がった楕円
チャープ 良好 ($\propto 1/B$) 中程度 ($\propto 1/T$) なし 傾いた楕円
パルス列 不良 ($\propto T$) 良好 ($\propto 1/MT_r$) 距離・速度曖昧性 くし形

理想的な波形: サムルーム

理想的なアンビギュイティ関数は「サムタック」(thumbtack)と呼ばれる形状で、原点に鋭いピークがあり、それ以外は完全に平坦な形状です。

$$ \chi_{\mathrm{ideal}}(\tau, f_d) = E^2 \delta(\tau)\delta(f_d) $$

しかし、体積保存の性質により、このような理想的な波形は存在しません。ピークを鋭くすると、必ずどこかにサイドローブが出現します。

現実の波形設計では、用途に応じて以下の戦略が取られます。

距離重視: 広帯域チャープ。距離分解能 $c/(2B)$ が優先され、速度分解能はパルス列処理で補います。

速度重視: 長いCWパルス列。ドップラー分解能が優先され、距離はパルス構造で測定します。

バランス型: 中程度の帯域幅のチャープパルス列。距離と速度の両方をある程度の分解能で測定します。

Pythonでの3D可視化

矩形パルスのアンビギュイティ関数

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def ambiguity_rect(tau, fd, T):
    """矩形パルスのアンビギュイティ関数"""
    chi = np.zeros_like(tau)
    mask = np.abs(tau) < T
    t = tau[mask]
    f = fd[mask]
    tri = 1 - np.abs(t) / T
    # sinc(fd * (T - |tau|))
    arg = f * (T - np.abs(t))
    sinc_val = np.sinc(arg)  # np.sinc(x) = sin(pi*x)/(pi*x)
    chi[mask] = (tri * sinc_val)**2
    return chi

# パラメータ
T = 10e-6  # パルス幅 [s]

# 遅延-ドップラー平面のグリッド
N_tau = 300
N_fd = 300
tau_axis = np.linspace(-1.5*T, 1.5*T, N_tau)
fd_axis = np.linspace(-3/T, 3/T, N_fd)
TAU, FD = np.meshgrid(tau_axis, fd_axis)

# アンビギュイティ関数の計算
CHI = ambiguity_rect(TAU, FD, T)

# --- 3Dサーフェスプロット ---
fig = plt.figure(figsize=(14, 10))

# 3Dプロット
ax1 = fig.add_subplot(2, 2, 1, projection='3d')
ax1.plot_surface(TAU*1e6, FD/1e3, 10*np.log10(CHI + 1e-10),
                  cmap='jet', vmin=-30, vmax=0, alpha=0.9)
ax1.set_xlabel('Delay τ [μs]')
ax1.set_ylabel('Doppler fd [kHz]')
ax1.set_zlabel('|χ|² [dB]')
ax1.set_title('Rectangular Pulse - 3D')
ax1.set_zlim([-30, 0])

# 等高線プロット
ax2 = fig.add_subplot(2, 2, 2)
levels = [-30, -20, -13.3, -10, -6, -3]
cs = ax2.contourf(TAU*1e6, FD/1e3, 10*np.log10(CHI + 1e-10),
                   levels=np.linspace(-30, 0, 20), cmap='jet')
ax2.set_xlabel('Delay τ [μs]')
ax2.set_ylabel('Doppler fd [kHz]')
ax2.set_title('Rectangular Pulse - Contour')
plt.colorbar(cs, ax=ax2, label='dB')

# 遅延方向カット (fd=0)
ax3 = fig.add_subplot(2, 2, 3)
chi_tau = ambiguity_rect(tau_axis, np.zeros_like(tau_axis), T)
ax3.plot(tau_axis*1e6, 10*np.log10(chi_tau + 1e-10), 'b-', linewidth=2)
ax3.set_xlabel('Delay τ [μs]')
ax3.set_ylabel('|χ|² [dB]')
ax3.set_title('Delay Cut (fd = 0)')
ax3.set_ylim([-30, 3])
ax3.grid(True, alpha=0.3)
ax3.axhline(y=-3, color='r', linestyle='--', alpha=0.5)

# ドップラー方向カット (tau=0)
ax4 = fig.add_subplot(2, 2, 4)
chi_fd = ambiguity_rect(np.zeros_like(fd_axis), fd_axis, T)
ax4.plot(fd_axis/1e3, 10*np.log10(chi_fd + 1e-10), 'r-', linewidth=2)
ax4.set_xlabel('Doppler fd [kHz]')
ax4.set_ylabel('|χ|² [dB]')
ax4.set_title('Doppler Cut (τ = 0)')
ax4.set_ylim([-30, 3])
ax4.grid(True, alpha=0.3)
ax4.axhline(y=-3, color='r', linestyle='--', alpha=0.5)

plt.tight_layout()
plt.show()

print(f"パルス幅 T = {T*1e6:.0f} μs")
print(f"距離分解能: Δτ ≈ T = {T*1e6:.0f} μs → ΔR = {3e8*T/2:.0f} m")
print(f"ドップラー分解能: Δfd ≈ 1/T = {1/T/1e3:.0f} kHz")

チャープ信号のアンビギュイティ関数

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def ambiguity_chirp(tau, fd, T, K):
    """線形FMチャープのアンビギュイティ関数"""
    chi = np.zeros_like(tau)
    mask = np.abs(tau) < T
    t = tau[mask]
    f = fd[mask]
    tri = 1 - np.abs(t) / T
    # sinc((fd + K*tau) * (T - |tau|))
    arg = (f + K * t) * (T - np.abs(t))
    sinc_val = np.sinc(arg)
    chi[mask] = (tri * sinc_val)**2
    return chi

# パラメータ
T = 10e-6      # パルス幅 [s]
B = 5e6        # 帯域幅 [Hz]
K = B / T      # チャープレート [Hz/s]

# 遅延-ドップラー平面のグリッド
N_tau = 400
N_fd = 400
tau_axis = np.linspace(-1.5*T, 1.5*T, N_tau)
fd_axis = np.linspace(-3*B/T*T, 3*B/T*T, N_fd)
# fd の範囲をチャープレートに合わせて調整
fd_max = 2 * B
fd_axis = np.linspace(-fd_max, fd_max, N_fd)
TAU, FD = np.meshgrid(tau_axis, fd_axis)

# アンビギュイティ関数の計算
CHI_chirp = ambiguity_chirp(TAU, FD, T, K)

# --- 可視化 ---
fig = plt.figure(figsize=(14, 10))

# 3Dプロット
ax1 = fig.add_subplot(2, 2, 1, projection='3d')
ax1.plot_surface(TAU*1e6, FD/1e6, 10*np.log10(CHI_chirp + 1e-10),
                  cmap='jet', vmin=-30, vmax=0, alpha=0.9)
ax1.set_xlabel('Delay τ [μs]')
ax1.set_ylabel('Doppler fd [MHz]')
ax1.set_zlabel('|χ|² [dB]')
ax1.set_title(f'LFM Chirp (B={B/1e6:.0f} MHz, T={T*1e6:.0f} μs)')
ax1.set_zlim([-30, 0])

# 等高線プロット
ax2 = fig.add_subplot(2, 2, 2)
cs = ax2.contourf(TAU*1e6, FD/1e6, 10*np.log10(CHI_chirp + 1e-10),
                   levels=np.linspace(-30, 0, 20), cmap='jet')
ax2.set_xlabel('Delay τ [μs]')
ax2.set_ylabel('Doppler fd [MHz]')
ax2.set_title('LFM Chirp - Contour')
plt.colorbar(cs, ax=ax2, label='dB')
# ピークの稜線 fd = -K*tau を表示
tau_line = np.linspace(-T, T, 100)
ax2.plot(tau_line*1e6, -K*tau_line/1e6, 'w--', linewidth=2, label='fd = -Kτ')
ax2.legend(fontsize=11)

# 遅延方向カット (fd=0) → パルス圧縮後の応答
ax3 = fig.add_subplot(2, 2, 3)
chi_tau_chirp = ambiguity_chirp(tau_axis, np.zeros_like(tau_axis), T, K)
chi_tau_rect = ambiguity_chirp(tau_axis, np.zeros_like(tau_axis), T, 0)  # K=0は矩形
ax3.plot(tau_axis*1e6, 10*np.log10(chi_tau_chirp + 1e-10), 'r-',
         linewidth=2, label=f'Chirp (B={B/1e6:.0f} MHz)')
ax3.plot(tau_axis*1e6, 10*np.log10(chi_tau_rect + 1e-10), 'b--',
         linewidth=2, label='Rectangular', alpha=0.7)
ax3.set_xlabel('Delay τ [μs]')
ax3.set_ylabel('|χ|² [dB]')
ax3.set_title('Delay Cut (fd = 0)')
ax3.set_ylim([-30, 3])
ax3.legend(fontsize=11)
ax3.grid(True, alpha=0.3)

# ドップラー方向カット (tau=0)
ax4 = fig.add_subplot(2, 2, 4)
chi_fd_chirp = ambiguity_chirp(np.zeros_like(fd_axis), fd_axis, T, K)
ax4.plot(fd_axis/1e6, 10*np.log10(chi_fd_chirp + 1e-10), 'r-', linewidth=2)
ax4.set_xlabel('Doppler fd [MHz]')
ax4.set_ylabel('|χ|² [dB]')
ax4.set_title('Doppler Cut (τ = 0)')
ax4.set_ylim([-30, 3])
ax4.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print(f"パルス幅 T = {T*1e6:.0f} μs, 帯域幅 B = {B/1e6:.0f} MHz")
print(f"チャープレート K = {K/1e12:.2f} THz/s")
print(f"時間-帯域幅積 TB = {T*B:.0f}")
print(f"距離分解能: 1/B = {1/B*1e6:.2f} μs → ΔR = {3e8/(2*B):.1f} m")
print(f"ドップラー分解能: 1/T = {1/T/1e3:.0f} kHz")

パルス列のアンビギュイティ関数

import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

def ambiguity_pulse_train(tau, fd, T, Tr, M):
    """パルス列のアンビギュイティ関数(近似)"""
    chi = np.zeros_like(tau)
    mask = np.abs(tau) < T
    t = tau[mask]
    f = fd[mask]

    # 単一パルスのアンビギュイティ
    tri = 1 - np.abs(t) / T
    sinc_single = np.sinc(f * (T - np.abs(t)))
    chi_single = (tri * sinc_single)**2

    # パルス列のディリクレ核
    denom = M * np.sin(np.pi * f * Tr + 1e-20)
    numer = np.sin(np.pi * M * f * Tr + 1e-20)
    dirichlet = (numer / denom)**2

    chi[mask] = chi_single * dirichlet
    return chi

# パラメータ
T = 1e-6        # パルス幅 [s]
Tr = 10e-6      # パルス繰り返し間隔 [s]
M = 8           # パルス数
PRF = 1 / Tr

# グリッド
N_tau = 500
N_fd = 500
tau_axis = np.linspace(-1.5*T, 1.5*T, N_tau)
fd_axis = np.linspace(-3*PRF, 3*PRF, N_fd)
TAU, FD = np.meshgrid(tau_axis, fd_axis)

CHI_train = ambiguity_pulse_train(TAU, FD, T, Tr, M)

# --- 可視化 ---
fig = plt.figure(figsize=(14, 10))

# 3Dプロット
ax1 = fig.add_subplot(2, 2, 1, projection='3d')
ax1.plot_surface(TAU*1e6, FD/1e3, 10*np.log10(CHI_train + 1e-10),
                  cmap='jet', vmin=-30, vmax=0, alpha=0.9)
ax1.set_xlabel('Delay τ [μs]')
ax1.set_ylabel('Doppler fd [kHz]')
ax1.set_zlabel('|χ|² [dB]')
ax1.set_title(f'Pulse Train (M={M}, T={T*1e6:.0f} μs, Tr={Tr*1e6:.0f} μs)')
ax1.set_zlim([-30, 0])

# 等高線プロット
ax2 = fig.add_subplot(2, 2, 2)
cs = ax2.contourf(TAU*1e6, FD/1e3, 10*np.log10(CHI_train + 1e-10),
                   levels=np.linspace(-30, 0, 20), cmap='jet')
ax2.set_xlabel('Delay τ [μs]')
ax2.set_ylabel('Doppler fd [kHz]')
ax2.set_title('Pulse Train - Contour')
plt.colorbar(cs, ax=ax2, label='dB')

# ドップラーカット (tau=0)
ax3 = fig.add_subplot(2, 2, 3)
chi_fd_train = ambiguity_pulse_train(np.zeros_like(fd_axis), fd_axis, T, Tr, M)
ax3.plot(fd_axis/1e3, 10*np.log10(chi_fd_train + 1e-10), 'g-', linewidth=1.5)
ax3.set_xlabel('Doppler fd [kHz]')
ax3.set_ylabel('|χ|² [dB]')
ax3.set_title('Doppler Cut (τ = 0)')
ax3.set_ylim([-30, 3])
ax3.grid(True, alpha=0.3)
# PRFの位置を示す
for k in range(-3, 4):
    if k != 0:
        ax3.axvline(x=k*PRF/1e3, color='gray', linestyle=':', alpha=0.5)
ax3.axhline(y=-3, color='r', linestyle='--', alpha=0.5)

# 遅延カット (fd=0)
ax4 = fig.add_subplot(2, 2, 4)
chi_tau_train = ambiguity_pulse_train(tau_axis, np.zeros_like(tau_axis), T, Tr, M)
ax4.plot(tau_axis*1e6, 10*np.log10(chi_tau_train + 1e-10), 'g-', linewidth=1.5)
ax4.set_xlabel('Delay τ [μs]')
ax4.set_ylabel('|χ|² [dB]')
ax4.set_title('Delay Cut (fd = 0)')
ax4.set_ylim([-30, 3])
ax4.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print(f"パルス幅 T = {T*1e6:.0f} μs")
print(f"パルス繰り返し間隔 Tr = {Tr*1e6:.0f} μs (PRF = {PRF/1e3:.0f} kHz)")
print(f"パルス数 M = {M}")
print(f"距離分解能: cT/2 = {3e8*T/2:.0f} m")
print(f"ドップラー分解能: 1/(M*Tr) = {1/(M*Tr):.0f} Hz")
print(f"ドップラー曖昧性間隔: PRF = {PRF/1e3:.0f} kHz")

3波形の比較

import numpy as np
import matplotlib.pyplot as plt

def ambiguity_rect(tau, fd, T):
    chi = np.zeros_like(tau)
    mask = np.abs(tau) < T
    tri = 1 - np.abs(tau[mask]) / T
    sinc_val = np.sinc(fd[mask] * (T - np.abs(tau[mask])))
    chi[mask] = (tri * sinc_val)**2
    return chi

def ambiguity_chirp(tau, fd, T, K):
    chi = np.zeros_like(tau)
    mask = np.abs(tau) < T
    tri = 1 - np.abs(tau[mask]) / T
    sinc_val = np.sinc((fd[mask] + K*tau[mask]) * (T - np.abs(tau[mask])))
    chi[mask] = (tri * sinc_val)**2
    return chi

# パラメータ
T = 10e-6
B = 5e6
K = B / T

# 等高線プロットの比較
fig, axes = plt.subplots(1, 3, figsize=(18, 5))

N = 300
tau_axis = np.linspace(-1.5*T, 1.5*T, N)

# (1) 矩形パルス
fd_axis_rect = np.linspace(-3/T, 3/T, N)
TAU, FD = np.meshgrid(tau_axis, fd_axis_rect)
CHI = ambiguity_rect(TAU, FD, T)
cs = axes[0].contourf(TAU*1e6, FD/1e3, 10*np.log10(CHI+1e-10),
                       levels=np.linspace(-30, 0, 15), cmap='jet')
axes[0].set_xlabel('Delay τ [μs]')
axes[0].set_ylabel('Doppler fd [kHz]')
axes[0].set_title('Rectangular Pulse')
plt.colorbar(cs, ax=axes[0], label='dB')

# (2) チャープ
fd_axis_chirp = np.linspace(-2*B, 2*B, N)
TAU, FD = np.meshgrid(tau_axis, fd_axis_chirp)
CHI = ambiguity_chirp(TAU, FD, T, K)
cs = axes[1].contourf(TAU*1e6, FD/1e6, 10*np.log10(CHI+1e-10),
                       levels=np.linspace(-30, 0, 15), cmap='jet')
axes[1].set_xlabel('Delay τ [μs]')
axes[1].set_ylabel('Doppler fd [MHz]')
axes[1].set_title(f'LFM Chirp (TB={int(T*B)})')
plt.colorbar(cs, ax=axes[1], label='dB')
# 稜線
tau_line = np.linspace(-T, T, 100)
axes[1].plot(tau_line*1e6, -K*tau_line/1e6, 'w--', linewidth=1.5)

# (3) パルス列(近似: くし形の概念図)
T_pulse = 1e-6
Tr = 10e-6
M = 8
PRF = 1/Tr
fd_axis_train = np.linspace(-3*PRF, 3*PRF, N)
tau_axis_train = np.linspace(-1.5*T_pulse, 1.5*T_pulse, N)
TAU_t, FD_t = np.meshgrid(tau_axis_train, fd_axis_train)

# 単一パルス部分
chi_single = np.zeros_like(TAU_t)
mask = np.abs(TAU_t) < T_pulse
tri = 1 - np.abs(TAU_t[mask]) / T_pulse
sinc_val = np.sinc(FD_t[mask] * (T_pulse - np.abs(TAU_t[mask])))
chi_single[mask] = (tri * sinc_val)**2

# ディリクレ核
denom = M * np.sin(np.pi * FD_t * Tr + 1e-20)
numer = np.sin(np.pi * M * FD_t * Tr + 1e-20)
dirichlet = (numer / denom)**2

CHI_t = chi_single * dirichlet

cs = axes[2].contourf(TAU_t*1e6, FD_t/1e3, 10*np.log10(CHI_t+1e-10),
                       levels=np.linspace(-30, 0, 15), cmap='jet')
axes[2].set_xlabel('Delay τ [μs]')
axes[2].set_ylabel('Doppler fd [kHz]')
axes[2].set_title(f'Pulse Train (M={M})')
plt.colorbar(cs, ax=axes[2], label='dB')

plt.tight_layout()
plt.show()

print("=== 波形特性の比較 ===")
print(f"矩形パルス: Δτ={T*1e6:.0f}μs, Δfd={1/T/1e3:.0f}kHz")
print(f"チャープ:    Δτ={1/B*1e6:.1f}μs, Δfd={1/T/1e3:.0f}kHz (TB={int(T*B)})")
print(f"パルス列:    Δτ={T_pulse*1e6:.0f}μs, Δfd={1/(M*Tr)/1e3:.2f}kHz")

上記のコードを実行すると、矩形パルス・チャープ信号・パルス列それぞれのアンビギュイティ関数が3Dサーフェスプロットと等高線プロットで可視化されます。矩形パルスの対角方向の広がり、チャープ信号の傾いた稜線構造、パルス列のくし形パターンという、各波形の本質的な特徴が明確に確認できます。

まとめ

本記事では、レーダー信号のアンビギュイティ関数を定義から丁寧に導出しました。

  • アンビギュイティ関数 $\chi(\tau, f_d) = |A(\tau, f_d)|^2$ は、遅延 $\tau$ とドップラー $f_d$ に対するマッチドフィルタ出力の2次元マップである
  • 基本性質として、原点で最大値 $E^2$(コーシー=シュワルツの不等式)、体積保存 $\iint \chi \, d\tau \, df_d = E^2$(パーセバルの定理)、原点対称性 $\chi(\tau, f_d) = \chi(-\tau, -f_d)$ が成り立つ
  • 矩形パルスのアンビギュイティ関数は $\mathrm{sinc}^2$ と三角関数の積であり、対角方向に広がった形状を持つ
  • チャープ信号では引数が $f_d + K\tau$ に置き換わり、傾いた楕円形状となる。遅延軸上のカットで $\Delta\tau = 1/B$ の分解能が得られ、これがパルス圧縮の本質である
  • パルス列はくし形パターンを形成し、ドップラー分解能は改善するが速度の曖昧性が生じる
  • 体積保存から、距離分解能と速度分解能を同時に任意に良くすることは不可能(レーダーの不確定性原理)
  • 波形設計とは、アンビギュイティ関数の一定体積を用途に応じて配分する問題である

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