Comprensione dell'output FFT


88

Ho bisogno di aiuto per comprendere l'output del calcolo DFT / FFT.

Sono un ingegnere informatico esperto e ho bisogno di interpretare alcune letture dell'accelerometro dello smartphone, come trovare le frequenze principali. Sfortunatamente, ho dormito per la maggior parte delle mie lezioni di EE al college quindici anni fa, ma ho letto su DFT e FFT negli ultimi giorni (con scarso successo, a quanto pare).

Per favore, nessuna risposta di "vai a prendere una lezione di EE". In realtà ho intenzione di farlo se il mio datore di lavoro mi pagherà. :)

Ecco il mio problema:

Ho catturato un segnale a 32 Hz. Ecco un campione di 1 secondo di 32 punti, che ho tracciato in Excel.

inserisci qui la descrizione dell'immagine

Ho quindi ricevuto del codice FFT scritto in Java dalla Columbia University (dopo aver seguito i suggerimenti in un post su " FFT affidabile e veloce in Java ").

L'output di questo programma è il seguente. Credo che stia eseguendo una FFT sul posto, quindi riutilizza lo stesso buffer sia per l'input che per l'output.

Before: 

Re: [0.887  1.645  2.005  1.069  1.069  0.69  1.046  1.847  0.808  0.617  0.792  1.384  1.782  0.925  0.751  0.858  0.915  1.006  0.985  0.97  1.075  1.183  1.408  1.575  1.556  1.282  1.06  1.061  1.283  1.701  1.101  0.702  ]

Im: [0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  0.0  ]

After: 

Re: [37.054  1.774  -1.075  1.451  -0.653  -0.253  -1.686  -3.602  0.226  0.374  -0.194  -0.312  -1.432  0.429  0.709  -0.085  0.0090  -0.085  0.709  0.429  -1.432  -0.312  -0.194  0.374  0.226  -3.602  -1.686  -0.253  -0.653  1.451  -1.075  1.774  ]

Im: [0.0  1.474  -0.238  -2.026  -0.22  -0.24  -5.009  -1.398  0.416  -1.251  -0.708  -0.713  0.851  1.882  0.379  0.021  0.0  -0.021  -0.379  -1.882  -0.851  0.713  0.708  1.251  -0.416  1.398  5.009  0.24  0.22  2.026  0.238  -1.474  ]

Quindi, a questo punto, non posso creare testa o croce con l'output. Comprendo i concetti DFT, come la parte reale essendo le ampiezze delle onde del coseno componenti e la parte immaginaria essendo le ampiezze delle onde sinusoidali componenti. Posso anche seguire questo diagramma dal grande libro " The Scientist and Engineer's Guide to Digital Signal Processing ": inserisci qui la descrizione dell'immagine

Quindi le mie domande specifiche sono:

  1. Dall'uscita della FFT, come trovo le "frequenze più ricorrenti"? Questo fa parte della mia analisi dei dati del mio accelerometro. Devo leggere gli array reali (coseno) o immaginari (seno)?

  2. Ho un input di 32 punti nel dominio del tempo. L'output della FFT non dovrebbe essere un array a 16 elementi per i reali e un array a 16 elementi per l'immaginario? Perché il programma mi fornisce output di array reali e immaginari entrambi di dimensione 32?

  3. In relazione alla domanda precedente, come si analizzano gli indici negli array di output? Dato il mio input di 32 campioni campionati a 32 Hz, la mia comprensione è che un'uscita di matrice a 16 elementi dovrebbe avere il suo indice distribuito uniformemente fino a metà della frequenza di campionamento (di 32 Hz), quindi ho ragione nel capire che ogni elemento della matrice rappresenta (32 Hz * 1/2) / 16 = 1 Hz?

  4. Perché l'uscita FFT ha valori negativi? Ho pensato che i valori rappresentassero le ampiezze di una sinusoide. Ad esempio, l'uscita di Real [3] = -1,075 dovrebbe significare un'ampiezza di -1,075 per un'onda coseno di frequenza 3. È esatto? Come può un'ampiezza essere negativa?


Cosa vorresti calcolare dalle letture dell'accelerometro: velocità, distanza? Il rumore delle letture dell'accelerometro segue la distribuzione gaussiana e non riesco a vedere come l'adattamento di un'onda sinusoidale possa rimediare.
Ali

2
il tag java dovrebbe essere rimosso in quanto è più generico rispetto a una lingua specifica
user3791372

Guardando la fonte della Columbia University, non è affatto efficiente. È un'implementazione semplice e non ottimizzata di Cooley-Tucky con tabelle di ricerca a farfalla e l'inversione di bit viene eseguita manualmente invece di utilizzare le funzioni di libreria esistenti
Mark Jeronimus

@MarkJeronimus: Puoi consigliare un'implementazione FFT efficiente in Java? Se ricordo bene, il motivo per cui ho scelto il codice della Columbia University era che la libreria FFTW era troppo complessa per essere eseguita su uno smartphone Android.
stackoverflowuser2010

Ho trovato alcune implementazioni "ottimizzate" sparse, ma sono fondamentalmente un algoritmo per dimensione N, quindi se hai bisogno di una gamma di dimensioni hai bisogno di tutte quelle routine. In pratica ho utilizzato principalmente Intel Integrated Performance Primitives (sì, da Java, tramite JNA), ma non è gratuito. A casa uso fondamentalmente lo stesso algoritmo che hai collegato, ma scritto da zero nel 2005 utilizzando un libro di testo. È solo FFT (Fast Fourier Transform), niente di così "Fast" da giustificare il nome "Fast FFT".
Mark Jeronimus

Risposte:


86
  1. Non dovresti nemmeno cercare la parte reale o immaginativa di un numero complesso (che qual è il tuo array reale e immaginario). Invece vuoi cercare l'ampiezza della frequenza che è definita come sqrt (real * real + imag * imag). Questo numero sarà sempre positivo. Ora tutto ciò che devi cercare è il valore massimo (ignora la prima voce nell'array. Questo è il tuo offset CC e non contiene informazioni dipendenti dalla frequenza).

  2. Ottieni 32 uscite reali e 32 immaginarie perché stai usando una FFT complessa o complessa. Ricorda che hai convertito i tuoi 32 campioni in 64 valori (o 32 valori complessi) estendendoli con zero parti immaginarie. Ciò si traduce in un'uscita FFT simmetrica in cui il risultato della frequenza si verifica due volte. Una volta pronto per l'uso nelle uscite da 0 a N / 2, e una volta specchiato nelle uscite da N / 2 a N. Nel tuo caso è più semplice ignorare semplicemente le uscite da N / 2 a N. Non ti servono, sono solo un artefatto su come calcoli la tua FFT.

  3. La frequenza dell'equazione fft-bin è (bin_id * freq / 2) / (N / 2) dove freq è la frequenza di campionamento (ovvero 32 Hz, e N è la dimensione della tua FFT). Nel tuo caso questo si semplifica a 1 Hz per bin. I bin da N / 2 a N rappresentano frequenze negative (strano concetto, lo so). Per il tuo caso non contengono informazioni significative perché sono solo uno specchio delle prime frequenze N / 2.

  4. Le parti reali e immaginarie di ogni contenitore formano un numero complesso. Va bene se le parti reali e immaginarie sono negative mentre la grandezza della frequenza stessa è positiva (vedi la mia risposta alla domanda 1). Ti suggerisco di leggere su numeri complessi. Spiegare come funzionano (e perché sono utili) supera ciò che è possibile spiegare in una singola domanda stackoverflow.

Nota: potresti anche voler leggere cos'è l'autocorrelazione e come viene utilizzata per trovare la frequenza fondamentale di un segnale. Ho la sensazione che questo sia quello che vuoi veramente.


1
Grazie. Per quanto riguarda 1: ho visto questa pagina Matlab che mostra uno spettro di frequenza ( mathworks.com/help/techdoc/ref/fft.html ). In quella pagina c'è un grafico con il titolo di "Spettro di ampiezza unilaterale di y (t)". Sta tracciando l'ampiezza della frequenza come hai suggerito, sqrt (real ^ 2 + img ^ 2)? Per quanto riguarda 3: ancora non ottengo il risultato di 2Hz per bin. Nel mio caso, N = 32 e freq = 32, giusto? Quindi ci sono N / 2 = 32/2 = 16 bin, e la frequenza più alta (Nyquist) è freq / 2 = 32/2 = 16 Hz, risultando in 16 Hz per 16 bin, dando 1 Hz per bin?
stackoverflowuser2010

1
Sì, il grafico mostra l'ampiezza dello spettro - | Y (f) |. Le barre del valore assoluto indicano la grandezza. Larghezza bin = frequenza di campionamento / dimensione FFT. La tua frequenza di campionamento è di 32 hz, la tua dimensione FFT è 32. Sì, hai ragione sulla larghezza del bin!
Matt Montag

Corretta la frequenza del bin.
André Chalella

1
Bella risposta, grazie! Scusa se sono un po 'in ritardo alla festa, ma forse potresti rispondermi che unità è la grandezza della frequenza (come detto da te al punto 1), in generale? Nel mio caso, su un segnale di valori da un accelerometro (è m / s ^ 2). Non riesco a capirlo.
Markus

Affascinante! Le mie barre di frequenza di visualizzazione della musica uscivano tutte specchiate da sinistra a destra; la risposta # 2 spiega questo !! Pazzo !!
Ryan S

11

Hai già alcune buone risposte, ma aggiungerò solo che hai davvero bisogno di applicare una funzione di finestra ai dati del dominio del tempo prima della FFT, altrimenti otterrai brutti artefatti nel tuo spettro, a causa della dispersione spettrale .


Apprezzo che sia passato molto tempo da questa risposta .. Tuttavia, saresti in grado di approfondire che tipo di artefatti intendi?
MattHusz

1
@ MattHusz: il termine generale per l'origine di questi artefatti è "dispersione spettrale" - ho aggiunto un collegamento alla risposta ora che lo spiega. Il modo migliore in cui posso descrivere l'effetto è che il tuo spettro sarà "macchiato" a causa della finestra rettangolare implicita.
Paul R

6

1) Cerca gli indici nell'array reale con i valori più alti, oltre al primo (che è il componente DC). Probabilmente avrai bisogno di una frequenza di campionamento notevolmente superiore a 32 Hz e di una dimensione della finestra più grande, per ottenere risultati significativi.

2) La seconda metà di entrambi gli array è lo specchio della prima metà. Ad esempio, si noti che l'ultimo elemento dell'array reale (1.774) è lo stesso del secondo elemento (1.774) e l'ultimo elemento dell'array immaginario (1.474) è il negativo del secondo elemento.

3) La frequenza massima che è possibile rilevare a una frequenza di campionamento di 32 Hz è 16 Hz ( limite di Nyquist ), quindi ogni passo è di 2 Hz. Come notato in precedenza, ricorda che il primo elemento è 0 Hz (ovvero, l'offset CC).

4) Certo, un'ampiezza negativa ha perfettamente senso. Significa solo che il segnale è "capovolto" - una FFT standard è basata su un coseno, che normalmente ha valore = 1 at = 0, quindi un segnale che aveva valore = -1 al tempo = 0 avrebbe un'ampiezza negativa .


Grazie per la risposta. (1) Intendi dire che posso ignorare l'array immaginario (seno) e, in tal caso, perché? Sicuramente la componente seno deve essere importante? (2) Perché si verifica questo mirroring? È solo il risultato dell'algoritmo FFT? La maggior parte delle persone ignora la metà speculare? (3) Come hai calcolato i passi di 2Hz? Capisco il limite di Nyquist di 16 Hz, quindi se ci sono 16 elementi di array (non specchiati), ogni elemento deve essere di 16 Hz / 16 = 1 Hz ciascuno? (4) Per trovare le frequenze principali, prendo semplicemente il valore assoluto dei valori di ampiezza negli array di output?
stackoverflowuser2010

Non dovresti cercare nell'array reale il valore più alto e non puoi ignorare l'array sine / I. Invece vuoi la grandezza del vettore complesso composito. Il mirroring si verifica perché metà dell'input (la matrice I) è tutto zero, quindi il risultato ha metà dei gradi di libertà. Puoi ignorarlo se i tuoi dati sono strettamente reali.
hotpaw2

@duskwuff Grazie mille: hai dato una risposta a una domanda che stavo per postare, se non avessi trovato la tua risposta: come interpretare la SECONDA parte della FFT. Voglio modificare i dati ed eseguire l'inverso e ho continuato a ottenere solo la metà dei risultati, perché ho modificato i dati sbagliati in quella parte. Grazie ancora.
Martin

(3), il valore di step = 2Hz rimane per me implicito finora. Abbiamo 16 contenitori, rappresentati da un array di lunghezza = 16. Dobbiamo descrivere tutte le frequenze da 0Hz a 16Hz. Presumo che ogni contenitore descriva un pezzo di quella gamma, non è vero?
krafter

@krafter penso che sia dimezzato perché non puoi dedurre una frequenza da un singolo valore (poiché non c'è ripetizione).
JVE999

5

Si noti che la "frequenza più ricorrente" può essere inserita in più contenitori FFT, anche con una funzione finestra. Quindi potrebbe essere necessario utilizzare una finestra più lunga, più finestre o l'interpolazione per stimare meglio la frequenza di eventuali picchi spettrali.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.