2011-04-11 11 views
7

Estoy buscando calcular una correlación rápida usando FFT y la biblioteca kissfft, y la escala debe ser precisa. ¿Qué escalado es necesario (hacia adelante y hacia atrás) y qué valor uso para escalar mis datos?escala de kissfft

+2

Sí que debería haber sido más específico. Esperaba que alguien me ahorrara el problema de descubrir el escalado yo mismo (específico de kissfft), sin embargo lo hice yo mismo y puedo decirte que tuve que ** escalar el inverso por 1/N **. Por supuesto, la escala se omite inicialmente para fines de eficiencia, pero es importante cuando se calculan las correlaciones. No importa tanto para la autocorrelación, ya que el resultado es proporcional, pero lo que sí importa es cuando se calcula algo como el ASDF que tiene dos términos precisos para agregar al final. –

+5

Información más detallada, probada en kiss_fftr (implementación para FFT reales): el fttr directo escala las amplitudes por 'nfft/2', mientras que el fftr inverso escala las amplitudes por' 2' independientemente de nfft. Para obtener las amplitudes originales, tiene que escalar por '2/nfft' y' 1/2' respectivamente. (Esto explica por qué tiene que escalar por '1/nfft' al hacer las FFT directas e inversas en serie.) – tmandry

Respuesta

11

Los 3 factores de escala FFT más comunes son:

  • 1,0 FFT directa, 1,0/N FFT inversa

  • 1,0/N FFT directa, FFT 1,0 inversa

  • 1.0/sqrt (N) en ambas direcciones, FFT & IFFT

Dada la posible ambigüedad en la documentación, y para cualquier escalado que el usuario espere sea "correcto" para sus propósitos, lo mejor es alimentar una onda sinusoidal pura de amplitud conocida (1.0 flotación o 255 enteros) y exactamente periódica en la longitud de FFT a la FFT (y/o IFFT) en cuestión, y ver si la escala coincide con uno de los anteriores, es tal vez diferente de uno de los anteriores por 2X o sqrt (2), o la escala deseada es algo completamente diferente.

p. Ej. Escriba una prueba unitaria para kissfft en su entorno para sus tipos de datos.

+2

Esto es lo que terminé haciendo, pero esperaba que alguien supiera que me ahorraría el problema. Este es un buen consejo en general. –

+1

No creerá cuán confusa es la literatura de FFT si no sabe que existen estas representaciones diferentes :) –

6

multiplicar cada respuesta de frecuencia por 1/sqrt (N), para una escala global de 1/N

en pseudocódigo:

ifft(fft(x)*conj(fft(y))/N) == circular_correlation(x,y)

Al menos esto es cierto para kisfft con punto flotante tipos.

La salida del siguiente código C++ ejemplo debe ser algo como

la correlación circular de [1, 3i, 0 0 ....] consigo mismo = (10,0), (1.19796e- 10,3), (- 4.91499e-08,1.11519e-15), (1.77301e-08, -1.19588e-08) ...

#include <complex> 
#include <iostream> 
#include "kiss_fft.h" 
using namespace std; 

int main() 
{ 
    const int nfft=256; 
    kiss_fft_cfg fwd = kiss_fft_alloc(nfft,0,NULL,NULL); 
    kiss_fft_cfg inv = kiss_fft_alloc(nfft,1,NULL,NULL); 

    std::complex<float> x[nfft]; 
    std::complex<float> fx[nfft]; 
    memset(x,0,sizeof(x)); 
    x[0] = 1; 
    x[1] = std::complex<float>(0,3); 

    kiss_fft(fwd,(kiss_fft_cpx*)x,(kiss_fft_cpx*)fx); 
    for (int k=0;k<nfft;++k) { 
     fx[k] = fx[k] * conj(fx[k]); 
     fx[k] *= 1./nfft; 
    } 
    kiss_fft(inv,(kiss_fft_cpx*)fx,(kiss_fft_cpx*)x); 
    cout << "the circular correlation of [1, 3i, 0 0 ....] with itself = "; 
    cout 
     << x[0] << "," 
     << x[1] << "," 
     << x[2] << "," 
     << x[3] << " ... " << endl; 
    kiss_fft_free(fwd); 
    kiss_fft_free(inv); 
    return 0; 
} 
+0

El código que estoy usando es: 'ifft (fft (x) * conj (fft (y)))/N == corr' Con kissfft v1_2_9 –

+0

Sí. Lamento dirigirlo al principio. He actualizado la descripción para que coincida con lo que mi código realmente estaba haciendo. –