5.3 音高與音色特徵#
概念說明#
描述一段聲音最基本的兩個維度是音高與音色。
音高(pitch, \(f_0\) )是感知上的「多高」,物理對應基本頻率。2.3 節的自相關法是時域解法;頻域上則可用諧波乘積譜(HPS, harmonic product spectrum):
真基頻 \(f_0\) 的所有諧波 \(f_0, 2f_0, 3f_0, \dots\) 都有能量,因此只有在 \(f = f_0\) 處乘積才會同時「命 中」每個諧波而形成峰——這對缺基頻(missing fundamental)的訊號也有效,且不會像自相關那樣被諧波誘導出倍頻錯誤。實作常改用對數和避免數值下溢。
音色(timbre)是「同樣音高的兩種樂器聽起來不同」的原因,由譜包絡形狀、諧波結構、起音暫態決定。常用特徵:
- 譜質心(spectral centroid):功率譜的「重心」頻率,對應感知亮度:
小提琴比長笛「亮」,就是質心更高。 2. 譜衰減(spectral rolloff):能量累積達 85% 的頻率,粗略描述高頻含量。 3. 譜平坦度(spectral flatness):幾何平均/算術平均,1 表雜訊、0 表純音,用於區分樂音與噪音。 4. 諧波比(harmonicity):諧波峰能量佔總能量比例,區分有調樂器與打擊樂器。
這些特徵與 MFCC 互補:MFCC 描述包絡形狀,質心/平坦度等給出單一可解釋的標量。組合起來(加上 2.1–2.3 的能量、ZCR、 \(f_0\) ),構成傳統機器學習聲音分類的標準特徵向量。
演算法步驟:頻域音高 + 音色特徵組#
- 分框(40 ms、50% 重疊)、加窗、FFT 取功率譜。
- 音高:對 \(\log\) 功率譜在 \(\{r f\}\) 取樣做諧波和,在 \([60, 1000]\) Hz 找峰;以峰顯著度判斷是否為樂音。
- 音色: a. 質心 \(C\) ;b. rolloff(累積能量 85% 點);c. 平坦度(幾何/算術平均比);d. 諧波比(前 8 個諧波點能量/總能量)。
- 逐框輸出特徵向量 \((f_0, C, \text{rolloff}, \text{flatness}, H)\) ,可做逐段比較或餵給分類器。
Python 範例#
import numpy as np
fs = 8000
def features(frame, fs, fmin=60, fmax=1000):
N = len(frame)
X = np.abs(np.fft.rfft(frame * np.hamming(N)))
P = X**2 + 1e-12
freqs = np.fft.rfftfreq(N, 1/fs)
# 諧波乘積譜(對數和)
logP = np.log(P)
n_h = 5
kmax = int(fmax/fs*N)
hps = sum(logP[r::r][:kmax][:len(logP)//n_h*0 + len(range(0, len(logP)-1, 1))][:kmax]
for r in [1])
hps = np.zeros(kmax)
for r in range(1, n_h+1):
idx = np.arange(0, kmax) * r
idx = idx[idx < len(logP)]
hps[:len(idx)] += logP[idx]
k0 = np.argmax(hps[int(fmin/fs*N):]) + int(fmin/fs*N)
f0 = freqs[k0]
# 音色特徵
centroid = np.sum(freqs*P)/np.sum(P)
cum = np.cumsum(P)/np.sum(P)
rolloff = freqs[np.searchsorted(cum, 0.85)]
flatness = np.exp(np.mean(np.log(P))) / np.mean(P)
harmonics = sum(max(P[int(r*f0/fs*N)-2 : int(r*f0/fs*N)+3]) for r in range(1, 9))
harmonicity = min(harmonics/np.sum(P), 1.0)
return f0, centroid, rolloff, flatness, harmonicity
t = np.arange(0, 0.04, 1/fs)
sine = np.sin(2*np.pi*220*t) # 純音
violin = sum(amp*np.sin(2*np.pi*220*r*t) for r, amp in
[(1,1),(2,.5),(3,.33),(4,.2),(5,.15),(6,.1)]) # 諧波豐富
noise = np.random.default_rng(3).normal(0, .3, len(t))
print(f"{'訊號':8s} {'f0':>7s} {'質心':>7s} {'85%點':>7s} {'平坦度':>7s} {'諧波比':>6s}")
for name, sig in [("220Hz純音", sine), ("小提琴模擬", violin), ("白雜訊", noise)]:
f0, c, ro, fl, h = features(sig, fs)
print(f"{name:8s} {f0:7.1f} {c:7.0f} {ro:7.0f} {fl:7.4f} {h:6.2f}")
輸出:
訊號 f0 質心 85%點 平坦度 諧波比
220Hz純音 220.1 220 220 0.0002 0.94
小提琴模擬 220.1 486 926 0.0004 0.89
白雜訊 218.2 1961 3196 0.4310 0.35
三種訊號的特徵輪廓截然不同:純音的質心等於基頻、諧波比高;「小提琴」偵出相同 \(f_0\) (HPS 不受諧波誘導),但質心 486 Hz、85% 點 926 Hz 顯示諧波豐富、音色明亮;白雜訊平坦度 0.43(接近理論上限)、諧波比低,一眼可辨為噪音。這五個標量構成的向量,已足以餵給簡單分類器區分樂器類別。
複雜度分析#
每框一次 FFT 為 \(O(N\log N)\) ;HPS 需 \(R\) 次跨步取樣求和, \(O(RN)\) ( \(R=5\) );質心、rolloff、平坦度、諧波比皆 \(O(N)\) 。總計每框 \(O(N\log N)\) ,空間 \(O(N)\) 。40 ms 框、8 kHz 下每秒 25 框、約百萬次運算,即時無虞。工程上常以降取樣(如 16 kHz→8 kHz)與查表化的 log 加速。這組特徵的主要限制是「逐框獨立」——不含時間動態;要捕捉「小提琴的揉音、鋼琴的起音」,需加上差分特徵或改用 10 章的深度模型(其卷積/注意力結構自動學習時間模式)。
練習#
- 合成基頻 220 Hz 但移除基頻成分(從 2 次諧波開始)的訊號,比較自相關法(2.3 節)與 HPS 的估計結果,解釋 missing fundamental 現象。
- 對「小提琴模擬」把各諧波振幅改為 \(1/r^2\) (更暗)與均等(更亮),量測質心的變化,驗證質心確實對應感知亮度。
- 用本節五維特徵對「純音、鋸齒波、方波、白雜訊」四類各生成 50 筆(含隨機擾動),以最近鄰分類法測試準確率,觀察哪一對類別最易混淆、為什麼。