Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Librosa's fft and Scipy's fft are different?

Both Librosa and Scipy have the fft function, however, they give me a different spectrogram output even with the same signal input.

Scipy

I am trying to get the spectrogram with the following code

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()

Then I get the following spectrogram enter image description here

Librosa

Now I try to get the same spectrogram with 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()

enter image description here

Question

The two spectrogram are obviously different, specifically, the Librosa version has an attack at the very beginning. What causes the difference? I don't see many parameters that I can tune in the documentation for Scipy and Librosa.

like image 875
Raven Cheuk Avatar asked May 24 '19 05:05

Raven Cheuk


1 Answers

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.

like image 100
Hendrik Avatar answered Nov 10 '22 00:11

Hendrik