|
# Originally from http://stackoverflow.com/a/6891772/125507 |
|
|
|
import scipy, pylab |
|
|
|
def stft(x, fs, framesz, hop): |
|
"""x is the time-domain signal |
|
fs is the sampling frequency |
|
framesz is the frame size, in seconds |
|
hop is the the time between the start of consecutive frames, in seconds |
|
|
|
""" |
|
framesamp = int(framesz*fs) |
|
hopsamp = int(hop*fs) |
|
w = scipy.hamming(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 is the short-time Fourier transform |
|
fs is the sampling frequency |
|
T is the total length of the time-domain output in seconds |
|
hop is the the time between the start of consecutive frames, in seconds |
|
|
|
""" |
|
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 |
|
|
|
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.020 # and hop size of 20 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)') |