Conversão A/D e transmissão Serial com Arduino DUE

Olá pessoal, estou usando esse código, mas ele está causando uma descontinuidade no fim da aquisição de 1000 pontos. Tenho certeza que essa descontinuidade é causada pelo tempo de transferência serial.

Como eu posso corrigir isso, para obter uma transmissão contínua sem perda de pontos ao final de cada aquisição de 1000 pontos?

Segue o código em anexo.

Att.

Exibições: 671

Anexos

Responder esta

Respostas a este tópico

Olá Elcid, segue a tela do meu programa onde leio o sinal, estou usando o labview para ler serialmente. Dá para notar no inicio do gráfico a descontinuidade. Dei mais uma organizada no meu código, mas ainda continuo com o problema. coloquei o código em anexo. Att.

Anexos

olá Thiago.

      Fiz medições usando seu código, e pude confirmar na prática o que eu havia deduzido pela avaliação das LIBs do Due.

      De fato o problema é por causa do Queue da Serial, que fica "entupido" por um bom período, o que acaba causando descontinuidade na aquisição.

      Mas independente disso, conforme te expliquei no chat aqui no LDG,  mesmo que vc aumentasse em 10x a velocidade da Serial, ainda assim iria ocorrer descontinuidade (por motivos técnicos que não descrevo agora aqui porque demoraria muito e consumira uma boa quantidade de texto).

      Então para tratar isso, é preciso usar outras técnicas.  Mas como vc está usando o MathLab,  isso já ajuda bastante, pois há algumas possibilidades adicionais (uma delas por exemplo, é enviar os dados na forma de "binário puro", ao invés de enviar strings ASCII  como está sendo feito no seu código atual).

      Lá pelo contato via Skype, te auxiliarei de forma mais eficiente, e então depois podemos postar os resultados aqui.

      Sobre o gráfico que vc postou,  é exatamente como eu tinha imaginado. Quando fizemos o cálculo do número de ciclos visualizados para uma senóide de 40kHz, eu considerei que o loop de aquisição não demorava mais que 1us em cada passagem, pois o ADC do Due tem taxa de 1MHz e considerei que o Compilador C++ gerou um código bem otimizado.  Porém ao fazer as medições,  revelou-se que está demorando 1.5us, o que significa que o código gerado pelo Compilador C++ não está tão otimizado (já que a taxa do ADC ainda é 1MHz e a conversão AD está programada para ser automática, e isto ocorre em paralelo com a execução do código).  Como são 1000 amostras, então cada ciclo completo de aquisição demora 1,5 ms, e você terá um pouco mais de ciclos da senóide que o valor que calculamos inicialmente (neste caso o número de ciclos será 60 = 1.5ms * 40KHz).

      A posição da descontinuidade no gráfico é aleatória, uma vez que o tempo de transmissão dos caracteres via Serial irá variar (mas em média são aqueles 6000 caracteres conforme demonstrei anteriormente), resultando em "gaps" de duração ligeiramente flutuantes. E também devido ao "desincronismo" entre aquisição e exibição.

      Bem, agora é preciso aplicar as técnicas adequadas para tratar isso. Mas uma delas me ocorreu de repente,  e ao consultar a documentação do Due vi que era uma possibilidade.  É sobre usar o "Native USB" do Due (que é USB "HiSpeed",  ou seja 480Mbps), ou seja, é uma Serial efetivamente Virtual  em ambas as extremidades (Due e PC).  Mas aí dependerá também do código executado no PC ter buferizações e temporizações adequadas).  Assim que possível te explico melhor.

      Importante:  eu já tinha olhado inúmeras vezes as LIBs da implementação Serial no Arduino. Mas nunca me atentei para analisar com mais cuidado a questão do "entupimento" do Queue do TX (porque eu quase sempre tomo os cuidados para evitar isso no código).  Mas agora depois de ter visto o comportamento no Due, fiquei curioso sobre se a implementação da LIB Serial no AVR (UNO, Mega, Nano, etc) teria o mesmo comportamento.  Então fui olhar isto. E advinha:  na implementação para o AVR  ocorre o mesmo comportamento. Isto significa que quando enviamos uma "tonelada" de dados via Serial  causando o "entupimento" do TX,  nenhum dado deixará de ser transmitido,  mas também por consequência a função de envio (print, println, write, etc) "trava" o processamento aguardando que o Queue do TX  fique pelo menos um byte livre, mas efetivamente o processamento do código acabará ficando "travado" dentro das funções de envio até que todos os bytes tenham sido transmitidos.  Então é aconselhável ter ciência disto.  Para o ESP32  eu não analisei, mas lá também são "dois cores", o que pode significar que esta "limitação" talvez  não ocorra.

      Abrçs,

      Elcids

Olá Elcids, vc descreveu perfeitamente o que está acontecendo.

Estou tentando entender mais sobre o funcionamento do comando Serial.write(), desta forma poderia enviar minhas amostras como bits conforme vc mencionou.

Há alguma forma de eu aumentar o BUFFER do Tx, talvez isso poderia desafogar um pouquinho. 

Essa porta NATIVE USB do DUE poderia ser a salvação mesmo pois a transmissão USB é muito rápida. Eu teria que estudar como poderia ler essas amostras pelo LabView via USB.

Sobre outros microcontroladores, o que vc acha do Teensy 3.2, será que com ele ficaria mais fácil a fluidez da transmissão?

Att. 

olá Thiago.

      Sobre a implementação usando o "Native USB" do Due, é algo até simples de fazer. Mas tem alguns detalhes técnicos como a questão do "Endian", que deve estar de acordo com quem recebe os dados (no seu caso, o LabView, executando provavelmente em x86, e neste caso usando "little endian"). Mas em suma é tranquilo.

      Sobre a questão de aumentar o Buffer do TX, não perca tempo com isso, pois não irá adiantar. A questão mesmo é reduzir o tempo de envio do Pack de Dados, e então casar o Ciclo de Amostragem  conforme esse tempo. Isso também é algo simples, mas não dá pra explicar por texto aqui neste post, pois demoraria um tanto. Então irei te explicar sobre isso via Skype e depois postamos resultados e conclusões.

      Como eu disse anteriormente, neste momento acho que vc deve continuar com o Due, pois ele tem condições de fazer isso,  se for usada a técnica adequada. E o problema nem é tanto a performance da CPU, mas sim o tempo de transmissão dos dados. O Teensy 3.2  é mais rápido que o Due,  mas essa velocidade adicional não  terá impacto na velocidade de transmissão dos dados.

      Sobre usar o "Native USB" do Due, encontrei um post no fórum do "arduino.cc",  onde algumas pessoas fizeram isso,  e postaram código e algumas dicas importantes sobre como implementar isso, e que podem ajudar muito (inclusive tem gente lá que também usou o LabView).  Dê uma olhada pois ajudará no processo. É esse aqui:   "DUE Native USB communication"

      Abrçs,

      Elcids

Olá Elcids, tive alguns avanços na transmissão USB do Arduino DUE para o LabView. Adaptei o programa de transmissão USB daquele link que vc me enviou, para o meu programa. Consegui realizar a transmissão para o LabView via USB, mas encontrei as seguintes respostas. Apliquei senóides no conversor AD com frequências de 1kHz, 1.6kHz, 1.7kHz e 5kHz. Notei que ainda há descontinuidades em intervalos aparentemente constantes, mas para a frequência de 1.7kHz a senóide se encaixou perfeitamente e consigo vê-la perfeitamente no gráfico. Quando vou variando a frequência parece que há um desencaixe e a descontinuidade aparece novamente. Acho que o problema agora não é devido a "lentidão" da transmissão. Estou colocando meu código em anexo, acho que deva ser alguma configuração errada que eu esteja fazendo. Em seguida segue as imagens dos gráficos das senóides que aquisitei de  1.6k e 1.7k  respectivamente:

Anexos

olá novamente Thiago.

      Legal que o link te ajudou a ir um pouco mais à frente, permitindo vc receber no LabView  os valores já em "binário puro".  Fique atento à questão do "Endian",  pois se vc usar um outro Computador não baseado em x86,  poderá ter problemas (o código no Due está enviando dados em "little endian",  mas caso precise mudar para "big endian",  isto é simples e requer apenas uma única linha a mais no código).

      Sobre a questão da continuidade na visualização do Sinal,  o que está ocorrendo é bastante claro:  são aqueles motivos que te expliquei no chat do LDG.  E quando vc "forçou" a frequência do Sinal (que no caso vc relatou sendo 1.7 kHz),  vc fez coincidir o período do Sinal  com o período  do ciclo da atual Taxa de Amostragem do seu Sistema (que na verdade não estava "imposta", mas sim "correndo livre").  Isto não é adequado e nem bom, porque vc está dependente do próprio sinal pra garantir a continuidade.

      Veja o que vc precisa fazer:  deve determinar qual a frequência máxima de sinal  vc deseja visualizar no LabView, com uma certa "qualidade" na visualização.  Então deve escolher um tamanho do "Pack de Amostras consecutivas" adequado. Para isso, deve determinar o tempo  que o "Native USB" gasta para enviar esse Pack,  e esse tempo deve estar de acordo com o total de amostras dentro de um único ciclo do Sinal na máxima frequência que vc determinou no início. Sei que pode parecer confuso, mas leia com atenção o que acabei de escrever e vc irá entender. Mas de fato, isto não é tão fácil de explicar aqui em poucas linhas de texto.

      Eu preparei um código que faz o "básico" do que descrevi acima. Vc pode usá-lo para testar com o LabView, exatamente como fez com o seu último código para o "Native USB". Então, analisando o comportamento e a forma como isso funciona, vc pode expandir a coisa de forma a conseguir resultados melhores e que te atendam.

      Veja:  para isto dar certo do jeito que está implementado neste código,  é preciso que o Mecanismo de recepção dos Packs no lado do Computador (ou seja, no lado do Labview) esteja eficiente e consiga receber e processar as amostras rápido o bastante. Se isso estiver ok,  vc verá sinais contínuos na tela gráfica do LabView.  Claro há um limite na frequência do Sinal, e isso depende da "qualidade" que vc quer ver na tela (uma vez que atualmente vc está plotando as amostras brutas, sem aplicar  Processamento de Sinal).  Em um cálculo bruto,  eu acredito que sinais de até uns 4 kHz poderão ser observados com relativa "qualidade", usando o código que preparei.

      É este código:   "ADC_DUE_Native_USB_02.zip" 

      Um detalhe importante:  no seu código vc estava usando a quantidade errada para o tamanho de um Pack enviado via "Native USB".  Lá vc enviou "512" bytes, e este é mais um motivo para descontinuidade, porque vc estava aquisitando 2000 bytes, ou seja, 1000 amostras contínuas.  Mas vc estava enviando apenas as primeiras 256 amostras (512 bytes) do seu Pack aquisitado. Claro, corrigir isso não irá resolver o problema da descontinuidade,  mas de fato  vc  estava  enviando  Packs incompletos e  isso já provoca uma descontinuidade "forçada".

      Por favor, leia com atenção todo o texto, e também os comentários no próprio código, pois irão ajudar. E mantenha seu código organizado, evitando algumas vícios que não são considerados "boa prática de programação" (eu encontrei alguns no seu código).

      Abrçs,

      Elcids

Olá Elcids, obrigado por toda a ajuda. Desculpe pela demora em responder. Já tive mais avanços com sua ajuda.

Eu desejo, inicialmente, ler sinais no LabView com uma banda de 0 à 1000Hz. Então pelo teorema de Nyquist, preciso ter pelo menos 2k Sa/s de frequência de amostragem. Gostaria de futuramente utilizar algoritmos para processamento do sinal aquisitado, como medir amplitude, frequência, Trigger e realizar uma FFT (tentando ver o Spectrum em tempo real se possível).

Comecei a fazer os testes com o algoritmo que você me enviou. Vi que o separa em funções, realmente fica muito mais “organizado”.

Inicialmente comecei ajustando o PACK DE AMOSTRAS e o TEMPO DE AMOSTRAGEM, tentando chegar na melhor combinação possível para obter um sinal com uma resolução aceitável e com continuidade para todo o sinal analógico de entrada.

Meu sinal analógico de entrada corresponde de uma senóide, em que vario de 10Hz à 1k Hz.

A melhor combinação que consegui buscando estes parâmetros foi para:

PACK DE AMOSTRAS: 200

TEMPO DE AMOSTRAGEM (us): 100

Como resposta obtive uma continuidade perfeita e uma boa resolução, mas somente para frequências até 200 Hz. Acima de 200 Hz começa haver a descontinuidade do sinal e perda de resolução. Pela teoria, considerando todo o sistema perfeito, teria uma frequência de amostragem de 2M SAMPLES por segundo. Descontando a performance do sistema esperava uma faixa de frequência mais alta.

Tentei deixar meu algoritmo no Labview está o mais enxuto possível, e algo que não estou entendendo direito é que ele lê sempre metade do PACK DE AMOSTRAS do Arduino, neste caso 100. Mesmo assim esperava leituras de frequências mais altas. O que poderia está acontecendo Elcids?

Att.

O Arduino DUE é capaz de fazer muito melhor que 200Hz....

Dá uma olhada neste link de um programa que lê a porta analógica e calcula FFT :

https://github.com/dujianyi/ardFFT

Minha sugestão (dada a situação atual) é vc implementar o conceito de trigger na amostragem. Faça "packs" em torno do trigger, e envie os "packs".

Neste caso, o circuito pode deixar de fazer amostras enquanto envia o "pack" porque o sinal estará sincronizado no envio do próximo pack pelo trigger. As "perdas" (não amostragem) não irão prejudicar a visualização se a entrada for senóide periódica. Haverá momentos do sinal que não serão registrados, então vc precisa avaliar esta ideia baseado nas suas necessidades.

Sugiro vídeos no YouTube para entender o que é um trigger.

Boa tarde Thiago, 

Não li todos os posts, mas parece que você pretende fazer um osciloscópio com o Arduino Due, correto?

"Eu desejo, inicialmente, ler sinais no LabView com uma banda de 0 à 1000Hz. Então pelo teorema de Nyquist, preciso ter pelo menos 2k Sa/s de frequência de amostragem." 

Incorreto! A frequência mínima do teorema de Nyquist serve somente se você for medir frequencia. Não serve para amostragem de um osciloscópio

Se você quer entender mais sobre frequência de amostragem, sugiro a leitura desses artigos da Analog Devices:

Fundamentals of Sampled Data Systems

What the Nyquist Criterion Means to Your Sampled Data System Design

Na realidade se você quer medir um sinal com frequencia máxima de 1000 Hz, precisará de uma frequência de amostragem de 10 a 20 vezes essa frequência, isto é 10 Ksps ou 20Ksps. (kilo samples per second). 

RSS

© 2024   Criado por Marcelo Rodrigues.   Ativado por

Badges  |  Relatar um incidente  |  Termos de serviço