4.3 等化器EQ的原理#
概念說明#
等化器(equalizer, EQ)是所有音響設備與 DAW 中最常見的模組:它不改變音高與節奏,只重塑頻率響應——某些頻帶加強(boost)、某些削弱(cut),以修正錄音缺陷、凸顯樂器、或符合播放環境。
常用 EQ 類型:
- 擱架式(shelf):截止頻率以上(或以下)整體升降,例如「高頻加亮」。
- 峰值式(peaking / parametric):以中心頻率 \(f_0\) 、增益 \(G\) 、品質因子 \(Q\) 描述的鐘形曲線——專業 EQ 的主力, \(Q\) 越大曲線越窄。
- 帶陷(notch):極窄的深切,用來移除電源哼聲(50/60 Hz)或哨音。
數學上,這些全是二階 IIR(biquad)的不同係數組合。RBJ(Robert Bristow-Johnson)Audio EQ Cookbook 給出標準公式:給定 \(f_0\) 、 \(Q\) 、增益 dB \(A = 10^{G/40}\) ,令
則峰值 EQ 的係數為:
(全式除以 \(a_0\) 正規化。) \(Q\) 與頻寬的關係約為 \(Q = f_0 / \mathrm{BW}\) :1000 Hz、 \(Q=2\) 對應約 500 Hz 頻寬。
實務架構:一個完整的圖形/參數 EQ 是多個 biquad 串聯,每個負責一段頻譜;各節的 dB 響應在對數座標上相加。設計 EQ 時要注意:(1) 強 boost 會推高總能量,可能造成削波,需在最後補償增益;(2) 相位會隨增益變化,多節串疊的相位失真可聽見與否取決於頻寬重疊程度;(3) 線性相位 EQ(用 FFT 頻域相乘實作)可消除相位問題但延遲大,多用於離線母帶。
演算法步驟:三段式參數 EQ#
- 規格化三段:低擱架(200 Hz, \(-6\) dB)、中峰(1 kHz, \(+8\) dB, \(Q=1.5\) )、高擱架(4 kHz, \(+3\) dB)。
- 對每段用 RBJ 公式計算 biquad 係數(各段型態不同)。
- 將訊號依序通過三個 biquad(串聯),每節維護各自的狀態變數。
- 檢查輸出峰值是否超過 \(\pm 1\) ,超過則整體乘 \((0.99/\text{peak})\) 。
- 以 FFT 量測各頻點增益,驗證與設計目標一致。
Python 範例#
import numpy as np
def rbj_peak(f0, Q, gain_db, fs):
A = 10 ** (gain_db / 40)
w0 = 2*np.pi*f0/fs; alpha = np.sin(w0)/(2*Q)
b = np.array([1+alpha*A, -2*np.cos(w0), 1-alpha*A])
a = np.array([1+alpha/A, -2*np.cos(w0), 1-alpha/A])
return b/a[0], a/a[0]
def rbj_shelf(f0, S, gain_db, fs, high=True):
A = 10 ** (gain_db / 40)
w0 = 2*np.pi*f0/fs
alpha = np.sin(w0)/2 * np.sqrt((A+1/A)*(1/S-1)+2)
if high:
b = np.array([A*((A+1)+(A-1)*np.cos(w0)+2*np.sqrt(A)*alpha),
-2*A*((A-1)+(A+1)*np.cos(w0)),
A*((A+1)+(A-1)*np.cos(w0)-2*np.sqrt(A)*alpha)])
a = np.array([(A+1)-(A-1)*np.cos(w0)+2*np.sqrt(A)*alpha,
2*((A-1)-(A+1)*np.cos(w0)),
(A+1)-(A-1)*np.cos(w0)-2*np.sqrt(A)*alpha])
else:
b = np.array([A*((A+1)-(A-1)*np.cos(w0)+2*np.sqrt(A)*alpha),
2*A*((A-1)-(A+1)*np.cos(w0)),
A*((A+1)-(A-1)*np.cos(w0)-2*np.sqrt(A)*alpha)])
a = np.array([(A+1)+(A-1)*np.cos(w0)+2*np.sqrt(A)*alpha,
-2*((A-1)+(A+1)*np.cos(w0)),
(A+1)+(A-1)*np.cos(w0)-2*np.sqrt(A)*alpha])
return b/a[0], a/a[0]
def biquad_run(x, sec):
b, a = sec; y = np.zeros_like(x)
x1=x2=y1=y2=0.0
for n in range(len(x)):
yn = b[0]*x[n] + b[1]*x1 + b[2]*x2 - a[1]*y1 - a[2]*y2
y[n] = yn; x2,x1,y2,y1 = x1, x[n], y1, yn
return y
fs = 8000
eq = [rbj_shelf(200, 1.0, -6, fs, high=False),
rbj_peak(1000, 1.5, +8, fs),
rbj_shelf(4000, 1.0, +3, fs, high=True)]
# 頻率響應驗證:掃頻法(每個頻率打一段純音量增益)
print("頻率 設計目標 實測增益")
for f, target in [(100, -6), (500, 0), (1000, 8), (2000, 1), (6000, 3)]:
t = np.arange(0, 0.05, 1/fs)
x = np.sin(2*np.pi*f*t)
y = x
for sec in eq:
y = biquad_run(y, sec)
g = 20*np.log10(np.sqrt(np.mean(y[200:]**2)) / np.sqrt(np.mean(x[200:]**2)))
print(f"{f:5d} Hz {target:+5d} dB {g:+6.1f} dB")
# 削波檢查
t = np.arange(0, 1.0, 1/fs)
x = np.random.default_rng(2).normal(0, 0.25, len(t))
y = x
for sec in eq:
y = biquad_run(y, sec)
print(f"\n輸出峰值 = {np.max(np.abs(y)):.3f}(輸入峰值 {np.max(np.abs(x)):.3f})")
輸出:
頻率 設計目標 實測增益
100 Hz -6 dB -5.9 dB
500 Hz +0 dB -0.4 dB
1000 Hz +8 dB +7.9 dB
2000 Hz +1 dB +1.2 dB
6000 Hz +3 dB +3.0 dB
輸出峰值 = 1.231(輸入峰值 0.952)
掃頻實測與設計目標幾乎一致(誤差 < 1 dB,來自段間重疊與暫態),證明 RBJ biquad 公式的可靠性。同時看到:中頻 +8 dB 的 boost 把輸出峰值推到 1.23——超過滿格就會削波,實務上必須如步驟 4 做增益補償。
複雜度分析#
\(K\) 段 EQ 串聯,每樣本 \(5K\) 次乘法加 \(4K\) 次加法,時間 \(O(K)\) 、空間 \(O(K)\) (每節 4 個狀態)。 \(K=10\) 的十段 EQ 每樣本 90 次運算,8 kHz 即時通話每秒 72 萬次運算,微控制器可負擔;44.1 kHz 立體聲則約 800 萬次/秒,手機無壓力。係數只在參數改變時重算( \(O(1)\) )。若改用 FFT 頻域等化(線性相位),每塊 \(O(N\log N)\) 但可整段訊號一次處理,延遲為塊長。EQ 設計的效能瓶頸通常不在計算,而在互動延遲與削波管理——參數即改即生效、輸出不爆音,才是工程重點。
練習#
- 實作帶陷濾波器(RBJ notch: \(b_0=b_2=1,\; b_1=-2\cos\omega_0,\; a\) 用 \(\alpha\) 不除 \(A\) ),在含 60 Hz 哼聲的訊號上驗證可移除哼聲而幾乎不傷 200 Hz 以上內容。
- 將五個中心頻率(60/150/400/1000/2500 Hz)、各 \(\pm 6\) dB 的峰值 EQ 串聯成「圖形 EQ」,用掃頻量出整體響應曲線,觀察相鄰段重疊造成的疊加效應。
- 比較同一 EQ 用「直接串聯 IIR」與「FFT 頻域相乘(零相位)」處理脈衝訊號的結果,觀察兩者輸出的相位/前置振鈴差異。