¿Cómo sé la frecuencia de muestreo?


16

Estoy empezando a confundirme un poco sobre las tasas de muestreo y las velocidades de transmisión, etc. Tengo este código 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;
        }
      }
    }
  }
}

Como no hay interrupción por retraso, ¿cuál es la frecuencia / frecuencia de muestreo? ¿Se basa en la velocidad ADC de Arduino? Cuando aumento la velocidad en baudios, ¿estoy aumentando la frecuencia de muestreo o solo la velocidad a la que envío datos a través del puerto serie?

Respuestas:


21

La velocidad de reloj del Arduino ADC está configurada en ..arduino-1.5.5 \ hardware \ arduino \ avr \ cores \ arduino \ cable.c

Aquí está la parte relevante

#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

Para un Arduino de 16 MHz, el reloj ADC está configurado en 16 MHz / 128 = 125 KHz. Cada conversión en AVR toma 13 relojes ADC, por lo que 125 KHz / 13 = 9615 Hz.

Esa es la frecuencia de muestreo máxima posible, pero la frecuencia de muestreo real en su aplicación depende del intervalo entre llamadas de conversiones sucesivas.
Como lee el resultado y lo envía a través del puerto serie, obtiene un retraso que aumenta a medida que disminuye la velocidad en baudios. Cuanto menor sea la velocidad de transmisión, más tardará en enviar la misma longitud de datos y más tardará en llamar a la próxima conversión de ADC.

La frecuencia de muestreo real en su aplicación se puede determinar con el uso de un depurador o un simulador, pero una solución más fácil es alternar un pin digital cada vez que ejecute una conversión y medir la frecuencia con la que el pin digital alterna.


Además, el tiempo entre mis marcas de tiempo aumenta de ~ 1300 hasta ~ 16400, ¿seguramente deberían permanecer igual? Es decir, a 9600, a 115200, aumentan solo a aproximadamente 1500 después de mucho tiempo.
user3284376

@ user3284376 con respecto a su código de marca de tiempo, creo que no puede funcionar en todo momento (puede estar sesgado por algunas interrupciones en el momento equivocado). Le sugiero que publique una pregunta específica sobre cómo obtener una sincronización de alta precisión en Arduino y coloque allí la parte relevante de su código.
jfpoilpret

7

También quería obtener una alta frecuencia de muestreo para un proyecto. Resulta que los bits ADPS2, ADPS1, ADPS0 del registro ADCSRA pueden configurarse para obtener una frecuencia de muestreo de 76923 s / so 76.8 ks / s. Pero, tenga en cuenta que estoy ejecutando el ADC de mi arduino en modo de ejecución libre, las siguientes líneas funcionaron para mí.

#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 esta frecuencia, los resultados habituales de 10 bits no son confiables. Significa que aumentar la frecuencia de muestreo disminuirá la precisión de los resultados. Así que solo uso los 8 bits superiores porque en este preescalar los 8 bits superiores son confiables. Puedes entrar en más detalles en esta página, ¡este tipo es genial! hizo un osciloscopio de alta frecuencia de muestreo utilizando UNO http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/


3

Cada ciclo está imprimiendo 8 caracteres sobre un enlace serial de 9600bps. Cada carácter toma 10 bits (1 inicio, 8 bits para el personaje, 1 parada). Eso significa que solo puede pasar por este ciclo ~ 120 veces / seg.

La analogRead()función puede muestrear a aproximadamente 9600 veces / seg en teoría, de manera realista es aproximadamente 8600 veces / seg.

Usted está siendo limitado por la comunicación en serie.


Entonces, aumentar a 115200, da 1440 veces / segundo, ¿es esa la frecuencia de muestreo?
user3284376

Da o toma, sí. Debe tener en cuenta que Serial requiere que el otro extremo responda, por lo que depende de la respuesta de la PC. Esto no es determinista, por lo que obtendrá nerviosismo.
Cybergibbons

Tienes razón en el extremo de Arduino, todo parece estar bien, pero en Python las cosas son mucho más lentas, ¿qué tipo de cosas necesitaría hacer para aumentar el rendimiento en el extremo de la computadora?
user3284376

No necesita ver esto como un problema con el rendimiento en serie en la PC, pero ¿cómo se puede desacoplar el muestreo del envío de datos?
Cybergibbons

1
@Cybergibbons: no, ya que esto se ejecuta en un Uno donde el USB y el serial están desacoplados, no hay dependencia en la PC más allá de emitir el carácter 'S' y no emitir el 'F'. El boceto publicado aquí y la plataforma en la que se ejecuta arrojará felizmente los datos en serie al micro USB de serie, sin darse cuenta ciegamente si eso o algo en el otro extremo del USB se mantiene.
Chris Stratton

3

Enviando 11 bits en serie a una velocidad de 9600 baudios, pero para el muestreo, lo almaceno en una matriz con el menor retraso posible, luego, una vez hecho, lo envío a través del puerto serie para que lo lea un script de Python. Estoy haciendo esto para una FFT usando matplotlib. Escucho una señal de 0-5 V, luego, sin usar la función delay (), almaceno los valores analogRead () en esa matriz. En una fracción de segundo se realiza la lectura, luego comienza el volcado de datos en serie. Cuando calibré la frecuencia de entrada usando el tono () de otro Arduino conectado, me di cuenta de que tenía que dividir el índice entre 8915 para obtener una precisión dentro de .1 Hz. Debido a que uno tendría que dividir por la frecuencia del muestreo para obtener los intervalos de índice adecuados, supongo que la frecuencia de muestreo de Arduino (al menos la mía con mi código) es 8915Hz.


1

Refiriéndose a la parte sobre la diferencia entre la frecuencia de muestreo y la velocidad de transmisión, son mediciones diferentes.

Sample Rate es la frecuencia con la que el dispositivo (arduino) puede recrear una representación digital de valores analógicos entrantes.

La velocidad en baudios es la velocidad a la que se transfiere la información en un canal de comunicación. Describe la velocidad de comunicación entre el microcontrolador y el mundo exterior (la computadora).

Recomendaría este enlace electronics_stack_exchange. /electronics/135056/sampling-rate-data-rate-and-bandwidth


0

8915Hz: está muy cerca de 125000/14 ~ = 8928.6 Mi conjetura inicial de que se requiere exactamente un espacio entre las conversiones adyacentes Un reloj ADC para el muestreo y 13 relojes ADC para la conversión misma. Un pequeño error podría ser el efecto de una fuente de reloj no perfecta de Arduino. Aun no estoy seguro. Este tema es real para mí ahora ya que los datos muestreados deben alimentar el filtro digital.


1
No estoy seguro de lo que quiere decir cuando dice "Este tema es real para mí ahora ya que los datos muestreados deben alimentar el filtro digital". ¿Tienes un problema similar?
VE7JRO

Cada conversión comienza en un flanco ascendente del reloj ADC, y al menos un ciclo de reloj ADC se pierde al ejecutar el código. Entonces sí, 8928.6 Hz es lo más rápido que puede obtener llamando analogRead()a un bucle cerrado, frente a un 9615.4 Hz muy consistente en modo de funcionamiento libre.
Edgar Bonet
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.