Oversampling
  • Retrofit
  • 18/05/2020

Oversampling

Se você precisasse mais resolução do ADC do Arduino, o que fazer? Trocar de processador? Colocar um ADC externo? Chamar o Batman? Não precisa nada disso. Existe uma técnica que você pode usar e ganhar alguns bits de resolução no ADC. E é sobre isto que vou tratar neste post.

A fórmula de como se conseguir mais resolução do conversor AD vem das teorias de estatísticas e aproveita-se do fato de que os sinais geralmente contém uma certa quantidade de ruído.

Basicamente, se você realizar uma quantidade x de medições de um sinal com o conversor AD, mesmo que o sinal esteja estável e não varie, o resultado das medições irá variar em torno do valor verdadeiro.

Vamos ver como isso funciona.

Por: Diego J. Stefanello e Ricardo B. Morim

 

Aumentando a resolução do ADC através do Oversampling

 

Você deve estar se perguntando então, como faço para aumentar a resolução do conversor AD do Arduino? A resposta está no próprio nome da técnica, Oversampling, que significa sobre amostragem.

Como existe o ruído branco (white noise) ou ruído Gaussiano, no sinal analógico, o que você deve fazer é aumentar a quantidade de leituras, isto é, obter mais amostras. Na Figura 1 você pode verificar o efeito de fazer várias amostras do mesmo sinal, quando se considera a distribuição das leituras em termos dos resultados delas, para um conversor AD de 12 bit.

Fig. 1: Histograma da conversão de sinal com ruído branco. Fonte: Silicon Labs AN-118.

 

O eixo x (horizontal) desta figura refere-se ao valor da leitura do conversor AD enquanto o eixo y mostra o número de amostras para cada valor do eixo x.

O que isto nos diz é que se você realizar um número expressivo de leituras, a maioria delas terá resultado igual ou muito próximo ao verdadeiro (no caso, 1024), porém, muitas das leituras terão resultado próximo ao verdadeiro, pois estão contaminadas pelo ruído Gaussiano. Isto é, teremos resultados distribuídos no entorno do valor central, correto.

Na aplicação da técnica de Oversampling nós tomamos vantagem disso, o que significa realizar um número expressivo de leituras e calcular a média delas, sabendo que a maioria das leituras terá resultado igual ou próximo do valor verdadeiro.

Você deve estar se perguntando qual seria o ônus ou limitação da aplicação desse método. Sim, o ônus que você irá pagar pelo benefício do aumento de resolução do conversor AD é a necessidade do aumento do número de amostras, no mesmo espaço de tempo. Para a aplicação da técnica, devemos amostrar o sinal em uma frequência de:

 

 

Onde:  é a frequência de Oversampling, n é o número de bits adicionais que desejamos aumentar na resolução do ADC e  é a frequência normal de funcionamento do conversor AD do Arduino, sem a utilização do Oversampling.

As leituras realizadas devem ser somadas para depois passarem por um processo chamado decimação (ou, em inglês, decimation). Tal processo consiste em dividir o somatório acumulado das  leituras por .

Portanto, como você pode verificar, são necessárias muito mais conversões AD no mesmo espaço de tempo. Este fato é crítico para processos que exigem leituras rápidas, porém, para aplicações nas quais não há necessidade de alta velocidade de conversão AD a sua implementação é simples e viável.

Para que você entenda melhor o conceito, vamos a um exemplo. Suponhamos que você queria realizar a medida de temperatura através de um sensor analógico, como o LM35 ou o TMP36, através do conversor AD do Arduino, que possui resolução de 10 bit.

Vamos supor que você queira fazer uma leitura a cada segundo. Vamos utilizar este exemplo aplicando a ele a técnica de oversampling para melhorar a resolução do conversor AD do Arduino de 10 bit para 14 bit. Com 14 bit de resolução e tensão de referência (Vref+) de 5 V para o conversor AD, a resolução da leitura se torna:

 

 

Pela técnica de Oversampling, considerando que estamos aumentando 4 bit de resolução do conversor AD (n = 4) e que o nosso tempo de amostragem é de 1 segundo (), o número de conversões deve ser aumentado para:

 

 

Ou seja, se antes você precisava realizar uma conversão por segundo, agora precisará realizar 256 conversões! Obviamente, no presente caso, não há nenhum problema em termos de sobrecarga de processamento, pois estas tarefas são relativamente simples para o processador do Arduino.

Durante o período de 1 segundo, os resultados destas 256 conversões devem ser somados e armazenados. Após, o somatório deve se dividido por , isto é, por 16, no exemplo dado. Em termos de código de programação, a divisão por números com expoente inteiro e base dois consiste uma rotação logical dos bits do registrador, para a direita, o que torna a implementação muito otimizada.

 


Fig. 2: Divisão por 2, através de rotação logica do registrador.

 

Implementando o oversampling

 

Para mostrar a efetividade do Oversampling no Arduino utilizaremos a aplicação do sensor de temperatura LM35. A utilização do sensor de temperatura LM35 no Arduino foi mostrada em outro post, aqui na TOT.

Agora, utilizando aquele mesmo código, e fazendo a adaptação para o oversampling, você será capaz de obter mais resolução numérica.

 

/**********************************************************************************

                           TOT Engenharia

 

Neste exemplo, você entenderá como é utilizada a tecnica de oversampling, no

conversor ADC do Arduino. Utilizaremos o LM35 para ler a temperatura e um display

LCD 16x2, para visualização dos dados.

 

 

Autor: Ricardo Morim

Revisão: Diego Stefanello

Data: 08/2018

Versão: 1.0

*********************************************************************************/

 

//--- Carrega a biblioteca LiquidCrystal ---

#include <LiquidCrystal.h>

 

 

//--- Definições de estados ---

#define ON 1

#define OFF 0

 

//--- Definições de pinos ---

#define LM35_PIN    A0

 

 

//--- Define os pinos que serão utilizados para comunição com o display ---

LiquidCrystal lcd( 6, 7, 8, 9, 10, 11); // Pinos do LCD: RS, ENABLE, D4, D5, D6, D7

 

 

//Array simbolo grau

byte grau[8] =

{

   0b01110,

   0b01010,

   0b01110,

   0b00000,

   0b00000,

   0b00000,

   0b00000,

   0b00000

};

 

 

 

//--- Inicialização ---

void setup()  

   Serial.begin(115200); // Inicializa a serial @ 115200bps

  

   lcd.begin(16, 2);  // Inicializa O LCD 16x2

  

   lcd.createChar(0, grau); //Cria o caractere customizado com o simbolo do grau

 

   // Cria o cabeçalho do display

   lcd.setCursor(0,0);  // Seta cursor no display (coluna, linha)

   lcd.print("ADC Oversampling"); // Envia o texto para o display

 

   lcd.setCursor(0,1);  // Seta cursor no display (coluna, linha)

   lcd.print("Temp:");  // Envia o texto para o display

 

   // Cria o cabeçalho para serial

   Serial.println("Sensor temperatura LM35 + oversampling");  // Envia texto pla serial, seguido por um caractere de retorno de

                                                              // carro (decimal 13 ou '\r') e um caractere de nova linha (decimal 10 ou '\n')

 

 

//--- Loop principal ---

void loop() 

{

   float t_lm35;   // Variavel do tipo float, para armazenar a temperatura em graus Celsius, do LM35

   unsigned long lm35; // Variável do tipo inteiro (32bits) para armazenar a conversão analogica do ADC

   unsigned int counter;

 

   lm35=0; // limpa o registrador acumulador

 

   for(counter=256; counter; counter--) // 4^n = 4^4 = 256

   {

      lm35 += analogRead(LM35_PIN); // Faz a conversão de 256 amostras do sinal analogico 

      delay(4); // 4 * 256 é aproximadamente 1 segundo.

   }

   

   lm35 >>= 4; // divide por 16  

  

   t_lm35 = ((float)lm35*5/16384); // Converte o valor lido em tensão (Volts)

   t_lm35 = (t_lm35 + 0.02) * 100; // Ajusta o offset e converte para temperatura, em ºC (tensão*100)

 

   Serial.print(t_lm35, 1); // Envio o valor da temperatura pela porta serial

   Serial.print("\xC2\xB0"); // Envia o simbolo "°". Arduino IDE 1.8.3 utiliza formatação UTF-8

   Serial.println("C"); // Envia o caracter "C" e o comando de nova linha e retorno

   

   lcd.setCursor(6, 1);   // Posiciona o cursor do LCD, na 1º linha

   lcd.print(t_lm35, 1);  // Envia para o display, o valor da temperatura, com um decimo de resolução

   lcd.write((byte)0); // Envia o simbolo do grau, formado pelo array

   lcd.print("C "); // Envia a letra C   

}

 

 

Para Finalizar, segue abaixo as imagens da minha realização prática.

 

Fig. 3: Teste final do ADC com oversampling.

 

Conclusão

Neste artigo, mostrei como   utilizar a técnica do oversampling, para aumentar a resolução do ADC.  A implementação pode ser feita com outros sensores e microcontroladores.

Como você pode notar, o ponto negativo é a maior quantidade de amostragem do sinal, que em sistemas de alta velocidade, pode ser um problema.

Gostou do artigo? Sobre o que você gostaria que escrevêssemos? Deixe o seu comentário!

Por: Ricardo B. Morim e Diego J. Stefanello