首页 > 解决方案 > Librosa 的 fft 和 Scipy 的 fft 不一样?

问题描述

Librosa 和 Scipy 都有这个fft功能,但是,即使输入相同的信号,它们也会给我不同的频谱图输出。

西皮

我正在尝试使用以下代码获取频谱图

import numpy as np                                       # fast vectors and matrices
import matplotlib.pyplot as plt                          # plotting
from scipy import fft      

X = np.sin(np.linspace(0,1e10,5*44100))

fs = 44100          # assumed sample frequency in Hz
window_size = 2048  # 2048-sample fourier windows
stride = 512        # 512 samples between windows
wps = fs/float(512) # ~86 windows/second
Xs = np.empty([int(2*wps),2048])

for i in range(Xs.shape[0]):
    Xs[i] = np.abs(fft(X[i*stride:i*stride+window_size]))

fig = plt.figure(figsize=(20,7))
plt.imshow(Xs.T[0:150],aspect='auto')
plt.gca().invert_yaxis()
fig.axes[0].set_xlabel('windows (~86Hz)')
fig.axes[0].set_ylabel('frequency')
plt.show()

然后我得到以下频谱图 在此处输入图像描述

利布罗萨

现在我尝试使用 Librosa 获得相同的频谱图

from librosa import stft

X_libs = stft(X, n_fft=window_size, hop_length=stride)
X_libs = np.abs(X_libs)[:,:int(2*wps)]

fig = plt.figure(figsize=(20,7))
plt.imshow(X_libs[0:150],aspect='auto')
plt.gca().invert_yaxis()
fig.axes[0].set_xlabel('windows (~86Hz)')
fig.axes[0].set_ylabel('frequency')
plt.show()

在此处输入图像描述

问题

两个频谱图明显不同,具体来说,Librosa版本一开始就有攻击。造成差异的原因是什么?在 Scipy 和 Librosa 的文档中,我没有看到很多可以调整的参数。

标签: pythonpython-3.xscipyspectrogramlibrosa

解决方案


The reason for this is the argument center for librosa's stft. By default it's True (along with pad_mode = 'reflect').

From the docs:

librosa.core.stft(y, n_fft=2048, hop_length=None, win_length=None, window='hann', center=True, dtype=, pad_mode='reflect')

center:boolean

If True, the signal y is padded so that frame D[:, t] is centered at y[t * hop_length].

If False, then D[:, t] begins at y[t * hop_length]

pad_mode:string

If center=True, the padding mode to use at the edges of the signal. By default, STFT uses reflection padding.

Calling the STFT like this

X_libs = stft(X, n_fft=window_size, hop_length=stride,
              center=False)

does lead to a straight line:

librosa.stft with center = False

Note that librosa's stft also uses the Hann window function by default. If you want to avoid this and make it more like your Scipy stft implementation, call the stft with a window consisting only of ones:

X_libs = stft(X, n_fft=window_size, hop_length=stride,
              window=np.ones(window_size),
              center=False)

librosa.stft with center = False and no window function

You'll notice that the line is thinner.


推荐阅读