背景
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.