Come faccio a sapere la frequenza di campionamento?


16

Sto iniziando a confondermi un po 'su frequenze di campionamento e baudrate ecc. Ho questo codice Arduino:

#include <eHealth.h>

extern volatile unsigned long timer0_overflow_count;
float fanalog0;
int analog0;
unsigned long time;


byte serialByte;
void setup() {
  Serial.begin(9600);
}

void loop() { 
  while (Serial.available()>0){  
    serialByte=Serial.read();
    if (serialByte=='S'){        
      while(1){
        fanalog0=eHealth.getECG();  
        // Use the timer0 => 1 tick every 4 us
        time=(timer0_overflow_count << 8) + TCNT0;        
        // Microseconds conversion.
        time=(time*4);   
        //Print in a file for simulation
        //Serial.print(time);
        //Serial.print(" ");
        Serial.print(fanalog0,5);
        Serial.print("\n");

        if (Serial.available()>0){
          serialByte=Serial.read();
          if (serialByte=='F')  break;
        }
      }
    }
  }
}

Poiché non vi è alcun interruzione di ritardo, qual è la frequenza / frequenza di campionamento? Si basa sulla velocità ADC di Arduino? Quando aumento il baudrate sto aumentando la frequenza di campionamento o solo la velocità con cui invio i dati tramite la porta seriale?

Risposte:


21

La velocità di clock di Arduino ADC è impostata in ..arduino-1.5.5 \ hardware \ arduino \ avr \ cores \ arduino \ cablaggio.c

Ecco la parte rilevante

#if defined(ADCSRA)
    // Set A/D prescale factor to 128
    // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range.
    // XXX: this will not work properly for other clock speeds, and
    // this code should use F_CPU to determine the prescale factor.
    sbi(ADCSRA, ADPS2);
    sbi(ADCSRA, ADPS1);
    sbi(ADCSRA, ADPS0);

    // Enable A/D conversions
    sbi(ADCSRA, ADEN);
#endif

Per un Arduino a 16 MHz l'orologio ADC è impostato su 16 MHz / 128 = 125 KHz. Ogni conversione in AVR richiede 13 clock ADC, quindi 125 KHz / 13 = 9615 Hz.

Questa è la massima frequenza di campionamento possibile, ma la frequenza di campionamento effettiva nell'applicazione dipende dall'intervallo tra le chiamate di conversione successive.
Dato che hai letto il risultato e lo hai inviato attraverso la porta seriale, ricevi un ritardo che aumenta man mano che la velocità di trasmissione diminuisce. Più bassa è la velocità di trasmissione, maggiore sarà il tempo necessario per inviare la stessa lunghezza di dati e maggiore sarà il tempo necessario per chiamare la successiva conversione ADC.

La frequenza di campionamento effettiva nella tua applicazione può essere determinata con l'uso di un debugger o di un simulatore, ma una soluzione più semplice è attivare / disattivare un pin digitale ogni volta che si esegue una conversione e misurare la frequenza con cui il pin digitale si attiva.


Inoltre, il tempo tra i miei timestamp aumenta da ~ 1300 fino a ~ 16400, sicuramente dovrebbero rimanere gli stessi? Cioè a 9600, a 115200, aumentano solo a circa 1500 dopo un sacco di tempo.
user3284376

@ user3284376 per quanto riguarda il codice timestamp, penso che non possa funzionare in qualsiasi momento (può essere distorto da alcuni interrupt al momento sbagliato). Ti suggerirei di pubblicare una domanda specifica su come ottenere un tempismo ad alta precisione su Arduino e inserire lì la parte pertinente del tuo codice.
jfpoilpret,

7

Volevo anche ottenere un'alta frequenza di campionamento, per un progetto. risulta che i bit ADPS2, ADPS1, ADPS0 del registro ADCSRA possono essere configurati per ottenere una frequenza di campionamento di 76923 s / so 76,8 ks / s. Ma attenzione che sto eseguendo l'ADC del mio arduino in modalità di esecuzione libera, le seguenti righe hanno funzionato per me.

#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

void setup() {
// Set the Prescaler to 16 (16000KHz/16 = 1MHz)
// WARNING: Above 200KHz 10-bit results are not reliable.
//ADCSRA |= B00000100;
sbi(ADCSRA, ADPS2);
cbi(ADCSRA, ADPS1);
cbi(ADCSRA, ADPS0);

// Set ADIE in ADCSRA (0x7A) to enable the ADC interrupt.
// Without this, the internal interrupt will not trigger.
//ADCSRA |= B00001000;
sbi(ADCSRA,ADIE)
}

A questa frequenza i soliti risultati a 10 bit non sono affidabili. Ciò significa che aumentando la frequenza di campionamento si ridurrà la precisione dei risultati. Quindi uso solo gli 8 bit superiori perché in questo momento i 8 bit superiori sono affidabili. Puoi andare più in dettaglio in questa pagina, questo tizio oscilla! ha realizzato un oscilloscpe ad alta frequenza di campionamento usando UNO http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/


3

Ad ogni ciclo si stampano 8 caratteri su un collegamento seriale a 9600 bps. Ogni carattere richiede 10 bit (1 inizio, 8 bit per il personaggio, 1 arresto). Ciò significa che puoi solo passare attraverso questo ciclo ~ 120 volte / sec.

La analogRead()funzione può campionare a circa 9600 volte / sec in teoria, realisticamente è di circa 8600 volte / sec.

Sei limitato dalla comunicazione seriale.


Quindi aumentando a 115200, dà 1440 volte / sec, è questa la frequenza di campionamento?
user3284376

Dai o dai, sì. È necessario tenere presente che Serial richiede che l'altra estremità risponda, quindi si dipende dalla risposta del PC. Questo non è deterministico, quindi otterrai jitter.
Cybergibbons

Hai ragione su Arduino, tutto sembra a posto, ma su Python le cose sono molto più lente, che tipo di cose dovrei fare per aumentare le prestazioni sul computer?
user3284376

Non è necessario considerare questo come un problema con le prestazioni seriali sul PC, ma come si fa a separare il campionamento dall'invio dei dati.
Cybergibbons

1
@Cybergibbons - no, poiché questo è in esecuzione su uno Uno in cui USB e seriale sono disaccoppiati, non vi è alcuna dipendenza dal PC oltre all'emissione del carattere "S" e non a quello "F". Lo schizzo pubblicato qui e la piattaforma su cui viene eseguito genereranno felicemente i dati seriali sul microcompagno USB-seriale, ciecamente ignari se questo o qualcosa sull'altra estremità dell'USB sta tenendo il passo.
Chris Stratton,

3

Inviando 11 bit su seriale a un baud di 9600, ma per il campionamento, lo memorizzo in un array con il minor ritardo possibile, quindi una volta fatto, lo invio attraverso la porta seriale per essere letto da uno script Python. Lo sto facendo per un FFT usando matplotlib. Ascolto un segnale 0-5 V, quindi senza utilizzare la funzione delay (), memorizzo i valori analogRead () in quell'array. In una frazione di secondo viene eseguita la lettura, quindi inizia il dump dei dati seriali. Quando ho calibrato la frequenza di ingresso usando tone () da un altro Arduino collegato, mi sono reso conto che dovevo dividere l'indice per 8915 per ottenere una precisione entro .1 Hz. Poiché si dovrebbe dividere per la frequenza del campionamento per ottenere gli intervalli di indice corretti, la mia ipotesi è che la frequenza di campionamento di Arduino (almeno la mia con il mio codice) sia 8915Hz.


1

Facendo riferimento alla parte sulla differenza tra frequenza di campionamento e baud rate, si tratta di misurazioni diverse.

La frequenza di campionamento è la frequenza con cui il dispositivo (arduino) può ricreare una rappresentazione digitale dei valori analogici in entrata.

Baud Rate è la velocità con cui le informazioni vengono trasferite in un canale di comunicazione. Descrive la velocità di comunicazione tra il microcontrollore e il mondo esterno (il computer).

Consiglierei questo link electronics_stack_exchange. /electronics/135056/sampling-rate-data-rate-and-bandwidth


0

8915Hz - è molto vicino a 125000/14 ~ = 8928.6 La mia ipotesi iniziale è che sia necessario esattamente uno spazio tra le conversioni adiacenti Un clock ADC per il campionamento e 13 clock ADC per la conversione stessa. Un piccolo errore potrebbe essere l'effetto di una sorgente di clock non perfetta di Arduino. Non sono ancora sicuro. Questo argomento è attuale per me poiché i dati campionati devono alimentare il filtro digitale.


1
Non sono sicuro di cosa intendi quando dici "Questo argomento è attuale per me, dato che i dati campionati devono alimentare il filtro digitale". Stai riscontrando un problema simile?
VE7JRO

Ogni conversione inizia su un fronte di salita del clock ADC e si perde almeno un ciclo di clock ADC eseguendo il codice. Quindi sì, 8928,6 Hz è il più veloce che puoi ottenere chiamando analogRead()in un circuito chiuso, rispetto a un 9615,4 Hz molto coerente in modalità di funzionamento libero.
Edgar Bonet,
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.