梅尔频谱(mel spectrogram)原理与使用

梅尔频谱(mel spectrogram)原理与使用

  • 原理

研究表明,人类对频率的感知并不是线性的,并且对低频信号的感知要比高频信号敏感。例如,人们可以比较容易地发现500和1000Hz的区别,确很难发现7500和8000Hz的区别。这时,梅尔标度(the Mel Scale)被提出,它是Hz的非线性变换,对于以mel scale为单位的信号,可以做到人们对于相同频率差别的信号的感知能力几乎相同。一个常用的变换公式为

m=2595*log_{10}(1+\frac{f}{700})

梅尔频谱就是一个在mel scale下的 spectrogram ,是通过spectrogram与若干个梅尔滤波器(即下图中的mel_f)点乘得到。

图片来源:https://librosa.org/doc/main/generated/librosa.feature.melspectrogram.html

梅尔滤波器组(如下图所示)中的每一个滤波器都是一个三角滤波器,将上面所说的点乘过程展开,等价于下面代码描述的操作。

# Copied from https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html
low_freq_mel = 0
# spectrogram纵轴的最高频率为 sample_rate / 2
# Convert Hz to Mel
high_freq_mel = (2595 * numpy.log10(1 + (sample_rate / 2) / 700))
# nfilt为梅尔滤波器的个数
mel_points = numpy.linspace(low_freq_mel, high_freq_mel, nfilt + 2)  # Equally spaced in Mel scale
# Convert Mel to Hz
hz_points = (700 * (10**(mel_points / 2595) - 1))  
# NFFT为求spectrogram时frame的长度
# spectrogram纵轴的频率增量为sample_rate/N,放缩完使增量变为1,方便下面计算fbank
bin = numpy.floor((NFFT + 1) * hz_points / sample_rate)
# 储存梅尔滤波器的数组
fbank = numpy.zeros((nfilt, int(numpy.floor(NFFT / 2 + 1))))
for m in range(1, nfilt + 1):
    f_m_minus = int(bin[m - 1])   # left
    f_m = int(bin[m])             # center
    f_m_plus = int(bin[m + 1])    # right
    for k in range(f_m_minus, f_m):
        fbank[m - 1, k] = (k - bin[m - 1]) / (bin[m] - bin[m - 1])
    for k in range(f_m, f_m_plus):
        fbank[m - 1, k] = (bin[m + 1] - k) / (bin[m + 1] - bin[m])
# pow_frames为 (power) spectrogram
filter_banks = numpy.dot(pow_frames, fbank.T)
filter_banks = numpy.where(filter_banks == 0, numpy.finfo(float).eps, filter_banks)  # Numerical Stability
filter_banks = 20 * numpy.log10(filter_banks)  # dB
图片来源:https://haythamfayek.com/2016/04/21/speech-processing-for-machine-learning.html
图片来源:https://blog.csdn.net/tengfei0973/article/details/103182621
  • 使用
import librosa
import numpy as np
signal = np.cos(2*np.pi*200*np.arange(10000)/10000)
signal = np.append(signal, np.cos(2*np.pi*1000*np.arange(10000)/10000))
# sample frequency
sr = 100