Invertible STFT و ISTFT في بايثون
-
20-09-2019 - |
سؤال
هل هناك أي الأغراض العامة شكل وقت قصير تحويل فورييه مع المقابلة معكوس تحويل بنيت في SciPy أو NumPy أو أيا كان ؟
هناك pyplot specgram
وظيفة في matplotlib التي المكالمات ax.specgram()
, الذي يدعو mlab.specgram()
, الذي يدعو _spectral_helper()
:
#The checks for if y is x are so that we can use the same function to #implement the core of psd(), csd(), and spectrogram() without doing #extra calculations. We return the unaveraged Pxy, freqs, and t.
ولكن
هذا هو مساعد الوظيفة التي تطبق القواسم المشتركة بين 204 #psd, csd, والطيفية.فمن لا من المفترض أن يتم استخدامها خارج mlab
لست متأكدا إذا كان هذا يمكن استخدامها للقيام STFT و ISTFT ، على الرغم من.هل هناك أي شيء آخر ، أو أن أترجم شيئا مثل هذه MATLAB وظائف?
أنا أعرف كيف أكتب بلدي المخصص التنفيذ ؛ أنا فقط أبحث عن شيء كامل المواصفات ، والتي يمكن التعامل مع مختلف وظائف النوافذ (ولكن لديه عاقل الافتراضي) ، تماما invertible مع الكولا ويندوز (istft(stft(x))==x
) ، تم اختبارها من قبل عدة أشخاص ، لا من جانب واحد الأخطاء يعالج ينتهي صفر الحشو جيدا, سريع RFFT تنفيذ حقيقي المدخلات ، إلخ.
المحلول
وأنا في وقت متأخر قليلا لهذا، ولكن scipy أدرك له يحمل في ثناياه عوامل <لأ href = "http://scipy.github.io/devdocs/generated/scipy.signal.istft.html#scipy.signal.istft" يختلط = "noreferrer نوفولو"> istft وظيفة اعتبارا من 0.19.0
نصائح أخرى
هنا هو بلدي كود بايثون مبسطة عن هذا الجواب:
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 array.يمكنني استخدام هذا لجعل الطيفية, chromagrams, 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)')
وهنا هو رمز STFT التي أستخدمها. STFT + ISTFT هنا يعطي <م> إعادة الإعمار المثالي م> (حتى بالنسبة للإطارات الأولى). I معدلة بشكل طفيف رمز معين هنا من قبل ستيف Tjoa: هنا حجم إشارة أعيد بناؤها هو نفسه كما ان من إشارة الدخل
import scipy, numpy as np
def stft(x, fftsize=1024, overlap=4):
hop = fftsize / overlap
w = scipy.hanning(fftsize+1)[:-1] # better reconstruction with this trick +1)[:-1]
return np.array([np.fft.rfft(w*x[i:i+fftsize]) for i in range(0, len(x)-fftsize, hop)])
def istft(X, overlap=4):
fftsize=(X.shape[1]-1)*2
hop = fftsize / overlap
w = scipy.hanning(fftsize+1)[:-1]
x = scipy.zeros(X.shape[0]*hop)
wsum = scipy.zeros(X.shape[0]*hop)
for n,i in enumerate(range(0, len(x)-fftsize, hop)):
x[i:i+fftsize] += scipy.real(np.fft.irfft(X[n])) * w # overlap-add
wsum[i:i+fftsize] += w ** 2.
pos = wsum != 0
x[pos] /= wsum[pos]
return x
librosa.core.stft
و <لأ href = "HTTP: //bmcfee.github.io/librosa/librosa.html#librosa.core.istft "يختلط =" noreferrer نوفولو "> istft
تبدو مشابهة جدا لما كنت تبحث عنه، على الرغم من أنها لم تكن موجودة في الوقت:
وlibrosa.core.stft(y, n_fft=2048, hop_length=None, win_length=None, window=None, center=True, dtype=<type 'numpy.complex64'>)
وانهم لا عكس تماما، على الرغم؛ ومدبب ينتهي.
وجدت آخر STFT لكن لا المقابلة معكوس الدالة:
http://code.google.com/p/pytfd/source/browse/trunk/pytfd/stft.py
def stft(x, w, L=None):
...
return X_stft
- w هو نافذة وظيفة كما صفيف
- L هو التداخل في عينات
وأيا من الإجابات أعلاه عملت بشكل جيد OOTB بالنسبة لي. لذلك أنا تعديل ستيف Tjoa ل.
import scipy, pylab
import numpy as np
def stft(x, fs, framesz, hop):
"""
x - signal
fs - sample rate
framesz - frame size
hop - hop size (frame size = overlap + hop size)
"""
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):
""" T - signal length """
length = T*fs
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]))
# calculate the inverse envelope to scale results at the ends.
env = scipy.zeros(T*fs)
w = scipy.hamming(framesamp)
for i in range(0, len(x)-framesamp, hopsamp):
env[i:i+framesamp] += w
env[-(length%hopsamp):] += w[-(length%hopsamp):]
env = np.maximum(env, .01)
return x/env # right side is still a little messed up...
وكما أنني وجدت هذا على جيثب، ولكن يبدو أن تعمل على خطوط الأنابيب بدلا من المصفوفات العادية:
http://github.com/ronw/frontend/blob /master/basic.py#LID281
def STFT(nfft, nwin=None, nhop=None, winfun=np.hanning):
...
return dataprocessor.Pipeline(Framer(nwin, nhop), Window(winfun),
RFFT(nfft))
def ISTFT(nfft, nwin=None, nhop=None, winfun=np.hanning):
...
return dataprocessor.Pipeline(IRFFT(nfft), Window(winfun),
OverlapAdd(nwin, nhop))
وأعتقد scipy.signal لديه ما كنت تبحث عنه. لديه افتراضات معقولة، ويدعم أنواع متعددة نافذة، الخ ...
HTTP: // مستندات. scipy.org/doc/scipy-0.17.0/reference/generated/scipy.signal.spectrogram.html
from scipy.signal import spectrogram
freq, time, Spec = spectrogram(signal)
وهناك نسخة من الجواب basj الثابتة.
import scipy, numpy as np
import matplotlib.pyplot as plt
def stft(x, fftsize=1024, overlap=4):
hop=fftsize//overlap
w = scipy.hanning(fftsize+1)[:-1] # better reconstruction with this trick +1)[:-1]
return np.vstack([np.fft.rfft(w*x[i:i+fftsize]) for i in range(0, len(x)-fftsize, hop)])
def istft(X, overlap=4):
fftsize=(X.shape[1]-1)*2
hop=fftsize//overlap
w=scipy.hanning(fftsize+1)[:-1]
rcs=int(np.ceil(float(X.shape[0])/float(overlap)))*fftsize
print(rcs)
x=np.zeros(rcs)
wsum=np.zeros(rcs)
for n,i in zip(X,range(0,len(X)*hop,hop)):
l=len(x[i:i+fftsize])
x[i:i+fftsize] += np.fft.irfft(n).real[:l] # overlap-add
wsum[i:i+fftsize] += w[:l]
pos = wsum != 0
x[pos] /= wsum[pos]
return x
a=np.random.random((65536))
b=istft(stft(a))
plt.plot(range(len(a)),a,range(len(b)),b)
plt.show()
إذا كان لديك الوصول إلى مكتبة ثنائي C أن تفعل ما تريد، ثم استخدم HTTP: // code.google.com/p/ctypesgen/ لتوليد واجهة بيثون إلى تلك المكتبة.