Algoritmos DSP com a STM32F4Discovery - Parte III

STM32F4Discovery
Este post faz parte da série Algoritmos DSP com a placa STM32F4Discovery. Leia também os outros posts da série:

Boas caros leitores, nos artigos anteriores apresentamtos a placa STM32F4Discovery e demos inicio a série tomando como primeiro assunto filtragem digital usando algoritmos simples, baseados nos algoritmos de média móvel e média móvel exponencial. Apesar dos filtros apresentados cobrirem uma gama grande de aplicações, eles possuem limitações já citadas nos artigos anteriores. Filtros digitais são um assunto amplo, podendo ganhar uma ordem de complexidade a nível de discussões entre doutores em processamento de sinais. Porém existem casos em que o leitor precisa de filtro digital simples, mas com alguns parâmetros conhecidos e bem definidos, como, por exemplo, quando o desejo é separar um sinal de áudio em várias componentes, para efetuar um processamento de equalização digital, precisa-se de filtros passa-faixas com frequências de corte bem determinadas.  É quando se faz necessário o uso de um filtro IIR ou FIR com coeficientes devidamente calculados para prover tal frequência de corte de atenuação. Relembrando a seguir temos as equações para filtros FIR e IIR:

 

Equação 1 : Filtro FIR

 

 

 

Equação 2 : Filtro IIR

 

 

Observando as equações 1 e 2, como ja explicado em artigos anteriores, a grande diferença entre filtros FIR e IIR, além da teoria em que filtros IIR podem responder a impulsos de múltiplas fontes (daí seu nome de filtro de resposta infinita), é que no primeiro filtro os valores computados de saída, dependem apenas dos valores corrente e "m - 1" valores anteriores computados, ou seja é um filtro sem recursão. No caso do segundo tipo de filtro, o IIR, além da saída depender da mesma ordem de valores de entrada, também são necessários calcular "m - 2" valores de amostras de saída anteriormente calculadas. Assim temos um elemento recursivo nesse segundo filtro. Suas estruturas trazem suas vantagens e alguns pontos que precisam de melhorias (ou projetos mais sofisticados), mas podemos resumir as vantagens e pontos de melhoria das duas estruturas básicas de filtragem:

 

Vantagens do filtro FIR:

  • Inerentemente estável, sob qualquer condição (função de transferência não possui pólos);
  • Coeficientes podem ser calculados usando a transformada de Fourier;
  • Fácil implementação.

 

Desvantagens do filtro FIR:

  • Filtros com resposta agressiva e precisam de muitos coeficientes;
  • Grande esforço computacional, uso de memória pouco eficiente;
  • Para cálculo em ponto fixo, exige um acumulador com uma largura de dados grande.

 

Vantagens dos filtros IIR:

  • Eficiente no uso de memória;
  • Precisa geralmente de muito menos coeficientes para uma resposta similar a um filtro FIR;
  • Pode ser modelado a partir de filtros analógicos cuja função de transferência é conhecida.

 

Desvantagens do filtro IIR:

  • Dependendo da estrutura basica adotada, a implementação é mais trabalhosa se comparado a um filtro FIR;
  • É marginalmente estável, ou seja, a sua estabilidade ocorre sob determinadas condições (possui pólos na função de transferência).

 

No artigo anterior, exploramos dois dos respectivos filtros, o média móvel e o média móvel exponencial, onde nesse ultimo tivemos resultados interessantes além de uma flexibilidade maior de projeto. Os filtros apresentados anteriormente são indicados a um bom número de aplicações onde o interesse maior fica por conta de suprimir ruídos de alta frequência que contaminam a banda do sinal adquirido, em sistemas embarcados irão existir aplicações onde um determinado filtro digital, com parâmetros além da frequência de corte, devem bem definidos, assim os coeficientes "h" ou "a/b" deverão ser calculados para que tal bloco cumpra esses requerimentos.

 

Eis então que somos confrontados com a dúvida de como calcular esses coeficientes. Para filtros FIR, pode-se utilizar métodos baseados na série de Fourier em conjunto com uma técnica chamada janelamento onde, a partir do sinal amostrado, analisa-se uma área de interesse desse e decompõe-se usando a série de Fourier, de forma que os coeficientes para as frequências indesejadas sejam impostos em nulo. Essa técnica básica é conhecida por janelamento retangular. Além dessa, existem diversas formas de janelamento que podem ser buscados nas referências.

 

Para filtros IIR, o método é um pouco mais intuitivo e prático, de forma que podemos partir de um modelo matemático discreto, e gerar diretamente a função de transferência, ou como já citado anteriormente, usando  o protótipo de algum modelo analógico e mapeando seus pólos e zeros para uma função de transferência digital, usando transformadas. Dentre aas utilizadas, uma bem conhecida chamada de transformada bilinear ou método de Tustin, essa simpática expressão mostrada na equação 3, e ja usada aqui no Embarcados na série PID digital. Para refrescar:

bilinear
Equação 3 : Transformada bilinear

  

 

 

 

Como se usa? É bem intuitivo, como o leitor mais detalhista reparou. Basta tomar o prototipo analógico e substituir o operador "s" da função de transferência, pela equivalência contendo operadores "z" e simplificar a expressão ao máximo possível. Nesse ponto ter-se-á uma ótima aproximação (a transformada bilinear é uma aproximação de segunda ordem, mas que pode ser expandida para ordem superiores, vide em [2]) do modelo de circuito analógico. Para quem leu a parte II da série PID digital, viu que mesmo uma função simples de segunda ordem, pode dar um trabalho jogando sinal pra lá, pra cá, além do fator erro humano (esse que vos escreve particularmente adora errar um sinal na primeira vez que resolve alguma conta no papel).

 

Ferramentas auxiliares para projeto de filtros

 

Se na sessão anterior ficamos apenas limitados a transformadas e receitas nada práticas para o projeto de um simples filtro digital, daqui em diante iremos usufruir de ferramentas de cálculo que foram desenvolvidas para auxiliar o projetista na hora de prover pelo menos um modelo matemático para projeto de filtros. Podemos citar logo de inicio uma ferramenta de cálculo numérico muito conhecida pelos leitores, principalmente de sua época de graduação. O Matlab da Mathworks é uma das ferramentas de cálculo computacional mais completas disponíveis, possui um sem número de ferramentas para projeto de sistemas, incluindo blocos para DSP podendo prover o modelo em diversas formas (função de transferência, funções complexas, modelos baseados em estados de espaço), além de oferecer em conjunto com o plugin embedded coder a possibilidade de gerar um projeto completo para download e avaliação num microcontrolador. Seriam apenas maravilhas para falar dessa ferramenta, se não fosse tão cara ou se pelo menos existisse uma versão sem custo para para comunidade ou estudantes. Ainda falando de ferramentas proprietárias, temos o LabView provido pela National Instruments. O grande diferencial aqui (além dos vários blocos para projetos de sistemas) é o fato de ser uma ferramenta gráfica simples de se programar, além disso o usuário que tiver um dos sem números de placas de aquisição pode testar os exemplos na hora rodando em tempo real. Em contrapartida essa também é uma ferramenta paga como já citado, e ainda tem o fator que a licença estudantil tem muito pouco a oferecer baseado em blocos para cálculo computacional. Nas andanças desse que vos escreve (mesmo possuindo uma licença do Matlab), deparei-me com um interessante projeto, que é o SciLab, essa ferramenta, apesar de não oferecer tantos blocos como o Matlab e tampouco ser gráfica como um LabView, possui um bom equilibrio com blocos de cálculo computacional, além de sintaxe quase totalmente compatível com seu colega pago, porém tudo isso de graça. Nos exemplos desenvolvidos usando as ferramentas como veremos em seguida, o filtro gerado pelo Scilab, não deve em nada para o gerado pelo Matlab em termos de desempenho.

 

Está fora do escopo dessa série, um tutorial sobre o uso dessas ferramentas, o propósito é demonstrar sua utilidade na hora de facilitar a vida do projetista, então vamos nos limitar a apenas fornecer os scripts utilizados para simular o projeto de nosso filtro de teste.

 

A aplicação

 

Para a aplicação dessa parte da série, iremos projetar um simpático, porém bem definido, filtro IIR do tipo passa-baixas. Optou-se pelo IIR justamente por partir do principio que, se ele for compreendido, uma estrutura desse tipo é análoga de se projetar. Para nosso código exemplo, vamos construir um simples filtro passa baixas digital do tipo butterworth de segunda ordem, onde o mesmo irá dar conta de processar em tempo real um sinal senoidal que será capturado pelo conversor A/D do microcontrolador, e será colocado na saída usando o conversor D/A. Assim, utilizaremos a mesma base de código anterior já desenvolvida. O objetivo também é demonstrar a capacidade de DSP em tempo real do micro colocado na discovery, no qual filtramos amostra a amostra, sem buffer e para o leitor mais atento, sim, a estrutura IIR usada nesse exemplo pode ser usada para construir um PID usando o algoritmo "2p2z" apenas ajustando os coeficientes.

 

Nosso filtro IIR então:

  • Passa-baixas;
  • Segunda ordem;
  • Frequência de corte 1000Hz ( amostragem a 10000Hz);
  • Ripple na região de stopband de 1dB.

 

O primeiro passo para isso, é fazer a instalação do Scilab (é multiplataforma) e abrir uma novo documento no scinotes, o usuário nesse momento deverá ter a seguinte tela:

 

Figura 1 : Tela do scinotes

 

 

Sim, um editor de programação, o Scilab possui uma sintaxe própria de forma similar ao Matlab. Nesse ponto iremos primeiro simular o nosso filtro. Para isso, leitor, coloque o script abaixo no editor, salve e execute:

 

//  Script para teste de uso de filtros digitais
//
//  Autor: FSN
//
//


//Parametros de amostragem:
fs = 10000;  //frequencia de amostragem
ts = 1/fs ;  //tempo de amostragem


//Parametros do filtro:
fcut = 1000; //frequencia de corte (Hz)


//cria um filtro digital passa baixas:
tf = iir(4, 'lp', 'butt' ,[(fcut/fs) 0], [0.1 0.1])

//Cria resposta em frequencia:
[frq, rep] = repfreq(tf, 0:0.001:0.25);
[db,phi] = dbphi(rep);

//Prepara pra plotar:
clf();
xtitle('Resposta em frequencia');
plot2d(fs * frq, db);


 

Sobre o trecho do script não há muito o que dizer, apenas devemos notar o respeito ao teorema de Nyquist ao projetar o filtro, o primeiro passo é selecionar a frequência de amostragem, na variável "fs". A partir desse valor iremos normalizar a frequência de corte do nosso filtro dentro de um valor situado entre 0 e metade da frequência de amostragem, assim o valor normalizado da frequência de corte será 1000Hz, dividido pela frequência de amostragem 10000Hz, ou seja, 0.1 . Ao executar esse script teremos o plot da resposta em frequência do filtro.

 

Figura 2 : Plotagem da resposta em frequência do filtro desejado

 

 

Fizemos o script, foi simulado, verificamos a resposta esperada, mas...e quando colocamos isso no processador? Bem, o script tem por primeira função checar se os parametros escolhidos ofereceram o desempenho desejado. O Scilab fornece como ja dito anteriormente diversas formas de saída ao chamar uma função para projeto de filtros, no nosso caso o tipo de saída mais interessante está em receber a função de transferência do filtro. Para tal selecione a linha 18 do script e volte ao console do scilab, cole essa linha e substitua "fcut" e "fs" pelos seus valores numéricos, e tecle enter, o console irá prover os coeficientes da função de transferência, conforme a imagem abaixo:

 

Figura 3 : Console do Scilab

 

 

Agora temos a função de transferência, mas ainda não podemos colocar isso em um processador. Até agora usamos poucos cálculos, num processo bem intuitivo, mas não vai ter jeito, vamos precisar fazer umas continhas para tomar a transformada inversa z, obtendo assim a equação de diferenças. Vamos ilustrar o processo com algumas passagens simples. 

 

Equação 4 : Função de transferência gerada pelo Scilab

 

 

Ao novo leitor da série, gosto sempre de lembrar para não se assustar com a expressão a primeira vista, e que o termo "z" da função de transferência vai assustar ainda menos se o tratarmos como operador de deslocamento de amostras num sistema discreto e não como uma incógnita (afinal em grande parte dos casos não se resolver uma função de transferência desse tipo para "z"). Então, sabendo desses dois "conselhos", vamos começar a trabalhar nossa função de transferência. Em primeiro lugar em um sistema digital é muito mais fácil trabalhar com amostras memorizadas (passadas) do que prever valores futuros das próximas amostras, sejam de entrada ou saída. Logo se o operador "z" representa o deslocamento de amosras no tempo de acordo com o sinal do expoente, então podemos modificar a equação 4 para ela trabalhar com amostras passadas ou com a corrente, logo temos:

 

Equação 5 : Função de transferência modificada

 

 

E agora, vamos colocar em função do sinal de saída:

 

Equação 6 : Filtro em função do sinal de saída

 

 

 

A última passagem feita, sem denominadores, está ideal para tomar a transformada inversa Z. Assim vamos obter a equação de diferenças final. Uma amostra de saída é calculada como:

 

IIR_tf_final
Equação 7 : Equação de diferenças IIR final

 

 

Ufa! Nada muito difícil, porém um pouquinho trabalhoso de fazer no editor de equações. Mas num rascunho ou mesmo de forma intuitiva a medida que se pega prática de fazer. Sim, a última linha é tudo que precisamos para implementar o filtro digital que tem a resposta simulada na figura 2, e sim caro leitor, não é coicidência, mas a equação 7 é exatamente a mesma equação 2 so que para um filtro IIR genérico. Repare que poderíamos reordenar os termos e escrever em forma de somatórios para provar isso, mas vou deixar essa tarefa por conta do leitor mais desconfiado. Agora pergunto: essa expressão pode ser embarcada no código de um microcontrolador? Sim! A resposta é tão óbvia quanto a pergunta.

 

No projeto hospedado no github o usuário terá acesso ao código fonte feito especialmente para implementação de filtros. Em termos de implementação de filtros IIR, existem alguns métodos já consolidados, como os Direct Form I e II, ilustrados nas figuras 4.

 

Figura 4 : IIR direct form I

 

 

No direct form I, o que temos é basicamente a operação da equação 2, onde a amostra de entrada denotada por "x" é multiplicada pelo seu coeficiente, bem como as amostras de entrada atrasadas por 1 e 2 periodos de amostragem respectivamente. O mesmo é feito com as amostras de saída atrasadas. Elas são multiplicadas pelos seus coeficientes e em seguida todos esses resultados são combinados em uma única soma algébrica. Por fim, a amostra de saída desejada é escalada e aparece na saída (denotada por "y") e o ciclo se completa, atualizado todas as amostras envolvidas no processo por 1 ciclo, onde a amostra mais antiga em todos eles é descartada.

 

Figura 5 : IIR firect form II

 

 

No algoritmo direct form II (também chamado de biquad) as linhas de atraso e os coeficientes foram ordenados. A grande vantagem desse tipo de implementação é a economia de memória, uma vez que precisamos de apenas uma linha de atraso para preservar as amostras anteriores, ante a duas da forma anterior. Nessa implementação a amostra de entrada é imediatamente somada com o resultado das amostras anteriores multiplicados por um do set de coeficientes do filtro. Em seguida, esse estagio intermediário é somado com o a mesma linha de atraso, só que agora multiplicada pelo segundo set de coeficientes, sendo escalado e colocado na saída. Vale reparar que o que é colocado na linha de atraso não são amostras anteriores de entrada ou saída mas sim os estados dos estágios intermediários.

 

Em nossa aplicação vamos optar pela implementação usando o direct form I. Se por um lado temos um uso maior de memória, por outro lado ganhamos na simplicidade de implementação e do fato do filtro possuir um ganho unitário, caracteristica não existente nos biquads, em que o sinal de saída recebe um segundo ganho vindo da própria implementação do filtro. Esse efeito, entretanto, pode ser bem desejável em implementações ponto flutuante o que não é nosso caso. Na pasta filtros, temos os arquivos embarcados IIR.c e .h contendo as definições e implementação do filtro. O código foi comentado afim de possibilitar expansões por parte do usuário. As linhas de atraso, diferentes do filtros de média móvel, foram construídas em cima de buffers circulares, ante ao método de atualização de histórico, tornando o filtro bem mais eficiente em termos de velocidade. O comprimento desses buffers deve ser preferencialmente potência de 2, pois apesar do núcleo ARM Cortex M4/M4F possuir um set básico de instruções DSP, ele peca por não possuir uma unidade geradora de endereços AGU, assim um buffer circular nessa arquitetura se mostra pouco eficiente de modo que, em alguns casos, ele fique ainda mais lento que o uso de atualização de histórico para operar a linha de atraso, com um uma potência de 2 isso é facilmente contornado, pois para apontar para fazer o incremento circular basta apenas adicionar a unidade ao ponto de leitura ou escrita seguida de uma operação e para mascarar todos os bits de ordem superior ao comprimento do buffer. Como apenas precisamos preservar três estados em nossa linha de atraso, optamos por um buffer de 4 posições. Os resultados foram bons! E por falar neles, vejam uma amostra do que obtive em bancada com a Discovery em operação:

 

Figura 5 : Sinal de 100Hz

 

 

Temos um sinal de 100Hz na entrada analógica da placa Discovery. Infelizmente o sinal de saída acaba contaminado pelo fato de estar sem o filtro anti-alias na entrada analógica. Observem a análise no domínio da frequência (a FFT abaixo) a atenuação é exatamente de 0 dB ou seja, estamos com ganho unitário.

 

Figura 6 : Sinal acima de 1000Hz

 

 

Aqui temos um sinal bem na frequência de corte de 1000Hz do filtro. Vejam que quase não temos sinal, e ainda na FFT tem-se uma atenuação inferior a -30dB, tal desvio do valor desejado pode ser explicado devida a quantização em ponto fixo de 16bits realizada com filtro, uma sugestão que deixo ao caro leitor que utilize a FPU do Cortex M4 para efetuar uma versão em ponto flutuante.

 

Conclusão

 

Mais uma vez espero que o certo misticismo que ronda a ciência de processamento digital de sinais, esteja sendo desfeita a você caro leitor. Vimos um pouco sobre como modelar um filtro IIR usando uma ferramenta inclusive open source, experiência que  pode ser levado para outros tipos de filtros. Ainda o Scilab por exemplo, oferece as mesmas ferramentas para fornecer a função de transferência de filtros passa-altas, passa-faixas e filtros passa-todas para deslocamento de fase. E para a próxima parte da série vamos entrar em novo assunto,  a transformada discreta de Fourier. Então é isso, até a próxima.

 

Referências

 

OPPENHEIM, Alan V. - Signals & Systems - 1983

OPPENHEIM, Alan V. - Digital Signal Processing - 1999

SMITH, Steven W. - The Scientist & Engineer's Guide to Digital Signal Processing - 1999

 

Materiais de apoio

 

Repositório no GitHub com código pronto para gravar na StmDiscovery 

 

Outros artigos da série

<< Algoritmos DSP com a placa STM32F4Discovery - Parte II
Este post faz da série Algoritmos DSP com a placa STM32F4Discovery. Leia também os outros posts da série:
NEWSLETTER

Receba os melhores conteúdos sobre sistemas eletrônicos embarcados, dicas, tutoriais e promoções.

Obrigado! Sua inscrição foi um sucesso.

Ops, algo deu errado. Por favor tente novamente.

Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.

Felipe Neves
Desenvolvedor de sistemas embarcados apaixonado pelo que faz, divide seu tempo entre trabalhar no Venturus desenvolvendo firmware de tudo quanto é coisa, na Aeolus Robotics se envolvendo com o que há de mais legal em robótica e na Overlay Tech desenvolvendo algumas coisas bem legais para o campo de motion control. Possui mestrado em engenharia elétrica pela Poli-USP e possui interesse em tópicos como: Software embarcado, sistemas de tempo real, controle, robótica móvel e manipuladores, Linux embedded e quase qualquer coisa por onde passe um elétron.

3
Deixe um comentário

avatar
 
2 Comment threads
1 Thread replies
1 Followers
 
Most reacted comment
Hottest comment thread
3 Comment authors
AlexandreFelipe NevesHaroldo Amaral Recent comment authors
  Notificações  
recentes antigos mais votados
Notificar
Alexandre
Visitante
Alexandre

Pq parou?? Parou pq?? Eu aqui como Barrichello lendo artigo de 2014 em 2017 e querendo saber porque não seguiu para a FFT :/ Me meti à besta ao propor um TCC de graduação envolvendo FFT em sinal de áudio rodando em microcontrolador e microfone digital (protocolo i2s) e claro... Acabei completamente perdido. É a vida... Sempre me propondo desafios maiores que minha corrente capacidade de resolve-los. Sei nada de bibliotecas. Já ví que existem algumas i2s no github mas não sei se são de comer ou passar no cabelo. Pensei que conseguiria usar um Arduino mas só alguns tem… Leia mais »

Haroldo Amaral
Visitante
Haroldo Amaral

Ótimo artigo Felipe Neves. Como tive processamento de sinais bem simples na faculdade, esta sendo bastante interessante. O trecho explicando como converter a função de transferência nos coeficientes ficou muito didática. Parabéns.

Você indicaria algum material ou site falando sobre o toolbox do Scilab para filtros digitais e a obtenção dos coeficientes?

Obrigado, abraço!

Felipe Neves
Visitante
Felipe Neves

Haroldo, obrigado pela leitura.

Que bom que ficou didático.

Respondendo a sua pergunta, o Scilab possui muita documentação interessante no próprio site do projeto, pro DSP toolbox, eu segui a didática de alguns artigos, incluindo esse do link:
http://www.academia.edu/4761013/SCILAB_Tutorial_for_DSP

Foi o que mais gostei pois cobriu bastante coisa sobre o scilab e XCos (o equivalente ao simulink).

Se tiver mais alguma coisa em que eu possa ajudar, fique a vontade.

Abs.

Felipe