【问题标题】:Librosa's fft and Scipy's fft are different?Librosa 的 fft 和 Scipy 的 fft 不一样?
【发布时间】:2019-10-10 16:47:22
【问题描述】:

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

Scipy

​​>

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

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 的文档中,我没有看到很多可以调整的参数。

【问题讨论】:

  • 您使用的是 librosa 的 STFT,而不是 FFT。有区别,因为 STFT 通常包括窗口和填充。请参阅下面的答案。

标签: python python-3.x scipy spectrogram librosa


【解决方案1】:

原因是 librosa 的 stft 的参数 center。默认为True(以及pad_mode = 'reflect')。

来自文档:

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

center:boolean

如果为 True,则填充信号 y,使帧 D[:, t] 以 y[t * hop_length] 为中心。

如果为 False,则 D[:, t] 从 y[t * hop_length] 开始

pad_mode:string

如果 center=True,则在信号边缘使用的填充模式。默认情况下,STFT 使用反射填充。

像这样调用 STFT

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

确实通向一条直线:

请注意,librosa 的 stft 默认也使用Hann window function。如果您想避免这种情况并使其更像您的 Scipy stft 实现,请使用仅包含 1 的窗口调用 stft:

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

你会注意到线条变细了。

【讨论】:

    猜你喜欢
    • 2015-11-16
    • 1970-01-01
    • 2020-10-23
    • 2020-03-17
    • 2017-09-28
    • 1970-01-01
    • 2014-09-21
    • 2014-06-16
    • 2021-03-09
    相关资源
    最近更新 更多