Domanda

Sono sconcertato dai risultati che sto ottenendo da FFT e gradirebbe qualsiasi aiuto.

sto usando FFTW 3.2.2 ma hanno ottenuto risultati simili con altre implementazioni FFT (in Java). Quando prendo la FFT di un'onda sinusoidale, la scala del risultato dipende dalla frequenza (Hz) dell'onda - particolare, se è vicino ad un numero intero oppure no. I valori risultanti sono in scala molto piccola quando la frequenza è vicino a un numero intero, e sono ordini di grandezza più grande quando la frequenza è tra numeri interi. Questo grafico mostra la grandezza del picco nel risultato FFT corrispondente alla frequenza dell'onda, per diverse frequenze. È giusto??

Ho verificato che la FFT inversa della FFT è uguale ai tempi originali onda sinusoidale il numero di campioni, ed è. La forma della FFT sembra essere corretta.

Non sarebbe poi così male se fossi all'analisi delle singole onde sinusoidali, perché ho potuto solo cercare il picco nella FFT a prescindere dalla sua altezza. Il problema è che voglio analizzare somme di onde sinusoidali. Se sto analizzando una somma di onde sinusoidali a, diciamo, 440 Hz e 523,25 Hz, allora solo il picco per l'uno a 523,25 Hz presenta. Il picco per l'altro è così piccolo che sembra proprio come il rumore. Ci deve essere un modo per fare questo lavoro perché in Matlab fa work-- ottengo picchi di dimensioni simili ad entrambe le frequenze. Come posso cambiare il codice sottostante per equalizzare la scala per diverse frequenze?

#include <cstdlib>
#include <cstring>
#include <cmath> 
#include <fftw3.h>
#include <cstdio>
using namespace std; 

const double PI = 3.141592;

/* Samples from 1-second sine wave with given frequency (Hz) */
void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor); 

int main(int argc, char** argv) {

 /* Args: frequency (Hz), samplesPerSecond, ampFactor */
 if (argc != 4)  return -1; 
 double frequency  = atof(argv[1]); 
 int samplesPerSecond = atoi(argv[2]); 
 double ampFactor  = atof(argv[3]); 

 /* Init FFT input and output arrays. */
 double * wave = new double[samplesPerSecond]; 
 sineWave(wave, frequency, samplesPerSecond, ampFactor); 
 double * fftHalfComplex = new double[samplesPerSecond]; 
 int fftLen = samplesPerSecond/2 + 1; 
 double * fft = new double[fftLen]; 
 double * ifft = new double[samplesPerSecond]; 

 /* Do the FFT. */
 fftw_plan plan = fftw_plan_r2r_1d(samplesPerSecond, wave, fftHalfComplex, FFTW_R2HC, FFTW_ESTIMATE);
 fftw_execute(plan); 
 memcpy(fft, fftHalfComplex, sizeof(double) * fftLen); 
 fftw_destroy_plan(plan);

 /* Do the IFFT. */
 fftw_plan iplan = fftw_plan_r2r_1d(samplesPerSecond, fftHalfComplex, ifft, FFTW_HC2R, FFTW_ESTIMATE); 
 fftw_execute(iplan); 
 fftw_destroy_plan(iplan);

 printf("%s,%s,%s", argv[1], argv[2], argv[3]); 
 for (int i = 0; i < samplesPerSecond; i++) {
  printf("\t%.6f", wave[i]); 
 }
 printf("\n"); 
 printf("%s,%s,%s", argv[1], argv[2], argv[3]); 
 for (int i = 0; i < fftLen; i++) {
  printf("\t%.9f", fft[i]); 
 }
 printf("\n"); 
 printf("\n"); 
 printf("%s,%s,%s", argv[1], argv[2], argv[3]); 
 for (int i = 0; i < samplesPerSecond; i++) {
  printf("\t%.6f (%.6f)", ifft[i], samplesPerSecond * wave[i]);  // actual and expected result
 }

 delete[] wave; 
 delete[] fftHalfComplex; 
 delete[] fft; 
 delete[] ifft; 
}

void sineWave(double a[], double frequency, int samplesPerSecond, double ampFactor) {
 for (int i = 0; i < samplesPerSecond; i++) {
  double time = i / (double) samplesPerSecond; 
  a[i] = ampFactor * sin(2 * PI * frequency * time); 
 }
}
È stato utile?

Soluzione

  

I valori risultanti sono in scala molto piccola quando la frequenza è vicino a un numero intero, e sono ordini di grandezza più grande quando la frequenza è tra numeri interi.

Questo perché una Fast Fourier Transform assume l'ingresso è periodica e viene ripetuta all'infinito. Se si dispone di un numero non integrale di onde sinusoidali, e si ripete questa forma d'onda, non è una sinusoide perfetta. Questo provoca un risultato FFT che soffre di "dispersione spettrale"

Se vuoi in funzioni finestra . Questi attenuano l'ingresso all'inizio e alla fine, in modo che le perdite spettrale è diminuita.

P.S .: se si desidera ottenere contenuti frequenza precisa intorno alla fondamentale, catturare un sacco di cicli d'onda e non hai bisogno di catturare troppi punti per ciclo (32 o 64 punti per ciclo è probabilmente un sacco). Se si desidera ottenere il contenuto di frequenza preciso in armoniche superiori, catturare un minor numero di cicli, e più punti per ciclo.

Altri suggerimenti

Posso solo raccomandare che si guarda il codice GNU Radio. Il file che potrebbe essere di particolare interesse per voi è usrp_fft.py.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top