畳み込み定理とフーリエ変換の関係

2つの信号を混ぜ合わせる操作 — たとえばマイクで録音した音声に残響を加えること、カメラで撮った画像をぼかすこと — これらは全て畳み込み(convolution)という同一の数学的操作で表現できます。

畳み込みの計算は本来 $O(N^2)$ かかりますが、「時間領域での畳み込みは周波数領域での乗算に等しい」という畳み込み定理を使えば、FFTによって $O(N\log N)$ で計算できます。この高速化は科学計算と信号処理の実用性を根本的に変えました。

畳み込み定理を理解すると、以下のような応用が開けます。

  • 信号処理: FIRフィルタの高速実装(オーバーラップ加算法、セーブ法)
  • 画像処理: 畳み込みニューラルネットワーク(CNN)の高速化
  • 統計学: 独立確率変数の和の分布の計算
  • 物理学: 線形システムのインパルス応答
  • 音響工学: リバーブ(残響)エフェクトのリアルタイム処理

本記事の内容

  • 畳み込みの定義と物理的意味
  • 畳み込み定理の証明(連続・離散)
  • 相関定理と自己相関
  • FFTを用いた高速畳み込みの実装
  • Pythonによる応用例(フィルタリング、画像処理)

前提知識

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

畳み込みとは — 直感的な理解

物理的な意味

畳み込みを理解するために、エコーのかかった部屋で手を叩く場面を想像してください。

手を叩いた音(インパルス)は、壁に反射して複数回聞こえます。この部屋の「インパルス応答」$h(t)$ は、直接音とそれに続く反射音の列です。

ここで音楽を再生すると、音楽信号 $f(t)$ の各瞬間がインパルスのように扱われ、それぞれに対して部屋のインパルス応答 $h(t)$ が発生します。これらの応答を全て重ね合わせたものが、部屋で聞こえる音 — すなわち $f$ と $h$ の畳み込み $(f * h)(t)$ です。

もう少し日常的な例で考えてみましょう。コーヒーショップで紙ナプキンにインクをこぼした場面を想像してください。インクは時間とともにナプキンに染み込んで広がります。ある時刻にこぼしたインクの量が $f(\tau)$ で、インクが時間 $t – \tau$ 後にどれだけ広がるかが $g(t – \tau)$ です。時刻 $t$ にナプキン上で観察される「にじみ」の総量は、過去にこぼした全てのインクの影響を足し合わせた結果 — つまり畳み込み $(f * g)(t)$ そのものです。

このように、畳み込みの本質は「過去の入力が現在にどれだけ影響を残すか」を全時刻にわたって足し合わせる操作です。線形時不変(LTI)システムの出力は、入力とインパルス応答の畳み込みで表されるため、畳み込みは工学のあらゆる場面に登場します。

幾何学的な見方 — スライドと重なり

畳み込みの積分を計算する手順を、幾何学的に理解しましょう。

  1. 反転: $g(\tau)$ を $\tau = 0$ の軸で左右反転し、$g(-\tau)$ を作ります
  2. スライド: 反転した $g(-\tau)$ を右に $t$ だけスライドさせ、$g(t – \tau)$ を得ます
  3. 乗算: $f(\tau)$ と $g(t – \tau)$ を各点で掛け合わせます
  4. 積分: 掛け合わせた結果を全区間にわたって積分します

$t$ を $-\infty$ から $+\infty$ まで動かしながらこの操作を繰り返すと、出力 $(f * g)(t)$ の全体像が得られます。なぜ「反転」が必要かというと、過去の入力 $f(\tau)$ に対する応答 $g$ は、現在時刻 $t$ から $\tau$ だけ遡った分だけ「古い」応答だからです。時間の向きを合わせるために反転が入ると考えると自然です。

数学的定義(連続)

2つの関数 $f(t)$ と $g(t)$ の畳み込み

$$ \begin{equation} (f * g)(t) = \int_{-\infty}^{\infty} f(\tau)\, g(t – \tau)\, d\tau \end{equation} $$

「$f$ を固定し、$g$ を時間反転させて $t$ だけスライドさせ、重なり部分の積を積分する」という操作です。

手計算で確かめる具体例

$f(t) = e^{-t} u(t)$(指数減衰)、$g(t) = u(t) – u(t-1)$(幅1の矩形パルス)の畳み込みを実際に計算してみましょう。ここで $u(t)$ は単位ステップ関数です。

$(f * g)(t)$ を計算するには、被積分関数 $f(\tau) g(t – \tau)$ が非ゼロとなる区間を特定します。$f(\tau) \neq 0$ は $\tau \geq 0$、$g(t – \tau) \neq 0$ は $0 \leq t – \tau \leq 1$、すなわち $t – 1 \leq \tau \leq t$ のときです。したがって、積分範囲は $\max(0, t-1) \leq \tau \leq t$ となります。

場合1: $0 \leq t \leq 1$ のとき、$\max(0, t-1) = 0$ なので

$$ (f * g)(t) = \int_{0}^{t} e^{-\tau}\, d\tau = \left[-e^{-\tau}\right]_{0}^{t} = 1 – e^{-t} $$

場合2: $t > 1$ のとき、$\max(0, t-1) = t – 1$ なので

$$ (f * g)(t) = \int_{t-1}^{t} e^{-\tau}\, d\tau = \left[-e^{-\tau}\right]_{t-1}^{t} = e^{-(t-1)} – e^{-t} = e^{-t}(e – 1) $$

たとえば $t = 0.5$ のとき $(f*g)(0.5) = 1 – e^{-0.5} \approx 0.393$、$t = 2$ のとき $(f*g)(2) = e^{-2}(e-1) \approx 0.233$ となります。このように、具体的な関数に対して畳み込みを手で計算する手順は、積分区間の場合分けがポイントです。

数学的定義(離散)

離散信号 $x[n]$ と $h[n]$ の畳み込みは

$$ \begin{equation} (x * h)[n] = \sum_{m=-\infty}^{\infty} x[m]\, h[n – m] \end{equation} $$

離散畳み込みの数値例

離散の場合も具体例で確認しましょう。$x = [1, 2, 3]$(長さ $M = 3$)、$h = [1, 1]$(長さ $L = 2$)の畳み込みを計算します。出力の長さは $M + L – 1 = 4$ です。

各出力を定義式に従って計算します。

$$ \begin{aligned} (x * h)[0] &= x[0] \cdot h[0] = 1 \times 1 = 1 \\ (x * h)[1] &= x[0] \cdot h[1] + x[1] \cdot h[0] = 1 \times 1 + 2 \times 1 = 3 \\ (x * h)[2] &= x[1] \cdot h[1] + x[2] \cdot h[0] = 2 \times 1 + 3 \times 1 = 5 \\ (x * h)[3] &= x[2] \cdot h[1] = 3 \times 1 = 3 \end{aligned} $$

したがって $x * h = [1, 3, 5, 3]$ です。$h = [1, 1]$ との畳み込みは「隣接2点の和をとる移動和フィルタ」に相当します。Pythonで np.convolve([1,2,3], [1,1]) を実行すると同じ結果 [1, 3, 5, 3] が得られます。

畳み込みの性質

性質
可換性 $f * g = g * f$
結合性 $(f * g) * h = f * (g * h)$
分配性 $f * (g + h) = f * g + f * h$
デルタとの畳み込み $f * \delta = f$
スケーリング $a(f * g) = (af) * g = f * (ag)$
微分 $(f * g)’ = f’ * g = f * g’$

可換性の証明

可換性は直感的には明らかではありませんが、変数変換で簡潔に示せます。$(f * g)(t)$ の定義式で $\tau’ = t – \tau$ と置換すると $d\tau’ = -d\tau$ であり、$\tau: -\infty \to \infty$ のとき $\tau’: \infty \to -\infty$ なので

$$ \begin{aligned} (f * g)(t) &= \int_{-\infty}^{\infty} f(\tau)\, g(t – \tau)\, d\tau \\ &= \int_{\infty}^{-\infty} f(t – \tau’)\, g(\tau’)\, (-d\tau’) \\ &= \int_{-\infty}^{\infty} g(\tau’)\, f(t – \tau’)\, d\tau’ \\ &= (g * f)(t) \end{aligned} $$

積分区間の反転と負号が相殺して、$f$ と $g$ の役割が入れ替わります。

デルタ関数との畳み込み

デルタ関数 $\delta(t)$ は「時刻0に集中した単位インパルス」です。これとの畳み込みが恒等操作になることは、畳み込みの「抽出性質」と呼ばれ、デルタ関数の篩(ふるい)性質そのものです。

$$ (f * \delta)(t) = \int_{-\infty}^{\infty} f(\tau)\, \delta(t – \tau)\, d\tau = f(t) $$

デルタ関数が $\tau = t$ 以外ではゼロなので、$f(\tau)$ の値を $\tau = t$ の点でそのまま「拾い上げる」のです。これは単位元としての性質であり、フィルタ設計において「何もしないフィルタ(パススルー)」はインパルス応答がデルタ関数であることに対応します。

微分との関係

畳み込みの微分が「どちらか一方の微分との畳み込み」になるという性質は、偏微分方程式の解法で威力を発揮します。

$$ \frac{d}{dt}(f * g)(t) = \frac{d}{dt}\int_{-\infty}^{\infty} f(\tau)\, g(t – \tau)\, d\tau = \int_{-\infty}^{\infty} f(\tau)\, g'(t – \tau)\, d\tau = (f * g’)(t) $$

ライプニッツの積分則により、微分を積分の中に入れて $g$ にだけ作用させることができます。この性質を使うと、グリーン関数を用いた微分方程式の解が畳み込みの形で自然に導かれます。

畳み込みの基本性質を理解したところで、いよいよ最も重要な定理 — 畳み込み定理 — の証明に進みましょう。

畳み込み定理の証明

連続版

定理: $f, g$ が絶対可積分な関数のとき

$$ \begin{equation} \mathcal{F}[f * g](\omega) = \hat{f}(\omega) \cdot \hat{g}(\omega) \end{equation} $$

証明: 畳み込みの定義にフーリエ変換を適用します。

$$ \mathcal{F}[f * g](\omega) = \int_{-\infty}^{\infty} \left[\int_{-\infty}^{\infty} f(\tau) g(t-\tau)\, d\tau\right] e^{-i\omega t}\, dt $$

積分順序を交換(フビニの定理を適用)すると

$$ = \int_{-\infty}^{\infty} f(\tau) \left[\int_{-\infty}^{\infty} g(t-\tau) e^{-i\omega t}\, dt\right] d\tau $$

内側の積分で $s = t – \tau$($dt = ds$)と置換すると

$$ \int_{-\infty}^{\infty} g(s) e^{-i\omega(s+\tau)}\, ds = e^{-i\omega\tau} \int_{-\infty}^{\infty} g(s) e^{-i\omega s}\, ds = e^{-i\omega\tau} \hat{g}(\omega) $$

これを外側の積分に戻すと

$$ = \int_{-\infty}^{\infty} f(\tau) e^{-i\omega\tau}\, d\tau \cdot \hat{g}(\omega) = \hat{f}(\omega) \cdot \hat{g}(\omega) $$

$\square$

証明のポイントは積分順序の交換(フビニの定理)と変数置換の2つだけです。$f, g$ が絶対可積分であるという条件は、フビニの定理を適用するために必要です。この条件により $\int |f(\tau) g(t-\tau) e^{-i\omega t}|\, d\tau\, dt < \infty$ が保証され、積分順序の交換が正当化されます。

逆定理(周波数領域の畳み込み)

時間領域での乗算は周波数領域での畳み込みに対応します。

$$ \begin{equation} \mathcal{F}[f \cdot g](\omega) = \frac{1}{2\pi}(\hat{f} * \hat{g})(\omega) \end{equation} $$

証明: フーリエ逆変換 $f(t) = \frac{1}{2\pi}\int_{-\infty}^{\infty} \hat{f}(\nu) e^{i\nu t}\, d\nu$ を使い、$f(t)g(t)$ のフーリエ変換を計算します。

$$ \mathcal{F}[f \cdot g](\omega) = \int_{-\infty}^{\infty} f(t) g(t) e^{-i\omega t}\, dt $$

ここで $f(t)$ を逆変換で置き換えると

$$ = \int_{-\infty}^{\infty} \left[\frac{1}{2\pi}\int_{-\infty}^{\infty} \hat{f}(\nu) e^{i\nu t}\, d\nu \right] g(t) e^{-i\omega t}\, dt $$

積分順序を交換して $t$ について先に積分すると

$$ = \frac{1}{2\pi}\int_{-\infty}^{\infty} \hat{f}(\nu) \left[\int_{-\infty}^{\infty} g(t) e^{-i(\omega – \nu) t}\, dt \right] d\nu $$

角括弧内は $g$ のフーリエ変換を $\omega – \nu$ で評価したもの、すなわち $\hat{g}(\omega – \nu)$ です。したがって

$$ = \frac{1}{2\pi}\int_{-\infty}^{\infty} \hat{f}(\nu)\, \hat{g}(\omega – \nu)\, d\nu = \frac{1}{2\pi}(\hat{f} * \hat{g})(\omega) $$

$\square$

この逆定理は、たとえば窓関数を信号に掛ける操作(時間領域の乗算)が、周波数領域ではスペクトルの「にじみ」(畳み込み)を引き起こすことを説明します。短時間フーリエ変換(STFT)における周波数分解能の限界は、まさにこの逆定理の帰結です。

離散版(巡回畳み込み)

$N$ 点の離散信号 $x[n]$ と $h[n]$ の巡回畳み込み

$$ (x \circledast h)[n] = \sum_{m=0}^{N-1} x[m]\, h[(n-m) \bmod N] $$

離散畳み込み定理:

$$ \text{DFT}[x \circledast h][k] = X[k] \cdot H[k] $$

証明: DFTの定義 $X[k] = \sum_{n=0}^{N-1} x[n] e^{-i2\pi kn/N}$ を巡回畳み込みに適用します。$W_N = e^{-i2\pi/N}$ と略記すると

$$ \text{DFT}[x \circledast h][k] = \sum_{n=0}^{N-1}\left[\sum_{m=0}^{N-1} x[m]\, h[(n-m) \bmod N]\right] W_N^{kn} $$

和の順序を交換し、$n$ についての和を先に計算します。$l = (n – m) \bmod N$ と置換すると $n = (l + m) \bmod N$ であり、$l$ は $0$ から $N-1$ を一巡するので

$$ = \sum_{m=0}^{N-1} x[m]\, W_N^{km} \sum_{l=0}^{N-1} h[l]\, W_N^{kl} = X[k] \cdot H[k] $$

ここで $W_N^{k(l+m)} = W_N^{km} \cdot W_N^{kl}$ を使いました。$\square$

この結果は非常に強力です。畳み込みは DFT → 要素ごとの乗算 → IDFT の3ステップで計算できることを意味します。

線形畳み込みへの適用

巡回畳み込みではなく線形畳み込みを求めるには、ゼロパディングが必要です。長さ $M$ と $L$ の信号の線形畳み込み(長さ $M + L – 1$)を計算するには、両方を $N \geq M + L – 1$ にゼロパディングしてから巡回畳み込みを行います。

なぜゼロパディングが必要か — 具体例で理解

$x = [1, 2, 3]$($M = 3$)と $h = [1, 1]$($L = 2$)を考えます。

線形畳み込みの結果は先ほど計算したとおり $[1, 3, 5, 3]$(長さ4)です。

一方、もし $N = 3$(ゼロパディングなし)で巡回畳み込みを行うと、$h$ を $[1, 1, 0]$ に拡張して

$$ \begin{aligned} (x \circledast h)[0] &= x[0]h[0] + x[1]h[2] + x[2]h[1] = 1 \cdot 1 + 2 \cdot 0 + 3 \cdot 1 = 4 \\ (x \circledast h)[1] &= x[0]h[1] + x[1]h[0] + x[2]h[2] = 1 \cdot 1 + 2 \cdot 1 + 3 \cdot 0 = 3 \\ (x \circledast h)[2] &= x[0]h[2] + x[1]h[1] + x[2]h[0] = 1 \cdot 0 + 2 \cdot 1 + 3 \cdot 1 = 5 \end{aligned} $$

結果は $[4, 3, 5]$ です。線形畳み込みの $[1, 3, 5, 3]$ とは全く異なります。これは巡回畳み込みで信号が「周回」して折り返し(エイリアシング)が発生しているためです。$N \geq M + L – 1 = 4$ にゼロパディングすれば折り返しが起きず、巡回畳み込みと線形畳み込みが一致します。

畳み込み定理の理論的背景を押さえたところで、次はこれをFFTで実装して計算を高速化する方法を見ていきましょう。

FFTを用いた高速畳み込み

アルゴリズム

  1. 入力 $x$ と $h$ を長さ $N \geq M + L – 1$ にゼロパディング
  2. $X = \text{FFT}(x)$, $H = \text{FFT}(h)$
  3. $Y = X \odot H$(要素ごとの乗算)
  4. $y = \text{IFFT}(Y)$

計算量: $O(N\log N)$(FFT 2回 + IFFT 1回 + 乗算 $O(N)$)

直接計算の $O(ML)$ と比較して、$M, L$ が大きいとき大幅に高速です。

計算量の比較 — 具体的な数値

具体的な数値で直接法とFFT法の演算量を比較してみましょう。$M = L = N$ として、主要な乗算回数を概算します。

信号長 $N$ 直接法 $O(N^2)$ FFT法 $O(N \log_2 N)$ 高速化倍率
$100$ $10{,}000$ $\sim 700$ $\sim 14\times$
$1{,}000$ $1{,}000{,}000$ $\sim 10{,}000$ $\sim 100\times$
$10{,}000$ $10^8$ $\sim 130{,}000$ $\sim 770\times$
$100{,}000$ $10^{10}$ $\sim 1{,}700{,}000$ $\sim 5{,}900\times$

$N = 100{,}000$ ではFFT法は直接法の約6,000倍高速です。音声処理やレーダー信号処理では $N$ が数十万〜数百万に達するため、FFTなしには実用的な畳み込みは不可能です。

実装上の注意点

FFT畳み込みを実装する際のポイントをまとめます。

  • 2のべき乗へのパディング: FFTアルゴリズムの多くは入力長が2のべき乗のとき最も効率的です。$N \geq M + L – 1$ を満たす最小の2のべき乗 $N_{\text{fft}} = 2^{\lceil \log_2 N \rceil}$ を使います
  • 実数FFTの活用: 入力が実数のとき np.fft.rfft を使うと、対称性を利用して計算量とメモリを約半分に削減できます
  • 数値精度: IFFT後の結果は微小な虚部を持つことがあります。.real で実部のみ取り出しますが、虚部が大きい場合は計算に問題がある可能性があります

オーバーラップ加算法

FFT畳み込みは非常に長い信号に対してはメモリ問題が生じます。たとえば数時間の音声データ(サンプリング周波数44.1kHzで数億点)を一度にFFTすることは現実的ではありません。

オーバーラップ加算法(overlap-add method)は、入力信号をブロックに分割して各ブロックをフィルタと畳み込み、結果を重ね合わせる手法です。

  1. 入力 $x$ を長さ $B$ のブロック $x_0, x_1, x_2, \ldots$ に分割
  2. 各ブロック $x_i$ とフィルタ $h$(長さ $L$)をFFT畳み込み(長さ $B + L – 1$)
  3. 各ブロックの出力を $iB$ だけシフトして重ね合わせ(overlap-add)

各ブロックのFFT畳み込みは $O((B+L)\log(B+L))$ で、全体では $O(\frac{N}{B}(B+L)\log(B+L))$ です。$B$ を適切に選ぶ(一般的には $B \approx L$ 〜 $4L$)と、リアルタイム処理にも適用できます。

FFTによる高速化の理論を理解したところで、Pythonで実際に実装して性能を確認しましょう。

Pythonでの実装

高速畳み込みの実装と検証

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

def fft_convolve(x, h):
    """FFTを用いた線形畳み込み"""
    N = len(x) + len(h) - 1
    # 2のべき乗に丸める(FFT効率のため)
    N_fft = 2**int(np.ceil(np.log2(N)))
    X = np.fft.fft(x, N_fft)
    H = np.fft.fft(h, N_fft)
    Y = X * H
    y = np.fft.ifft(Y).real
    return y[:N]

# テスト信号
np.random.seed(42)
M, L = 1000, 500
x = np.random.randn(M)
h = np.exp(-np.arange(L) / 50.0)  # 指数減衰フィルタ

# 直接畳み込み
y_direct = np.convolve(x, h)

# FFT畳み込み
y_fft = fft_convolve(x, h)

print(f"直接 vs FFT: ||差|| = {np.linalg.norm(y_direct - y_fft):.2e}")

# ベンチマーク
sizes = [100, 500, 1000, 5000, 10000, 50000]
times_direct = []
times_fft = []

for n in sizes:
    x_test = np.random.randn(n)
    h_test = np.random.randn(n // 5)

    t0 = time.perf_counter()
    np.convolve(x_test, h_test)
    times_direct.append(time.perf_counter() - t0)

    t0 = time.perf_counter()
    fft_convolve(x_test, h_test)
    times_fft.append(time.perf_counter() - t0)

fig, axes = plt.subplots(1, 2, figsize=(14, 5.5))

ax = axes[0]
ax.loglog(sizes, times_direct, "ro-", linewidth=2, markersize=6, label="Direct (numpy.convolve)")
ax.loglog(sizes, times_fft, "bs-", linewidth=2, markersize=6, label="FFT convolution")
ax.set_xlabel("Signal length N", fontsize=12)
ax.set_ylabel("Time (sec)", fontsize=12)
ax.set_title("Convolution: Direct vs FFT", fontsize=13)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3, which="both")

# フィルタリングのデモ
ax = axes[1]
fs = 1000
t = np.arange(2000) / fs
signal = np.sin(2*np.pi*5*t) + 0.5*np.sin(2*np.pi*50*t) + 0.3*np.random.randn(len(t))

# ローパスフィルタ(sinc関数)
fc = 20  # カットオフ周波数
n_taps = 101
n_range = np.arange(n_taps) - n_taps//2
h_lp = np.sinc(2*fc*n_range/fs) * np.hanning(n_taps)
h_lp /= np.sum(h_lp)

filtered = fft_convolve(signal, h_lp)[:len(signal)]

ax.plot(t[:500], signal[:500], "b-", alpha=0.5, linewidth=1, label="Original")
ax.plot(t[:500], filtered[:500], "r-", linewidth=2, label="Filtered (20 Hz LPF)")
ax.set_xlabel("Time (s)", fontsize=12)
ax.set_ylabel("Amplitude", fontsize=12)
ax.set_title("Low-Pass Filtering via FFT Convolution", fontsize=13)
ax.legend(fontsize=10)
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig("convolution_fft.png", dpi=150, bbox_inches="tight")
plt.show()

このグラフから、FFT畳み込みの実用性が2つの観点で確認できます。

左図(計算時間比較) について詳しく見ましょう。横軸が信号長 $N$、縦軸が計算時間で、どちらも対数スケールです。直接畳み込み(赤丸)は傾きが約2の直線、すなわち $O(N^2)$ の計算量を反映しています。一方、FFT畳み込み(青四角)は傾きが約1の直線で、$O(N \log N)$ に近い挙動です。$N = 100$ 程度では差は小さいですが、$N = 50{,}000$ ではFFTが数十倍高速になっていることが確認できます。実用的な目安として、$N \gtrsim 50$ 程度からFFT法が有利になる場合が多いです。

右図(ローパスフィルタリング) では、5Hzと50Hzの正弦波にガウスノイズを加えた合成信号(青、薄い線)に対し、カットオフ周波数20Hzのsinc型ローパスフィルタ(Hanning窓付き、タップ数101)を適用しています。フィルタ後の信号(赤、太い線)では50Hz成分とノイズが大幅に除去され、5Hzの正弦波だけが残っています。波形の位相が少し遅れて見えるのは、FIRフィルタの群遅延(タップ数の半分に相当する約50サンプル = 50ms)によるものです。この群遅延は線形位相FIRフィルタの特性であり、全周波数成分が均等に遅延するため波形の形状は保たれます。

相関定理と自己相関

畳み込み定理と密接に関連する重要な結果として、相関定理があります。

相互相関の定義

2つの信号 $f(t)$ と $g(t)$ の相互相関(cross-correlation)は

$$ (f \star g)(t) = \int_{-\infty}^{\infty} \overline{f(\tau)}\, g(\tau + t)\, d\tau $$

畳み込みとの違いは、$f$ が反転されない点です(代わりに複素共役をとります)。相互相関は「$f$ と $g$ がどれだけ似ているか」を時間シフト $t$ の関数として表す指標です。

相関定理

相互相関のフーリエ変換は

$$ \mathcal{F}[f \star g](\omega) = \overline{\hat{f}(\omega)} \cdot \hat{g}(\omega) $$

証明: 相互相関は $f$ の時間反転・複素共役 $\overline{f(-t)}$ との畳み込みと見なせます。

$$ (f \star g)(t) = (\overline{f(-\cdot)} * g)(t) $$

$\overline{f(-t)}$ のフーリエ変換を計算すると

$$ \mathcal{F}[\overline{f(-\cdot)}](\omega) = \int_{-\infty}^{\infty} \overline{f(-t)}\, e^{-i\omega t}\, dt $$

$s = -t$ と置換すると $dt = -ds$ で

$$ = \int_{\infty}^{-\infty} \overline{f(s)}\, e^{i\omega s}\, (-ds) = \int_{-\infty}^{\infty} \overline{f(s)}\, e^{i\omega s}\, ds = \overline{\hat{f}(\omega)} $$

最後の等号は $\hat{f}(\omega) = \int f(s) e^{-i\omega s}\, ds$ の複素共役が $\overline{\hat{f}(\omega)} = \int \overline{f(s)} e^{i\omega s}\, ds$ であることから従います。

畳み込み定理を適用して $\mathcal{F}[f \star g] = \overline{\hat{f}} \cdot \hat{g}$ を得ます。$\square$

自己相関とパワースペクトル密度

$g = f$ の場合、相互相関は自己相関(autocorrelation)$R_{ff}(t) = (f \star f)(t)$ になります。相関定理より

$$ \mathcal{F}[R_{ff}](\omega) = |\hat{f}(\omega)|^2 $$

これはウィーナー=ヒンチンの定理と呼ばれ、自己相関関数のフーリエ変換がパワースペクトル密度(PSD)に等しいことを述べています。レーダー工学や通信工学では、信号の周期性やSN比の推定にこの関係が頻繁に用いられます。

相関定理は畳み込み定理の一般化であり、パターンマッチングやテンプレートマッチングなどの信号処理技術の基盤となっています。次に、畳み込み定理の代表的な応用をいくつか見ていきましょう。

畳み込み定理の応用

独立確率変数の和の分布

確率論における畳み込み定理の重要な応用として、独立な確率変数の和の分布があります。

$X$, $Y$ が独立な確率変数で、確率密度関数がそれぞれ $f_X(x)$, $f_Y(y)$ のとき、和 $Z = X + Y$ の確率密度関数は畳み込みで与えられます。

$$ f_Z(z) = (f_X * f_Y)(z) = \int_{-\infty}^{\infty} f_X(\tau)\, f_Y(z – \tau)\, d\tau $$

畳み込み定理を適用すると、特性関数(フーリエ変換の確率論版)の領域では単純な乗算になります。

$$ \varphi_Z(\omega) = \varphi_X(\omega) \cdot \varphi_Y(\omega) $$

たとえば、平均 $\mu_1$, 分散 $\sigma_1^2$ の正規分布と平均 $\mu_2$, 分散 $\sigma_2^2$ の正規分布の和が平均 $\mu_1 + \mu_2$, 分散 $\sigma_1^2 + \sigma_2^2$ の正規分布になることは、特性関数の乗算から直ちに導けます。正規分布の特性関数は $\varphi(\omega) = \exp(i\mu\omega – \sigma^2\omega^2/2)$ なので

$$ \varphi_Z(\omega) = \exp\left(i(\mu_1+\mu_2)\omega – \frac{(\sigma_1^2+\sigma_2^2)\omega^2}{2}\right) $$

となり、これは平均 $\mu_1+\mu_2$, 分散 $\sigma_1^2+\sigma_2^2$ の正規分布の特性関数です。畳み込み定理のおかげで、直接積分を計算するよりもはるかに簡潔に導出できます。

画像処理への応用

2次元の畳み込み定理は画像処理の基盤です。画像 $I(x, y)$ にカーネル(フィルタ)$K(x, y)$ を畳み込む操作は

$$ (I * K)(x, y) = \iint I(u, v)\, K(x-u, y-v)\, du\, dv $$

2次元フーリエ変換に拡張した畳み込み定理により

$$ \mathcal{F}_{\text{2D}}[I * K] = \hat{I} \cdot \hat{K} $$

大きな画像(例: $4096 \times 4096$ ピクセル)に大きなカーネル(例: $64 \times 64$)を適用する場合、直接計算では約 $4096^2 \times 64^2 \approx 7 \times 10^{10}$ 回の乗算が必要ですが、2次元FFTを使えば $O(N^2 \log N)$ に削減されます。

ガウシアンぼかしを例に考えると、ガウス関数のフーリエ変換もガウス関数なので、周波数領域でガウスフィルタを掛けることは高周波成分を滑らかに減衰させることに対応します。カーネルサイズが大きいほどカットオフ周波数が低くなり、ぼかしが強くなるという直感的な理解が畳み込み定理から得られます。

線形システム解析

線形時不変(LTI)システムでは、入力 $x(t)$ と出力 $y(t)$ の関係がインパルス応答 $h(t)$ との畳み込み $y = x * h$ で記述されます。畳み込み定理を適用すると

$$ Y(\omega) = X(\omega) \cdot H(\omega) $$

ここで $H(\omega)$ は伝達関数(周波数応答)です。これにより、システムの入出力関係が周波数ごとの独立な乗算に分解されます。

伝達関数 $H(\omega)$ の振幅 $|H(\omega)|$ はそれぞれの周波数成分をどれだけ増幅・減衰させるかを、位相 $\angle H(\omega)$ は各周波数成分をどれだけ遅延させるかを表します。たとえばローパスフィルタの伝達関数は低周波で $|H| \approx 1$(通過)、高周波で $|H| \approx 0$(遮断)となります。

まとめ

本記事では、畳み込み定理の理論的基盤から実践的な応用まで、体系的に解説しました。

  • 畳み込みは「一方の関数を反転・スライドさせて積分する」操作であり、線形システムの応答を記述する。直感的には「過去の入力が現在にどれだけ影響を残すかを全時刻にわたって足し合わせる」操作である
  • 畳み込み定理 $\mathcal{F}[f*g] = \hat{f} \cdot \hat{g}$ は時間領域の畳み込みを周波数領域の乗算に変換する。証明の核心は積分順序の交換(フビニの定理)と変数置換である
  • 逆定理 $\mathcal{F}[f \cdot g] = \frac{1}{2\pi}\hat{f} * \hat{g}$ は、窓関数による切り出し操作がスペクトルのにじみを引き起こすことを説明する
  • 高速畳み込み: FFT → 乗算 → IFFT により $O(N\log N)$ で畳み込みが計算でき、$N = 100{,}000$ では直接法の約6,000倍高速である
  • 離散版では巡回畳み込みとなるため、線形畳み込みにはゼロパディング($N \geq M + L – 1$)が必要
  • 相関定理 $\mathcal{F}[f \star g] = \overline{\hat{f}} \cdot \hat{g}$ は畳み込み定理の一般化であり、ウィーナー=ヒンチンの定理やパターンマッチングの基盤となる
  • 確率分布の和、画像処理、LTIシステム解析など、工学全般に幅広い応用がある

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