Como sei a frequência de amostragem?

16

Estou começando a ficar um pouco confuso sobre taxas de amostragem e taxas de transmissão, etc. Eu tenho esse código do 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 não há atraso na interrupção, qual é a taxa / frequência de amostragem? É baseado na velocidade do Arduino ADC? Ao aumentar a taxa de transmissão, estou aumentando a frequência de amostragem ou apenas a taxa na qual envio dados pela porta serial?

user3284376
fonte

Respostas:

21

A velocidade do clock do Arduino ADC é definida em ..arduino-1.5.5 \ hardware \ arduino \ avr \ núcleos \ arduino \iring.c

Aqui está a 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 um Arduino de 16 MHz, o relógio ADC é definido como 16 MHz / 128 = 125 KHz. Cada conversão no AVR leva 13 relógios ADC, então 125 KHz / 13 = 9615 Hz.

Essa é a taxa de amostragem máxima possível, mas a taxa de amostragem real em seu aplicativo depende do intervalo entre chamadas de conversões sucessivas.
Como você lê o resultado e o envia pela porta serial, você recebe um atraso que aumenta à medida que a taxa de transmissão diminui. Quanto menor a taxa de transmissão, mais tempo levará para enviar o mesmo comprimento de dados e mais tempo levará para chamar a próxima conversão ADC.

A taxa de amostragem real em seu aplicativo pode ser determinada com o uso de um depurador ou simulador, mas uma solução mais fácil é alternar um pino digital toda vez que você executa uma conversão e mede a frequência em que o pino digital alterna.

alexan_e
fonte
Além disso, o tempo entre meus carimbos de hora aumenta de ~ 1300 até ~ 16400; certamente eles devem permanecer iguais? Ou seja, em 9600, em 115200, eles aumentam apenas para cerca de 1500 depois de muito tempo.
user3284376
@ user3284376 em relação ao seu código de carimbo de data / hora, acho que ele não pode funcionar o tempo todo (pode ser influenciado por algumas interrupções no momento errado). Sugiro que você publique uma pergunta específica sobre como obter um timing de alta precisão no Arduino e coloque a parte relevante do seu código lá.
jfpoilpret
7

Eu também queria obter uma alta taxa de amostragem para um projeto. Acontece que os bits ADPS2, ADPS1, ADPS0 do registro ADCSRA podem ser configurados para obter uma taxa de amostragem de 76923 s / s ou 76,8 ks / s. Mas tenha cuidado ao executar o ADC do meu arduino no modo de execução livre, as seguintes linhas funcionaram para mim.

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

Nesta frequência, os resultados usuais de 10 bits não são confiáveis. Isso significa que aumentar a taxa de amostragem diminuirá a precisão dos resultados. Então, eu só uso os 8 bits superiores porque neste pré-escalar os 8 bits superiores são confiáveis. Você pode entrar em mais detalhes nesta página, esse cara é demais! ele fez um osciloscópio de alta taxa de amostragem usando o UNO http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/

Salar Khan
fonte
3

A cada loop, você imprime 8 caracteres em um link serial de 9600bps. Cada caractere leva 10 bits (1 início, 8 bits para o caractere, 1 parada). Isso significa que você só pode passar por esse loop ~ 120 vezes / s.

A analogRead()função pode amostrar em cerca de 9600 vezes / s em teoria, realisticamente, é cerca de 8600 vezes / s.

Você está sendo limitado pela comunicação serial.

Cybergibbons
fonte
Então, aumentar para 115200, dá 1.440 vezes / s, é essa a taxa de amostragem?
user3284376
Mais ou menos, sim. Você precisa ter em mente que o Serial exige que a outra extremidade responda; portanto, você depende do PC responder. Isso não é determinístico, então você ficará instável.
Cybergibbons
Você está certo no final das coisas no Arduino, tudo parece bem, mas no Python as coisas são muito mais lentas, que tipo de coisas eu precisaria fazer para aumentar o desempenho no final do computador?
user3284376
Você não precisa considerar isso como um problema com o desempenho serial no PC, mas como dissociar a amostragem do envio de dados.
Cybergibbons
1
@Cybergibbons - não, como isso está sendo executado em um Uno em que o USB e o serial são dissociados, não há dependência do PC além de emitir o caractere 'S' e não de 'F'. O esboço postado aqui e a plataforma na qual ele roda lançará alegremente dados seriais no micro complementar USB, esquecendo cegamente se isso ou algo do outro lado do USB está mantendo.
Chris Stratton
3

Enviando 11 bits por serial a uma taxa de transmissão de 9600, mas para a amostragem, eu o armazeno em uma matriz com o mínimo de atraso possível; depois que estiver pronto, envio-o pela porta serial para ser lido por um script python. Estou fazendo isso para uma FFT usando matplotlib. Eu escuto um sinal de 0-5V e, sem usar a função delay (), armazeno os valores analogRead () nesse array. Em uma fração de segundo, a leitura é feita e o despejo de dados seriais é iniciado. Quando calibrei a frequência de entrada usando tone () de outro Arduino conectado, percebi que tinha que dividir o índice por 8915 para obter precisão dentro de 0,1 Hz. Como seria necessário dividir pela frequência da amostragem para obter os intervalos de índice adequados, acho que a frequência de amostragem do Arduino (pelo menos a minha com o meu código) é 8915Hz.

user34028
fonte
1

Referindo-se à parte sobre a diferença entre taxa de amostragem e taxa de transmissão, são medidas diferentes.

Sample Rate é a frequência na qual o dispositivo (arduino) pode recriar uma representação digital dos valores analógicos recebidos.

Taxa de transmissão é a taxa na qual as informações são transferidas em um canal de comunicação. Ele descreve a taxa de comunicação entre o microcontrolador e o mundo exterior (o computador).

Eu recomendaria este link electronics_stack_exchange. /electronics/135056/sampling-rate-data-rate-and-bandwidth

ThermoRestart
fonte
0

8915Hz - está muito próximo de 125000/14 ~ = 8928,6 Meu palpite inicial é de que exatamente um intervalo seja necessário entre as conversões adjacentes. Um relógio ADC para amostragem e 13 relógios ADC para a própria conversão. Um pequeno erro pode ser efeito da fonte de clock não perfeita do Arduino. Ainda não tenho certeza. Este tópico é atual para mim agora, pois os dados amostrados devem alimentar o filtro digital.

E_Sh
fonte
1
Não sei ao certo o que você quer dizer quando diz "Este tópico é atual para mim agora, pois os dados amostrados devem alimentar o filtro digital". Você está tendo um problema semelhante?
VE7JRO
Cada conversão inicia em uma borda ascendente do relógio ADC e pelo menos um ciclo de relógio ADC é perdido na execução do código. Então sim, 8928,6 Hz é o mais rápido que você pode obter chamando analogRead()em um loop apertado, contra 9615,4 Hz muito consistentes no modo de execução livre.
Edgar Bonet