Woher weiß ich die Abtastfrequenz?

16

Ich fange an, ein bisschen verwirrt über Abtastraten und Baudraten usw. zu werden. Ich habe diesen Arduino-Code:

#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;
        }
      }
    }
  }
}

Wie hoch ist die Abtastrate / -frequenz, da es keine Verzögerungsunterbrechung gibt? Basiert es auf der Arduino ADC-Geschwindigkeit? Wenn ich die Baudrate erhöhe, erhöhe ich dann die Abtastfrequenz oder nur die Rate, mit der ich Daten über die serielle Schnittstelle sende?

user3284376
quelle

Antworten:

21

Die Arduino ADC-Taktrate wird in ..arduino-1.5.5 \ hardware \ arduino \ avr \ cores \ arduino \ wiring.c eingestellt

Hier ist der relevante Teil

#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

Für einen 16-MHz-Arduino ist der ADC-Takt auf 16 MHz / 128 = 125 kHz eingestellt. Jede Konvertierung in AVR benötigt 13 ADC-Takte, also 125 KHz / 13 = 9615 Hz.

Dies ist die maximal mögliche Abtastrate. Die tatsächliche Abtastrate in Ihrer Anwendung hängt jedoch vom Intervall zwischen aufeinanderfolgenden Conversion-Aufrufen ab.
Da Sie das Ergebnis lesen und über die serielle Schnittstelle senden, tritt eine Verzögerung auf, die mit abnehmender Baudrate zunimmt. Je niedriger die Baudrate, desto länger dauert das Senden der gleichen Datenlänge und desto länger dauert das Aufrufen der nächsten ADC-Konvertierung.

Die tatsächliche Abtastrate in Ihrer Anwendung kann mithilfe eines Debuggers oder Simulators ermittelt werden. Eine einfachere Lösung besteht jedoch darin, bei jeder Konvertierung einen digitalen Pin umzuschalten und die Frequenz zu messen, mit der der digitale Pin umschaltet.

alexan_e
quelle
Außerdem steigt die Zeit zwischen meinen Zeitstempeln von ~ 1300 bis auf ~ 16400, sollten sie doch gleich bleiben? Das ist bei 9600, bei 115200, sie steigen nach langer Zeit nur auf ungefähr 1500 an.
User3284376
@ user3284376 in Bezug auf Ihren Zeitstempelcode, ich denke, es kann nicht immer funktionieren (kann durch einige Interrupts zum falschen Zeitpunkt verzerrt werden). Ich würde vorschlagen, dass Sie eine bestimmte Frage dazu stellen, wie Sie hochpräzises Timing auf Arduino erhalten und den relevanten Teil Ihres Codes dort platzieren.
jfpoilpret
7

Ich wollte auch eine hohe Abtastrate für ein Projekt bekommen. Es stellt sich heraus, dass die ADPS2-, ADPS1- und ADPS0-Bits des ADCSRA-Registers so konfiguriert werden können, dass sie eine Abtastrate von 76923 s / s oder 76,8 ks / s erreichen. Beachten Sie jedoch, dass ich den ADC meines Arduino im Freilaufmodus betreibe. Die folgenden Zeilen haben bei mir funktioniert.

#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)
}

Bei dieser Frequenz sind die üblichen 10-Bit-Ergebnisse nicht zuverlässig. Dies bedeutet, dass eine Erhöhung der Abtastrate die Genauigkeit der Ergebnisse verringert. Daher verwende ich nur die oberen 8 Bits, da bei diesem Prescalar die oberen 8 Bits zuverlässig sind. Sie können auf dieser Seite näher eingehen, dieser Typ rockt! Mit UNO hat er ein Oszilloskop mit hoher Abtastrate hergestellt. http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/

Salar Khan
quelle
3

In jeder Schleife werden 8 Zeichen über eine serielle 9600-Bit / s-Verbindung gedruckt. Jedes Zeichen benötigt 10 Bits (1 Start, 8 Bits für das Zeichen, 1 Stopp). Das heißt, Sie können diese Schleife nur ~ 120 Mal pro Sekunde durchlaufen.

Die analogRead()Funktion kann theoretisch mit etwa 9600 mal / s abtasten, realistisch sind es etwa 8600 mal / s.

Sie sind an die serielle Kommunikation gebunden.

Cybergibbons
quelle
Wenn Sie also auf 115200 erhöhen, erhalten Sie 1440 Mal / Sek. Ist das die Abtastrate?
user3284376
Geben oder Nehmen, ja. Sie müssen bedenken, dass Serial erfordert, dass das andere Ende antwortet, sodass Sie davon abhängig sind, dass der PC antwortet. Dies ist nicht deterministisch, so dass Sie Jitter bekommen.
Cybergibbons
Sie sind am Arduino-Ende der Dinge richtig, alles scheint in Ordnung zu sein, aber auf Python sind die Dinge viel langsamer. Welche Dinge müsste ich tun, um die Leistung am Computer zu steigern?
user3284376
Sie müssen dies nicht als Problem mit der seriellen Leistung auf dem PC betrachten, sondern wie können Sie die Abtastung vom Senden von Daten entkoppeln.
Cybergibbons
1
@Cybergibbons - Nein, da dies auf einem Uno ausgeführt wird, bei dem USB und seriell entkoppelt sind, besteht keine Abhängigkeit vom PC, außer dass das Zeichen "S" und nicht das Zeichen "F" ausgegeben wird. Die hier veröffentlichte Skizze und die Plattform, auf der sie ausgeführt wird, werfen problemlos serielle Daten auf das USB-Serial-Companion-Mikro, ohne dass dies oder etwas auf der anderen Seite des USB-Geräts bemerkt wird.
Chris Stratton
3

Senden von 11 Bit über seriell mit einer Baudrate von 9600, aber für die Abtastung speichere ich es in einem Array mit so geringer Verzögerung wie möglich. Sobald dies erledigt ist, sende ich es über die serielle Schnittstelle, damit es von einem Python-Skript gelesen werden kann. Ich mache dies für eine FFT mit Matplotlib. Ich höre ein 0-5-V-Signal und speichere dann ohne Verwendung der delay () -Funktion die analogRead () -Werte in diesem Array. In einem Bruchteil einer Sekunde ist der Lesevorgang abgeschlossen, und der serielle Datenspeicherauszug beginnt. Als ich die Eingangsfrequenz mit tone () von einem anderen angeschlossenen Arduino kalibrierte, wurde mir klar, dass ich den Index durch 8915 teilen musste, um eine Genauigkeit von 0,1 Hz zu erzielen. Da man durch die Frequenz der Abtastung dividieren müsste, um die richtigen Indexintervalle zu erhalten, ist die Arduino-Abtastfrequenz (zumindest meine mit meinem Code) 8915 Hz.

user34028
quelle
1

Bezogen auf den Teil über den Unterschied zwischen Abtastrate und Baudrate handelt es sich um unterschiedliche Messungen.

Die Abtastrate ist die Frequenz, mit der das Gerät (Arduino) eine digitale Darstellung eingehender Analogwerte erstellen kann.

Baudrate ist die Rate, mit der Informationen in einem Kommunikationskanal übertragen werden. Es beschreibt die Kommunikationsgeschwindigkeit zwischen dem Mikrocontroller und der Außenwelt (dem Computer).

Ich würde diesen electronics_stack_exchange-Link empfehlen. /electronics/135056/sampling-rate-data-rate-and-bandwidth

ThermoRestart
quelle
0

8915Hz - es ist sehr nahe an 125000/14 ~ = 8928.6 Meine anfängliche Schätzung, dass genau eine Lücke zwischen benachbarten Umwandlungen erforderlich ist. Ein ADC-Takt für die Abtastung und 13 ADC-Takte für die Umwandlung selbst. Ein kleiner Fehler könnte auf eine nicht perfekte Taktquelle von Arduino zurückzuführen sein. Ich bin mir noch nicht sicher. Dieses Thema ist für mich jetzt aktuell, da abgetastete Daten den Digitalfilter speisen müssen.

E_Sh
quelle
1
Ich bin mir nicht sicher, was Sie damit meinen, wenn Sie sagen "Dieses Thema ist für mich aktuell, da abgetastete Daten den digitalen Filter speisen müssen." Haben Sie ein ähnliches Problem?
VE7JRO
Jede Umwandlung beginnt mit einer ansteigenden Flanke des ADC-Takts, und mindestens ein ADC-Taktzyklus geht verloren, während der Code ausgeführt wird. Also ja, 8928,6 Hz sind die schnellsten, die Sie durch Aufrufen analogRead()in einer engen Schleife erzielen können, im Gegensatz zu 9615,4 Hz im Freilaufmodus.
Edgar Bonet