Go Down

Topic: Problema con la libreria FFT (Read 2226 times) previous topic - next topic

kama90

Salve a tutti, sono un nuovo arrivato appassionato di programmazione ed elettronica.
Ultimamente mi sono interessato all' analisi in frequenza di un segnale . Dopo essermi informato ho tentato di utilizzare il mio Arduino Uno con la libreria FFT. Ho provato a utilizzare il programma di esempio che si trova nella libreria per fare alcune prove,collegando alla porta analogica A0 un potenziometro e variando manualmente la tensione. Il programma di esempio dovrebbe mostrare i valori determinati dalla FFT sul monitor seriale ma nel mio caso mostra strane lettere e parentesi che si ripetono ad intermittenza, perchè?
Grazie a tutti e scusate l' ignoranza!!!

pelletta

Posta lo sketch, probabilmente o hai impostato male il baud rate oppure hai inizializzato male la variabile che contiene i valori del potenziometro.
Ciao

uwefed

il baudrate impostato nel sketch corrisponde con quello impostato nel terminale?
Ciao Uwe

kama90

Ecco il codice...

Code: [Select]
#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft

#include <FFT.h> // include the library

void setup() {
  Serial.begin(115200); // use the serial port
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fft_input[i] = k; // put real data into even bins
      fft_input[i+1] = 0; // set odd bins to 0
    }
    fft_window(); // window the data for better frequency response
    fft_reorder(); // reorder the data before doing the fft
    fft_run(); // process the data in the fft
    fft_mag_log(); // take the output of the fft
    sei();
    Serial.write(255); // send a start byte
    Serial.write(fft_log_out, 128); // send out the data
  }
}

vittorio68

Lo sketch che hai postato, invia sulla seriale il valore di ciascun byte fft_log_out. Questo array contiene dati binari, non dati ASCII.

Il serial monitor si aspetta che i dati in arrivo siano ASCII. Mi spiego meglio, se vede arrivare un byte = 65 lui stampa la lettera A perchè 65 è il codice ASCII di questa lettera. Nel tuo caso invece il numero 65 che arriva significa proprio 65 cioè il valore numerico.

Probabilmente lo sketch originale da cui sei partito, era fatto per comunicare ad un PC lo spettro calcolato da Arduino tramite la FFT. Ma il programma in ascolto sul PC era scritto ad hoc e si aspettava dati binari.

Un'altra cosa, che non riguarda il problema specifico da te riscontrato. La FFT calcola lo spettro di un segnale analogico, ossia l'ampiezza delle frequenza che lo costituiscono. Se colleghi semplicemente un potenziometro all'ingresso, ho idea che il risultato non sia esattamente quello che ti aspetti. Forse dovresti collegare, per esempio, un segnale audio.

Ciao.
Vittorio.



leo72

C'è un'altra cosa.
Sicuro che quello sketch sia compatibile con l'IDE 1.x?
A partire dalla versione 1.0 la seriale viene gestita tramite interrupt, se mandi in stampa dei dati e poi disattivi ed attivi gli interrupt, mi sembra logico che ci siano problemi di trasmissione.

kama90

Grazie a tutti per i consigli!!
Ora sto riscrivendo lo sketch ma rileggendo le istruzioni sulla funzione fft_run() ( http://wiki.openmusiclabs.com/wiki/FFTFunctions ), non capisco bene cosa voglia dire che in ingresso sono necessari un blocco di dati già in SRAM.
Ecco la bozza del codice:
Code: [Select]
#define LOG_OUT 1
#define FFT_N 256

#include <FFT.h>


void setup() {
  Serial.begin(115200);

    }

void loop () {
  int sensorvoltage = analogRead(A0);
  float voltage = sensorvoltage * (5.0 / 1023.0);
  for( int i=0 ; i< 512 ; i += 2) {

    fft_input[i] = voltage;
    fft_input[i+1] = 0;
  }
    fft_window();
    fft_reorder();
    fft_run();
    fft_mag_log();
    Serial.write(255);
    Serial.write(fft_log_out, 128);
   
   
    }



Grazie ancora!  :D

leo72


Ora sto riscrivendo lo sketch ma rileggendo le istruzioni sulla funzione fft_run() ( http://wiki.openmusiclabs.com/wiki/FFTFunctions ), non capisco bene cosa voglia dire che in ingresso sono necessari un blocco di dati già in SRAM.

Non lo so, non so come funzioni quella lib.
Parliamo di questa lib?
http://code.google.com/p/neuroelec/downloads/list
Ho visto che esistono 2 versioni, di cui 1 appositamente per l'IDE 1.0 ma che contiene un esempio diverso da quello che hai pubblicato tu. Stiamo parlando della stessa lib? Ma tu quale IDE usi?

astrobeed


Parliamo di questa lib?


Sembra di no, lui sta usando la libreria che si trova sul sito che ha linkato, a quanto pare non è una fft generica, è un caso limitato e di uso ristretto, da quello che ho visto non c'è nemmeno un programma pc per la visualizzazione dei dati ottenuti che sono sotto forma di array binario.

leo72

Ma non è che forse spedisce i dati compressi?
Mi pare che accenni qualcosa qui:
http://wiki.openmusiclabs.com/wiki/ArduinoFFT
Ma non è che quel sito sia ricco di dettagli.


vittorio68

Scusami, magari mi sbaglio, ma io continuo a pensare che ci sia un problema di fondo che avevo già accennato nel mio primo intervento.

Cerco di fare un brevissimo riassunto sulla trasformata per capirci. Magari sarà anche molto approssimativo dal punto di vista matematico perchè si tratta di reminiscenze universitarie.

La trasformata di Fourier consente scomporre un segnale complesso nelle componenti sinusoidali (ossia le loro frequenze) che lo compongono determinando l'ampiezza di ciascuna di esse.

Partiamo da un segnale campionato con una frequenza Fc. Questo significa che abbiamo acquisito N campioni ciascuno ad un intervallo di tempo pari a 1/Fc secondi. Il teorema fondamentale del campionamento afferma che Fc deve essere maggiore o uguale del doppio della massima frequenza contenuta nel segnale da campionare. Quindi, se stiamo campionando una voce umana (che va da 500Hz a 2 KHz) dobbiamo campionare almeno a 4 Khz cioè 4000 campioni al secondo.

Questi campioni costituiscono il tuo vettore di input ossia fft_input. Il calcolo della FFT ti restituisce un nuovo vettore in cui la metà dei valori rappresenta l'ampiezza di N/2 (N erano il numero di campioni) sinusoidi che compongono il segnale originale. Il primo valore è l'ampiezza della componente continua, il valore all'indice N/2 è il valore della massima frequenza campionabile (nel nostro esempio 2KHz), i valori intermedi sono equispaziati. Se avessimo raccolto 1024 campioni (la FFT funziona con un numero di campioni pari ad una potenza di 2) allora il valore all'indice 512 rappresenta l'ampiezza della sinusoide a 2KHz i valori precedenti rappresentano l'ampiezza delle sinusoidi di frequenza pari a 0Hz (componente continua del segnale), 3.8Hz, 7.6Hz, 11.4Hz e così via.

Nel tuo caso, stai campionando un segnale continuo ossia il valore della tensione presente sul centrale del potenziometro. Mi aspetto quindi che in output tu ottenga un unico valore diverso da zero e cioè il primo valore del vettore di output che, come detto, rappresenta l'ampiezza della componente continua del segnale di ingresso.

Scusami per la lunghezza dell'intervento... alla fine la domanda è: ma cosa devi fare? Se ce lo dici forse riusciamo a ragionare insieme sulla implementazione.

Ciao.
Vittorio.

kama90

Ora rispondo a tutte le domande
1) L' IDE che sto usando è 1.0.1 ma credo che la libreria del sito http://code.google.com/p/neuroelec/downloads/detail?name=ffft_Library.zip&can=2&q= sia solo per 1.0
2) il mio progetto è quello di costruire un analizzatore di campi magnetici che attraverso una sonda di hall mi determini l' intensità del campo e la frequenza delle onde magnetiche. Per la determinazione dell' intensità del campo non penso di avere problemi, ma per portare il segnale dal dominio del tempo a quello della frequenza è necessario utilizzare la FFT sulle differenti tensioni inviate dalla sonda di hall ad Arduino.

Grazie ancora per tutti questi consigli  XD

leo72


Ora rispondo a tutte le domande
1) L' IDE che sto usando è 1.0.1 ma credo che la libreria del sito http://code.google.com/p/neuroelec/downloads/detail?name=ffft_Library.zip&can=2&q= sia solo per 1.0

Tra 1.0 e 1.0.1 cambia poco.

Quote

2) il mio progetto è quello di costruire un analizzatore di campi magnetici che attraverso una sonda di hall mi determini l' intensità del campo e la frequenza delle onde magnetiche. Per la determinazione dell' intensità del campo non penso di avere problemi, ma per portare il segnale dal dominio del tempo a quello della frequenza è necessario utilizzare la FFT sulle differenti tensioni inviate dalla sonda di hall ad Arduino.

Grazie ancora per tutti questi consigli  XD

Non so se ti può tornare utile, ma l'autore ha sviluppato una nuova lib che dice essere può performante della FFT, la FHT. Forse, essendo rivista e più recente, ha meno problemi.

astrobeed


Nel tuo caso, stai campionando un segnale continuo ossia il valore della tensione presente sul centrale del potenziometro. Mi aspetto quindi che in output tu ottenga un unico valore diverso da zero e cioè il primo valore del vettore di output che, come detto, rappresenta l'ampiezza della componente continua del segnale di ingresso.


Quoto al 100%, infatti iniettando sul ADC una tensione continua, invece di un segnale che varia nel tempo, in uscita dalla FFT ottieni solo un valore costante.

astrobeed


sulle differenti tensioni inviate dalla sonda di hall ad Arduino.


Non tensioni, ma segnale che varia nel tempo in ampiezza e in frequenza altrimenti la FFT non serve nulla.

Go Up