JTransforms FFT en Android de datos de PCM

He estado jugando con esto ahora por algún tiempo, no puedo resolver lo que estoy destinado a hacer aquí.

Estoy leyendo en datos de audio PCM en una matriz audioData:

recorder.read(audioData,0,bufferSize); //read the PCM audio data into the audioData array 

Quiero usar la biblioteca JTransform de Piotr Wendykier para preformar una FFT en mis datos PCM para obtener la frecuencia.

 import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D; 

Por el momento tengo esto:

  DoubleFFT_1D fft = new DoubleFFT_1D(1024); // 1024 is size of array for (int i = 0; i < 1023; i++) { a[i]= audioData[i]; if (audioData[i] != 0) Log.v(TAG, "audiodata=" + audioData[i] + " fft= " + a[i]); } fft.complexForward(a); 

No puedo hacer sentido de cómo trabajar esto, alguien puede darme algunos consejos? ¿Tendré que realizar cálculos después de esto?

Estoy seguro de que estoy muy lejos, cualquier cosa sería muy apreciada!

Ben

Si sólo está buscando la frecuencia de un solo tono sinusoidal en la forma de onda de entrada, entonces necesita encontrar el pico FFT con la magnitud más grande, donde:

 Magnitude = sqrt(re*re + im*im) 

El índice i de este pico de magnitud más grande le indicará la frecuencia aproximada de su sinusoide:

 Frequency = Fs * i / N 

dónde:

 Fs = sample rate (Hz) i = index of peak N = number of points in FFT (1024 in this case) 

Sí, usted necesita utilizar la función realForward en lugar de complexForward, porque le pasa una matriz real y no una matriz compleja de doc .

EDITAR:

O puede obtener la parte real y realizar complejo a fft complejo como este:

 double[] in = new double[N]; read ... double[] fft = new double[N * 2]; for(int i = 0; i < ffsize; ++i) { fft[2*i] = mic[i]; fft[2*i+1] = 0.0; } fft1d.complexForward(fft); 

Procuro y comparo resultados con matlab, y no obtengo los mismos resultados … (magnitud)

Ya que he pasado algunas horas en conseguir esto para trabajar aquí es una implementación completa en Java:

 import org.jtransforms.fft.DoubleFFT_1D; public class FrequencyScanner { private double[] window; public FrequencyScanner() { window = null; } /** extract the dominant frequency from 16bit PCM data. * @param sampleData an array containing the raw 16bit PCM data. * @param sampleRate the sample rate (in HZ) of sampleData * @return an approximation of the dominant frequency in sampleData */ public double extractFrequency(short[] sampleData, int sampleRate) { /* sampleData + zero padding */ DoubleFFT_1D fft = new DoubleFFT_1D(sampleData.length + 24 * sampleData.length); double[] a = new double[(sampleData.length + 24 * sampleData.length) * 2]; System.arraycopy(applyWindow(sampleData), 0, a, 0, sampleData.length); fft.realForward(a); /* find the peak magnitude and it's index */ double maxMag = Double.NEGATIVE_INFINITY; int maxInd = -1; for(int i = 0; i < a.length / 2; ++i) { double re = a[2*i]; double im = a[2*i+1]; double mag = Math.sqrt(re * re + im * im); if(mag > maxMag) { maxMag = mag; maxInd = i; } } /* calculate the frequency */ return (double)sampleRate * maxInd / (a.length / 2); } /** build a Hamming window filter for samples of a given size * See http://www.labbookpages.co.uk/audio/firWindowing.html#windows * @param size the sample size for which the filter will be created */ private void buildHammWindow(int size) { if(window != null && window.length == size) { return; } window = new double[size]; for(int i = 0; i < size; ++i) { window[i] = .54 - .46 * Math.cos(2 * Math.PI * i / (size - 1.0)); } } /** apply a Hamming window filter to raw input data * @param input an array containing unfiltered input data * @return a double array containing the filtered data */ private double[] applyWindow(short[] input) { double[] res = new double[input.length]; buildHammWindow(input.length); for(int i = 0; i < input.length; ++i) { res[i] = (double)input[i] * window[i]; } return res; } } 

FrequencyScanner devolverá una aproximación de la frecuencia dominante en los datos de muestra presentados. Aplica una ventana Hamming a su entrada para permitir el paso de muestras arbitrarias de un flujo de audio. La precisión se consigue mediante relleno interno cero de los datos de la muestra antes de realizar la transformación FFT. (Sé que hay maneras mejores – y mucho más complejas de hacer esto pero el acercamiento del relleno es suficiente para mis necesidades personales).

I testet it contra raw 16bit PCM muestras creadas a partir de sonidos de referencia para 220hz y 440hz y los resultados coinciden.

Si está buscando la FFT de una entrada de audio (1D, datos reales), ¿no debería estar usando el 1D REAL FFT?

  • Creación de un archivo WAV a partir de datos PCM sin procesar utilizando el SDK de Android
  • Convertir PCM-16 a AMR usando AmrInputStream
  • PCM -> AAC (Encoder) -> PCM (Decodificador) en tiempo real con optimización correcta
  • Android AudioRecord y AudioTrack codec opciones?
  • ¿Cómo puedo obtener datos de frecuencia de PCM usando FFT
  • Android AudioTrack que juega el archivo .wav, consiguiendo solamente el ruido blanco
  • Android MediaPlayer hace que el juego se congele con "AudioHardware pcm la reproducción se va a esperar"
  • ¿Cómo obtener la frecuencia del resultado fft?
  • Conversión de PCM a AAC mediante mediacodec
  • Codificar wav a AAC en Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.