ステップド周波数レーダーによる高分解能レンジプロファイル

空港の手荷物検査で使われるミリ波スキャナ、橋梁やコンクリート内部の鉄筋探査、あるいは航空機を識別する軍用レーダー — これらに共通するのは「数十センチメートル以下の細かさで物体の距離方向の構造を見分けたい」という要求です。ところが、レーダーで距離方向の細かさ(距離分解能)を上げるには、送信信号の帯域幅を広げる必要があります。1 cm の分解能を得るには 15 GHz もの帯域が必要で、これだけ広い帯域を一瞬で送受信するには、超高速のサンプリングを行うアナログ・デジタル変換器(ADC)が要求され、装置が高価で大電力消費になってしまいます。

そこで考案されたのが「ステップド周波数レーダー(Stepped Frequency Radar, SFR)」です。広い帯域を一度に送るのではなく、単一周波数の連続波(CW)を少しずつ周波数を変えながら何度も送受信し、各周波数での反射の強さと位相(複素反射係数)を集めます。最後にこれらをまとめて逆離散フーリエ変換(IDFT)すると、あたかも広帯域パルスを送ったかのような高分解能の距離プロファイルが「合成」されるのです。狭帯域の受信機で広帯域の性能を得られるため、ハードウェアが格段に安く軽くなります。

ステップド周波数の原理を理解すると、以下のような応用分野への見通しが格段によくなります。

  • 地中レーダー(GPR)・非破壊検査: コンクリート内部の鉄筋や空洞、地中の埋設管を、安価なベクトルネットワークアナライザ(VNA)で高分解能に探査します
  • レーダー断面積(RCS)計測・ターゲット識別: 航空機や艦船の散乱中心を距離方向に分解し、どの部位がどれだけ反射しているか(レンジプロファイル)を求めます
  • 生体・産業センシング: ミリ波で皮膚下や材料内部の層構造を見分ける医療・品質検査用イメージング
  • 合成開口レーダー(SAR)の距離方向: 高分解能 SAR の距離圧縮の一手法として、合成帯域処理が使われます

本記事の内容

  • ステップド周波数レーダーの基本概念と「合成帯域」という考え方
  • 各周波数で測定する複素反射係数 $H(f_n)$ の物理的意味
  • 複素応答の IDFT が距離方向のインパルス応答になることの導出(省略なし)
  • 距離分解能 $\Delta R = c/(2 B)$ の一行ずつの導出
  • 非曖昧距離 $R_{\max} = c/(2\Delta f)$ の導出と折り返し(エイリアシング)の理解
  • Python 実装: 複数点目標のレンジプロファイル再構成、分解能と曖昧距離のトレードオフ、窓関数によるサイドローブ抑制

前提知識

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

ステップド周波数レーダーとは

「広帯域を時間で分割して稼ぐ」という発想

レーダーの距離分解能は、つまるところ「どれだけ広い周波数帯域を使えるか」で決まります。これは後で厳密に導きますが、直感的には、広い帯域を使うほど時間軸上で鋭い(短い)パルスを作れるからです。ギターの弦をはじいたときの音を思い浮かべてください。たった一つの周波数(純音)を長く鳴らし続けると、それが「いつ始まったか」を時間的に細かく特定するのは困難です。逆に、多くの周波数を一瞬だけ重ね合わせると「パチン」という鋭いクリック音になり、発生時刻がはっきりします。鋭い時間パルス=広い周波数帯域、というのは波の世界の普遍的な関係なのです。

ステップド周波数レーダーは、この「多くの周波数を重ねると鋭いパルスになる」という事実を逆手に取ります。広帯域パルスを一度に送る代わりに、周波数 $f_0, f_1, f_2, \dots, f_{N-1}$ を一つずつ順番に送って、それぞれの反射を測定します。各周波数での測定は狭帯域(実質的に単一周波数)なので、受信機はゆっくりサンプリングすれば十分です。そして測定が全部終わってから、$N$ 個の測定値をコンピュータ上で「足し合わせて」鋭いパルスを合成します。実際の物理的な広帯域パルスは一度も存在しないのに、まるでそれを送ったかのような結果が得られる — これが「合成帯域(synthetic bandwidth)」と呼ばれる所以です。

測定の手順

具体的な測定手順は次の通りです。送信周波数を $f_n = f_0 + n\,\Delta f$($n = 0, 1, \dots, N-1$)と等間隔 $\Delta f$ で刻みます。各 $f_n$ について、

  1. 周波数 $f_n$ の連続波(純粋な正弦波)を送信する
  2. 目標から戻ってきた反射波を受信し、送信波と比較して振幅と位相を測定する
  3. この振幅と位相を一つの複素数 $H(f_n)$ として記録する

すべての $f_n$ について測定が終わると、$N$ 個の複素数の列 $H(f_0), H(f_1), \dots, H(f_{N-1})$ が得られます。これは目標の「周波数応答」、すなわち各周波数でどれだけどんな位相で反射するかを表すデータです。最後にこの列を IDFT すると、距離方向のプロファイルが復元されます。

この測定は、ベクトルネットワークアナライザ(VNA)が周波数を掃引しながら $S_{11}$ や $S_{21}$ を測るのと本質的に同じ操作です。だからこそ、非破壊検査の分野では VNA をそのままレーダーとして使えるのです。

ここまでで、ステップド周波数レーダーが「周波数を刻んで複素反射係数を集める」装置であることがわかりました。では、その複素反射係数 $H(f_n)$ は数式でどう書けるのでしょうか。次節で、目標までの往復遅延がどのように位相に焼き付けられるかを見ていきましょう。

複素反射係数 $H(f_n)$ の数学的記述

単一点目標がつくる位相

まず最も簡単な状況として、レーダーから距離 $R$ の位置に一つの点目標(反射体)があり、それ以外には何もないとします。レーダーが周波数 $f_n$ の連続波を送ると、その電波は目標まで距離 $R$ を進み、反射して再び距離 $R$ を戻ってくるので、往復で $2R$ の距離を伝搬します。電波の速度を光速 $c$ とすると、往復にかかる時間(往復遅延時間)は次のようになります。

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

送信した信号を $e^{j 2\pi f_n t}$ とすると、受信信号はこの遅延 $\tau$ だけ遅れた $e^{j 2\pi f_n (t – \tau)}$ になります。これを送信信号と「比較」する(コヒーレント検波、すなわち送信信号で割って復調する)と、時間 $t$ に依存する $e^{j2\pi f_n t}$ の部分が打ち消され、遅延だけに由来する位相項が残ります。これが複素反射係数 $H(f_n)$ です。

$$ H(f_n) = \sigma \, e^{-j 2\pi f_n \tau} $$

ここで $\sigma$ は目標の反射の強さ(複素散乱係数。振幅と固有の位相を含む)です。$\tau = 2R/c$ を代入すると、

$$ H(f_n) = \sigma \, \exp\!\left(-j 2\pi f_n \frac{2R}{c}\right) = \sigma \, \exp\!\left(-j \frac{4\pi f_n R}{c}\right) $$

この式の意味を噛みしめてください。目標までの距離 $R$ は、周波数 $f_n$ に比例した位相 $-4\pi f_n R / c$ として複素反射係数に焼き付けられているのです。周波数を $\Delta f$ だけ増やすと、位相は $-4\pi \Delta f R / c$ だけ回転します。つまり、周波数を刻んでいくと $H(f_n)$ は複素平面上を一定の角速度でぐるぐると回転し、その回転の「速さ」が距離 $R$ に対応します。逆に言えば、$H(f_n)$ の周波数に対する回転の速さを読み取れば、距離 $R$ がわかるはずです。この「周波数に対する位相の回転速度から遅延を読む」操作こそ、フーリエ変換そのものです。

複数点目標の場合 — 重ね合わせ

現実の目標は一点ではなく、航空機なら機首・主翼・エンジン・尾翼など、複数の散乱中心(点目標)の集まりとみなせます。距離 $R_k$ にある $k$ 番目の散乱中心が反射強度 $\sigma_k$ を持つとすると、線形なシステムでは各反射波が単純に重ね合わさるので、複素反射係数は各点目標の寄与の和になります。

$$ H(f_n) = \sum_{k} \sigma_k \, \exp\!\left(-j \frac{4\pi f_n R_k}{c}\right) $$

それぞれの散乱中心が、自分の距離 $R_k$ に応じた回転速度の「複素正弦波」を周波数軸上に描き、それらが足し合わさったものが測定データ $H(f_n)$ になります。複数の音が混ざった音波から個々の音程を聞き分けるのと同じで、混ざった周波数応答からそれぞれの回転速度(=距離)を分離する操作が必要です。それがフーリエ変換、離散的に実装するなら IDFT です。

ここまでで、測定データ $H(f_n)$ が「距離に比例した回転速度をもつ複素正弦波の重ね合わせ」であることがわかりました。では、この周波数領域のデータに IDFT を施すと、なぜ距離方向のプロファイルが現れるのでしょうか。次節で丁寧に導出します。

IDFT によるレンジ圧縮の導出

サンプリングされた周波数応答

実際の測定では、周波数は離散的に $f_n = f_0 + n\,\Delta f$($n = 0, 1, \dots, N-1$)と刻まれています。単一点目標(距離 $R$、反射強度 $\sigma$)の複素反射係数を、この離散周波数で書き下すと、

$$ H[n] = \sigma \, \exp\!\left(-j \frac{4\pi (f_0 + n\Delta f) R}{c}\right) $$

指数の中を、$n$ に依存しない項と $n$ に比例する項に分けます。

$$ H[n] = \sigma \, \exp\!\left(-j \frac{4\pi f_0 R}{c}\right) \cdot \exp\!\left(-j \frac{4\pi \,\Delta f \, R}{c} n\right) $$

第 1 の指数は $n$ によらない定数(開始周波数 $f_0$ に由来する一定の位相)なので、まとめて $\sigma’ = \sigma \exp(-j 4\pi f_0 R / c)$ と書きます。すると、

$$ H[n] = \sigma’ \, \exp\!\left(-j \frac{4\pi \,\Delta f \, R}{c} n\right) $$

これは、$n$ に対して一定の角周波数で回転する離散的な複素正弦波にほかなりません。その正規化角周波数($n$ が 1 増えるごとの位相回転量)を $\Omega$ と置くと、

$$ \Omega = \frac{4\pi \,\Delta f \, R}{c} $$

です。距離 $R$ が大きいほど、$n$ に対する位相回転が速くなる($\Omega$ が大きくなる)ことがはっきり見て取れます。

IDFT の定義と適用

ここで、$N$ 点の数列 $H[n]$ に対する逆離散フーリエ変換(IDFT)を定義通りに適用します。IDFT は次式で与えられます(規格化係数 $1/N$ の置き方には流儀がありますが、ここでは標準的なものを採用します)。

$$ h[p] = \frac{1}{N}\sum_{n=0}^{N-1} H[n] \, \exp\!\left(+j \frac{2\pi}{N} p n\right), \quad p = 0, 1, \dots, N-1 $$

ここで添字 $p$ は「距離ビン(range bin)」の番号で、後で実際の距離に換算します。単一点目標の $H[n] = \sigma’ \exp(-j\Omega n)$ を代入すると、

$$ h[p] = \frac{\sigma’}{N}\sum_{n=0}^{N-1} \exp\!\left(-j\Omega n\right)\exp\!\left(+j \frac{2\pi}{N} p n\right) $$

指数をまとめると、和は等比数列(幾何級数)の形になります。

$$ h[p] = \frac{\sigma’}{N}\sum_{n=0}^{N-1} \exp\!\left[j\left(\frac{2\pi p}{N} – \Omega\right) n\right] $$

ここで $\theta = \frac{2\pi p}{N} – \Omega$ と置くと、$\sum_{n=0}^{N-1} e^{j\theta n}$ という有限等比級数になります。この和は、$\theta$ が $2\pi$ の整数倍のとき $N$(全項が 1 で揃う)、それ以外のときは小さな値になります。すなわち、$h[p]$ は

$$ \frac{2\pi p}{N} = \Omega \quad\Longleftrightarrow\quad p = \frac{N\,\Omega}{2\pi} $$

を満たす距離ビン $p$ で鋭いピーク(理想的にはデルタ関数状)を持ち、それ以外ではほぼゼロになります。つまり、周波数応答 $H[n]$ を IDFT すると、目標がある距離ビンにだけピークが立つのです。これがレンジ圧縮(range compression)であり、合成された「距離方向のインパルス応答」です。

ピーク位置が距離になることの確認

ピークが立つビン $p_{\text{peak}} = N\Omega/(2\pi)$ に、先ほど求めた $\Omega = 4\pi \Delta f R / c$ を代入してみましょう。

$$ p_{\text{peak}} = \frac{N}{2\pi}\cdot\frac{4\pi \,\Delta f\, R}{c} = \frac{2 N \,\Delta f\, R}{c} $$

総帯域幅を $B = N\,\Delta f$(厳密には $(N-1)\Delta f$ ですが、$N$ が大きければほぼ同じ)と書くと、$N\Delta f = B$ なので、ピークビンと距離の関係は次のようにまとめられます。

$$ p_{\text{peak}} = \frac{2 B R}{c} \quad\Longrightarrow\quad R = \frac{c}{2 B}\, p_{\text{peak}} $$

距離ビン番号 $p$ に係数 $c/(2B)$ を掛ければ、実際の距離に換算できることがわかりました。この係数 $c/(2B)$ こそが、次節で導く距離分解能 $\Delta R$ の正体です。

ここまでで、IDFT が周波数応答を距離プロファイルに変換し、目標距離がピーク位置として現れることを示しました。次に、この合成プロファイルがどれだけ細かく距離を見分けられるか(距離分解能)と、どこまで遠くを曖昧なく測れるか(非曖昧距離)という、二つの最重要パラメータを導出します。

距離分解能と非曖昧距離の導出

距離分解能 $\Delta R$

距離分解能とは、「どれだけ近い二つの目標を別々のピークとして見分けられるか」の限界です。IDFT の出力は離散的な距離ビンで与えられ、隣り合うビンの間隔が分解能の目安になります。前節の換算式 $R = (c/2B)\,p$ で、ビン番号 $p$ を 1 つ進めたときの距離の増分が、ちょうど 1 ビンあたりの距離です。

$$ \Delta R = \frac{c}{2B}\,(p+1) – \frac{c}{2B}\,p = \frac{c}{2B} $$

すなわち、

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

ここで $B = N\Delta f$ は合成された総帯域幅です。導出を振り返ると、(1) 往復伝搬で距離が 2 倍効くので分母に 2 が現れ、(2) 帯域 $B$ が広いほど IDFT のピークが鋭くなるので分母に $B$ が現れる、という二つの効果が距離分解能を決めています。

この式は通常のパルスレーダーの距離分解能 $\Delta R = c/(2B)$ と完全に一致します。ステップド周波数レーダーの本質は、「物理的に広帯域 $B$ のパルスを送る」代わりに「$N$ 個の狭帯域測定を合成して実効帯域 $B = N\Delta f$ を稼ぐ」点にあり、得られる分解能は同じなのです。たとえば $B = 1$ GHz の合成帯域なら、$\Delta R = (3\times10^8)/(2\times10^9) = 0.15$ m = 15 cm の分解能が得られます。$B = 15$ GHz まで広げれば 1 cm の分解能に達します。

非曖昧距離(曖昧距離)$R_{\max}$

一方で、ステップド周波数レーダーには「どこまで遠くの目標を正しく測れるか」という別の限界があります。これは周波数を離散的に刻んでいることに起因する、フーリエ変換特有のエイリアシング(折り返し)の問題です。

復習すると、単一点目標の周波数応答は $H[n] = \sigma’ \exp(-j\Omega n)$、$\Omega = 4\pi \Delta f R/c$ という離散複素正弦波でした。離散信号の角周波数 $\Omega$ は $2\pi$ の周期性を持ちます。すなわち、$\Omega$ と $\Omega + 2\pi$ は数列としてまったく区別がつきません。したがって、距離 $R$ が大きくなって $\Omega$ が $2\pi$ に達すると、ピークは折り返してビンの先頭に戻ってしまいます。曖昧さなく測れる最大距離 $R_{\max}$ は、$\Omega$ が $2\pi$ に達する直前までです。

$$ \Omega = \frac{4\pi \,\Delta f\, R}{c} = 2\pi $$

これを $R$ について解きます。両辺を $2\pi$ で割ると $2\Delta f R/c = 1$ となり、$R$ について整理すると、

$$ \boxed{\;R_{\max} = \frac{c}{2\,\Delta f}\;} $$

が得られます。距離が $R_{\max}$ を超える目標は、$R_{\max}$ だけ手前に「折り返して」誤った位置に現れます(距離エイリアシング)。たとえば周波数ステップ $\Delta f = 10$ MHz なら、$R_{\max} = (3\times10^8)/(2\times10^7) = 15$ m です。それより遠い目標は 15 m の範囲内に折り返してしまいます。

トレードオフ — 分解能と曖昧距離は両立しにくい

ここで重要なトレードオフが見えてきます。二つの式

$$ \Delta R = \frac{c}{2 N \Delta f}, \qquad R_{\max} = \frac{c}{2 \Delta f} $$

を見比べると、両者の比は

$$ \frac{R_{\max}}{\Delta R} = \frac{c/(2\Delta f)}{c/(2N\Delta f)} = N $$

となり、ちょうど周波数ステップ数 $N$ に等しくなります。つまり、$R_{\max}$ は「見える範囲」、$\Delta R$ は「見える細かさ」で、その比(=距離ビンの総数)はステップ数 $N$ で決まるのです。

このトレードオフは設計上きわめて実践的です。

  • 分解能を上げたい($\Delta R$ を小さく)→ 総帯域 $B = N\Delta f$ を広げる
  • 遠くまで測りたい($R_{\max}$ を大きく)→ 周波数ステップ $\Delta f$ を細かくする
  • 両方を欲張る → ステップ数 $N$ を増やす(ただし測定時間が長くなり、目標が動くと位相がぶれる)

たとえば $\Delta R = 15$ cm かつ $R_{\max} = 15$ m を両立するには、$N = R_{\max}/\Delta R = 100$ ステップが必要です。$\Delta f = 10$ MHz、$N = 100$ なら総帯域は $B = 1$ GHz となり、確かに整合します。

ここまでで、ステップド周波数レーダーの二大パラメータ $\Delta R$ と $R_{\max}$、そしてそれらが $N$ で結ばれるトレードオフを数式で導きました。理論はそろったので、いよいよ Python でこれらを実装し、レンジプロファイルの合成と各パラメータの効果を目で確かめましょう。

Python による実装と可視化

複数点目標のレンジプロファイル合成

まず、複数の点目標を仮想的に配置し、それぞれが作る複素反射係数 $H[n]$ を重ね合わせて測定データを合成します。次にそれを IDFT して距離プロファイルを復元し、目標が正しい距離にピークとして現れるかを確認します。

import numpy as np
import matplotlib.pyplot as plt

# 物理定数・レーダーパラメータ
c = 3e8            # 光速 [m/s]
f0 = 10e9          # 開始周波数 [Hz] (Xバンド 10 GHz)
N = 128            # 周波数ステップ数
df = 5e6           # 周波数ステップ間隔 [Hz] (5 MHz)
B = N * df         # 合成総帯域幅 [Hz]

# 導出した分解能・曖昧距離
dR = c / (2 * B)        # 距離分解能 [m]
Rmax = c / (2 * df)     # 非曖昧距離 [m]
print(f"合成帯域 B = {B/1e6:.0f} MHz")
print(f"距離分解能 ΔR = {dR*100:.2f} cm")
print(f"非曖昧距離 Rmax = {Rmax:.2f} m")

# 点目標の配置: (距離 [m], 反射強度)
targets = [(2.0, 1.0), (3.5, 0.7), (3.8, 0.7), (8.0, 0.5)]

# 各周波数 fn での複素反射係数 H[n] を合成
n = np.arange(N)
fn = f0 + n * df
H = np.zeros(N, dtype=complex)
for R, amp in targets:
    H += amp * np.exp(-1j * 4 * np.pi * fn * R / c)

このコードは、距離 2.0 m / 3.5 m / 3.8 m / 8.0 m の 4 つの点目標が作る周波数応答 H[n] を合成しました。実行すると、合成帯域 640 MHz、距離分解能 23.4 cm、非曖昧距離 30 m と表示されます。3.5 m と 3.8 m の目標は 30 cm しか離れておらず、分解能 23.4 cm とほぼ同程度なので、後で「ぎりぎり分離できるか」の確認に使います。

次に、この H[n] を IDFT してレンジプロファイルを復元します。

# IDFT でレンジ圧縮 (numpy の ifft は 1/N 規格化込み)
h = np.fft.ifft(H)
profile = np.abs(h)                    # 振幅プロファイル

# 距離ビンを実距離に換算: R = (c / 2B) * p
p = np.arange(N)
R_axis = (c / (2 * B)) * p

# dB 表示で可視化
profile_db = 20 * np.log10(profile / profile.max() + 1e-12)

plt.figure(figsize=(9, 5))
plt.plot(R_axis, profile_db, color='navy')
for R, amp in targets:
    plt.axvline(R, color='red', ls='--', alpha=0.5)
plt.xlabel('Range [m]')
plt.ylabel('Normalized amplitude [dB]')
plt.title('Synthesized Range Profile (IDFT of stepped-frequency response)')
plt.ylim(-60, 5)
plt.xlim(0, Rmax)
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

このグラフ(赤い破線が真の目標位置)から、いくつかの重要な特徴が読み取れます。第一に、2.0 m と 8.0 m の孤立した目標は、それぞれ正しい距離にくっきりとピークが立っており、IDFT によって「鋭いパルス」が合成されていることが確認できます。第二に、3.5 m と 3.8 m の近接した二目標は、二つのピークとして辛うじて分離されているか、分解能限界に近いために裾が重なって一つの幅広いピークに見えます。これは導出した $\Delta R \approx 23$ cm と目標間隔 30 cm の関係そのものを反映しています。第三に、各ピークの周りに「サイドローブ」と呼ばれる小さな波打ちが見えます。これは矩形に区切られた有限の帯域を IDFT したことによる宿命的な副産物で、後ほど窓関数で抑制します。

帯域とステップ間隔を振って分解能・曖昧距離を確認

次に、理論式 $\Delta R = c/(2B)$ と $R_{\max} = c/(2\Delta f)$ が実装で本当に成り立つかを、パラメータを変えながら確かめます。まず帯域を変えて分解能の変化を見ます。

import numpy as np
import matplotlib.pyplot as plt

c = 3e8
f0 = 10e9

def synth_profile(N, df, targets):
    """N点・ステップdfでレンジプロファイルを合成して返す"""
    n = np.arange(N)
    fn = f0 + n * df
    H = np.zeros(N, dtype=complex)
    for R, amp in targets:
        H += amp * np.exp(-1j * 4 * np.pi * fn * R / c)
    h = np.abs(np.fft.ifft(H))
    R_axis = (c / (2 * N * df)) * n
    return R_axis, h / h.max()

# 2つの近接目標 (3.0 m と 3.4 m, 間隔 40 cm)
targets = [(3.0, 1.0), (3.4, 1.0)]

plt.figure(figsize=(9, 5))
for N, df, label in [(64, 5e6, 'B=320 MHz (ΔR=47cm)'),
                     (128, 5e6, 'B=640 MHz (ΔR=23cm)'),
                     (256, 5e6, 'B=1.28 GHz (ΔR=12cm)')]:
    R_axis, prof = synth_profile(N, df, targets)
    plt.plot(R_axis, 20*np.log10(prof + 1e-12), label=label)
plt.axvline(3.0, color='gray', ls=':')
plt.axvline(3.4, color='gray', ls=':')
plt.xlim(2, 4.5)
plt.ylim(-40, 3)
plt.xlabel('Range [m]')
plt.ylabel('Normalized amplitude [dB]')
plt.title('Effect of Synthetic Bandwidth on Range Resolution')
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

このグラフは、40 cm 離れた二つの目標を、帯域を変えて観測した結果です。$B = 320$ MHz($\Delta R = 47$ cm)では二目標が完全に融合して一つの山にしか見えませんが、$B = 640$ MHz($\Delta R = 23$ cm)では二つの峰が見え始め、$B = 1.28$ GHz($\Delta R = 12$ cm)でははっきりと二つに分離します。分解能 $\Delta R$ が目標間隔より小さくなった瞬間に分離できるようになるという、$\Delta R = c/(2B)$ の意味が視覚的に確認できます。帯域を倍にするとピークが半分の幅に絞られる関係も読み取れます。

続いて、周波数ステップ $\Delta f$ を変えて、非曖昧距離を超えた目標がどう折り返すかを観察します。

import numpy as np
import matplotlib.pyplot as plt

c = 3e8
f0 = 10e9
N = 128

def synth_profile(N, df, targets):
    n = np.arange(N)
    fn = f0 + n * df
    H = np.zeros(N, dtype=complex)
    for R, amp in targets:
        H += amp * np.exp(-1j * 4 * np.pi * fn * R / c)
    h = np.abs(np.fft.ifft(H))
    R_axis = (c / (2 * N * df)) * n
    return R_axis, h / h.max()

# 距離 5 m と 22 m の目標
targets = [(5.0, 1.0), (22.0, 0.8)]

plt.figure(figsize=(9, 5))
for df in [5e6, 10e6]:
    Rmax = c / (2 * df)
    R_axis, prof = synth_profile(N, df, targets)
    plt.plot(R_axis, prof, label=f'Δf={df/1e6:.0f} MHz (Rmax={Rmax:.0f} m)')
plt.axvline(5.0, color='green', ls='--', alpha=0.6, label='target 5 m')
plt.axvline(22.0, color='red', ls='--', alpha=0.6, label='target 22 m')
plt.xlabel('Range [m]')
plt.ylabel('Normalized amplitude')
plt.title('Range Ambiguity: targets beyond Rmax fold back')
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

このグラフから、距離エイリアシングの挙動がはっきりわかります。$\Delta f = 5$ MHz のとき $R_{\max} = 30$ m なので、5 m と 22 m の目標はどちらも範囲内に正しく現れます。一方 $\Delta f = 10$ MHz のとき $R_{\max} = 15$ m に縮むため、22 m の目標は $22 – 15 = 7$ m の位置に折り返して偽の像として現れてしまいます。$R_{\max} = c/(2\Delta f)$ の導出通り、ステップを粗くする($\Delta f$ を大きくする)と見える範囲が狭くなり、遠方目標が手前に化けることが確認できました。実機ではこの折り返しを避けるため、想定する最大目標距離に応じて $\Delta f$ を十分小さく設計します。

窓関数によるサイドローブ抑制

最初のレンジプロファイルで見えた「ピーク周りの波打ち(サイドローブ)」は、有限帯域を矩形(一様な重み)で切り取ったことに由来します。フーリエ変換のペアとして、矩形窓は時間(距離)領域で sinc 関数になり、その第一サイドローブは約 $-13$ dB と高めです。小さな目標が大きな目標のサイドローブに埋もれて見えなくなる「マスキング」を防ぐため、周波数応答 $H[n]$ に滑らかな窓関数(ハミング窓など)を掛けてからIDFTします。

import numpy as np
import matplotlib.pyplot as plt

c = 3e8
f0 = 10e9
N = 128
df = 5e6
B = N * df

# 強い目標(5 m)と弱い目標(7 m)
targets = [(5.0, 1.0), (7.0, 0.05)]   # 弱い目標は -26 dB

n = np.arange(N)
fn = f0 + n * df
H = np.zeros(N, dtype=complex)
for R, amp in targets:
    H += amp * np.exp(-1j * 4 * np.pi * fn * R / c)

R_axis = (c / (2 * B)) * n
win = np.hamming(N)   # ハミング窓

# 窓なし / 窓あり それぞれ IDFT
prof_rect = np.abs(np.fft.ifft(H))
prof_ham = np.abs(np.fft.ifft(H * win))
prof_rect /= prof_rect.max()
prof_ham /= prof_ham.max()

plt.figure(figsize=(9, 5))
plt.plot(R_axis, 20*np.log10(prof_rect + 1e-12),
         label='Rectangular (no window)', color='tomato')
plt.plot(R_axis, 20*np.log10(prof_ham + 1e-12),
         label='Hamming window', color='navy')
plt.axvline(5.0, color='gray', ls=':')
plt.axvline(7.0, color='gray', ls=':')
plt.xlim(0, 12)
plt.ylim(-70, 3)
plt.xlabel('Range [m]')
plt.ylabel('Normalized amplitude [dB]')
plt.title('Sidelobe Suppression by Windowing')
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

このグラフから、窓関数の効果と代償が同時に読み取れます。窓なし(矩形)では強い目標(5 m)の第一サイドローブが $-13$ dB 付近まで立ち上がり、$-26$ dB しかない弱い目標(7 m)がサイドローブの裾に埋もれて判別しにくくなっています。ハミング窓を掛けると、サイドローブが $-40$ dB 以下まで大きく下がり、弱い目標がはっきりと独立したピークとして浮かび上がります。一方で、ハミング窓を掛けたメインローブは窓なしより少し太くなっており、これは「サイドローブを下げると分解能がわずかに犠牲になる」という窓関数の普遍的なトレードオフを示しています。実用では、ダイナミックレンジ(弱い目標を見たいか)と分解能のどちらを優先するかで窓を選びます。

ゼロパディングによる距離プロファイルの平滑表示

最後に、表示を滑らかにするテクニックとして、周波数応答の末尾にゼロを詰めてから IDFT する「ゼロパディング」を試します。これは新しい情報を増やすわけではなく、sinc 関数の形を細かくサンプリングして見やすくするだけですが、ピーク位置の読み取り精度を上げるのに役立ちます。

import numpy as np
import matplotlib.pyplot as plt

c = 3e8
f0 = 10e9
N = 64
df = 5e6
B = N * df

targets = [(3.0, 1.0), (6.0, 0.6)]
n = np.arange(N)
fn = f0 + n * df
H = np.zeros(N, dtype=complex)
for R, amp in targets:
    H += amp * np.exp(-1j * 4 * np.pi * fn * R / c)

win = np.hamming(N)
Hw = H * win

# ゼロパディング: 4倍長に
M = 4 * N
prof = np.abs(np.fft.ifft(Hw))[:N]
prof_zp = np.abs(np.fft.ifft(Hw, M))[:M]
prof /= prof.max()
prof_zp /= prof_zp.max()

R_axis = (c / (2 * B)) * np.arange(N)
R_axis_zp = (c / (2 * B)) * (np.arange(M) * N / M)

plt.figure(figsize=(9, 5))
plt.plot(R_axis, prof, 'o-', label=f'N={N} bins', alpha=0.6)
plt.plot(R_axis_zp, prof_zp, '-', label=f'zero-padded to {M}', color='navy')
plt.xlim(0, 9)
plt.xlabel('Range [m]')
plt.ylabel('Normalized amplitude')
plt.title('Zero-padding for smoother range profile display')
plt.legend()
plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()

このグラフから、ゼロパディングの役割がわかります。元の $N = 64$ 点だけでは距離ビンが粗く(丸印)、ピークの頂点がビンとビンの間に落ちると真のピーク位置や高さを読み誤る恐れがあります。4 倍にゼロパディングした曲線は、同じ sinc 状の形をはるかに細かくサンプリングしており、ピークの位置と高さが滑らかに読み取れます。ただし二つの曲線の「山の幅(分解能)」は同じであることに注意してください。ゼロパディングは見かけの細かさを増やすだけで、分解能 $\Delta R = c/(2B)$ そのものは帯域 $B$ が決めており、変わりません。これは初学者が誤解しやすい重要な点です。

まとめ

本記事では、ステップド周波数レーダーによる高分解能レンジプロファイルの原理を、複素反射係数の物理から IDFT によるレンジ圧縮まで、数式を省略せずに導出し、Python で実装しました。要点を整理します。

  • 合成帯域の発想: 広帯域パルスを一度に送る代わりに、周波数 $f_n = f_0 + n\Delta f$ を刻んで複素反射係数 $H(f_n)$ を集め、後から IDFT で鋭いパルスを合成する。狭帯域受信機で広帯域性能が得られる
  • 複素反射係数: 距離 $R$ の点目標は $H(f_n) = \sigma\,e^{-j 4\pi f_n R/c}$ という、距離に比例した回転速度をもつ複素正弦波として周波数応答に焼き付けられる
  • IDFT がレンジ圧縮: 周波数応答を IDFT すると、目標距離 $p_{\text{peak}} = 2BR/c$ のビンに鋭いピークが立つ
  • 距離分解能 $\Delta R = c/(2B)$: 合成総帯域 $B = N\Delta f$ が広いほど細かく見分けられる
  • 非曖昧距離 $R_{\max} = c/(2\Delta f)$: 周波数ステップ $\Delta f$ が細かいほど遠くまで曖昧なく測れる。両者の比は $R_{\max}/\Delta R = N$
  • 窓関数: ハミング窓などでサイドローブを抑えると弱い目標が見えるが、分解能はわずかに犠牲になる

ステップド周波数レーダーは、レーダー方程式が与える探知距離の枠組みの上に、パルス圧縮と同じ「広帯域=高分解能」の原理を、離散フーリエ変換という信号処理で実現したものです。ここで学んだ「周波数応答を集めて IDFT で距離を復元する」という考え方は、合成開口レーダー(SAR)の距離圧縮や、ベクトルネットワークアナライザを用いた非破壊検査など、幅広い計測技術の土台になります。

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