Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

Arduino e o cálculo da FFT

2012, Arduino e o cálculo da FFT

É objectivo deste artigo mostrar quais são as capacidades e limitações do uso da plataforma de desenvolvimento Arduino, num caso concreto, o cálculo da FFT (Fast Fourier Transform) para diferentes frequências do sinal de entrada. Para tal vão ser efectuadas algumas medições de carácter prático utilizando o modelo Arduino Duemilinove. Como segundo objectivo, e não menos importante, espera-se fazer uma comparação entre os microcontroladores utilizados nos modelos Arduino Mega com ATmega1280, Arduino Duemilinove com ATmega168 e Arduino Duemilinove com ATmega328. Tentando assim dar uma perspectiva das suas capacidades e limitações neste campo.

A PROGRAMAR Arduino e o cálculo da FFT Introdução É objectivo deste artigo mostrar quais são as capacidades e limitações do uso da plataforma de desenvolvimento Arduino, num caso concreto, o cálculo da FFT (Fast Fourier Transform) para diferentes frequências do sinal de entrada. Para tal vão ser efectuadas algumas medições de carácter prático utilizando o modelo Arduino Duemilinove. Como segundo objectivo, e não menos importante, espera-se fazer uma comparação entre os microcontroladores utilizados nos modelos Arduino Mega com ATmega1280, Arduino Duemilinove com ATmega168 e Arduino Duemilinove com ATmega328. Tentando assim dar uma perspectiva das suas capacidades e limitações neste campo. Variáveis vs Memória disponível Como primeiro passo para o início de uma análise pormenorizada do tema, torna-se necessário ter em consideração a quantidade de memória SRAM (Static Random Access Memory) disponível nos diversos modelos de microcontroladores utilizados. Flash ATmega168 ATmega328 ATmega1280 16 KBytes 32 KBytes 128 KBytes (2 KBytes Bootloader) (2 KBytes Bootloader) (4 KBytes Bootloader) SRAM 1024 Bytes 2048 Bytes 8192 Bytes EEPROM 512 Bytes 1024 Bytes 4096 Bytes Tabela 1 – Quantidades de memória disponíveis O Arduino Duemilinove está equipado com o ATMega168, podendo ser “actualizado” facilmente substituindo o microcontrolador actual (ATmega168), por um ATMega328 pré-programado (com o respectivo Bootloader). Fazendo uma breve análise à tabela 1 (valores retirados do datasheet de cada microcontrolador), é possível verificar que a versão Arduino Mega com o ATmega1280 leva clara “vantagem” em termos de capacidade, mas resta analisar até que ponto nesta aplicação concreta será suficiente essa “vantagem”. Ao ser declarada (utilizada) uma variável do tipo float estão a ser reservados 4 bytes (32 bits) na memória SRAM. Se considerarmos que ao efectuar a FFT vamos obter resultados com parte real e imaginária, vamos ter de reservar dois “espaços” de um array (vector)do tipo float para cada número. O que nos leva a que ao ser declarado p.ex. um array de f[i] com i=1 a N com N=128 , teremos um array que corres- 14 ponderá a 64 números do tipo “a+jb)”. Em que p.ex. corresponderá à parte real (“a”), e f[2] corresponderá a (“b”) do primeiro número. Esta conclusão vai ser importante nos cálculos efectuados, para achar a capacidade máxima de armazenamento em SRAM dos microcontroladores referidos na Tabela 1. Numa situação ideal, em que mais nenhuma variável necessitaria de ser usada, a capacidade de armazenamento (para este caso concreto) seria a seguinte:  Arduino Duemilinove (ATMega168)  Arduino Duemilinove (ATMega328)  Arduino Mega (ATMega1280) Pela análise dos valores acima obtidos, podemos constatar que poderíamos armazenar 128 números do tipo “a+jb” num ATMega168, 256 num ATMega328 e 1000 recorrendo ao uso de um ATMega1280. Mas como é óbvio é necessário recorrer a variáveis para o próprio cálculo da FFT, bem como a variáveis “intermédias” para obter e guardar os valores obtidos nas diferentes entradas analógicas presentes no Arduino (qualquer que seja a versão a considerar). O que nos leva desde já a tomar os valores acima descritos como um exercício meramente teórico. Após uma abordagem sobre os valores teóricos de armazenamento em SRAM, dos diversos modelos de microcontrolador utilizado na plataforma de desenvolvimento Arduino, vai ser tomado em consideração o tempo de conversão A/D levado pelo ADC (Analog-to-digital-converter ou conversor analógico-digital). Vai também ser tomado em consideração o tempo necessário para a aplicação do algoritmo de cálculo da FFT utilizado. A PROGRAMAR ARDUINO E O CÁLCULO DA FFT Arduino e o ADC void loop() { b = micros();); //Atribui à variável “b” o //tempo actual de execução do programa actual a = analogRead(0); c = micros(); // Atribui à variável “c” o //tempo actual de execução do programa actual Serial.print(c-b); //Envia (série) o valor //necessário para executar a instrução //analogRead” (conversão A/D) } Para esta aplicação específica torna-se necessária uma análise do tempo de conversão A/D, com vista a saber qual o tempo que se consegue obter entre amostras. Para tal foram lidos os valores de tempo de conversão obtidos experimentalmente, modificando os valores do factor de divisão. Este factor de divisão (Prescaler) define o input clock do conversor A/D, ou seja, se tivermos um factor de divisão de 32 e um clock de sistema de 16 MHz (comum a todos os modelos de Arduino) teremos um input clock no conversor A/D de: Ao fazer variar o conteúdo do registo ADCSRA, mais precisamente dos bits designados por ADPS2, ADPS1 e ADPS0, é possível fazer variar o valor do factor de divisão referido anteriormente. As combinações possíveis encontram-se descritas na seguinte tabela: Cada conversão A/D (de acordo com o especificado no datasheet do microcontrolador) demora cerca de 13 ciclos de clock, à excepção da primeira conversão que demorará 25 ciclos de clock (efectua a inicialização do conversor A/D). Ao considerar o valor obtido no cálculo efectuado acima, iríamos obter uma taxa de amostragem de: ADPS2 ADPS1 ADPS0 Factor de divisão obtido 0 0 0 2 0 0 1 2 0 1 0 4 O que não corresponderá aos valores obtidos experimentalmente, correspondendo o valor acima a um valor teoricamente esperado. Devido a este facto vão ser efectuadas medições experimentais, tentando assim obter estimativas mais reais dos tempos necessários para efectuar a conversão A/D. 0 1 1 8 1 0 0 16 1 0 1 32 1 1 0 64 Para obter os valores de tempo de conversão, execução da instrução “analogRead”, vai ser utilizada a função “micros()”. Esta função retorna o valor de tempo, em µs, que passou desde que se iniciou a execução do programa. Ao fazer a diferença entre os valores de retorno da função, em sítios distintos da execução do nosso programa, conseguimos obter o tempo dispendido na sua execução. O código a utilizar será o seguinte: 1 1 1 128 Tabela 2 – Combinações possíveis (Registo ADCSRA) Os valores obtidos, utilizando um Arduino Duemilinove com ATMega168 (modelo testado), foram os seguintes: #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(void) { Serial.begin(9600); ); //Inicializa o envio //por Série, e define a Baud Rate sbi(ADCSRA, ADPS2); //Neste caso concreto o //bit ADPS2 será definido com o valor 1 cbi(ADCSRA, ADPS1); //Neste caso concreto o //bit ADPS1 será definido com o valor 0 cbi(ADCSRA, ADPS0); //Neste caso concreto o //bit ADPS0 será definido com o valor 0 } int a,b,c; Tabela 3 – Tempo de conversão A/D obtido Os valores obtidos na Tabela 3 correspondem a uma média de 1000 valores obtidos para cada caso (Recolha e cálculo da média efectuado recorrendo ao Software MatLab), ou seja, aos valores de tempo obtidos ao fazer variar o respectivo factor de divisão. 15 A PROGRAMAR ARDUINO E O CÁLCULO DA FFT Outra conclusão a retirar das medições efectuadas, e que foi possível verificar através da experiência, é o facto de apenas se deverem considerar valores do factor de divisão (Prescaler) acima de 2. Verificando-se que para factores de divisão de valor 2 são obtidos alguns erros na conversão A/D (Obtiveram-se alguns valores de leitura nulos). rosa e algo complexa. O código utilizado neste estudo baseia-se no algoritmo redescoberto por “Danielson and Lanczos” em 1942 (Press, Teukolsky et al. 1992). O array de entrada (do tipo float) deverá ter uma dimensão correspondente a uma potência de dois, ou seja, neste caso concreto analisado f[i] deverá estar compreendido entre 0 e 2n - 1 ( n ϵ N). O que limita a utilização da memória SRAM disponível a vectores que possuam essas dimensões. Num caso concreto em que se queira aplicar o algoritmo a um conjunto de números do tipo “a+jb”, que não seja exactamente uma potência de dois, deverá ser reservado espaço de memória para um array f[i] com um valor máximo de i que corresponda ao valor da potência de dois imediatamente acima do número pretendido menos um (2n –1). Ao ser efectuada a passagem do array para a função de cálculo da FFT deverá ser efectuado Zero padding (Chu 2008), ou seja, todos os restantes valores do array deverão ser preenchidos com o valor zero. Pela análise da Tabela 3, e pelo descrito acima, é óbvio que o tempo de conversão mínimo que se pode obter será de ≅12µs. Este valor é apenas referente a uma entrada analógica, se quisermos considerar as 6 entradas analógicas disponíveis teremos de multiplicar esse valor por 6. Obtendo assim: Podendo assim considerar que obtemos uma “conversão muito mais rápida” ao efectuar a conversão A/D de cada canal individualmente. Ao utilizar a versão Arduino Duemilinove com ATmega168, e como foi referido anteriormente, podemos armazenar na memória SRAM disponível um array (do tipo float) com a dimensão máxima de 128. Mas devido às razões enumeradas no início deste artigo o número de pontos máximo que se consegue calcular actualmente será de 64. Os valores da Tabela 3 podem ser descritos em número de amostras por segundo (taxa de amostragem). Sendo os valores obtidos descritos na tabela seguinte: Tornando-se agora possível, e recorrendo a um raciocínio semelhante ao utilizado no cálculo experimental da conversão A/D, calcular qual o tempo necessário para executar o algoritmo redescoberto por “Danielson and Lanczos”. Estimando assim o tempo total levado pelo Arduino a adquirir e a aplicar a função de cálculo da FFT. Os tempos de cálculo obtidos, utilizando o Arduino Duemilinove com ATMega168, foram os seguintes: A taxa de amostragem que se consegue obter tem influência directa, segundo o teorema de Nyquist, na frequência máxima do sinal de entrada que se consegue reconstruir sem perda de informação. Ou seja, se conseguirmos uma taxa de amostragem de 125KHz, a frequência máxima (sinal de entrada) que poderíamos reconstruir estaria situada nos 62.5KHz. Arduino e o Cálculo da FFT O algoritmo utilizado não foi “feito de raiz”, mas sim adaptado de um já existente. Tentando assim neste artigo, apenas encontrar e adaptar uma função existente na linguagem de programação C que permitisse efectuar o cálculo da FFT. A adaptação consistiu em alterar certas instruções utilizadas pelo algoritmo original, que recorria a bibliotecas próprias da linguagem C, para instruções equivalentes (que permitissem obter o mesmo resultado) existentes actualmente nas bibliotecas disponíveis para o Arduino. A principal dificuldade prendeu-se com a utilização, por parte dos algoritmos existentes em C, de bibliotecas não existentes no ambiente de desenvolvimento do Arduino. Tornando a adaptação de certos algoritmos encontrados uma tarefa mo- Tabela 5 – Tempo total despendido (Cálculo FFT+ADC) 16 A PROGRAMAR ARDUINO E O CÁLCULO DA FFT Os valores obtidos na coluna 4 (Cálculo da FFT) da Tabela 5 foram obtidos efectuando a média de 1000 valores obtidos experimentalmente (Recolha e cálculo da média efectuado recorrendo ao Software MatLab). O algoritmo utilizado no cálculo da FFT foi aplicado variando o número de pontos a calcular, mas utilizando o mesmo array f[i] para todos os testes efectuados. (Todos os pontos a calcular foram considerados como sendo 1+j). A Tabela 6 apenas serve como indicação da gama de valores de tempo (em µs ) de execução, necessários para converter o número de pontos indicado na coluna 2 de analógico para digital (por cada entrada analógica) e aplicar o respectivo algoritmo de cálculo da FFT. É de salientar que o valor obtido para o cálculo final (coluna 3 da Tabela 6) utilizando um factor de divisão de 2 e adquirindo 64 pontos (de cada entrada analógica) corresponde apenas a ≅ 0.13s. A coluna 3 corresponde ao produto do tempo de conversão obtido na Tabela 3 pelo número de pontos a serem adquiridos, obtendo assim uma estimativa para o tempo de conversão A/D necessário em cada caso. Conclusões No modelo testado (Arduino Duemilinove com ATmega168), e numa situação ideal, existiria a possibilidade de efectuar o armazenamento em SRAM de cerca de 128 pontos distintos. O que não se pode comparar quase aos 1000 pontos que se conseguiriam armazenar utilizando o Arduino Mega com ATmega1280. O que nos leva a considerar, e se quisermos continuar a apostar no cálculo da FFT recorrendo directamente ao Arduino (e não ao processamento recorrendo a computador), a considerar a sua aquisição (custo de aquisi- O algoritmo utilizado poderá ser melhorado e a sua execução poderá ser optimizada, porém esse não será factor mais importante mas sim a velocidade com que se efectua a amostragem do sinal de entrada. A coluna 5 (Tempo total) corresponde à soma do tempo necessário para efectuar a conversão A/D dos pontos referidos na coluna 2 (Número de pontos utilizados) com o tempo necessário para aplicar o algoritmo de cálculo da FFT a esses pontos. Se considerarmos que temos seis entradas analógicas, os tempos totais necessários serão o produto dos valores obtidos na coluna 5 por um factor de 6. Resultando os seguintes valores finais: ção ≅45€ por unidade). Recorrendo ao uso do Arduino Mega teríamos a possibilidade de efectuar a aquisição e o cálculo da FFT para 512 pontos. Este valor surge pois 2 11 corresponde a um valor de 2048, ou seja, 1024 números do tipo “a + jb” o que excede a capacidade máxima de armazenamento disponível. A solução é considerar a potência de dois imediatamente abaixo 210 que corresponde a um valor de 1024, ou seja, a 512 pontos do tipo “a+jb”. Como se sabe, o que irá definir se o desempenho obtido é suficiente será o destino para o qual o nosso sistema é desenvolvido. Em caso de necessidade de maiores capacidades de processamento, não se deve descartar a hipótese do cálculo da FFT recorrendo ao uso de p.ex. um computador (e uso do Arduino apenas como datalogger). Caso se queira melhorar o desempenho do Arduino no cálculo da FFT, será sem dúvida um bom desafio pois “O saber não ocupa espaço de memória”. Bibliografia Chu, E. (2008). Discrete AND Continuous Fourier Transform. Boca Raton, USA, A CHAPMAN & HALL BOOK. Press, W. H., S. A. Teukolsky, et al. (1992). Numerical Recipes in C. Melborne, Australia, Cambridge University Press. Tabela 6 – Tempo total despendido para 6 entradas AUTOR Escrito por Nuno Pessanha Santos Mestrado em Engenharia Naval ramo de Armas e Electrónica pela Escola Naval. É um apaixonado pela área da electrónica e das telecomunicações. 17