Este artigo demonstra os passos necessários para a elaboração de um Filtro Digital IIR Passa-Faixa utilizando o Controlador Digital de Sinais dsPIC30F4013 com a DSP Library da Microchip.
Filtros Digitais do tipo FIR (Resposta ao Impulso Finita) e IIR (Resposta ao Impulso Infinita) são muito utilizados por DSPs (Processadores Digitais de Sinais) para a filtragem de sinais.
Semelhantes aos filtros analógicos, os filtros digitais podem ser classificados em 4 tipos quanto à frequência:
- Passa Baixa;
- Passa Alta;
- Passa Faixa;
- Rejeita Faixa.
Funções de Janela são utilizadas em Filtros Digitais FIR para reduzir oscilações. Podem ser:
- janela Retangular;
- janela de Hamming;
- janela de Blackman;
- janela de Kaiser.
Para resolver problemas de aproximação em Filtros Digitais IIR podemos utilizar:
- filtro Butterworth
- filtro Tschebyscheff
- filtro Tschebyscheff inverso
- filtro Elliptic
- filtro Bessel
A Figura 1 mostra os 3 passos para você criar seu Filtro Digital.
A Figura 1 mostra os 3 passos para você criar seu Filtro Digital.
Figura 1 - Passos para criar um Filtro Digital
Para este artigo, foi escolhido a construção de um Filtro Digital IIR Passa-Faixa do tipo Blutterworth.
Vamos a algumas considerações do nosso projeto.
Objetivo do circuito:
Filtrar um sinal entre 0 e 500 Hz e deixar "passar a faixa" de 60 à 180 Hz com 100 % da amplitude.
Especificações:
- de acordo com o Teorema de Nyquist, a frequência de amostragem do ADC será portanto 1000 Hz (1 ksps).
- o microcontrolador escolhido é o dsPIC30F4013, um Controlador Digital de Sinais (DSC) da Microchip, que possui as funções para o Filtro Digital IIR disponíveis na DSP Library. O DSC possui as funções de um microcontrolador e de um DSP. Possui capacidade de processamento de 30 MIPS @117 MHz.
- será utilizado um programa de Digital Filter Design para definir os parâmetros do filtro digital passa-faixa a fim de obter o sinal filtrado especificado. O software fornece os coeficientes necessários para o cálculo do filtro.
- os coeficientes são utilizados no código fonte C do DSC (dsPIC). O programa consiste basicamente em declarar as variáveis (estruturadas), inicializar os ponteiros e variáveis, iniciar a estrutura do filtro com IIRLatticeInit ( ) e executar o cálculo do filtro digital com IIRLattice ( ).
- os dados resultantes do cálculo do filtro digital IIR executado em 117 pontos amostrados periodicamente são mostrados em um display gráfico GLCD para se ter uma ideia do que é "visto" pelo DSC.
- para teste do nosso circuito um gerador de sinais (ou software no computador) aplica um sinal senoidal com amplitude constante e frequência de 0 à 500 Hz à entrada analógica do DSC que aplica o cálculo do filtro passa-faixa. O resultado é mostrado no display.
Definindo os parâmetros do Filtro Digital e gerando os coeficientes
No primeiro passo temos que definir alguns parâmetros para poder utilizar um software para gerar os coeficientes necessários para o cálculo do filtro digital pelo PIC.
A Figura 2 traz graficamente a representação de cada parâmetro do filtro:
- frequência de amostragem;
- passband;
- stopband;
- máximo ripple no passband;
- mínima atenuação do stopband.
Figura 2 - Especificação do FIltro Digital passa-faixa
No segundo passo utilizaremos o QEDesign, um Digital Filter Design Software, para modelar o nosso filtro digital com estes parâmetros e gerar os coeficientes para o programa do DSC.
No menu Design / IIR Design... iniciaremos o design para um Filtro Digital IIR.
A Figura 3 mostra a primeira tela de configuração. Selecionaremos:
- método para o design do filtro: transformação bilinear;
- método de realização do filtro: estrutura Lattice;
- tipo de filtro: bandpass.
No menu Design / IIR Design... iniciaremos o design para um Filtro Digital IIR.
A Figura 3 mostra a primeira tela de configuração. Selecionaremos:
- método para o design do filtro: transformação bilinear;
- método de realização do filtro: estrutura Lattice;
- tipo de filtro: bandpass.
Figura 3 - Design para o Filtro Digital IIR
Na segunda tela, Figura 4, preencheremos os parâmetros do filtro passa-faixa conforme ilustrado anteriormente na Figura 2.
Figura 4 - Configurando os parâmetros para o filtro passa-faixa.
Na terceira tela selecionaremos a 8ª ordem para o filtro Butterworth, conforme Figura 5.
Figura 5 - Seleção da ordem do filtro.
A Figura 6 mostra o resultado para a modelagem do nosso filtro digital IIR passa faixa de acordo com os parâmetros fornecidos.
Figura 6 - Resultado da Modelagem do Filtro Digital IIR.
O gráfico da Magnitude vs Frequência da resposta do filtro é visto na Figura 7. Note que de 60 à 180 Hz teremos 100 % do sinal de entrada na saída. Na medida que distanciamos da faixa do filtro o sinal de entrada será atenuado.
Figura 7 - Gráfico Magnitude vs Frequência da resposta do filtro.
Clicando no botão "Save C File" o software irá gerar um código fonte padrão na linguagem C para o filtro digital IIR construído, que pode ser visto na Figura 8. Com ele você pode construir seu filtro DIgital IIR em outro compilador C para computador ou outro modelo de microcontrolador.
O que nos interessa neste código são os valores dos coeficientes kappa e gamma, que iremos utilizar no programa do dsPIC.
O que nos interessa neste código são os valores dos coeficientes kappa e gamma, que iremos utilizar no programa do dsPIC.
/***************************************************************************
****************************************************************************
* File: C:\Arquivos de programas\MDS\Filter Design\codigo C.c
* Created by QEDesign
* C Code Generator
****************************************************************************
* Code Fragment to implement filter
*
* The functions defined in 'qed_filt.c' must be compiled and linked in.
* This can be accomplished by either #include "qed_filt.c"
* or by separately compiling and linking 'qed_filt.c'
*
*** following is actual code fragment
* extern LAT_filter LAT_codigo C;
*
* init_lat_dbl (&LAT_codigo C); // initialize filter structure
*
* LAT_codigo C.filter ( x, y, n, &LAT_codigo C); // x is an array of input samples
* // y is an array of output samples
* // n is number of samples to process
* // &LAT_codigo C is a pointer to the
* // filter structure
*****************************************************************************
* This is a complete program which can be compiled and run to test the filter.
* To change this to a subroutine only, just add in this program or add globally
* in "qed_cgen.h" the line with the definition of DEFINE_SUBROUTINE as follows
* #define DEFINE_SUBROUTINE
*****************************************************************************
****************************************************************************/
/* qed_cgen.h contains definitions of filter structures and function prototypes */
#include "qed_cgen.h"
/* filter functions are in files 'qed_filt.c' */
double codigo C_kappa[9] = {
-9.7948455815389446e-001, /* 0 */
9.7849500351160967e-001, /* 1 */
-8.6112175002729441e-001, /* 2 */
5.3530472709660060e-001, /* 3 */
-5.0440878979478099e-001, /* 4 */
3.9935338248048824e-001, /* 5 */
-1.2523348830583417e-001, /* 6 */
3.0071693969749614e-002, /* 7 */
0.0000000000000000e+000}; /* 8 */
double codigo C_gamma[9] = {
5.1559577576911972e-004, /* 0 */
1.4085406081475862e-002, /* 1 */
3.6377697302576006e-002, /* 2 */
-1.1820731695711806e-001, /* 3 */
-3.7374705510515338e-001, /* 4 */
-1.4384357653258961e-001, /* 5 */
1.7693240143750988e-001, /* 6 */
1.7571299176925376e-001, /* 7 */
4.6649062145300228e-002}; /* 8 */
double codigo C_f[9];
double codigo C_b[9];
double codigo C_gain = 1.0000000000000000e+000; /* initial gain */
LAT_filter LAT_codigo C = {
1, /* quantization: 0 off, 1 on */
1, /* quantization type */
/* 0 Floating point */
/* 1 Fixed point fractional */
8, /* lattice order */
&codigo C_gain, /* ptr to gain */
codigo C_kappa, /* ptr to kappa coefficients */
codigo C_gamma, /* ptr to gamma coefficients */
codigo C_f, /* ptr to forward function values */
codigo C_b, /* ptr to backward function values */
lat_dbl}; /* ptr to filter routine */
/* call the following function first and normally only once */
/* init_lat_dbl (&LAT_codigo C) */
/* where &LAT_codigo C is a pointer to the LAT_filter */
/* structure defining the filter */
/* call the following function to filter n samples */
/* LAT_codigo C.filter (pIn, pOut, int n, &LAT_codigo C); */
/* where pIn is a pointer to an array or buffer of samples to be filtered */
/* pOut is a pointer to the array of filtered samples output by the filter */
/* n is the number of samples to filter */
/* &LAT_codigo C is a pointer to the structure defining the filter */
#ifndef DEFINE_SUBROUTINE
/* The following main program can be used to test the filter. */
/* input is in file 'in' and the filtered samples are in file 'out' */
/* The input and output files are ascii floating point values */
/* e.g 1.0342 with 1 sample per line */
/* The input files can be created in DSPworks and exported as */
/* ascii floating point or any other system capable of creating */
/* ascii files with floating point values. */
/* The filtered output file can be imported into DSPworks as an ascii */
/* floating point file and an FFT can be run to validate */
/* the frequency response. */
#include "qed_filt.c"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define INSZ1 1000
#define OUTSZ1 1000
static double x[INSZ1], y[OUTSZ1];
int main(int argc, char *argv[])
{
int i, in_count, file_status, error;
FILE *fin; /* input file of samples */
FILE *fout; /* output file of filtered samples */
fprintf (stderr," ***** start filter test *****\n");
fprintf (stderr," this program accepts 0,1 or 2 command line arguments\n");
fprintf (stderr," the first argument is the filename of the input file\n");
fprintf (stderr," the second argument is the filename of the output file\n");
fprintf (stderr," if there are 0 arguments, input and output is respectively\n");
fprintf (stderr," stdin and stdout\n");
fprintf (stderr," if only one argument is specified, then output is stdout\n");
fprintf (stderr," if input is stdin rather than a file, then fscanf expects input\n");
fprintf (stderr," from the console which may be piped in or entered directly\n");
fin = stdin;
fout = stdout;
error = 0;
if (argc == 1) {
fprintf(stderr," ***** waiting for input *****\n");
}
if (argc >= 2) {
fin = fopen (argv[1], "r");
if (fin == NULL) {
fprintf(stderr,"\n error - Cannot open file %s for input\n", argv[1]);
error = 1;
}
}
if (argc >= 3) {
fout = fopen (argv[2], "w");
if (fout == NULL) {
fprintf(stderr,"\n error - Cannot open file %s for output\n", argv[2]);
error = 1;
}
}
if (error) {
fprintf(stderr," ***** end filter test *****\n");
return(0);
}
init_lat_dbl (&LAT_codigo C);
do {
/* get input samples */
for (in_count = 0; in_count < INSZ1; in_count++) {
file_status = fscanf(fin,"%lf",&x[in_count]);
if (file_status != 1)
break;
}
/* filter samples */
if (in_count == 0) break;
LAT_codigo C.filter( x, y, in_count, &LAT_codigo C);
for (i = 0; i < in_count; i++)
fprintf (fout,"%f\n",y[i]);
} while (file_status == 1);
fclose (fin);
fclose (fout);
fprintf(stderr," ***** end filter test *****\n");
return(1);
}
#endif
Figura 8 - Código gerado pelo Digital Filter Design.
O Hardware
Utilizaremos o mínimo de componentes necessários para criar e testar o Filtro Digital IIR.
A Figura 9 mostra o diagrama simplificado do circuito.
Figura 9 - Diagrama simplificado do circuito.
A seguir a explicação para cada etapa:
SINAL ANALÓGICO: Deve estar compreendido dentro da faixa de medição do
conversor analógico-digital (ADC) do microcontrolador: amplitude e
frequência.
BIAS: Offset no sinal de entrada para metade da
tensão de referência do ADC: os cálculos do filtro digital da biblioteca
DSP necessitam que o sinal de entrada esteja na faixa de -1,0 à 1,0
(escala fracionária). Assim o zero será 2,5 V para uma tensão de
referência do ADC de 0 Vcc (min) e 5 Vcc (max).
AMPLIFICADOR: para aumentar a amplitude do sinal de entrada.
FILTRO
ANTI-ALIASING: é um filtro passa-baixa para evitar erros na medição.
Assegura o Teorema de Nyquist: o sinal amostrado terá no máximo a metade
da frequência de amostragem. Ex.: 500 Hz no máximo quando fs é 1000
sps.
dsPIC: Controlador Digital de Sinal (microcontrolador &
DSP). Executa os cálculos matemáticos no sinal discreto amostrado
através da biblioteca DSP da Microchip. Neste projeto utiliza os
cálculos de um filtro digital IIR Lattice passa-faixa Butterworth de 8ª
ordem.
No terceiro passo elaboraremos o programa do PIC no compilador MPLAB C30 da Microchip. Podem ser utilizadas as linguagens C ou Assembly. Optamos pela linguagem C.
Incluímos em nosso projeto a biblioteca "dsp.h" que possui as funções para o cálculo dos filtros digitais IIR, FIR e outras utilizadas em cálculos de processamentos digitais, como a FFT.
O código fonte do PIC
No terceiro passo elaboraremos o programa do PIC no compilador MPLAB C30 da Microchip. Podem ser utilizadas as linguagens C ou Assembly. Optamos pela linguagem C.
Incluímos em nosso projeto a biblioteca "dsp.h" que possui as funções para o cálculo dos filtros digitais IIR, FIR e outras utilizadas em cálculos de processamentos digitais, como a FFT.
Na Figura 10 é visto parte do código em dsp.h relacionado à declaração da estrutura do Filtro Digital IIR Lattice.
/* Estrutura do Filtro Digital IIR Lattice */
typedef struct {
int order; // filter order (M)
// M <= N (see IIRLattice for N)
fractional* kappaVals; // ptr to lattice coefficients
// (k[m], 0 <= m <= M)
// either in X-Data or P-MEM
fractional* gammaVals; // ptr to ladder coeficients
// (g[m], 0 <= m <= M)
// either in X-Data or P-MEM
// NULL for all pole implementation
int coeffsPage; // page number of program memory if
// coefficients are in program memory
// COEFFS_IN_DATA if not
fractional* delay; // ptr to delay
// (d[m], 0 <= m <= M)
// only in Y-Data
} IIRLatticeStruct; // IIR Lattice filter structure
extern fractional* IIRLattice ( // IIR Lattice filtering
int numSamps, // number of input samples (N)
fractional* dstSamps, // ptr to output samples
// (y[n], 0 <= n < N)
fractional* srcSamps, // ptr to input samples
// (x[n], 0 <= n < N)
IIRLatticeStruct* filter // filter structure
// returns dstSamps
);
extern void IIRLatticeInit ( // Zero out dealy in filter structure
IIRLatticeStruct* filter // Lattice filter structure
);
Figura 10 - Estrutura do filtro IIR Lattice na biblioteca dsp.h.
No cógigo main.c do dsPIC iremos declarar:
- a variável fooiir do tipo IIRLatticeStruct que irá conter a estrutura do nosso Filtro IIR Lattice;
- os vetores que irão conter os coeficientes do Filtro Digital IIR: kappa [ ], gamma [ ] e delayiir [ ];
- o vetor para os dados de entrada do filtro: adc_data [ ]. Os dados podem ser coletados pelo conversor analógico-digital do dsPIC, por exemplo;
- o vetor para os dados de saída do filtro: out_iir [ ].
O código contendo as declarações está contido na Figura 11.
/* declara estrutura Lattice filter structure com nome*/
IIRLatticeStruct fooiir;
fractional kappa[9] __attribute__ ((section (".xbss, bss, xmemory")));
fractional gamma[9] __attribute__ ((section (".xbss, bss, xmemory")));
fractional delayiir[9] __attribute__ ((section (".ybss, bss, ymemory")));
//fractional iniir [117]; ==> adc_data
fractional outiir [117];
int numero_amostra;
fractional adc_data [117]= {0,0,0,0,0,0,0,0,0,0, //vetor de dados para o grafico de tendencia no GLCD
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0};
Figura 11 - Declaração das variáveis do filtro em main.c.
Após o início do programa, na função main ( ) temos que iniciar as variáveis e atribuir os coeficientes do filtro. Os valores para kappa e gamma foram retirados do código C gerado pelo Digital Filter Design Software.
A inicialização das variáveis é vista no código da Figura 12.
A inicialização das variáveis é vista no código da Figura 12.
//------------- inicializa variaveis da estrutura filtro iir ---------------------------
//------------- filtro passa Faixa 40 A 180 Hz, amostragem 1 khz -----------------------
fooiir.kappaVals = &kappa [0]; //inicia ponteiros
fooiir.gammaVals = &gamma [0];
fooiir.delay = &delayiir [0];
fooiir.coeffsPage = COEFFS_IN_DATA; //coeficientes do filtro estao na memoria RAM
fooiir.order = 8; //seta a ordem do filtro
numero_amostra =117;
// Coeficientes do filtro iir lattice
kappa[0] = Q15(-9.7948455815389446e-001); //passa faixa 40 a 180 hz 8 polos
kappa[1] = Q15( 9.7849500351160967e-001);
kappa[2] = Q15(-8.6112175002729441e-001);
kappa[3] = Q15( 5.3530472709660060e-001);
kappa[4] = Q15(-5.0440878979478099e-001);
kappa[5] = Q15( 3.9935338248048824e-001);
kappa[6] = Q15(-1.2523348830583417e-001);
kappa[7] = Q15( 3.0071693969749614e-002);
kappa[8] = Q15( 0.0000000000000000e+000);
gamma[0] = Q15( 5.1559577576911972e-004);
gamma[1] = Q15( 1.4085406081475862e-002);
gamma[2] = Q15(3.6377697302576006e-002);
gamma[3] = Q15(-1.1820731695711806e-001);
gamma[4] = Q15( -3.7374705510515338e-001);
gamma[5] = Q15( -1.4384357653258961e-001);
gamma[6] = Q15( 1.7693240143750988e-001);
gamma[7] = Q15(1.7571299176925376e-001);
gamma[8] = Q15( 4.6649062145300228e-002);
Figura 12 - Inicialização das variáveis e coeficientes do filtro.
Após o início do hardware do PIC e inicializadas as variáveis e coeficientes o programa pode passar por um loop infinito while (true), lendo dados do conversor analógico-digital e executando os cálculos do filtro.
A Figura 13, mostra o código necessário para executar o cálculo do filtro.
Considera-se que os dados de entrada (vindos do ADC) já estejam no vetor adc_data [ ].
2 funções são necessárias:
- IIRLatticeInit: inicializa a estrutura do Filtro Digital IIR Lattice;
- IIRLattice: executa o cálculo do Filtro Digital IIR Lattice;
Considera-se que os dados de entrada (vindos do ADC) já estejam no vetor adc_data [ ].
2 funções são necessárias:
- IIRLatticeInit: inicializa a estrutura do Filtro Digital IIR Lattice;
- IIRLattice: executa o cálculo do Filtro Digital IIR Lattice;
//inicializa estrutura do filtro digital IIR Lattice
IIRLatticeInit (&fooiir);
//executa calculos do filtro iir lattice
IIRLattice (numero_amostra, &outiir[0], &adc_data[0], &fooiir); //(numeroamostragem, *y (n), *x (n), *estrutura do filtro)
Figura 13 - Inicializando estrutura e executando o cálculo do Filtro Digital IIR Lattice.
O resultado final do nosso circuito é visto na Figura 14. Interligando um display gráfico GLCD 128x64 vemos o sinal de 60 Hz após ser aplicado ao Filtro Digital IIR.
Observação: se no hardware não for considerado o filtro anti-aliasing (passa-baixa) pode-se ter um resultado desagradável na saída do filtro. Na Figura 15 fizemos este teste, retirando o filtro anti-aliasing do circuito e aplicando um sinal de entrada maior do que 500 Hz.
Figura 15 - Efeito de aliasing na amostragem digital.
O vídeo a seguir mostra o nosso circuito com o Filtro Digital IIR sendo elaborado e testado com um sinal de entrada variando de 0 à 500 Hz. O erro de aliasing também pode ser observado.
Video do circuito do Filtro Digital IIR com dsPIC
Referência Bibliográfica
SCANDELARI, L. Filtros Digitais. Cap. 5. Disponível em: http://paginapessoal.utfpr.edu.br/scandelari/laboratorio-de-pds/filtros.pdf/at_download/file
MICROCHIP. Filter Design for dsPIC. Digital Filter Design and Analysis System. Disponível em: http://ww1.microchip.com/downloads/en/DeviceDoc/SW300001%20manual.pdf
MICROCHIP. CE005 - Using FIR Filters from dsPIC Filter Design and DSP library. Disponível em: http://ww1.microchip.com/downloads/en/DeviceDoc/CE005_FIR_DSP_lib_Filter.zip
Hermano me podrias ayudar con un codigo sencillo a modo de ejemplo para guiarme.Es un filtro IIR con el dsapic30f2011.
ResponderExcluirOlá Miguel, qual seu email?
Excluirhi Márcio nice work
ResponderExcluircan u send me your code and circuit on borseyogesh1436@gmail.com
thanks