为什么我的 8kHz wav 文件的 mel 特征在 sr = 16kHz 和 44.1kHz 中的提取方式不同

val*_*day 5 python audio audio-processing librosa

我目前正在从我的婴儿哭声数据集中提取 mel 特征,wav 文件的采样率为 8kHz、16 位、单声道和大约 7 秒。

sr = 16000 时的梅尔谱图 sr = 44100 时的梅尔谱图

但是正如您所看到的,每当我以不同的采样率提取特征时sr,梅尔谱图的值都会发生变化。我认为由于wav文件的采样率为8kHz,如果我将采样率设置为16kHz以上,赫兹的值必须相同。

我将 wav 文件的采样率 8kHz 转换为 44.1kHz 并再次提取,但没有任何变化。

这是我的代码:

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

sr = 44100 # or 16000 
frame_length = 0.1  
frame_stride = 0.01  
path = '...'
train = []  

j, sr = librosa.load(path + '001.wav', sr, duration = 5.0)   
input_nfft = int(round(sr*frame_length))   
input_stride = int(round(sr*frame_stride))   
mel = librosa.feature.melspectrogram(j, n_mels = 128, n_fft = input_nfft, hop_length=input_stride, sr = sr)            
train.append(mel)

plt.figure(figsize=(10,4))  
librosa.display.specshow(librosa.power_to_db(train[0], ref=np.max), y_axis='mel', sr=sr, hop_length=input_stride, x_axis='time')  
plt.colorbar(format='%+2.0f dB')  
plt.title('Mel-Spectrogram')  
plt.tight_layout()  
plt.show()  
Run Code Online (Sandbox Code Playgroud)

y 轴的值必须相同,sr = 44100否则16000 我不明白为什么会发生这种情况。

hen*_*rik 8

当您要求 librosa 创建 mel 谱图时,您要求它执行两个步骤:

基于傅里叶变换的频谱

首先,您要求它在可能的范围内创建基于 FFT 的频谱图。要了解可能的范围是多少,您必须了解Nyquist-Shannon 定理,该定理(粗略地)指出,当您以 sr Hz 采样信号时,您无法表示超过 sr/2 Hz(sr = 采样率)的频率。因此,以 44.1kHz 采样的信号的可能频率范围是 0 到 22.05 kHz。

librosa 生成一个规则的线性间隔频谱图作为中间结果。频率范围为 0 至 sr/2 Hz。

梅尔谱图

与常规的基于 FT 的频谱图相反,梅尔频谱图没有线性频率标度,而是(几乎)对数标度。为了将基于 FT 的频谱图映射到对数刻度,所有可用数据都被映射到特定数量的对数间隔的 bin。使用的 bin 数量指定为n_mels,即梅尔带的数量。

把它放在一起

因此,对于n_mels = 128,如果您有一个以 44.1kHz 采样的信号,则可以表示从 0 到 22.05 Hz 的范围。该范围映射到 128 个对数间隔的波段。如果您的信号以 16 kHz 采样,则可以表示 0 到 8 Hz 的范围。这个范围被映射到 128 个对数间隔的频段,即 0-8 kHz 的范围被分成 128 个部分,而不是 0-22.05 kHz 的范围。这必然导致不同的结果。

解决方案

如果要确保映射到n_melsmel 频段的频率范围始终相同,而不管采样率如何,则必须指定关键字参数fminand fmax(请参阅此处)。

例如:

fmin = 0.
fmax = 4000.  # since your original signal is sampled at 8 kHz
mel = librosa.feature.melspectrogram(j, n_mels=128,
                                     n_fft=input_nfft,
                                     hop_length=input_stride,
                                     sr=sr,
                                     fmin=fmin,
                                     fmax=fmax)            
Run Code Online (Sandbox Code Playgroud)