在 Librosa 中获取与 STFT 关联的频率

Getting the frequencies associated with STFT in Librosa

使用librosa.stft()计算频谱图时,如何取回相关的频率值?我对生成 librosa.display.specshow 中的图像不感兴趣,但我想掌握这些值。

y, sr = librosa.load('../recordings/high_pitch.m4a')
stft = librosa.stft(y, n_fft=256, window=sig.windows.hamming)
spec = np.abs(stft)

spec 给了我每个频率的 'amplitude' 或 'power',但不是频率仓本身。我已经看到有一个 display.specshow 函数会在热图的垂直轴上显示这些频率值,但不会 return 值本身。

我正在为单个 FFT 寻找类似于 nn.fft.fttfreq() 的东西,但在 librosa 文档中找不到它的等价物。

我想特别指出这个问题和答案:How do I obtain the frequencies of each value in an FFT?. In addition to consulting the documentation for the STFT from librosa,我们知道横轴是时间轴,纵轴是频率。频谱图中的每一列都是时间切片的 FFT,其中该时间点的中心有一个 window 放置有 n_fft=256 个分量。

我们还知道有一个跳跃长度,它告诉我们在计算下一个 FFT 之前需要跳过多少音频样本。默认情况下为 n_fft / 4,因此您的音频中每 256 / 4 = 64 个点,我们都会计算一个以 n_fft=256 点长的时间点为中心的新 FFT。如果您想知道每个 window 的确切时间点,只需 i / Fsi 是音频信号的索引,它是 64 的倍数。

现在,对于每个 FFT window,对于实数信号,频谱是对称的,因此我们只考虑 FFT 的正侧。这是由文档验证的,其中行数和频率分量的数量是 1 + n_fft / 2,其中 1 是直流分量。既然我们现在有了这个,参考上面的post,从bin号到相应频率的关系是i * Fs / n_fft,其中i是bin号,Fs是采样频率和n_fft=256 作为 FFT 中的点数 window。由于我们只查看半光谱,而不是从 0 到 n_ffti,因此它从 0 到 1 + n_fft / 2,而不是 1 + n_fft / 2 之外的区间是半频谱的反射版本,因此我们不考虑超出 Fs / 2 Hz 的频率分量。

如果您想生成这些频率的 NumPy 数组,您可以这样做:

import numpy as np
freqs = np.arange(0, 1 + n_fft / 2) * Fs / n_fft

freqs 将是一个数组,将 FFT 中的 bin 编号映射到相应的频率。作为说明性示例,假设我们的采样频率为 16384 Hz,并且 n_fft = 256。因此:

In [1]: import numpy as np

In [2]: Fs = 16384

In [3]: n_fft = 256

In [4]: np.arange(0, 1 + n_fft / 2) * Fs / n_fft
Out[4]:
array([   0.,   64.,  128.,  192.,  256.,  320.,  384.,  448.,  512.,
        576.,  640.,  704.,  768.,  832.,  896.,  960., 1024., 1088.,
       1152., 1216., 1280., 1344., 1408., 1472., 1536., 1600., 1664.,
       1728., 1792., 1856., 1920., 1984., 2048., 2112., 2176., 2240.,
       2304., 2368., 2432., 2496., 2560., 2624., 2688., 2752., 2816.,
       2880., 2944., 3008., 3072., 3136., 3200., 3264., 3328., 3392.,
       3456., 3520., 3584., 3648., 3712., 3776., 3840., 3904., 3968.,
       4032., 4096., 4160., 4224., 4288., 4352., 4416., 4480., 4544.,
       4608., 4672., 4736., 4800., 4864., 4928., 4992., 5056., 5120.,
       5184., 5248., 5312., 5376., 5440., 5504., 5568., 5632., 5696.,
       5760., 5824., 5888., 5952., 6016., 6080., 6144., 6208., 6272.,
       6336., 6400., 6464., 6528., 6592., 6656., 6720., 6784., 6848.,
       6912., 6976., 7040., 7104., 7168., 7232., 7296., 7360., 7424.,
       7488., 7552., 7616., 7680., 7744., 7808., 7872., 7936., 8000.,
       8064., 8128., 8192.])

In [5]: freqs = _; len(freqs)
Out[5]: 129

我们可以看到我们已经生成了一个 1 + n_fft / 2 = 129 元素数组,它告诉我们每个对应 bin 编号的频率。


注意事项

请注意,librosa.display.specshow 的默认采样率为 22050 Hz,因此如果您未将采样率 (sr) 设置为与音频信号相同的采样频率,则垂直轴和水平轴将不正确。确保指定 sr 输入标志以匹配传入音频的采样频率。

除了 by rayryeng, it should be noted that the direct equivalent of numpy.fft.fftfreq() in librosa would be librosa.fft_frequencies()

您可以按如下方式使用:

y, sr = librosa.load('../recordings/high_pitch.m4a')
Nfft = 256
stft = librosa.stft(y, n_fft=Nfft, window=sig.windows.hamming)
freqs = librosa.fft_frequencies(sr=sr, n_fft=Nfft)

您可以按如下方式计算累积能量

samplerate = 48000
Nfft = 8192
freqs = librosa.fft_frequencies(sr=sr, n_fft=Nfft)
plt.loglog(freqs, np.mean(mag**2, axis=1)/(Nfft/2)**2)
plt.xlabel('freq [Hz]')

如果你想对一个频率范围内的能量求和,你可以在频率上使用索引 mag,例如

np.sum(np.mean(mag[(freqs > 1000) & (freqs < 1480), :]**2, axis=1))/(Nfft/2)**2

更一般地说,您可以应用过滤器 gain(f),上面的结果是使用 gain(f) 矩形获得的。

np.sum(np.mean(mag**2, axis=1)*gain(freq))/(Nfft/2)**2

免责声明:我不知道这些比例因子是否适合您。只有形状。