これが私のPythonコードで、この回答のために簡略化されています:
import scipy, pylab
def stft(x, fs, framesz, hop):
framesamp = int(framesz*fs)
hopsamp = int(hop*fs)
w = scipy.hanning(framesamp)
X = scipy.array([scipy.fft(w*x[i:i+framesamp])
for i in range(0, len(x)-framesamp, hopsamp)])
return X
def istft(X, fs, T, hop):
x = scipy.zeros(T*fs)
framesamp = X.shape[1]
hopsamp = int(hop*fs)
for n,i in enumerate(range(0, len(x)-framesamp, hopsamp)):
x[i:i+framesamp] += scipy.real(scipy.ifft(X[n]))
return x
ノート:
- リスト内包表記は、numpy/scipy でシグナルのブロック処理をシミュレートするために使用するのが好きなちょっとしたトリックです。それ
blkproc
はMatlabのようなものです。for
ループの代わりに、コマンド (例: fft
) をリスト内包表記内の信号の各フレームに適用し、scipy.array
それを 2D 配列にキャストします。これを使用して、スペクトログラム、クロマグラム、MFCC グラムなどを作成します。
- この例では、単純なオーバーラップ アンド アド メソッドを で使用し
istft
ます。元の信号を再構築するために、連続するウィンドウ関数の合計は一定でなければならず、できれば 1.0 に等しい必要があります。この場合、ハン (またはhanning
) ウィンドウと 50% のオーバーラップを選択しましたが、これは完全に機能します。詳細については、このディスカッションを参照してください。
- ISTFT を計算するもっと原理的な方法があるでしょう。この例は、主に教育を目的としています。
テスト:
if __name__ == '__main__':
f0 = 440 # Compute the STFT of a 440 Hz sinusoid
fs = 8000 # sampled at 8 kHz
T = 5 # lasting 5 seconds
framesz = 0.050 # with a frame size of 50 milliseconds
hop = 0.025 # and hop size of 25 milliseconds.
# Create test signal and STFT.
t = scipy.linspace(0, T, T*fs, endpoint=False)
x = scipy.sin(2*scipy.pi*f0*t)
X = stft(x, fs, framesz, hop)
# Plot the magnitude spectrogram.
pylab.figure()
pylab.imshow(scipy.absolute(X.T), origin='lower', aspect='auto',
interpolation='nearest')
pylab.xlabel('Time')
pylab.ylabel('Frequency')
pylab.show()
# Compute the ISTFT.
xhat = istft(X, fs, T, hop)
# Plot the input and output signals over 0.1 seconds.
T1 = int(0.1*fs)
pylab.figure()
pylab.plot(t[:T1], x[:T1], t[:T1], xhat[:T1])
pylab.xlabel('Time (seconds)')
pylab.figure()
pylab.plot(t[-T1:], x[-T1:], t[-T1:], xhat[-T1:])
pylab.xlabel('Time (seconds)')