Comment connaître la fréquence d'échantillonnage?

16

Je commence à être un peu confus au sujet des taux d'échantillonnage et des débits en bauds, etc. J'ai ce code 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;
        }
      }
    }
  }
}

Puisqu'il n'y a pas d'interruption de retard, quelle est la fréquence / fréquence d'échantillonnage? Est-il basé sur la vitesse de l'ADC Arduino? Lorsque j'augmente la vitesse de transmission, est-ce que j'augmente la fréquence d'échantillonnage ou simplement la vitesse à laquelle j'envoie des données sur le port série?

user3284376
la source

Réponses:

21

La vitesse d'horloge Arduino ADC est définie dans ..arduino-1.5.5 \ hardware \ arduino \ avr \ cores \ arduino \ câblage.c

Voici la partie pertinente

#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

Pour un Arduino 16 MHz, l'horloge ADC est réglée sur 16 MHz / 128 = 125 KHz. Chaque conversion en AVR nécessite 13 horloges ADC, donc 125 KHz / 13 = 9615 Hz.

Il s'agit du taux d'échantillonnage maximal possible, mais le taux d'échantillonnage réel dans votre application dépend de l'intervalle entre les appels de conversions successifs.
Puisque vous lisez le résultat et l'envoyez via le port série, vous obtenez un retard qui augmente à mesure que la vitesse de transmission diminue. Plus le débit en bauds est faible, plus il faudra de temps pour envoyer la même longueur de données et plus il faudra de temps pour appeler la prochaine conversion ADC.

Le taux d'échantillonnage réel dans votre application peut être déterminé à l'aide d'un débogueur ou d'un simulateur, mais une solution plus simple consiste à basculer une broche numérique chaque fois que vous exécutez une conversion et à mesurer la fréquence à laquelle la broche numérique bascule.

alexan_e
la source
De plus, le temps entre mes horodatages passe de ~ 1300 jusqu'à ~ 16400, ils devraient sûrement rester les mêmes? C'est à 9600, à 115200, ils n'augmentent qu'à environ 1500 après beaucoup de temps.
user3284376
@ user3284376 concernant votre code d'horodatage, je pense qu'il ne peut pas fonctionner à tout moment (peut être biaisé par certaines interruptions au mauvais moment). Je vous suggère de poster une question spécifique sur la façon d'obtenir un timing de haute précision sur Arduino et d'y mettre la partie pertinente de votre code.
jfpoilpret
7

Je voulais aussi obtenir un taux d'échantillonnage élevé, pour un projet. s'avère que les bits ADPS2, ADPS1, ADPS0 du registre ADCSRA peuvent être configurés pour obtenir un taux d'échantillonnage de 76923 s / s ou 76,8 ks / s. Mais, méfiez-vous que j'exécute l'ADC de mon arduino en mode de fonctionnement libre, les lignes suivantes ont fonctionné pour moi.

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

À cette fréquence, les résultats habituels sur 10 bits ne sont pas fiables. Cela signifie que l'augmentation de la fréquence d'échantillonnage diminuera la précision des résultats. Je n'utilise donc que les 8 bits supérieurs car à ce niveau pré-calaire, les 8 bits supérieurs sont fiables. Vous pouvez aller plus en détail sur cette page, ce mec berce! il a fait un oscilloscpe à taux d'échantillonnage élevé en utilisant UNO http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/

Salar Khan
la source
3

À chaque boucle, vous imprimez 8 caractères sur une liaison série à 9600 bps. Chaque caractère prend 10 bits (1 début, 8 bits pour le caractère, 1 arrêt). Cela signifie que vous ne pouvez parcourir cette boucle que 120 fois / sec.

La analogRead()fonction peut échantillonner à environ 9600 fois / s en théorie, en réalité, elle est d'environ 8600 fois / s.

Vous êtes limité par la communication série.

Cybergibbons
la source
Donc augmenter à 115200, donne 1440 fois / sec, est-ce le taux d'échantillonnage?
user3284376
Donnez ou prenez, oui. Vous devez garder à l'esprit que Serial exige que l'autre extrémité réponde, donc vous dépendez de la réponse du PC. Ce n'est pas déterministe, vous obtiendrez donc une gigue.
Cybergibbons
Vous avez raison côté Arduino, tout semble bien, mais sur Python, les choses sont beaucoup plus lentes, quel genre de choses devrais-je faire pour augmenter les performances côté ordinateur?
user3284376
Vous ne devez pas considérer cela comme un problème avec les performances en série sur le PC, mais comment découpler l'échantillonnage de l'envoi de données.
Cybergibbons
1
@Cybergibbons - non, car cela fonctionne sur un Uno où l'USB et la série sont découplés, il n'y a aucune dépendance à l'égard du PC au-delà de l'émission du caractère `` S '' et non de celui du `` F ''. Le croquis affiché ici et la plate-forme sur laquelle il s'exécute seront heureux de jeter des données série sur le micro compagnon série USB, aveuglément inconscient si cela ou quoi que ce soit à l'autre extrémité de l'USB se maintient.
Chris Stratton
3

Envoi de 11 bits sur série à un baud de 9600, mais pour l'échantillonnage, je le stocke dans un tableau avec le moins de retard possible, puis une fois cela fait, je l'envoie via le port série pour être lu par un script python. Je fais cela pour une FFT utilisant matplotlib. J'écoute un signal 0-5 V, puis sans utiliser la fonction delay (), je stocke les valeurs analogRead () dans ce tableau. En une fraction de seconde, la lecture est effectuée, puis le vidage des données série démarre. Lorsque j'ai calibré la fréquence d'entrée en utilisant la tonalité () d'un autre Arduino connecté, j'ai réalisé que je devais diviser l'index par 8915 afin d'obtenir une précision à 0,1 Hz près. Parce qu'il faudrait diviser par la fréquence d'échantillonnage pour obtenir les intervalles d'index appropriés, je suppose que la fréquence d'échantillonnage Arduino (au moins la mienne avec mon code) est de 8915 Hz.

user34028
la source
1

Se référant à la partie sur la différence entre la fréquence d'échantillonnage et la vitesse de transmission, ce sont des mesures différentes.

La fréquence d'échantillonnage est la fréquence à laquelle l'appareil (Arduino) peut recréer une représentation numérique des valeurs analogiques entrantes.

Baud Rate est le taux auquel les informations sont transférées dans un canal de communication. Il décrit le taux de communication entre le microcontrôleur et le monde extérieur (l'ordinateur).

Je recommanderais ce lien electronics_stack_exchange. /electronics/135056/sampling-rate-data-rate-and-bandwidth

ThermoRestart
la source
0

8915Hz - il est très proche de 125000/14 ~ = 8928.6 Ma supposition initiale qu'exactement un écart est requis entre les conversions adjacentes Une horloge ADC pour l'échantillonnage et 13 horloges ADC pour la conversion elle-même. Une petite erreur pourrait être due à une source d'horloge non parfaite d'Arduino. Je ne suis pas encore sûr. Ce sujet est réel pour moi maintenant car les données échantillonnées doivent alimenter le filtre numérique.

E_Sh
la source
1
Je ne sais pas ce que vous voulez dire lorsque vous dites "Ce sujet est réel pour moi maintenant car les données échantillonnées doivent alimenter le filtre numérique.". Rencontrez-vous un problème similaire?
VE7JRO
Chaque conversion commence sur un front montant de l'horloge ADC, et au moins un cycle d'horloge ADC est perdu en exécutant le code. Alors oui, 8928,6 Hz est le plus rapide que vous pouvez obtenir en appelant analogRead()en boucle serrée, contre un 9615,4 Hz très cohérent en mode libre.
Edgar Bonet