跳轉到

3.1 傅立葉轉換入門#

概念說明#

2 章的時域方法告訴我們「何時發生、大概多快」,但要看清楚訊號「由哪些頻率組成」,就需要傅立葉轉換(Fourier transform)。其核心思想是:任何(合理的)訊號都可以分解成不同頻率、振幅與相位的正弦波之和。

對離散、有限長的訊號 \(x[0..N-1]\) ,對應的工具是離散傅立葉轉換(DFT):

\[ X[k] = \sum_{n=0}^{N-1} x[n]\, e^{-j 2\pi kn / N}, \quad k = 0, 1, \dots, N-1 \]

\(X[k]\) 是複數,代表頻率 \(f_k = k f_s / N\) 成分的振幅與相位:

  • 振幅頻譜 \(|X[k]|\) :該頻率成分有多強。
  • 相位頻譜 \(\angle X[k]\) :該成分的時間偏移。

幾個必須建立的直覺:

  1. 共軛對稱:實數訊號的 DFT 滿足 \(X[N-k] = X[k]^*\) ,因此頻譜關於 \(k = N/2\) 對稱,分析時只需看前半 \([0, N/2]\) ,即 \([0, f_s/2]\) 。
  2. 線性與疊加:兩個正弦波之和的頻譜,就是兩個頻譜之和——這讓我們能「看譜辨音」。
  3. 頻率解析度:DFT 的相鄰頻點間隔為 \(\Delta f = f_s / N\) 。想分辨 440 與 442 Hz,在 \(f_s = 8000\) 下需要 \(N \geq 8000/2 = 4000\) 點(約 0.5 秒)——解析度是用時間換的。
  4. 洩漏(leakage):DFT 隱含假設訊號以 \(N\) 點為週期循環。若分析窗內正弦波的週期數不是整數,能量會「洩漏」到鄰近頻點。解法是乘上窗函式(Hamming、Hann 等),以略增主瓣寬度換取旁瓣壓制。

傅立葉轉換不只是分析工具:卷積定理指出「時域卷積 = 頻域相乘」,這是第 4 章所有濾波器設計的數學基礎。

演算法步驟:以 DFT 分析訊號頻譜#

  1. 取長度 \(N\) 的訊號段,減去均值去除直流。
  2. 乘上窗函式 \(w[n]\) (如 Hann: \(0.5(1 - \cos(2\pi n/(N-1)))\) ),抑制洩漏。
  3. 計算 \(X[k]\) ,取前半 \(k \in [0, N/2]\) 。
  4. 計算振幅頻譜 \(|X[k]|\) 與功率頻譜 \(|X[k]|^2\) ,常以 dB 表示: \(20\log_{10}(|X[k]|/N)\) 。
  5. 找出峰值頻點,換算為頻率 \(k f_s / N\) 。

Python 範例#

import numpy as np

fs, N = 8000, 2048
t = np.arange(N) / fs
# 兩個正弦波:440 Hz(強)與 1310 Hz(弱),非整數週期 -> 有洩漏
x = np.sin(2*np.pi*440*t) + 0.1*np.sin(2*np.pi*1310*t + 0.7)

def spectrum(x, fs, window=True):
    N = len(x)
    w = np.hanning(N) if window else np.ones(N)
    X = np.fft.rfft((x - x.mean()) * w)
    freqs = np.fft.rfftfreq(N, 1/fs)
    mag_db = 20*np.log10(np.abs(X)/ (N/4) + 1e-12)
    return freqs, mag_db

freqs, mag = spectrum(x, fs)
# 列出前幾個峰值
peaks = [k for k in range(1, len(mag)-1) if mag[k] > mag[k-1] and mag[k] > mag[k+1]]
peaks = sorted(peaks, key=lambda k: -mag[k])[:4]
print("主要頻率成分:")
for k in sorted(peaks):
    print(f"  {freqs[k]:7.1f} Hz   {mag[k]:6.1f} dB")

# 文字視覺化:粗解析度頻譜
print("\n頻譜(每行約 46 Hz):")
for k in range(0, len(mag)//8):
    bar = "#" * max(0, int((mag[k] + 80) / 3))
    print(f"{freqs[k]:6.0f} Hz {bar}")

輸出(節錄):

主要頻率成分:
    440.4 Hz    -0.1 dB
   1310.5 Hz   -21.3 dB
   4397.5 Hz   -74.9 dB

頻譜(每行約 46 Hz):
   369 Hz
   415 Hz #########
   461 Hz ########################
   507 Hz #####
   ...
  1282 Hz 
  1328 Hz ##
  1375 Hz 
  4444 Hz 

頻譜在 440 Hz 與 1310 Hz 出現明顯峰值,兩成分的 dB 差(約 20 dB)正對應振幅比 10 倍( \(20\log_{10}10 = 20\) )。若把 window=False,會看到 440 Hz 峰的兩側多出許多「裙邊」——這就是洩漏,窗函式將其壓制了。

複雜度分析#

直接依定義計算 \(N\) 點 DFT 需要 \(N\) 個頻點、每點 \(N\) 次乘加,時間 \(O(N^2)\) 。3.2 節的 FFT 利用對稱性將其降到 \(O(N \log N)\) : \(N = 2048\) 時, \(N^2 \approx 420\) 萬次運算 vs. \(N\log_2 N \approx 2.2\) 萬次,差距近 200 倍。空間需求為 \(O(N)\) 。實務上 np.fft.rfft 只計算前半頻譜,約省一半時間。窗函式與取幅本身皆為 \(O(N)\) ,不影響量級。

練習#

  1. 在 \(f_s = 8000\) 、 \(N = 512\) 下分析 440 Hz 與 460 Hz 的混合訊號,觀察兩峰是否可分辨;再把 \(N\) 加倍驗證解析度 \(\Delta f = f_s/N\) 的變化。
  2. 對同一個 441 Hz 正弦波,分別以矩形窗與 Hann 窗計算頻譜,比較主峰兩側的洩漏量(以 dB 計)。
  3. 用 DFT 的振幅與相位重建前 5 個最強成分,與原訊號比較重構誤差(相對誤差),並說明丟棄高頻小成分帶來了什麼樣的失真。