理解梅爾譜圖 Understanding the Mel Spectrogram

明日會吹明日的風發表於2023-02-16

理解梅爾譜圖(Understanding the Mel Spectrogram)

文章中的示例音訊
音訊檔案

訊號

訊號就是某一特定量隨時間變化。對於音訊來說,這個特定的變化量就是氣壓。那我們如何去數字化地捕獲這些資訊呢?我們可以在某個時間段內對氣壓進行取樣。我們採集資料的取樣率是可以變化的,但是最常用的是44.1kHz(每秒採集44100個樣)。我們採集到的訊號叫做波形(waveform),並且它可以透過計算機軟體進行解釋,修改和分析。

import librosa
import librosa.display
import matplotlib.pyplot as plt

y, sr = librosa.load('CantinaBand3.wav')
plt.plot(y)
plt.title('Signal')
plt.xlabel('Time (samples)')
plt.ylabel('Amplitude')
plt.savefig('音訊頻率圖.png')


好棒!我們現在擁有了一個可以處理的語音訊號數字表示。歡迎來到訊號處理的領域!然後,你可能會想,那我們如何從這裡提取中有用的資訊的?目前看起來是一團亂麻。別擔心,我們的朋友傅立葉變換正在款款走來!

傅立葉變換

一個音訊訊號由多個單頻聲波組成。當我們隨著時間對訊號進行取樣時,我們僅僅能夠捕獲到最終疊加後的振幅(amplitude)。傅立葉變換是一個數學工具,它能夠幫助我們將一個訊號分解為多個頻率以及頻率對應的振幅。換句話說,它可以將訊號從時域轉化為頻域。最終的結果成為譜(spectrum)。

這是可能的,因為每一個訊號都能分解為一些列正弦波和餘弦波的疊加。這就是著名的傅立葉定理。
快速傅立葉變換(fast Fourier transform, FFT)是一種可以高效計算傅立葉變換的演算法。被廣泛運用於訊號處理領域。我們在音訊的加窗段上使用這個演算法。

import numpy as np

n_fft = 2048
ft = np.abs(librosa.stft(y[: n_fft], hop_length = n_fft + 1))
plt.plot(ft)
plt.title('Spectrum')
plt.xlabel('Frequency Bin')
plt.ylabel('Amplitude')
plt.savefig('spectrum.png')

頻譜圖

快速傅立葉變換時讓我們分析訊號內容中頻率含量的有力工具,但是如果我們的訊號中頻率含量含量時隨時間變化的呢?例如音樂,講話。它們又叫做非週期訊號。你可能會想:“我們不能透過對多個訊號加窗段進行FFT,從而得到多個譜嗎?”是的,這就是我們在做的,我們稱為短時傅立葉變換(short-time Fourier transform,STFT),FFT訊號在訊號的重疊加窗段上計算,我們就得到了所謂的頻譜圖(spectrogram)。

你可以把頻譜圖當作一堆FFTs彼此疊加的結果。這是一種訊號響度,或者頻率的視覺表現,因為它隨著時間在不同頻率上進行變化。除此之外,在計算頻譜圖的時候還有一些額外的細節。如下圖所示,y軸,也就是頻率軸以log為尺度(你可以認為是頻率取log),並且顏色維度用於表示分貝。這是因為人類只能感知非常小而集中的頻率和振幅的範圍。

spec = np.abs(librosa.stft(y, hop_length=512))
spec = librosa.amplitude_to_db(spec, ref=np.max)
librosa.display.specshow(spec, sr=sr, x_axis='time', y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title('Spectrogram')
plt.savefig('spectrogram.png')

梅爾刻度(Mel Scale)

研究表明人們對頻率的感知不是線性的,相較於高頻率我們對低頻率的感知更加好一些。例如我們可以輕鬆地分辨出500Hz和1000Hz的區別,但是我們很難分辨出10000Hz和10500Hz的區別,儘管這兩對頻率的差距是相同的。
在1937年,Stevens,Volkmann,和Newmann提出了一種音高單位,這種單位中相同的差距對聽者來說也是相等的。我們稱為梅爾刻度。我們對頻率進行數學操作使其變為梅爾刻度。

梅爾頻譜(Mel Spectrogram)

梅爾頻譜是頻率轉換為梅爾刻度的頻譜。他可以透過幾行程式碼實現。

spect = librosa.feature.melspectrogram(y=y, sr=sr, n_fft=2048, hop_length=1024)
mel_spect = librosa.power_to_db(spect, ref=np.max)
librosa.display.specshow(mel_spect, y_axis='mel', fmax=8000, x_axis='time')
plt.title('Mel Spectrogram')
plt.colorbar(format='%+2.f dB')
plt.savefig('mel_spectrogram.png')

總結

  1. 我們隨著時間對氣壓進行取樣得到數字化的音訊訊號(signal)表示
  2. 我們透過快速傅立葉變換(fast Fourier Transform, FFT)將音訊訊號從時域對映到頻域。我們對音訊訊號進行了重疊加窗處理。
  3. 我們將y軸(頻率)轉化為log刻度,將顏色(振幅)維度轉化為音響從而得到頻譜圖(spectrogram)。
  4. 我們將y軸(頻率)轉化為梅爾刻度(mel scale)從而得到梅爾譜圖。

來源

Understanding the mel spectrogram

相關文章