08. Fourier Transforms

08. Fourier Transforms

Learning Objectives

  • Understand the transition from Fourier series to Fourier transform and derive the spectral representation for aperiodic functions
  • Prove and apply key properties of Fourier transforms (linearity, shift, scaling, differentiation)
  • Calculate and physically interpret core transform pairs such as Gaussian, rectangular function, Dirac delta function
  • Understand the convolution theorem and apply it to practical applications such as signal filtering
  • Understand the principles of Discrete Fourier Transform (DFT) and FFT algorithms and explain the meaning of the Nyquist theorem
  • Apply Fourier transforms to physics applications such as uncertainty principle, Fraunhofer diffraction, and spectral analysis

1. From Fourier Series to Fourier Transform

1.1 Generalization from Periodic to Aperiodic Functions

The Fourier series of a function $f(x)$ with period $T$ can be written as:

$$f(x) = \sum_{n=-\infty}^{\infty} c_n \cdot \exp\left(i \cdot \frac{2\pi n x}{T}\right)$$

where the complex Fourier coefficients $c_n$ are:

$$c_n = \frac{1}{T} \int_{-T/2}^{T/2} f(x) \cdot \exp\left(-i \cdot \frac{2\pi n x}{T}\right) dx$$

Defining the fundamental frequency as $\omega_0 = 2\pi/T$ and the frequency spacing as $\Delta\omega = \omega_0 = 2\pi/T$:

$$f(x) = \sum_{n=-\infty}^{\infty} c_n \cdot \exp(i n \omega_0 x)$$

$$c_n = \frac{1}{T} \int_{-T/2}^{T/2} f(x) \cdot \exp(-i n \omega_0 x) \, dx$$

Key idea: As the period $T$ approaches infinity ($T \to \infty$), the discrete frequencies $n\omega_0$ become a continuous variable $\omega$, and the sum becomes an integral.

$$T \to \infty \quad \Rightarrow \quad \Delta\omega \to 0$$

$$n \omega_0 \to \omega \quad \text{(continuous variable)}$$

$$\sum \to \int$$

In this limit, defining $c_n \cdot T$ as a new function $F(\omega)$:

$$F(\omega) = \lim_{T \to \infty} c_n \cdot T = \int_{-\infty}^{\infty} f(x) \cdot e^{-i\omega x} \, dx$$

This is precisely the Fourier transform.

1.2 Definition of Continuous Fourier Transform

Fourier Transform:

$$F(\omega) = \int_{-\infty}^{\infty} f(x) \cdot e^{-i\omega x} \, dx$$

Inverse Fourier Transform:

$$f(x) = \frac{1}{2\pi} \int_{-\infty}^{\infty} F(\omega) \cdot e^{i\omega x} \, d\omega$$

Note on conventions: The placement of the $2\pi$ factor varies across textbooks and disciplines. The Boas textbook follows the above convention, while physics often uses a symmetric convention ($1/\sqrt{2\pi}$ on both sides). Any convention works as long as the transform-inverse transform pair is consistent.

Existence condition: If $f(x)$ is absolutely integrable, the Fourier transform exists:

$$\int_{-\infty}^{\infty} |f(x)| \, dx < \infty$$

import numpy as np
import matplotlib.pyplot as plt
from scipy import fft as sp_fft

# 예제: μ£ΌκΈ° Tλ₯Ό μ¦κ°€μ‹œν‚€λ©΄μ„œ 이산 μŠ€νŽ™νŠΈλŸΌ -> 연속 μŠ€νŽ™νŠΈλŸΌμœΌλ‘œμ˜ μ „ν™˜ κ΄€μ°°

fig, axes = plt.subplots(2, 3, figsize=(15, 8))
periods = [2, 5, 20]

for idx, T in enumerate(periods):
    # μœ ν•œ κ΅¬κ°„μ—μ„œμ˜ κ°€μš°μ‹œμ•ˆ ν•¨μˆ˜
    x = np.linspace(-T/2, T/2, 1000)
    sigma = 0.5
    f_x = np.exp(-x**2 / (2 * sigma**2))

    # μ‹œκ°„ μ˜μ—­
    axes[0, idx].plot(x, f_x, 'b-', linewidth=1.5)
    axes[0, idx].set_title(f'f(x), T = {T}')
    axes[0, idx].set_xlabel('x')
    axes[0, idx].set_xlim(-5, 5)
    axes[0, idx].grid(True, alpha=0.3)

    # 푸리에 κ³„μˆ˜ (이산 μŠ€νŽ™νŠΈλŸΌ)
    n_max = 30
    n_vals = np.arange(-n_max, n_max + 1)
    omega_0 = 2 * np.pi / T
    c_n = []
    for n in n_vals:
        integrand = f_x * np.exp(-1j * n * omega_0 * x)
        cn = np.trapz(integrand, x) / T
        c_n.append(np.abs(cn))

    omega_vals = n_vals * omega_0
    axes[1, idx].stem(omega_vals, c_n, linefmt='b-', markerfmt='bo', basefmt='k-')
    axes[1, idx].set_title(f'|c_n|, T = {T}')
    axes[1, idx].set_xlabel('omega')
    axes[1, idx].set_xlim(-15, 15)
    axes[1, idx].grid(True, alpha=0.3)

plt.suptitle('μ£ΌκΈ° T 증가 β†’ 이산 μŠ€νŽ™νŠΈλŸΌμ΄ 연속 μŠ€νŽ™νŠΈλŸΌμ— μ ‘κ·Ό', fontsize=14)
plt.tight_layout()
plt.savefig('fourier_discrete_to_continuous.png', dpi=150, bbox_inches='tight')
plt.show()

2. Properties of Fourier Transform

2.1 Linearity and Symmetry

Linearity: The Fourier transform is a linear operator:

$$\mathcal{F}[a f(x) + b g(x)] = a F(\omega) + b G(\omega)$$

where $a, b$ are constants, and $F(\omega) = \mathcal{F}[f]$, $G(\omega) = \mathcal{F}[g]$.

Symmetry (Duality):

If the Fourier transform of $f(x)$ is $F(\omega)$, then:

$$\mathcal{F}[F(x)] = 2\pi f(-\omega)$$

That is, swapping the roles of time and frequency domains returns the original function (reflected).

Symmetry for real functions: If $f(x)$ is real:

$$F(-\omega) = F^*(\omega) \quad \text{(Hermitian symmetry)}$$

$$|F(-\omega)| = |F(\omega)| \quad \text{(magnitude spectrum is even)}$$

2.2 Time Shift and Frequency Shift

Time Shift: Shifting a function by $x_0$ only changes the phase in the frequency domain:

$$\mathcal{F}[f(x - x_0)] = e^{-i\omega x_0} \cdot F(\omega)$$

The magnitude spectrum $|F(\omega)|$ remains unchanged; only the phase changes by $\omega x_0$.

Frequency Shift (Modulation): Shifting by $\omega_0$ in the frequency domain:

$$\mathcal{F}[f(x) \cdot e^{i\omega_0 x}] = F(\omega - \omega_0)$$

This is the principle of modulation in communications. Multiplying by a carrier frequency $\omega_0$ shifts the spectrum by $\omega_0$.

2.3 Scaling Theorem

When the time axis of a function is compressed/expanded by a factor $a$:

$$\mathcal{F}[f(ax)] = \frac{1}{|a|} F\left(\frac{\omega}{a}\right)$$

Physical meaning: If a signal becomes narrower in the time domain ($a > 1$), it becomes broader in the frequency domain. This is the mathematical basis of the uncertainty principle.

import numpy as np
import matplotlib.pyplot as plt

# μŠ€μΌ€μΌλ§ 정리 μ‹œκ°ν™”: 쒁은 νŽ„μŠ€ ↔ 넓은 μŠ€νŽ™νŠΈλŸΌ

fig, axes = plt.subplots(2, 3, figsize=(15, 8))
a_values = [0.5, 1.0, 2.0]

x = np.linspace(-5, 5, 1000)
dx = x[1] - x[0]
omega = np.linspace(-10, 10, 1000)

for idx, a in enumerate(a_values):
    # κ°€μš°μ‹œμ•ˆ: f(ax) = exp(-(ax)^2 / 2)
    f = np.exp(-(a * x)**2 / 2)

    # 해석적 푸리에 λ³€ν™˜: (1/|a|) * sqrt(2*pi) * exp(-omega^2 / (2*a^2))
    F_analytical = (1 / abs(a)) * np.sqrt(2 * np.pi) * np.exp(-omega**2 / (2 * a**2))

    axes[0, idx].plot(x, f, 'b-', linewidth=2)
    axes[0, idx].set_title(f'f({a}x) = exp(-({a}x)Β²/2)')
    axes[0, idx].set_xlabel('x')
    axes[0, idx].set_ylim(-0.1, 1.5)
    axes[0, idx].grid(True, alpha=0.3)

    axes[1, idx].plot(omega, F_analytical, 'r-', linewidth=2)
    axes[1, idx].set_title(f'F(omega), a = {a}')
    axes[1, idx].set_xlabel('omega')
    axes[1, idx].set_ylim(-0.1, 6)
    axes[1, idx].grid(True, alpha=0.3)

plt.suptitle('μŠ€μΌ€μΌλ§ 정리: 쒁은 νŽ„μŠ€ ↔ 넓은 μŠ€νŽ™νŠΈλŸΌ', fontsize=14)
plt.tight_layout()
plt.savefig('scaling_theorem.png', dpi=150, bbox_inches='tight')
plt.show()

2.4 Differentiation and Integration

Differentiation theorem: Differentiation in the time domain corresponds to multiplication by $i\omega$ in the frequency domain:

$$\mathcal{F}[f'(x)] = i\omega \cdot F(\omega)$$

$$\mathcal{F}[f^{(n)}(x)] = (i\omega)^n \cdot F(\omega)$$

This property allows transforming differential equations into algebraic equations.

Example: Heat equation

$$\frac{\partial u}{\partial t} = k \frac{\partial^2 u}{\partial x^2}$$

Applying Fourier transform in $x$ to both sides:

$$\frac{dU}{dt} = k (i\omega)^2 U = -k\omega^2 U$$

This is an ODE with $\omega$ as a parameter, with solution:

$$U(\omega, t) = U(\omega, 0) \cdot e^{-k\omega^2 t}$$

Differentiation in frequency domain: Differentiation in frequency corresponds to multiplying by $-ix$ in time domain:

$$\mathcal{F}[-ix \cdot f(x)] = F'(\omega)$$

$$\mathcal{F}[(-ix)^n \cdot f(x)] = F^{(n)}(\omega)$$


3. Important Transform Pairs

3.1 Gaussian Function

The Fourier transform of a Gaussian is again a Gaussian. This property makes the Gaussian special:

$$f(x) = e^{-ax^2} \quad (a > 0)$$

$$F(\omega) = \sqrt{\frac{\pi}{a}} \cdot e^{-\omega^2/(4a)}$$

Proof sketch: Completing the square in the exponential:

$$F(\omega) = \int_{-\infty}^{\infty} e^{-ax^2} \cdot e^{-i\omega x} \, dx$$

$$= \int_{-\infty}^{\infty} \exp\left[-a\left(x + \frac{i\omega}{2a}\right)^2 - \frac{\omega^2}{4a}\right] dx$$

$$= e^{-\omega^2/(4a)} \sqrt{\frac{\pi}{a}}$$

The last step uses the Gaussian integral: $\int e^{-au^2} \, du = \sqrt{\pi/a}$.

Key point: The Gaussian is an eigenfunction of the Fourier transform β€” its form is preserved under transformation. The product of the width in time domain $\sigma_x = 1/\sqrt{2a}$ and the width in frequency domain $\sigma_\omega = \sqrt{2a}$ is always constant: $\sigma_x \cdot \sigma_\omega = 1$.

3.2 Rectangle Function (rect) and sinc Function

Rectangle function:

$$\text{rect}(x/a) = \begin{cases} 1, & |x| < a/2 \\ 0, & |x| > a/2 \end{cases}$$

Fourier transform:

$$\mathcal{F}[\text{rect}(x/a)] = a \cdot \text{sinc}\left(\frac{\omega a}{2\pi}\right) = a \cdot \frac{\sin(\omega a/2)}{\omega a/2}$$

where the sinc function is $\text{sinc}(u) = \sin(\pi u) / (\pi u)$.

import numpy as np
import matplotlib.pyplot as plt

fig, axes = plt.subplots(2, 3, figsize=(15, 8))
widths = [1.0, 2.0, 4.0]

for idx, a in enumerate(widths):
    # μ§μ‚¬κ°ν˜• ν•¨μˆ˜
    x = np.linspace(-5, 5, 1000)
    rect = np.where(np.abs(x) < a / 2, 1.0, 0.0)

    # 해석적 푸리에 λ³€ν™˜: a * sin(omega*a/2) / (omega*a/2)
    omega = np.linspace(-20, 20, 1000)
    # omega = 0일 λ•Œ 특이점 처리
    with np.errstate(divide='ignore', invalid='ignore'):
        F_omega = a * np.sinc(omega * a / (2 * np.pi))

    axes[0, idx].plot(x, rect, 'b-', linewidth=2)
    axes[0, idx].set_title(f'rect(x/{a}), 폭 = {a}')
    axes[0, idx].set_xlabel('x')
    axes[0, idx].set_ylim(-0.2, 1.5)
    axes[0, idx].grid(True, alpha=0.3)

    axes[1, idx].plot(omega, F_omega, 'r-', linewidth=1.5)
    axes[1, idx].set_title(f'F(omega), a = {a}')
    axes[1, idx].set_xlabel('omega')
    axes[1, idx].grid(True, alpha=0.3)

plt.suptitle('μ§μ‚¬κ°ν˜• ν•¨μˆ˜ ↔ sinc ν•¨μˆ˜: 폭이 λ„“μ„μˆ˜λ‘ μŠ€νŽ™νŠΈλŸΌμ΄ 쒁음', fontsize=14)
plt.tight_layout()
plt.savefig('rect_sinc_pair.png', dpi=150, bbox_inches='tight')
plt.show()

Physical meaning: A narrow slit (small rect width) creates a wide diffraction pattern (broad sinc), and a wide slit creates a narrow diffraction pattern. This is the essence of Fraunhofer diffraction.

3.3 Dirac Delta Function

The Dirac delta function $\delta(x)$ is a distribution satisfying:

$$\int_{-\infty}^{\infty} \delta(x) \cdot g(x) \, dx = g(0)$$

$$\delta(x) = 0 \quad (x \neq 0)$$

$$\int_{-\infty}^{\infty} \delta(x) \, dx = 1$$

Fourier transform of Dirac delta:

$$\mathcal{F}[\delta(x)] = \int_{-\infty}^{\infty} \delta(x) \cdot e^{-i\omega x} \, dx = 1$$

That is, the spectrum of a Dirac delta is uniformly spread across all frequencies β€” a white spectrum.

Conversely: The Fourier transform of the constant function 1 is $2\pi\delta(\omega)$:

$$\mathcal{F}[1] = 2\pi \delta(\omega)$$

Physical meaning: An infinitely short impulse in the time domain contains all frequency components equally. Conversely, a pure tone lasting forever (constant) has only a single frequency.

Shifted delta function:

$$\mathcal{F}[\delta(x - x_0)] = e^{-i\omega x_0}$$

$$\mathcal{F}[e^{i\omega_0 x}] = 2\pi \delta(\omega - \omega_0)$$

3.4 Table of Major Transform Pairs

$f(x)$ $F(\omega)$ Notes
$e^{-a|x|}$ $\frac{2a}{a^2 + \omega^2}$ Lorentzian
$e^{-ax^2}$ $\sqrt{\pi/a} \cdot e^{-\omega^2/(4a)}$ Gaussian
$\text{rect}(x/a)$ $a \cdot \text{sinc}(\omega a/(2\pi))$ Rectangle ↔ sinc
$\delta(x)$ $1$ Impulse ↔ white
$1$ $2\pi\delta(\omega)$ Constant ↔ DC
$e^{i\omega_0 x}$ $2\pi\delta(\omega - \omega_0)$ Complex exponential
$\cos(\omega_0 x)$ $\pi[\delta(\omega-\omega_0) + \delta(\omega+\omega_0)]$ Cosine
$x^n e^{-a|x|}$ $\frac{d^n}{d\omega^n}\left[\frac{2a}{a^2+\omega^2}\right]$ modified Damped polynomial
$\frac{1}{x^2 + a^2}$ $\frac{\pi}{a} e^{-a|\omega|}$ Lorentz inverse
$e^{-ax} u(x)$ $\frac{1}{a + i\omega}$ One-sided exponential, $u(x)$=step function

4. Convolution Theorem

4.1 Definition of Convolution

The convolution of two functions $f(x)$ and $g(x)$ is defined as:

$$(f * g)(x) = \int_{-\infty}^{\infty} f(t) \cdot g(x - t) \, dt$$

Geometrically, this operation reflects $g$, slides it over $f$, and calculates the overlapping area.

Commutativity of convolution: $f * g = g * f$

4.2 Time Domain Convolution ↔ Frequency Domain Multiplication

Convolution Theorem:

$$\mathcal{F}[f * g] = F(\omega) \cdot G(\omega)$$

That is, convolution in the time domain corresponds to multiplication in the frequency domain.

The converse also holds:

$$\mathcal{F}[f \cdot g] = \frac{1}{2\pi} (F * G)(\omega) \quad \text{(transform of product)}$$

Multiplication in the time domain corresponds to convolution in the frequency domain.

Proof:

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

Exchanging the order of integration and substituting $u = x - t$:

$$= \int_{-\infty}^{\infty} f(t) e^{-i\omega t} \, dt \cdot \int_{-\infty}^{\infty} g(u) e^{-i\omega u} \, du = F(\omega) \cdot G(\omega)$$

4.3 Application: Filtering

The most important application of the convolution theorem is signal filtering.

Passing an input signal $x(t)$ through a filter $h(t)$:

$$y(t) = (x * h)(t) \quad \text{(time domain: convolution)}$$

$$Y(\omega) = X(\omega) \cdot H(\omega) \quad \text{(frequency domain: multiplication)}$$

$H(\omega)$ is called the transfer function or frequency response.

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import fftconvolve

# μ»¨λ³Όλ£¨μ…˜ 정리 μ‹œκ°ν™”: μ‹ ν˜Έ 필터링

np.random.seed(42)
N = 1024
dt = 0.01
t = np.arange(N) * dt

# 원본 μ‹ ν˜Έ: κΉ¨λ—ν•œ μ‚¬μΈνŒŒ + 작음
freq_signal = 5.0  # 5 Hz μ‹ ν˜Έ
signal_clean = np.sin(2 * np.pi * freq_signal * t)
noise = 0.5 * np.random.randn(N)
signal_noisy = signal_clean + noise

# κ°€μš°μ‹œμ•ˆ 저역톡과 ν•„ν„° (Low-pass filter)
sigma_filter = 0.05
t_filter = np.arange(-50, 51) * dt
h = np.exp(-t_filter**2 / (2 * sigma_filter**2))
h /= h.sum()  # μ •κ·œν™”

# μ‹œκ°„ μ˜μ—­ μ»¨λ³Όλ£¨μ…˜
signal_filtered = fftconvolve(signal_noisy, h, mode='same')

# 주파수 μ˜μ—­ 확인
freqs = np.fft.fftfreq(N, dt)
X_noisy = np.fft.fft(signal_noisy)
H_freq = np.fft.fft(h, N)  # ν•„ν„°λ₯Ό 같은 길이둜 FFT
Y_freq = X_noisy * H_freq

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

# μ‹œκ°„ μ˜μ—­
axes[0, 0].plot(t, signal_noisy, 'gray', alpha=0.7, label='작음 μ‹ ν˜Έ')
axes[0, 0].plot(t, signal_clean, 'b-', linewidth=2, label='원본 μ‹ ν˜Έ')
axes[0, 0].set_title('μž…λ ₯ μ‹ ν˜Έ (μ‹œκ°„ μ˜μ—­)')
axes[0, 0].set_xlabel('t (s)')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

axes[1, 0].plot(t_filter, h, 'g-', linewidth=2)
axes[1, 0].set_title('κ°€μš°μ‹œμ•ˆ ν•„ν„° h(t)')
axes[1, 0].set_xlabel('t (s)')
axes[1, 0].grid(True, alpha=0.3)

axes[2, 0].plot(t, signal_filtered, 'r-', linewidth=2, label='필터링 κ²°κ³Ό')
axes[2, 0].plot(t, signal_clean, 'b--', linewidth=1, label='원본 μ‹ ν˜Έ')
axes[2, 0].set_title('좜λ ₯ μ‹ ν˜Έ y(t) = (x * h)(t)')
axes[2, 0].set_xlabel('t (s)')
axes[2, 0].legend()
axes[2, 0].grid(True, alpha=0.3)

# 주파수 μ˜μ—­
mask = freqs >= 0
axes[0, 1].plot(freqs[mask], np.abs(X_noisy[mask]) / N, 'gray', alpha=0.7)
axes[0, 1].set_title('|X(omega)| μž…λ ₯ μŠ€νŽ™νŠΈλŸΌ')
axes[0, 1].set_xlabel('주파수 (Hz)')
axes[0, 1].set_xlim(0, 50)
axes[0, 1].grid(True, alpha=0.3)

axes[1, 1].plot(freqs[mask], np.abs(H_freq[mask]), 'g-', linewidth=2)
axes[1, 1].set_title('|H(omega)| ν•„ν„° 주파수 응닡')
axes[1, 1].set_xlabel('주파수 (Hz)')
axes[1, 1].set_xlim(0, 50)
axes[1, 1].grid(True, alpha=0.3)

axes[2, 1].plot(freqs[mask], np.abs(Y_freq[mask]) / N, 'r-', linewidth=2)
axes[2, 1].set_title('|Y(omega)| = |X(omega)| * |H(omega)|')
axes[2, 1].set_xlabel('주파수 (Hz)')
axes[2, 1].set_xlim(0, 50)
axes[2, 1].grid(True, alpha=0.3)

plt.suptitle('μ»¨λ³Όλ£¨μ…˜ 정리: μ‹œκ°„ μ˜μ—­ μ»¨λ³Όλ£¨μ…˜ = 주파수 μ˜μ—­ κ³±μ…ˆ', fontsize=14)
plt.tight_layout()
plt.savefig('convolution_theorem.png', dpi=150, bbox_inches='tight')
plt.show()

5. Discrete Fourier Transform (DFT) and FFT

5.1 From Continuous to Discrete

Real measurement data is not continuous but sampled at regular intervals $\Delta t$:

$$x_n = f(n \Delta t), \quad n = 0, 1, 2, \ldots, N-1$$

With $N$ samples total, the entire observation time is $T = N \Delta t$.

Approximating the integral of the continuous Fourier transform with a discrete sum yields the DFT.

5.2 Definition of DFT

Discrete Fourier Transform (DFT):

$$X_k = \sum_{n=0}^{N-1} x_n \cdot \exp\left(-i \frac{2\pi k n}{N}\right), \quad k = 0, 1, \ldots, N-1$$

Inverse DFT:

$$x_n = \frac{1}{N} \sum_{k=0}^{N-1} X_k \cdot \exp\left(i \frac{2\pi k n}{N}\right), \quad n = 0, 1, \ldots, N-1$$

Frequency resolution: The physical frequency corresponding to the $k$-th frequency component is:

$$f_k = \frac{k}{N \Delta t} = \frac{k}{T}$$

The frequency resolution $\Delta f = 1/T$ is inversely proportional to the observation time.

5.3 Overview of FFT Algorithm

Direct computation of the DFT requires $O(N^2)$ operations. The Fast Fourier Transform (FFT) reduces this to $O(N \log N)$.

Cooley-Tukey algorithm (1965) key idea:

  1. Split the DFT of $N$ points into DFTs of $N/2$ even and $N/2$ odd indices:

$$X_k = \sum_{\text{even } n} x_n W^{kn} + \sum_{\text{odd } n} x_n W^{kn} = E_k + W^k O_k$$

where $W = \exp(-i 2\pi / N)$ (twiddle factor)

  1. Recursively repeating this process completes in $\log_2(N)$ stages.
import numpy as np
import time
import matplotlib.pyplot as plt

# DFT vs FFT 계산 μ‹œκ°„ 비ꡐ

def dft_naive(x):
    """μˆœμ§„ν•œ DFT κ΅¬ν˜„: O(N^2)"""
    N = len(x)
    X = np.zeros(N, dtype=complex)
    for k in range(N):
        for n in range(N):
            X[k] += x[n] * np.exp(-2j * np.pi * k * n / N)
    return X

# λ‹€μ–‘ν•œ ν¬κΈ°μ—μ„œ μ‹œκ°„ μΈ‘μ •
sizes = [64, 128, 256, 512, 1024]
times_dft = []
times_fft = []

for N in sizes:
    x = np.random.randn(N)

    # DFT (μˆœμ§„ν•œ κ΅¬ν˜„)
    t_start = time.perf_counter()
    X_dft = dft_naive(x)
    t_dft = time.perf_counter() - t_start
    times_dft.append(t_dft)

    # FFT (NumPy)
    t_start = time.perf_counter()
    X_fft = np.fft.fft(x)
    t_fft = time.perf_counter() - t_start
    times_fft.append(t_fft)

    # κ²°κ³Ό 검증
    error = np.max(np.abs(X_dft - X_fft))
    print(f"N={N:5d}: DFT={t_dft:.4f}s, FFT={t_fft:.6f}s, "
          f"speedup={t_dft/t_fft:.0f}x, max_error={error:.2e}")

plt.figure(figsize=(10, 6))
plt.loglog(sizes, times_dft, 'ro-', label='DFT O(NΒ²)', markersize=8)
plt.loglog(sizes, times_fft, 'bs-', label='FFT O(N log N)', markersize=8)
plt.xlabel('N (데이터 크기)')
plt.ylabel('계산 μ‹œκ°„ (초)')
plt.title('DFT vs FFT 계산 μ‹œκ°„ 비ꡐ')
plt.legend(fontsize=12)
plt.grid(True, alpha=0.3)
plt.savefig('dft_vs_fft_timing.png', dpi=150, bbox_inches='tight')
plt.show()

5.4 Nyquist Theorem and Aliasing

Nyquist-Shannon Sampling Theorem:

When the maximum frequency in a signal is $f_{\max}$, the sampling frequency $f_s$ must be at least $2f_{\max}$ to perfectly reconstruct the original signal.

$$f_s \geq 2 f_{\max} \quad \text{(Nyquist condition)}$$

$$f_{\text{Nyquist}} = \frac{f_s}{2} \quad \text{(Nyquist frequency: maximum representable frequency)}$$

Aliasing: When the Nyquist condition is not satisfied, high-frequency components incorrectly fold into low frequencies.

import numpy as np
import matplotlib.pyplot as plt

# 앨리어싱 μ‹œκ°ν™”

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

# 원본 연속 μ‹ ν˜Έ: 10 Hz μ‚¬μΈνŒŒ
f_signal = 10.0  # Hz
t_continuous = np.linspace(0, 1, 10000)
signal_continuous = np.sin(2 * np.pi * f_signal * t_continuous)

# μΌ€μ΄μŠ€ 1: μΆ©λΆ„ν•œ μƒ˜ν”Œλ§ (f_s = 50 Hz > 2 * 10 Hz)
f_s_good = 50.0
t_good = np.arange(0, 1, 1/f_s_good)
signal_good = np.sin(2 * np.pi * f_signal * t_good)

# μΌ€μ΄μŠ€ 2: λΆ€μ‘±ν•œ μƒ˜ν”Œλ§ (f_s = 12 Hz < 2 * 10 Hz)
f_s_bad = 12.0
t_bad = np.arange(0, 1, 1/f_s_bad)
signal_bad = np.sin(2 * np.pi * f_signal * t_bad)

# μ•¨λ¦¬μ–΄μ‹±λœ 주파수: |f_signal - f_s_bad| = |10 - 12| = 2 Hz
f_alias = abs(f_signal - f_s_bad)
signal_alias = np.sin(2 * np.pi * f_alias * t_continuous)

# μ‹œκ°„ μ˜μ—­: μΆ©λΆ„ν•œ μƒ˜ν”Œλ§
axes[0, 0].plot(t_continuous, signal_continuous, 'b-', alpha=0.3, label=f'원본 {f_signal} Hz')
axes[0, 0].stem(t_good, signal_good, linefmt='b-', markerfmt='bo', basefmt='k-')
axes[0, 0].set_title(f'μΆ©λΆ„ν•œ μƒ˜ν”Œλ§: f_s = {f_s_good} Hz')
axes[0, 0].set_xlabel('t (s)')
axes[0, 0].set_xlim(0, 0.5)
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# μ‹œκ°„ μ˜μ—­: λΆ€μ‘±ν•œ μƒ˜ν”Œλ§
axes[0, 1].plot(t_continuous, signal_continuous, 'b-', alpha=0.3, label=f'원본 {f_signal} Hz')
axes[0, 1].plot(t_continuous, signal_alias, 'r--', alpha=0.5, label=f'μ•¨λ¦¬μ–΄μŠ€ {f_alias} Hz')
axes[0, 1].stem(t_bad, signal_bad, linefmt='r-', markerfmt='ro', basefmt='k-')
axes[0, 1].set_title(f'λΆ€μ‘±ν•œ μƒ˜ν”Œλ§: f_s = {f_s_bad} Hz (앨리어싱 λ°œμƒ!)')
axes[0, 1].set_xlabel('t (s)')
axes[0, 1].set_xlim(0, 0.5)
axes[0, 1].legend()
axes[0, 1].grid(True, alpha=0.3)

# 주파수 μ˜μ—­: μΆ©λΆ„ν•œ μƒ˜ν”Œλ§
N_good = len(signal_good)
freqs_good = np.fft.fftfreq(N_good, 1/f_s_good)
X_good = np.fft.fft(signal_good) / N_good
mask_good = freqs_good >= 0
axes[1, 0].stem(freqs_good[mask_good], 2 * np.abs(X_good[mask_good]),
                linefmt='b-', markerfmt='bo', basefmt='k-')
axes[1, 0].axvline(x=f_s_good/2, color='g', linestyle='--', label=f'f_Nyquist = {f_s_good/2} Hz')
axes[1, 0].set_title('μŠ€νŽ™νŠΈλŸΌ (μΆ©λΆ„ν•œ μƒ˜ν”Œλ§)')
axes[1, 0].set_xlabel('주파수 (Hz)')
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)

# 주파수 μ˜μ—­: λΆ€μ‘±ν•œ μƒ˜ν”Œλ§
N_bad = len(signal_bad)
freqs_bad = np.fft.fftfreq(N_bad, 1/f_s_bad)
X_bad = np.fft.fft(signal_bad) / N_bad
mask_bad = freqs_bad >= 0
axes[1, 1].stem(freqs_bad[mask_bad], 2 * np.abs(X_bad[mask_bad]),
                linefmt='r-', markerfmt='ro', basefmt='k-')
axes[1, 1].axvline(x=f_s_bad/2, color='g', linestyle='--', label=f'f_Nyquist = {f_s_bad/2} Hz')
axes[1, 1].set_title('μŠ€νŽ™νŠΈλŸΌ (λΆ€μ‘±ν•œ μƒ˜ν”Œλ§ β†’ 앨리어싱)')
axes[1, 1].set_xlabel('주파수 (Hz)')
axes[1, 1].legend()
axes[1, 1].grid(True, alpha=0.3)

plt.suptitle('λ‚˜μ΄ν€΄μŠ€νŠΈ 정리와 앨리어싱', fontsize=14)
plt.tight_layout()
plt.savefig('nyquist_aliasing.png', dpi=150, bbox_inches='tight')
plt.show()

6. Physics Applications

6.1 Uncertainty Principle (Time-Frequency Relation)

Mathematical uncertainty principle: For any function $f(x)$ and its Fourier transform $F(\omega)$:

$$\Delta x \cdot \Delta\omega \geq \frac{1}{2}$$

where $\Delta x$, $\Delta\omega$ are standard deviations in time/frequency domains.

Connection to quantum mechanics: By the de Broglie relation $p = \hbar k$ ($k = 2\pi/\lambda$), this becomes the position-momentum uncertainty principle:

$$\Delta x \cdot \Delta p \geq \frac{\hbar}{2}$$

This is a fundamental principle of quantum mechanics, but its mathematical essence is a property of the Fourier transform.

import numpy as np
import matplotlib.pyplot as plt

# λΆˆν™•μ •μ„± 원리 μ‹œκ°ν™”: κ°€μš°μ‹œμ•ˆ νŒŒλ™ νŒ¨ν‚·

fig, axes = plt.subplots(2, 3, figsize=(16, 9))
sigmas = [0.5, 1.0, 2.0]  # μœ„μΉ˜ κ³΅κ°„μ—μ„œμ˜ 폭

x = np.linspace(-10, 10, 2000)
k = np.linspace(-10, 10, 2000)

for idx, sigma_x in enumerate(sigmas):
    # μœ„μΉ˜ 곡간 νŒŒλ™ν•¨μˆ˜ (κ°€μš°μ‹œμ•ˆ νŒŒλ™ νŒ¨ν‚·)
    k0 = 3.0  # 쀑심 파수
    psi_x = (1 / (2 * np.pi * sigma_x**2)**0.25) * \
            np.exp(-x**2 / (4 * sigma_x**2)) * np.exp(1j * k0 * x)

    # μš΄λ™λŸ‰ 곡간 νŒŒλ™ν•¨μˆ˜ (푸리에 λ³€ν™˜)
    sigma_k = 1 / (2 * sigma_x)  # μš΄λ™λŸ‰ κ³΅κ°„μ˜ 폭
    psi_k = (2 * sigma_x**2 / np.pi)**0.25 * \
            np.exp(-(k - k0)**2 * sigma_x**2)

    # λΆˆν™•μ •μ„± κ³±
    product = sigma_x * sigma_k

    # μœ„μΉ˜ 곡간
    axes[0, idx].plot(x, np.abs(psi_x)**2, 'b-', linewidth=2, label=f'|psi(x)|^2')
    axes[0, idx].fill_between(x, np.abs(psi_x)**2, alpha=0.2, color='blue')
    axes[0, idx].axvspan(-sigma_x, sigma_x, alpha=0.1, color='red', label=f'sigma_x = {sigma_x}')
    axes[0, idx].set_title(f'μœ„μΉ˜ 곡간: sigma_x = {sigma_x}')
    axes[0, idx].set_xlabel('x')
    axes[0, idx].legend(fontsize=9)
    axes[0, idx].grid(True, alpha=0.3)

    # μš΄λ™λŸ‰ 곡간
    axes[1, idx].plot(k, np.abs(psi_k)**2, 'r-', linewidth=2, label=f'|psi(k)|^2')
    axes[1, idx].fill_between(k, np.abs(psi_k)**2, alpha=0.2, color='red')
    axes[1, idx].axvspan(k0 - sigma_k, k0 + sigma_k, alpha=0.1, color='blue',
                          label=f'sigma_k = {sigma_k:.2f}')
    axes[1, idx].set_title(f'μš΄λ™λŸ‰ 곡간: sigma_k = {sigma_k:.2f}\n'
                           f'sigma_x * sigma_k = {product:.2f} >= 0.5')
    axes[1, idx].set_xlabel('k')
    axes[1, idx].legend(fontsize=9)
    axes[1, idx].grid(True, alpha=0.3)

plt.suptitle('ν•˜μ΄μ  λ² λ₯΄ν¬ λΆˆν™•μ •μ„± 원리: Delta_x * Delta_k >= 1/2', fontsize=14)
plt.tight_layout()
plt.savefig('uncertainty_principle.png', dpi=150, bbox_inches='tight')
plt.show()

Gaussian wave packets are the only functions that satisfy the equality in the uncertainty principle (minimum uncertainty state).

6.2 Fraunhofer Diffraction

The Fraunhofer diffraction pattern of light passing through a single slit is the Fourier transform of the aperture function:

$$U(\theta) \sim \mathcal{F}[A(x)]$$

where $A(x)$ is the aperture function, and the relationship between observation angle $\theta$ and spatial frequency is:

$$\omega = \frac{2\pi}{\lambda} \sin\theta$$

Single slit: Since $A(x) = \text{rect}(x/a)$:

$$U(\theta) \sim \text{sinc}\left(\frac{\pi a \sin\theta}{\lambda}\right)$$

$$I(\theta) \sim \text{sinc}^2\left(\frac{\pi a \sin\theta}{\lambda}\right)$$

import numpy as np
import matplotlib.pyplot as plt

# ν”„λΌμš΄ν˜ΈνΌ 회절: 단일 슬릿과 이쀑 슬릿

fig, axes = plt.subplots(2, 3, figsize=(16, 10))
wavelength = 500e-9  # 500 nm (μ΄ˆλ‘μƒ‰ λΉ›)
k = 2 * np.pi / wavelength

theta = np.linspace(-0.05, 0.05, 2000)  # κ΄€μΈ‘ 각도 (λΌλ””μ•ˆ)

# --- 단일 슬릿 ---
slit_widths = [10e-6, 20e-6, 50e-6]  # 10, 20, 50 λ§ˆμ΄ν¬λ‘œλ―Έν„°

for idx, a in enumerate(slit_widths):
    beta = np.pi * a * np.sin(theta) / wavelength
    # sincΒ² νŒ¨ν„΄ (beta=0μ—μ„œ 특이점 처리)
    with np.errstate(divide='ignore', invalid='ignore'):
        intensity = np.where(beta == 0, 1.0, (np.sin(beta) / beta)**2)

    axes[0, idx].plot(np.degrees(theta), intensity, 'b-', linewidth=1.5)
    axes[0, idx].set_title(f'단일 슬릿: a = {a*1e6:.0f} um')
    axes[0, idx].set_xlabel('theta (도)')
    axes[0, idx].set_ylabel('I / I_0')
    axes[0, idx].grid(True, alpha=0.3)

# --- 이쀑 슬릿 ---
a = 20e-6       # 슬릿 폭
d_values = [50e-6, 100e-6, 200e-6]  # 슬릿 간격

for idx, d in enumerate(d_values):
    beta = np.pi * a * np.sin(theta) / wavelength
    delta = np.pi * d * np.sin(theta) / wavelength

    with np.errstate(divide='ignore', invalid='ignore'):
        envelope = np.where(beta == 0, 1.0, (np.sin(beta) / beta)**2)
    interference = np.cos(delta)**2
    intensity = envelope * interference

    axes[1, idx].plot(np.degrees(theta), intensity, 'r-', linewidth=1, label='총 νŒ¨ν„΄')
    axes[1, idx].plot(np.degrees(theta), envelope, 'b--', linewidth=1, alpha=0.5, label='회절 μ—”λ²¨λ‘œν”„')
    axes[1, idx].set_title(f'이쀑 슬릿: a = {a*1e6:.0f} um, d = {d*1e6:.0f} um')
    axes[1, idx].set_xlabel('theta (도)')
    axes[1, idx].set_ylabel('I / I_0')
    axes[1, idx].legend(fontsize=9)
    axes[1, idx].grid(True, alpha=0.3)

plt.suptitle('ν”„λΌμš΄ν˜ΈνΌ 회절 = 슬릿 ν•¨μˆ˜μ˜ 푸리에 λ³€ν™˜', fontsize=14)
plt.tight_layout()
plt.savefig('fraunhofer_diffraction.png', dpi=150, bbox_inches='tight')
plt.show()

For a double slit, the aperture function is the sum of two rectangles:

$$A(x) = \text{rect}\left(\frac{x - d/2}{a}\right) + \text{rect}\left(\frac{x + d/2}{a}\right)$$

By linearity and shift theorem of the Fourier transform:

$$I(\theta) \sim \text{sinc}^2(\beta) \cdot \cos^2(\delta)$$

$$= \text{(diffraction envelope)} \times \text{(interference fringes)}$$

6.3 Signal Processing and Spectral Analysis

The most widely used FFT application in physics experiments is spectral analysis.

import numpy as np
import matplotlib.pyplot as plt

# μ‹€μ œ μ‘μš©: 볡합 μ‹ ν˜Έμ˜ μŠ€νŽ™νŠΈλŸΌ 뢄석

# μƒ˜ν”Œλ§ μ„€μ •
f_s = 1000  # μƒ˜ν”Œλ§ 주파수 (Hz)
T = 2.0     # 총 κ΄€μΈ‘ μ‹œκ°„ (s)
N = int(f_s * T)
t = np.arange(N) / f_s

# 볡합 μ‹ ν˜Έ: μ—¬λŸ¬ 주파수 μ„±λΆ„ + 작음
# 물리학 μ‹€ν—˜μ—μ„œ ν”νžˆ λ³Ό 수 μžˆλŠ” 상황
f1, A1 = 50, 1.0    # 50 Hz, 진폭 1.0 (μ£Ό μ‹ ν˜Έ)
f2, A2 = 120, 0.5   # 120 Hz, 진폭 0.5 (2μ°¨ 고쑰파 근처)
f3, A3 = 300, 0.2   # 300 Hz, 진폭 0.2 (μ•½ν•œ μ„±λΆ„)

signal = (A1 * np.sin(2 * np.pi * f1 * t) +
          A2 * np.sin(2 * np.pi * f2 * t) +
          A3 * np.sin(2 * np.pi * f3 * t))

# 백색 작음 μΆ”κ°€
np.random.seed(42)
noise_level = 0.8
signal_noisy = signal + noise_level * np.random.randn(N)

# FFT 계산
X = np.fft.fft(signal_noisy)
freqs = np.fft.fftfreq(N, 1/f_s)

# νŒŒμ›Œ μŠ€νŽ™νŠΈλŸΌ 밀도 (Power Spectral Density)
psd = (2.0 / N) * np.abs(X[:N//2])**2
freqs_pos = freqs[:N//2]

# μœˆλ„μž‰ (Hanning window) 적용 ν›„ μŠ€νŽ™νŠΈλŸΌ
window = np.hanning(N)
signal_windowed = signal_noisy * window
X_windowed = np.fft.fft(signal_windowed)
# μœˆλ„μš° 보정: μ—λ„ˆμ§€ 보쑴을 μœ„ν•΄ μ •κ·œν™”
window_correction = np.sum(window**2) / N
psd_windowed = (2.0 / (N * window_correction)) * np.abs(X_windowed[:N//2])**2

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

# μ‹œκ°„ μ˜μ—­ μ‹ ν˜Έ
axes[0, 0].plot(t[:200], signal_noisy[:200], 'gray', alpha=0.7, label='작음 μ‹ ν˜Έ')
axes[0, 0].plot(t[:200], signal[:200], 'b-', linewidth=1.5, label='원본 μ‹ ν˜Έ')
axes[0, 0].set_title('μ‹œκ°„ μ˜μ—­ μ‹ ν˜Έ (처음 0.2초)')
axes[0, 0].set_xlabel('t (s)')
axes[0, 0].set_ylabel('진폭')
axes[0, 0].legend()
axes[0, 0].grid(True, alpha=0.3)

# 진폭 μŠ€νŽ™νŠΈλŸΌ
amplitude_spectrum = (2.0 / N) * np.abs(X[:N//2])
axes[0, 1].plot(freqs_pos, amplitude_spectrum, 'b-', linewidth=1)
axes[0, 1].set_title('진폭 μŠ€νŽ™νŠΈλŸΌ |X(f)|')
axes[0, 1].set_xlabel('주파수 (Hz)')
axes[0, 1].set_ylabel('진폭')
axes[0, 1].set_xlim(0, 400)
axes[0, 1].grid(True, alpha=0.3)
# 피크 주파수 ν‘œμ‹œ
for f_peak, A_peak, label in [(f1, A1, '50 Hz'), (f2, A2, '120 Hz'), (f3, A3, '300 Hz')]:
    axes[0, 1].annotate(label, xy=(f_peak, A_peak), fontsize=10,
                        arrowprops=dict(arrowstyle='->', color='red'),
                        xytext=(f_peak + 20, A_peak + 0.1))

# νŒŒμ›Œ μŠ€νŽ™νŠΈλŸΌ 밀도 (μ„ ν˜• μŠ€μΌ€μΌ)
axes[1, 0].plot(freqs_pos, psd, 'b-', linewidth=1, alpha=0.5, label='μ§μ‚¬κ°ν˜• μœˆλ„μš°')
axes[1, 0].plot(freqs_pos, psd_windowed, 'r-', linewidth=1.5, label='해닝 μœˆλ„μš°')
axes[1, 0].set_title('νŒŒμ›Œ μŠ€νŽ™νŠΈλŸΌ 밀도 (PSD)')
axes[1, 0].set_xlabel('주파수 (Hz)')
axes[1, 0].set_ylabel('νŒŒμ›Œ')
axes[1, 0].set_xlim(0, 400)
axes[1, 0].legend()
axes[1, 0].grid(True, alpha=0.3)

# νŒŒμ›Œ μŠ€νŽ™νŠΈλŸΌ 밀도 (둜그 μŠ€μΌ€μΌ, dB)
psd_db = 10 * np.log10(psd_windowed + 1e-20)  # 0 λ°©μ§€
axes[1, 1].plot(freqs_pos, psd_db, 'r-', linewidth=1.5)
axes[1, 1].set_title('νŒŒμ›Œ μŠ€νŽ™νŠΈλŸΌ 밀도 (dB μŠ€μΌ€μΌ)')
axes[1, 1].set_xlabel('주파수 (Hz)')
axes[1, 1].set_ylabel('νŒŒμ›Œ (dB)')
axes[1, 1].set_xlim(0, 400)
axes[1, 1].grid(True, alpha=0.3)

plt.suptitle('FFTλ₯Ό μ΄μš©ν•œ μŠ€νŽ™νŠΈλŸΌ 뢄석', fontsize=14)
plt.tight_layout()
plt.savefig('spectral_analysis.png', dpi=150, bbox_inches='tight')
plt.show()

Practical tips for spectral analysis:

  1. Windowing: When applying FFT to finite data, apply window functions such as Hanning, Hamming, or Blackman to reduce spectral leakage caused by discontinuities at the boundaries.

  2. Zero-padding: Adding zeros after the data increases the FFT size, providing an interpolation effect on the frequency axis (the frequency resolution itself does not change).

  3. dB scale: Displaying the power spectrum in dB (decibels) allows viewing components with very different magnitudes together: $P_{\text{dB}} = 10 \log_{10}(P)$.


Practice Problems

Problem 1: Basic Transform Calculation

Find the Fourier transforms of the following functions analytically.

(a) $f(x) = e^{-3|x|}$

(b) $f(x) = x e^{-x^2}$

(c) $f(x) = \frac{1}{1 + x^2}$

Hint: (a) Divide into positive and negative regions for integration. (b) Use the differentiation property of Gaussian transforms. (c) Use the residue theorem or refer to transform pair tables.

Problem 2: Using Properties

Using the fact that the Fourier transform of $f(x) = e^{-x^2}$ is $F(\omega) = \sqrt{\pi} e^{-\omega^2/4}$:

(a) Find the Fourier transform of $g(x) = e^{-(x-3)^2}$. (time shift)

(b) Find the Fourier transform of $h(x) = e^{-4x^2}$. (scaling)

(c) Find the Fourier transform of $p(x) = x^2 e^{-x^2}$. (frequency differentiation)

Problem 3: Convolution

(a) Calculate $\text{rect}(x) * \text{rect}(x)$ (direct integration or using transforms). Show that the result is a triangle function.

(b) Show that for the heat equation, when the initial temperature distribution is $\delta(x)$, the solution can be expressed as a convolution of Gaussians.

Problem 4: FFT Practice

# λ‹€μŒ μ½”λ“œλ₯Ό μ™„μ„±ν•˜μ—¬ λ―Έμ§€μ˜ μ‹ ν˜Έμ—μ„œ 주파수 성뢄을 μ°ΎμœΌμ‹œμ˜€.

import numpy as np
import matplotlib.pyplot as plt

# λ―Έμ§€μ˜ μ‹ ν˜Έ 생성
np.random.seed(2024)
f_s = 500  # μƒ˜ν”Œλ§ 주파수
t = np.arange(0, 2, 1/f_s)

# 3개의 μˆ¨κ²¨μ§„ 주파수 μ„±λΆ„ + 작음
signal = (0.7 * np.sin(2*np.pi*___*t) +
          1.2 * np.sin(2*np.pi*___*t) +
          0.4 * np.cos(2*np.pi*___*t) +
          0.5 * np.random.randn(len(t)))

# TODO: FFTλ₯Ό μˆ˜ν–‰ν•˜κ³ , μˆ¨κ²¨μ§„ 주파수λ₯Ό μ°ΎμœΌμ‹œμ˜€
# 1. np.fft.fft()둜 FFT μˆ˜ν–‰
# 2. np.fft.fftfreq()둜 주파수 μΆ• 계산
# 3. 진폭 μŠ€νŽ™νŠΈλŸΌμ„ κ·Έλ €μ„œ 피크 주파수 확인

Problem 5: Physics Applications

(a) When light with wavelength $\lambda = 632.8$ nm (He-Ne laser) passes through a single slit of width $a = 50$ ΞΌm, find the angle $\theta$ of the first minimum.

(b) For a Gaussian wave packet $\psi(x) = A e^{-x^2/(4\sigma^2)} e^{ik_0 x}$: - Find the momentum space wavefunction $\phi(k)$ - Calculate $\Delta x \cdot \Delta k$ and verify that it satisfies the uncertainty principle

(c) Explain why the ground state of a harmonic oscillator with mass $m$ has Gaussian form, connecting it to the uncertainty principle.

Problem 6: Parseval's Theorem

Parseval's theorem: Prove that energy is conserved in time and frequency domains.

$$\int_{-\infty}^{\infty} |f(x)|^2 \, dx = \frac{1}{2\pi} \int_{-\infty}^{\infty} |F(\omega)|^2 \, d\omega$$

Hint: Express the product of $f(x)$ and $f^*(x)$ as an inverse transform and exchange the order of integration.


References

Textbooks

  • Mary L. Boas, Mathematical Methods in the Physical Sciences, 3rd Edition
  • Chapter 7: Fourier Series and Transforms
  • Chapter 15: Integral Transforms (advanced)
  • Arfken, Weber, Harris, Mathematical Methods for Physicists, 7th Edition, Chapter 20
  • Riley, Hobson, Bence, Mathematical Methods for Physics and Engineering, Chapter 13

Advanced Topics

  • Bracewell, R.N., The Fourier Transform and Its Applications, McGraw-Hill
  • Classic reference known as the bible of Fourier transforms
  • Oppenheim, A.S. & Willsky, A.S., Signals and Systems, Prentice Hall
  • Fourier transforms from a signal processing perspective
  • Goodman, J.W., Introduction to Fourier Optics, W.H. Freeman
  • Applications of Fourier transforms in optics (diffraction, imaging)

Online Resources

  • 3Blue1Brown: "But what is the Fourier Transform?" (visual intuition)
  • MIT OCW 18.03: Differential Equations (Fourier series/transform lectures)
  • NumPy FFT Documentation: https://numpy.org/doc/stable/reference/routines.fft.html
  • SciPy FFT Documentation: https://docs.scipy.org/doc/scipy/reference/fft.html

Next Lesson

07. Partial Differential Equations and Boundary Value Problems uses Fourier transforms to solve key PDEs in physics such as the heat equation, wave equation, and Laplace equation. We cover solution techniques based on boundary conditions and eigenfunction expansions.

to navigate between lessons