フーリエ級数展開の定義と導出をわかりやすく解説

フーリエ級数展開は、周期関数を三角関数(sin と cos)の無限和で表現する手法です。18世紀にジョゼフ・フーリエが熱伝導の研究で導入したこの方法は、現代の信号処理、量子力学、画像圧縮、音響工学など極めて幅広い分野で基盤的な役割を果たしています。

イメージとしては、「どんな複雑な形の周期的な波も、シンプルなサイン波とコサイン波を適切に重ね合わせることで再現できる」という考え方です。音楽で言えば、複雑な音色も基本的な純音の合成として理解できるということです。本記事では、この直感的な理解から出発して、数学的に厳密なフーリエ級数の導出を行い、Pythonで実際に級数近似を可視化します。

本記事の内容

  • フーリエ級数展開の直感的な理解
  • 三角関数の直交性の証明
  • フーリエ係数の数学的な導出
  • フーリエ級数の収束性
  • 矩形波のフーリエ級数展開(具体例)
  • Pythonでの実装と可視化

前提知識

この記事を読む前に、以下の知識があると理解が深まります。

  • 三角関数の基本的な性質(加法定理、積和公式)
  • 定積分の計算
  • 級数の収束に関する基礎知識

フーリエ級数展開とは

フーリエ級数展開とは、周期 $T$ を持つ関数 $f(x)$ を、三角関数の無限和として表現することです。大雑把に言うと、「複雑な波形を、異なる周波数の単純な波に分解する」操作に相当します。

たとえば、矩形波(カクカクした波形)を考えてみましょう。この波形はとても滑らかとは言えませんが、フーリエは「このような不連続な関数でさえ、三角関数の和で表現できる」ことを発見しました。

なぜこのような分解が可能なのでしょうか? その鍵は 三角関数の直交性 にあります。異なる周波数の三角関数どうしが「直交する」という性質を利用することで、各周波数成分の大きさ(フーリエ係数)を系統的に求めることができるのです。

数学的定義

フーリエ級数の定式化

周期 $2L$ の関数 $f(x)$ のフーリエ級数展開は、次のように定義されます。

$$ f(x) = \frac{a_0}{2} + \sum_{n=1}^{\infty} \left( a_n \cos\frac{n\pi x}{L} + b_n \sin\frac{n\pi x}{L} \right) $$

ここで、$a_0, a_n, b_n$ は フーリエ係数 と呼ばれ、以下の公式で計算されます。

$$ \begin{equation} a_0 = \frac{1}{L} \int_{-L}^{L} f(x) \, dx \end{equation} $$

$$ \begin{equation} a_n = \frac{1}{L} \int_{-L}^{L} f(x) \cos\frac{n\pi x}{L} \, dx \quad (n = 1, 2, 3, \dots) \end{equation} $$

$$ \begin{equation} b_n = \frac{1}{L} \int_{-L}^{L} f(x) \sin\frac{n\pi x}{L} \, dx \quad (n = 1, 2, 3, \dots) \end{equation} $$

$a_0 / 2$ は $f(x)$ の1周期にわたる平均値に対応し、$a_n$ は $\cos$ 成分の振幅、$b_n$ は $\sin$ 成分の振幅を表します。

三角関数の直交性の証明

フーリエ係数を導出するために、まず三角関数系の直交性を証明します。直交性とは、異なる周波数の三角関数どうしの内積(積の積分)がゼロになるという性質です。

直交関係式

区間 $[-L, L]$ において、以下の3つの直交関係が成り立ちます。

関係1: cos 同士の直交性

$$ \int_{-L}^{L} \cos\frac{m\pi x}{L} \cos\frac{n\pi x}{L} \, dx = \begin{cases} 0 & (m \neq n) \\ L & (m = n \neq 0) \\ 2L & (m = n = 0) \end{cases} $$

関係2: sin 同士の直交性

$$ \int_{-L}^{L} \sin\frac{m\pi x}{L} \sin\frac{n\pi x}{L} \, dx = \begin{cases} 0 & (m \neq n) \\ L & (m = n \neq 0) \end{cases} $$

関係3: cos と sin の直交性

$$ \int_{-L}^{L} \cos\frac{m\pi x}{L} \sin\frac{n\pi x}{L} \, dx = 0 \quad (\text{任意の } m, n) $$

関係1の証明(cos 同士)

$m \neq n$ の場合を証明します。積和公式を用いて変形します。

$$ \begin{align} &\int_{-L}^{L} \cos\frac{m\pi x}{L} \cos\frac{n\pi x}{L} \, dx \\ &= \frac{1}{2} \int_{-L}^{L} \left[ \cos\frac{(m-n)\pi x}{L} + \cos\frac{(m+n)\pi x}{L} \right] dx \\ &= \frac{1}{2} \left[ \frac{L}{(m-n)\pi} \sin\frac{(m-n)\pi x}{L} + \frac{L}{(m+n)\pi} \sin\frac{(m+n)\pi x}{L} \right]_{-L}^{L} \\ &= \frac{1}{2} \left[ \frac{L}{(m-n)\pi} \sin(m-n)\pi + \frac{L}{(m+n)\pi} \sin(m+n)\pi \right] \\ &\quad – \frac{1}{2} \left[ \frac{L}{(m-n)\pi} \sin\{-(m-n)\pi\} + \frac{L}{(m+n)\pi} \sin\{-(m+n)\pi\} \right] \\ &= \frac{L}{(m-n)\pi} \sin(m-n)\pi + \frac{L}{(m+n)\pi} \sin(m+n)\pi \\ &= 0 \quad (\because m-n, m+n \text{ は整数なので } \sin k\pi = 0) \end{align} $$

$m = n \neq 0$ の場合は、

$$ \begin{align} \int_{-L}^{L} \cos^2\frac{n\pi x}{L} \, dx &= \frac{1}{2} \int_{-L}^{L} \left( 1 + \cos\frac{2n\pi x}{L} \right) dx \\ &= \frac{1}{2} \left[ x + \frac{L}{2n\pi} \sin\frac{2n\pi x}{L} \right]_{-L}^{L} \\ &= \frac{1}{2} \left[ (L – (-L)) + \frac{L}{2n\pi}(\sin 2n\pi – \sin(-2n\pi)) \right] \\ &= \frac{1}{2} \cdot 2L = L \end{align} $$

関係3の証明(cos と sin)

$\cos\frac{m\pi x}{L}$ は偶関数、$\sin\frac{n\pi x}{L}$ は奇関数なので、その積は奇関数です。対称区間 $[-L, L]$ における奇関数の積分はゼロとなります。

$$ \int_{-L}^{L} \cos\frac{m\pi x}{L} \sin\frac{n\pi x}{L} \, dx = 0 $$

これは任意の整数 $m, n$ に対して成立します。

フーリエ係数の導出

三角関数の直交性を利用して、フーリエ係数の公式を導出します。

$a_n$ の導出

フーリエ級数の両辺に $\cos\frac{m\pi x}{L}$ を掛けて、区間 $[-L, L]$ で積分します。

$$ \begin{align} &\int_{-L}^{L} f(x) \cos\frac{m\pi x}{L} \, dx \\ &= \int_{-L}^{L} \frac{a_0}{2} \cos\frac{m\pi x}{L} \, dx + \sum_{n=1}^{\infty} a_n \int_{-L}^{L} \cos\frac{n\pi x}{L} \cos\frac{m\pi x}{L} \, dx \\ &\quad + \sum_{n=1}^{\infty} b_n \int_{-L}^{L} \sin\frac{n\pi x}{L} \cos\frac{m\pi x}{L} \, dx \end{align} $$

直交性により、右辺の第1項は $m \neq 0$ のとき $0$ になります。第3項は関係3からすべて $0$ です。第2項は $n = m$ の項だけが残ります。

$$ \begin{align} \int_{-L}^{L} f(x) \cos\frac{m\pi x}{L} \, dx &= a_m \int_{-L}^{L} \cos^2\frac{m\pi x}{L} \, dx \\ &= a_m \cdot L \end{align} $$

したがって、

$$ a_m = \frac{1}{L} \int_{-L}^{L} f(x) \cos\frac{m\pi x}{L} \, dx $$

$a_0$ の導出

フーリエ級数の両辺をそのまま区間 $[-L, L]$ で積分します。

$$ \begin{align} \int_{-L}^{L} f(x) \, dx &= \int_{-L}^{L} \frac{a_0}{2} \, dx + \sum_{n=1}^{\infty} a_n \int_{-L}^{L} \cos\frac{n\pi x}{L} \, dx + \sum_{n=1}^{\infty} b_n \int_{-L}^{L} \sin\frac{n\pi x}{L} \, dx \\ &= \frac{a_0}{2} \cdot 2L + 0 + 0 \\ &= a_0 L \end{align} $$

ここで、$\cos$ と $\sin$ の整数周期分の積分はすべて $0$ になることを使いました。よって、

$$ a_0 = \frac{1}{L} \int_{-L}^{L} f(x) \, dx $$

これは $a_n$ の公式で $n = 0$ とした場合と一致します。$a_0 / 2$ の形で級数に現れるのは、このような統一的な表記を可能にするためです。

$b_n$ の導出

フーリエ級数の両辺に $\sin\frac{m\pi x}{L}$ を掛けて区間 $[-L, L]$ で積分すると、$a_n$ と同様の議論により、

$$ \begin{align} \int_{-L}^{L} f(x) \sin\frac{m\pi x}{L} \, dx &= b_m \int_{-L}^{L} \sin^2\frac{m\pi x}{L} \, dx \\ &= b_m \cdot L \end{align} $$

したがって、

$$ b_m = \frac{1}{L} \int_{-L}^{L} f(x) \sin\frac{m\pi x}{L} \, dx $$

フーリエ級数の収束性

フーリエ級数がもとの関数にどのような意味で「等しく」なるかは、数学的に重要な問題です。ここでは主要な収束定理を紹介します。

ディリクレの収束定理

$f(x)$ が周期 $2L$ の関数で、1周期内で区分的に滑らか(有限個の不連続点を除いて微分可能で、不連続点では左右の極限値が存在する)であるとき、フーリエ級数は以下のように収束します。

$$ \frac{a_0}{2} + \sum_{n=1}^{\infty} \left( a_n \cos\frac{n\pi x}{L} + b_n \sin\frac{n\pi x}{L} \right) = \begin{cases} f(x) & (f \text{ が連続な点}) \\ \dfrac{f(x^+) + f(x^-)}{2} & (\text{不連続点}) \end{cases} $$

ここで、$f(x^+) = \lim_{h \to 0^+} f(x+h)$、$f(x^-) = \lim_{h \to 0^+} f(x-h)$ は右極限と左極限です。つまり、不連続点では左右の極限値の平均に収束します。

ギブズ現象

不連続点の近傍では、フーリエ級数の部分和にオーバーシュート(行き過ぎ)が現れます。これを ギブズ現象 と呼びます。項数を増やしてもオーバーシュートの大きさ(約9%)は変わらず、不連続点に近づくだけです。この現象は後ほどPythonの可視化で確認します。

具体例: 矩形波のフーリエ級数展開

周期 $2\pi$ の矩形波を考えます。

$$ f(x) = \begin{cases} 1 & (0 < x < \pi) \\ -1 & (-\pi < x < 0) \end{cases} $$

この関数は奇関数($f(-x) = -f(x)$)です。奇関数のフーリエ級数では $a_n = 0$(すべての $n$)となり、$\sin$ の項だけが残ります。

フーリエ係数の計算

$L = \pi$ として $b_n$ を計算します。

$$ \begin{align} b_n &= \frac{1}{\pi} \int_{-\pi}^{\pi} f(x) \sin(nx) \, dx \\ &= \frac{2}{\pi} \int_{0}^{\pi} \sin(nx) \, dx \quad (\because f(x)\sin(nx) \text{ は偶関数}) \\ &= \frac{2}{\pi} \left[ -\frac{1}{n} \cos(nx) \right]_{0}^{\pi} \\ &= \frac{2}{\pi} \left( -\frac{\cos(n\pi)}{n} + \frac{1}{n} \right) \\ &= \frac{2}{n\pi} (1 – \cos(n\pi)) \\ &= \frac{2}{n\pi} (1 – (-1)^n) \end{align} $$

$n$ が偶数のとき $1 – (-1)^n = 0$、$n$ が奇数のとき $1 – (-1)^n = 2$ なので、

$$ b_n = \begin{cases} \dfrac{4}{n\pi} & (n = 1, 3, 5, \dots) \\ 0 & (n = 2, 4, 6, \dots) \end{cases} $$

したがって、矩形波のフーリエ級数は、

$$ f(x) = \frac{4}{\pi} \left( \sin x + \frac{1}{3} \sin 3x + \frac{1}{5} \sin 5x + \cdots \right) = \frac{4}{\pi} \sum_{k=0}^{\infty} \frac{\sin(2k+1)x}{2k+1} $$

奇数次の高調波だけが現れるのが矩形波の特徴です。

Pythonでの実装

フーリエ級数近似の可視化

矩形波をフーリエ級数で近似し、項数を増やしていくとどのように収束するかを可視化します。

import numpy as np
import matplotlib.pyplot as plt

# 矩形波の定義
def square_wave(x):
    """周期2piの矩形波"""
    return np.sign(np.sin(x))

# フーリエ級数近似(矩形波)
def fourier_series_square(x, N):
    """矩形波のフーリエ級数近似(N項まで)"""
    result = np.zeros_like(x, dtype=float)
    for k in range(N):
        n = 2 * k + 1  # 奇数次のみ
        result += (4 / (n * np.pi)) * np.sin(n * x)
    return result

# 可視化
x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
f_exact = square_wave(x)

fig, axes = plt.subplots(2, 2, figsize=(12, 8))
terms_list = [1, 3, 10, 50]

for ax, N in zip(axes.ravel(), terms_list):
    f_approx = fourier_series_square(x, N)
    ax.plot(x, f_exact, 'k--', alpha=0.5, label='Square wave')
    ax.plot(x, f_approx, 'b-', linewidth=1.5, label=f'N = {N} terms')
    ax.set_xlim(-2 * np.pi, 2 * np.pi)
    ax.set_ylim(-1.5, 1.5)
    ax.set_xlabel('x')
    ax.set_ylabel('f(x)')
    ax.set_title(f'Fourier Series Approximation (N = {N})')
    ax.legend()
    ax.grid(True, alpha=0.3)

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

項数 $N = 1$ ではただの正弦波ですが、$N = 3$ で矩形波の輪郭が見え始め、$N = 10$ でかなり矩形波に近づきます。$N = 50$ ではほぼ完全に一致しますが、不連続点付近にわずかなオーバーシュート(ギブズ現象)が残っていることが確認できます。

ギブズ現象の詳細な可視化

不連続点付近のオーバーシュートを拡大して観察します。

import numpy as np
import matplotlib.pyplot as plt

# フーリエ級数近似(矩形波)
def fourier_series_square(x, N):
    """矩形波のフーリエ級数近似(N項まで)"""
    result = np.zeros_like(x, dtype=float)
    for k in range(N):
        n = 2 * k + 1
        result += (4 / (n * np.pi)) * np.sin(n * x)
    return result

# 不連続点付近を拡大
x_zoom = np.linspace(-0.5, 0.5, 2000)

fig, ax = plt.subplots(figsize=(10, 6))
for N in [10, 50, 200, 1000]:
    f_approx = fourier_series_square(x_zoom, N)
    ax.plot(x_zoom, f_approx, linewidth=1.2, label=f'N = {N}')

# 元の関数
ax.axhline(y=1, color='k', linestyle='--', alpha=0.5, label='Target value')
ax.axhline(y=-1, color='k', linestyle='--', alpha=0.5)
ax.axvline(x=0, color='gray', linestyle=':', alpha=0.5)

ax.set_xlabel('x')
ax.set_ylabel('f(x)')
ax.set_title('Gibbs Phenomenon near Discontinuity')
ax.legend()
ax.grid(True, alpha=0.3)
plt.savefig("gibbs_phenomenon.png", dpi=150, bbox_inches="tight")
plt.show()

項数を10, 50, 200, 1000と増やしても、不連続点でのオーバーシュート(約9%)は消えず、ピークが不連続点に近づいていくだけであることが確認できます。これがギブズ現象の本質です。

一般の関数に対するフーリエ係数の数値計算

解析的に係数が求まらない関数に対しても、数値積分によりフーリエ係数を計算できます。

import numpy as np
import matplotlib.pyplot as plt
from scipy import integrate

# フーリエ係数の数値計算
def compute_fourier_coefficients(f, L, N):
    """
    関数fのフーリエ係数a_n, b_nをN次まで数値計算する
    f: 周期2Lの関数
    L: 半周期
    N: 計算する最大次数
    """
    a = np.zeros(N + 1)
    b = np.zeros(N + 1)

    # a_0の計算
    a[0], _ = integrate.quad(f, -L, L)
    a[0] /= L

    for n in range(1, N + 1):
        # a_nの計算
        integrand_cos = lambda x, n=n: f(x) * np.cos(n * np.pi * x / L)
        a[n], _ = integrate.quad(integrand_cos, -L, L)
        a[n] /= L

        # b_nの計算
        integrand_sin = lambda x, n=n: f(x) * np.sin(n * np.pi * x / L)
        b[n], _ = integrate.quad(integrand_sin, -L, L)
        b[n] /= L

    return a, b

# フーリエ級数の再構成
def reconstruct_fourier(x, a, b, L):
    """フーリエ係数からもとの関数を再構成する"""
    N = len(a) - 1
    result = a[0] / 2 * np.ones_like(x)
    for n in range(1, N + 1):
        result += a[n] * np.cos(n * np.pi * x / L) + b[n] * np.sin(n * np.pi * x / L)
    return result

# 例: 三角波(周期2pi)
def triangle_wave(x):
    """周期2piの三角波"""
    return np.abs((x % (2 * np.pi)) - np.pi) - np.pi / 2

L = np.pi
N = 20
a, b = compute_fourier_coefficients(triangle_wave, L, N)

# 可視化
x = np.linspace(-2 * np.pi, 2 * np.pi, 1000)
f_exact = triangle_wave(x)

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

# 左: 関数の近似
for n_terms in [1, 5, 20]:
    f_approx = reconstruct_fourier(x, a[:n_terms+1], b[:n_terms+1], L)
    axes[0].plot(x, f_approx, label=f'N = {n_terms}')
axes[0].plot(x, f_exact, 'k--', alpha=0.5, label='Exact')
axes[0].set_xlabel('x')
axes[0].set_ylabel('f(x)')
axes[0].set_title('Triangle Wave - Fourier Approximation')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# 右: フーリエ係数のスペクトル
n_indices = np.arange(N + 1)
axes[1].stem(n_indices, np.abs(a), linefmt='b-', markerfmt='bo', basefmt='k-', label='|a_n|')
axes[1].stem(n_indices, np.abs(b), linefmt='r-', markerfmt='ro', basefmt='k-', label='|b_n|')
axes[1].set_xlabel('n')
axes[1].set_ylabel('Coefficient magnitude')
axes[1].set_title('Fourier Coefficients')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

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

三角波は連続関数なので、フーリエ係数は $1/n^2$ のオーダーで急速に減衰し、少ない項数でもよい近似が得られます。一方、矩形波のような不連続関数では係数が $1/n$ のオーダーでしか減衰しないため、多くの項が必要です。

まとめ

本記事では、フーリエ級数展開の定義と導出について解説しました。

  • フーリエ級数は、周期関数を三角関数の無限和で表現する手法です
  • 三角関数の直交性(積和公式を用いた証明)がフーリエ係数の導出の根幹にあります
  • フーリエ係数 $a_n, b_n$ は、関数と三角関数の内積として計算されます
  • ディリクレの収束定理により、区分的に滑らかな関数に対してフーリエ級数は収束します
  • 不連続点では左右の極限値の平均に収束し、ギブズ現象(約9%のオーバーシュート)が現れます
  • 矩形波のフーリエ級数は奇数次の高調波のみで構成されます

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