Análisis de frecuencia en Python

Estoy tratando de usar Python para recuperar las frecuencias dominantes de una entrada de audio en vivo. Por el momento estoy experimentando con la transmisión de audio del micrófono incorporado de mi Laptop, pero al probar el siguiente código, estoy obteniendo resultados muy pobres.

# 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() 

El código es canibalizado a partir de esta pregunta , que trata sobre el análisis de Fourier de un archivo wave. Está en la estructura modular actual, ya que lo estoy implementando con el entorno de juego de Blender (de ahí la clave de importación en la parte superior), pero estoy bastante seguro de que mi problema se encuentra en el módulo AnalyseStream.

Cualquier consejo que pueda ofrecer sería muy apreciado.

ACTUALIZACIÓN: Obtengo los valores correctos de vez en cuando, pero se encuentran con poca frecuencia entre los valores incorrectos (<10Hz). Eso y el programa se ejecuta REALMENTE lentamente.

Hola, encuentre el máximo de cómputo que el FFT para el análisis en tiempo real se vuelve un poco lento.

Si no trabajará con formas de onda complejas para encontrar las frecuencias, puede utilizar cualquier método basado en el dominio del tiempo, como el cruce por cero, donde el rendimiento será mejor.

En el último año realizo una función simple para calcular la frecuencia mediante el cruce por cero.

 #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

También está la función scipy.signal.lombscargle que calcula el periodogtwig de Lomb-Scargle y está disponible desde v0.10.0. Este método debería funcionar incluso para señales muestreadas de manera desigual. Parece que la media de los datos se debe restar para que este método funcione correctamente, aunque esto no se menciona en la documentación. Más información se puede encontrar en la guía de referencia de scipy: http://docs.scipy.org/doc/scipy/reference/tutorial/signal.html#lomb-scargle-periodograms-spectral-lombscargle