2012-01-31 24 views
11

Canlı ses girişinin baskın frekanslarını almak için Python kullanmaya çalışıyorum. Şu an için, Laptop'umun yerleşik mikrofonunda ses akışını denemeyi deniyorum, ancak aşağıdaki kodu test ederken çok kötü sonuçlar elde ediyorum.Python'da Sıklık Analizi

# Read from Mic Input and find the freq's 
    import pyaudio 
    import numpy as np 
    import bge 
    import wave 

    chunk = 2048 

    # use a Blackman window 
    window = np.blackman(chunk) 
    # open stream 
    FORMAT = pyaudio.paInt16 
    CHANNELS = 1 
    RATE = 1920 

    p = pyaudio.PyAudio() 
    myStream = p.open(format = FORMAT, channels = CHANNELS, rate = RATE, input = True, frames_per_buffer = chunk) 

    def AnalyseStream(cont): 
     data = myStream.read(chunk) 
     # unpack the data and times by the hamming window 
     indata = np.array(wave.struct.unpack("%dh"%(chunk), data))*window 
     # Take the fft and square each value 
     fftData=abs(np.fft.rfft(indata))**2 
     # find the maximum 
     which = fftData[1:].argmax() + 1 
     # use quadratic interpolation around the max 
     if which != len(fftData)-1: 
      y0,y1,y2 = np.log(fftData[which-1:which+2:]) 
      x1 = (y2 - y0) * .5/(2 * y1 - y2 - y0) 
      # find the frequency and output it 
      thefreq = (which+x1)*RATE/chunk 
      print("The freq is %f Hz." % (thefreq)) 
     else: 
      thefreq = which*RATE/chunk 
      print("The freq is %f Hz." % (thefreq)) 

    # stream.close() 
    # p.terminate() 

kodu bir dalga dosya Fourier analizi ile ilgilidir this question gelen cannibalized edilir. Blender Oyun Ortamı ile (bu nedenle de üstte içe aktarım beze) uygulayacağım mevcut modüler yapıdadır, ama benim sorunumun AnalyseStream modülünde yer aldığından eminim.

Sunduğunuz herhangi bir tavsiye çok takdir edilecektir.

GÜNCELLEŞTIRME: Doğru değerleri her şimdi ve tekrar alıyorum, ancak yanlış değerler arasında nadiren bulunurlar (< 10Hz). Bu ve program yavaşça GERÇEKTEN çalışır.

+1

1920 örnek oranı balık görünüyor. Daha tipik ses örnek oranları 8000 veya 44100'dür. Doğruluk testi için ne tür bir ses kullanıyorsunuz? Eğer bir sinüs dalgası jeneratöründen değilse, duyduğunuz ses seviyesi ve frekans pikleri çok farklı olabilir. – hotpaw2

cevap

6

Merhaba, gerçek zamanlı analiz için FFT'nin maksimum hesaplaması biraz yavaşlıyor.

Eğer frekansları bulmak için karmaşık dalga formlarıyla çalışmazsanız, performansın daha iyi olacağı sıfır geçişi gibi Zaman alanına dayalı herhangi bir yöntemi kullanabilirsiniz.

Geçen yıl, Sıfır geçişi ile frekansı dengelemek için basit bir işlev yapıyorum.

#Eng Eder de Souza 01/12/2011 
#ederwander 
from matplotlib.mlab import find 
import pyaudio 
import numpy as np 
import math 


chunk = 1024 
FORMAT = pyaudio.paInt16 
CHANNELS = 1 
RATE = 44100 
RECORD_SECONDS = 20 


def Pitch(signal): 
    signal = np.fromstring(signal, 'Int16'); 
    crossing = [math.copysign(1.0, s) for s in signal] 
    index = find(np.diff(crossing)); 
    f0=round(len(index) *RATE /(2*np.prod(len(signal)))) 
    return f0; 


p = pyaudio.PyAudio() 

stream = p.open(format = FORMAT, 
channels = CHANNELS, 
rate = RATE, 
input = True, 
output = True, 
frames_per_buffer = chunk) 

for i in range(0, RATE/chunk * RECORD_SECONDS): 
    data = stream.read(chunk) 
    Frequency=Pitch(data) 
    print "%f Frequency" %Frequency 

ederwander

2

da Lomb-Scargle periodogramı hesaplar ve v0.10.0 beri mevcuttur fonksiyonu scipy.signal.lombscargle bulunmaktadır. Bu yöntem, eşit olmayan örnekleme sinyalleri için bile çalışmalıdır. Bu yöntemin belgelerde belirtilmesine rağmen, bu yöntemin çıkartılması için verilerin ortalamasının çıkarılması gerektiği görülmektedir. fazla bilgi scipy başvuru kılavuzunda bulunabilir: http://docs.scipy.org/doc/scipy/reference/tutorial/signal.html#lomb-scargle-periodograms-spectral-lombscargle