Sommario:

EasyFFT: Trasformata di Fourier veloce (FFT) per Arduino: 6 passaggi
EasyFFT: Trasformata di Fourier veloce (FFT) per Arduino: 6 passaggi

Video: EasyFFT: Trasformata di Fourier veloce (FFT) per Arduino: 6 passaggi

Video: EasyFFT: Trasformata di Fourier veloce (FFT) per Arduino: 6 passaggi
Video: Fast Fourier Transforms Revisited On Arduino 2024, Dicembre
Anonim
Image
Image

La misurazione della frequenza dal segnale catturato può essere un compito difficile, specialmente su Arduino in quanto ha una potenza di calcolo inferiore. Sono disponibili metodi per catturare lo zero-crossing in cui la frequenza viene catturata controllando quante volte il segnale attraversa le linee dello zero entro un determinato tempo. Tale metodo potrebbe non funzionare quando il segnale è una combinazione di varie frequenze.

Questo è in qualche modo difficile da codificare se non provieni da un tale background. Ma essendo un armeggiare questo codice può essere molto utile per vari progetti legati alla musica, all'analisi del segnale. Il motivo di questo progetto era preparare un codice che fosse facile da implementare su Arduino senza passare in secondo piano.

Questo progetto non spiega il funzionamento di FFT ma spiega l'applicazione della funzione FFT. Lo stesso procedimento è spiegato anche nel video allegato.

Se sei interessato solo all'applicazione del codice e non a una sua spiegazione. Puoi saltare direttamente al passaggio n. 3.

Passaggio 1: Introduzione alla trasformazione di frequenza

Introduzione alla trasformazione di frequenza
Introduzione alla trasformazione di frequenza
Introduzione alla trasformazione di frequenza
Introduzione alla trasformazione di frequenza

Qualsiasi segnale può essere composto da una combinazione di varie onde sinusoidali. Quindi qualsiasi segnale basato sul tempo può essere mostrato anche come una combinazione dei vari seni di diverse ampiezze.

Ho provato a spiegare il funzionamento di DFT (trasformata di Fourier discreta) in uno dei precedenti istruttori (https://www.instructables.com/id/Arduino-Frequency…). Questi metodi sono estremamente lenti per qualsiasi applicazione in tempo reale. che lo rende quasi inutile.

Nell'immagine viene mostrato un segnale che è una combinazione di due frequenze f2 e f5. Questo segnale viene moltiplicato per le onde sinusoidali di prova di valori da f1 a f5.

Si può dimostrare matematicamente che la sommatoria della moltiplicazione di due set di dati armonici aventi frequenza diversa tende a zero (un numero maggiore di dati può portare a risultati di pastella). Nel nostro caso, se queste due frequenze di moltiplicazione hanno la stessa frequenza (o molto vicina), la somma della moltiplicazione è il numero diverso da zero.

Quindi, se il nostro segnale viene moltiplicato per f1, la sommatoria della moltiplicazione sarà zero (vicino a zero per l'applicazione reale). simile è il caso di f3, f4. Tuttavia, per il valore, l'output di f2 e f5 non sarà zero, ma significativamente superiore al resto dei valori.

Qui un segnale viene testato con 5 frequenze, quindi il segnale deve essere moltiplicato per cinque frequenze. Un calcolo così intenso richiede un tempo maggiore. Matematicamente si dimostra che per N numero di campioni ci vogliono N*N moltiplicazioni complesse.

Passaggio 2: trasformata di Fourier veloce

Per rendere più veloce il calcolo della DFT, l'algoritmo FFT è stato sviluppato da James Cooley e John Tukey. Questo algoritmo è anche considerato uno degli algoritmi più importanti del XX secolo. Divide un segnale in una parte in sequenza pari e dispari che riduce il numero di calcoli richiesti. Usandolo, la moltiplicazione complessa totale richiesta può essere ridotta a NlogN. che è un miglioramento significativo.

Puoi fare riferimento di seguito ai riferimenti a cui ho fatto riferimento durante la scrittura del codice per una comprensione dettagliata della matematica alla base di FFT:

1.

2.

3.

4.

Passaggio 3: spiegazione del codice

1. Seno e coseno veloci:

Calcolo FFT prende il valore di vari seno e coseno più volte. La funzione integrata di Arduino non è abbastanza veloce e richiede una buona quantità di tempo per fornire il valore richiesto. Il che rende il codice significativamente più lento (raddoppia il tempo per 64 campioni). Per contrastare questo problema, il valore del seno da 0 a 90 gradi viene memorizzato come multiplo di 255. In questo modo eliminerai la necessità di memorizzare i numeri come float e possiamo memorizzarlo come byte che occupa 1/4 di spazio su Arduino. Sine_data deve essere incollato all'inizio del codice per dichiararlo come variabile globale.

Oltre a sine_data, un array chiamato f_peaks dichiarato come variabile globale. Dopo ogni esecuzione della funzione FFT, questo array si aggiorna. Dove f_peaks[0] è la frequenza più dominante e ulteriori valori in ordine decrescente.

byte sine_data [91]= { 0, 4, 9, 13, 18, 22, 27, 31, 35, 40, 44, 49, 53, 57, 62, 66, 70, 75, 79, 83, 87, 91, 96, 100, 104, 108, 112, 116, 120, 124, 127, 131, 135, 139, 143, 146, 150, 153, 157, 160, 164, 167, 171, 174, 177, 180, 183, 186, 189, 192, 195, 198, 201, 204, 206, 209, 211, 214, 216, 219, 221, 223, 225, 227, 229, 231, 233, 235, 236, 238, 240, 241, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 253, 254, 254, 254, 255, 255, 255, 255}; float f_peaks[5];

Poiché abbiamo memorizzato il valore del seno da 0 a 90 gradi, è possibile calcolare qualsiasi valore di seno o coseno. Sotto la funzione il primo round del numero a zero punto decimale e restituisce il valore dai dati memorizzati. questo metodo richiede solo una divisione mobile. Questo può essere ulteriormente ridotto memorizzando direttamente i valori del seno (non 255 multipli). ma questo consuma molta memoria su Arduino.

L'utilizzo della procedura di cui sopra riduce la precisione ma migliora la velocità. Per 64 punti dà il vantaggio di 8 ms e per 128 punti dà un vantaggio di 20 ms.

Passaggio 4: spiegazione del codice: funzione FFT

La FFT può essere eseguita solo per la dimensione del campione di 2, 4, 8, 16, 32, 64 e così via. se il valore non è 2^n, prenderà il lato inferiore del valore. Ad esempio, se scegliamo la dimensione del campione di 70, prenderà in considerazione solo i primi 64 campioni e ometterà il resto.

Si consiglia sempre di avere una dimensione del campione di 2^n. quale può essere:

2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, …

Due float out_r e out_im occuperanno una quantità elevata di memoria. per Arduino nano non funzionerà per campioni superiori a 128 (e in alcuni casi 128) a causa della mancanza di memoria disponibile.

dati int unsigned[13]={1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048};

int a, c1, f, o, x; a=N; for(int i=0;i<12;i++) //calcolo dei livelli { if(data<=a){o=i;} } int in_ps[data[o]={}; //input per il sequenziamento float out_r[data[o]={}; //parte reale della trasformazione float out_im[data[o]={}; //parte immaginaria della trasformazione

L'ulteriore flusso è il seguente:

1. Il codice genera un bit invertito nell'ordine per la dimensione del campione data (dettagli sull'inversione dei bit sui riferimenti: passaggio 2)

2. Inserire i dati ordinati secondo l'ordine generato, 3. FFT eseguita

4. L'ampiezza del numero complesso calcolato, 5. I picchi vengono rilevati e ordinati in ordine decrescente

6. è possibile accedere ai risultati da f_peaks.

[per accedere ad altri dati (a parte la frequenza di picco) il codice dovrebbe essere modificato, in modo che la variabile locale possa essere copiata in qualche variabile globale predefinita]

Passaggio 5: test del codice

Testare il codice
Testare il codice
Testare il codice
Testare il codice

Come input viene fornita un'onda triangolare campione. per questa frequenza di campionamento dell'onda è 10 Hz e la frequenza dell'onda stessa è 1,25 Hz.

Come si può vedere dall'output grezzo, il valore corrisponde alla FFT calcolata da Scilab. tuttavia, questi valori non sono esattamente gli stessi di un'onda sinusoidale a bassa precisione ma più veloce.

Nella frequenza dell'array di frequenza di uscita sono 1,25 e 3,75. non è necessario ottenere ogni volta il valore esatto. in genere questi numeri sono chiamati bin di frequenza. quindi il valore di output potrebbe essere ovunque all'interno dei bin specificati.

Velocità:

per Arduino nano ci vogliono:

16 punti: 4ms32 punti: 10ms 64 punti: 26ms 128 punti: 53ms

Passaggio 6: conclusione

Questo codice FFT può essere utilizzato in applicazioni in tempo reale. Poiché occorrono circa 30 ms per completare il calcolo. Tuttavia, la sua risoluzione è limitata da un numero di campioni. Il numero del campione è limitato dalla memoria Arduino. Utilizzando Arduino Mega o un'altra scheda ad alte prestazioni è possibile migliorare la precisione.

se hai domande, suggerimenti o correzioni non esitare a commentare.

Aggiornamento (2/5/21)

Aggiornamenti://--------------Funzione FFT--------------- -----------------//float FFT(int in, int N, float Frequenza)

Il tipo di dati di N è cambiato in Integer (byte esistente) per supportare una dimensione del campione >255. Se la dimensione del campione è <=128, è necessario utilizzare il tipo di dati in byte.

Consigliato: