複素フーリエ級数

実数のフーリエ級数($\cos$, $\sin$)は複素指数関数 $e^{in\omega t}$ を用いて統一的に記述できます。複素フーリエ級数は数学的に簡潔であり、スペクトル解析の自然な表現です。

本記事の内容

  • 実フーリエ級数から複素形への変換
  • 複素フーリエ係数 $c_n$ の定義
  • 振幅スペクトルと位相スペクトル
  • Pythonでの計算と可視化

前提知識

実フーリエ級数から複素形へ

実フーリエ級数:

$$ f(t) = \frac{a_0}{2} + \sum_{n=1}^{\infty}(a_n\cos n\omega t + b_n\sin n\omega t) $$

オイラーの公式 $e^{i\theta} = \cos\theta + i\sin\theta$ を用いると:

$$ \cos n\omega t = \frac{e^{in\omega t} + e^{-in\omega t}}{2}, \quad \sin n\omega t = \frac{e^{in\omega t} – e^{-in\omega t}}{2i} $$

代入して整理すると:

$$ \boxed{f(t) = \sum_{n=-\infty}^{\infty} c_n e^{in\omega t}} $$

複素フーリエ係数

$$ \boxed{c_n = \frac{1}{T}\int_0^T f(t) e^{-in\omega t}\,dt} $$

実係数との関係:

$$ c_0 = \frac{a_0}{2}, \quad c_n = \frac{a_n – ib_n}{2}, \quad c_{-n} = \frac{a_n + ib_n}{2} = c_n^* $$

$f(t)$ が実関数のとき $c_{-n} = c_n^*$(複素共役)が成り立ちます。

振幅スペクトルと位相スペクトル

$$ |c_n| = \frac{1}{2}\sqrt{a_n^2 + b_n^2} \quad \text{(振幅)} $$

$$ \arg(c_n) = -\arctan\frac{b_n}{a_n} \quad \text{(位相)} $$

具体例:矩形波

周期 $T$、振幅 $A$ の矩形波:

$$ c_n = \begin{cases} 0 & (n\text{ が偶数}) \\ \frac{2A}{in\pi} & (n\text{ が奇数}) \end{cases} $$

$$ |c_n| = \frac{2A}{|n|\pi} \quad (n\text{ が奇数}) $$

Pythonでの可視化

import numpy as np
import matplotlib.pyplot as plt

# 矩形波の複素フーリエ係数
T = 2*np.pi; omega = 2*np.pi/T; A = 1
N_terms = 20

def rect_wave(t, T):
    return np.where(np.mod(t, T) < T/2, A, -A)

# 数値的にフーリエ係数を計算
t_int = np.linspace(0, T, 10000)
dt = t_int[1] - t_int[0]
f_vals = rect_wave(t_int, T)

n_range = np.arange(-N_terms, N_terms+1)
cn = np.zeros(len(n_range), dtype=complex)
for i, n in enumerate(n_range):
    cn[i] = np.sum(f_vals * np.exp(-1j*n*omega*t_int)) * dt / T

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

# (1) 振幅スペクトル
axes[0,0].stem(n_range, np.abs(cn), linefmt='b-', markerfmt='bo', basefmt='k-')
axes[0,0].set_xlabel('$n$'); axes[0,0].set_ylabel('$|c_n|$')
axes[0,0].set_title('Amplitude spectrum', fontsize=13); axes[0,0].grid(True, alpha=0.3)

# (2) 位相スペクトル
phase = np.angle(cn)
phase[np.abs(cn) < 1e-10] = 0
axes[0,1].stem(n_range, phase, linefmt='r-', markerfmt='ro', basefmt='k-')
axes[0,1].set_xlabel('$n$'); axes[0,1].set_ylabel('$\\arg(c_n)$ [rad]')
axes[0,1].set_title('Phase spectrum', fontsize=13); axes[0,1].grid(True, alpha=0.3)

# (3) 復元信号
t_plot = np.linspace(0, 2*T, 500)
f_reconstructed = np.zeros_like(t_plot, dtype=complex)
for i, n in enumerate(n_range):
    f_reconstructed += cn[i] * np.exp(1j*n*omega*t_plot)

axes[1,0].plot(t_plot, rect_wave(t_plot, T), 'k-', lw=1, alpha=0.5, label='Original')
axes[1,0].plot(t_plot, f_reconstructed.real, 'b-', lw=2, label=f'N={N_terms}')
axes[1,0].set_xlabel('$t$'); axes[1,0].set_ylabel('$f(t)$')
axes[1,0].set_title('Reconstruction', fontsize=13)
axes[1,0].legend(); axes[1,0].grid(True, alpha=0.3)

# (4) 項数による収束
for N in [1, 3, 5, 15]:
    f_N = np.zeros_like(t_plot, dtype=complex)
    for n in range(-N, N+1):
        idx = n + N_terms
        if 0 <= idx < len(cn):
            f_N += cn[idx] * np.exp(1j*n*omega*t_plot)
    axes[1,1].plot(t_plot, f_N.real, lw=1.5, label=f'N={N}')
axes[1,1].set_xlabel('$t$'); axes[1,1].set_ylabel('$f(t)$')
axes[1,1].set_title('Convergence', fontsize=13)
axes[1,1].legend(); axes[1,1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

まとめ

  • 複素フーリエ級数: $f(t) = \sum_{n=-\infty}^{\infty} c_n e^{in\omega t}$
  • 複素フーリエ係数: $c_n = \frac{1}{T}\int_0^T f(t)e^{-in\omega t}\,dt$
  • $c_{-n} = c_n^*$(実関数の場合)
  • 振幅・位相スペクトルで周波数成分を可視化

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