たれぱんのびぼーろく

わたしの備忘録、生物学とプログラミングが多いかも

librosaとscipyでFFTをマッチさせる

背景

librosaはSTFTがとっても便利。
プリミティブにFFTをしようと思ったらscipy.fft.rfftになる.
この2つ、同じ動作するのだろうか?

動作

デフォルト動作だと違う動きをする.
以下が同じ動作をする

librosa.stft(x_full, n_fft=n_fft, window="boxcar", center=False)
scipy.fft.rfft(x)

librosa.stftは実数信号のみを受け付け、デフォルトで窓関数を適用、windowはcenteringする.
なので窓関数をboxcar/矩形波にして事実上の窓無し、centering OFFにする.

scipy.fft.rfftはただただ入力全長にDFT掛けるだけ.

検証

import numpy as np
import scipy.fft
import matplotlib.pyplot as plt
import librosa

# Settings
n_fft = 512
input_r = np.linspace(0., 1., n_fft)

# Conversion
spec_mag_rfft = np.abs(scipy.fft.rfft(input_r))
spec_mag_stft = np.abs(librosa.stft(input_r, n_fft=n_fft, window="boxcar", center=False))[:, 0]
spec_mag_stft_hann = np.abs(librosa.stft(input_r, n_fft=n_fft, center=False))[:, 0]

# Plot
freq = scipy.fft.rfftfreq(n_fft)

plt.subplot(2, 1, 1)
plt.title("Frequency domain")
plt.plot(freq, spec_mag_rfft)
plt.plot(freq, spec_mag_stft)

plt.subplot(2, 1, 2)
plt.title("Diff")
plt.plot(freq, spec_mag_rfft - spec_mag_stft)
print(f"maximum diff: {np.max(np.abs(spec_mag_rfft - spec_mag_stft))}") # 0.
print(f"maximum diff (window): {np.max(np.abs(spec_mag_rfft - spec_mag_stft_hann))}") # very big

IFFT

も同じ感じ.

import sys
import numpy as np
import scipy.fft
import matplotlib.pyplot as plt
import librosa

# Settings
n_fft = 512
input_log_mag_spec = 20. * np.log(np.abs(scipy.fft.rfft(np.linspace(0., 1., n_fft)))  + sys.float_info.min)

# Conversion
ceps_irfft = np.abs(scipy.fft.irfft(input_log_mag_spec))
ceps_istft = np.abs(librosa.istft(input_log_mag_spec.reshape((input_log_mag_spec.shape[0], 1)), window="boxcar", center=False))

# Plot
freq = range(0, n_fft)

plt.subplot(2, 1, 1)
plt.title("Cefrency domain")
plt.plot(freq, ceps_irfft)
plt.plot(freq, ceps_istft)

plt.subplot(2, 1, 2)
plt.title("Diff")
plt.plot(freq, ceps_irfft - ceps_istft)
print(f"maximum diff: {np.max(np.abs(ceps_irfft - ceps_istft))}") # 0.