Que tal montar o seu próprio equalizador de áudio para grave e agudo?
Este post apresenta um circuito analógico com 2 filtros ativos de segunda ordem para filtrar frequências baixas e altas de um sinal. O circuito foi desenvolvido e simulado com o software EWB 5.0 Eletronics Workbench.
A Figura 1 mostra o diagrama do circuito. Ele possui um circuito integrado (CI) LM324, um Amplificador Operacional Quádruplo, ou seja, 4 Amp Ops (AO) em um único chip. Os AO são alimentados neste circuito com uma fonte de tensão simétrica, ou seja, com 2 alimentações: +12 Vcc e -12Vcc.
O primeiro AO está montado com a configuração de buffer para fornecer uma alta impedância de entrada para o sinal.
O segundo AO constitui um filtro passa baixa (LPF) ativo de segunda ordem. Esta etapa é responsável pelo ajuste dos tons agudos do nosso equalizador de áudio a partir de um potenciômetro duplo de 50 kohms.
O terceiro AO está configurado como um filtro passa alta (HPF) ativo de segunda ordem. Ele faz o ajuste dos tons graves do equalizador, também utiliza um potenciômetro duplo de 50 kohms.
Figura 1 - Diagrama do circuito do filtro de segunda ordem.
Filtro é um circuito eletrônico utilizado para filtrar um sinal elétrico retirando as faixas de frequências indesejadas. São utilizados por exemplo, para limpar um sinal amostrado retirando os ruídos elétricos presentes. Em áudio os filtros são amplamente utilizados para os controles de grave e agudo.
Os filtros ainda podem ser do tipo analógico, com componentes discretos, ou digitais, implementados por algoritmos executados tipicamente por DSPs (Processador Digital de Sinais)
O termo "ativo" refere-se ao fato das etapas do filtro possuírem componentes ativos (o AO neste caso) e não apenas as etapas dos circuitos RC, com capacitor e resistor. Com o AO é possível configurar um "ganho" para o sinal de entrada ao passar pela etapa de filtragem. Os filtros "passivos" são construídos apenas com pares de resistores e capacitores (circuito RC).
A frequência de corte do filtro é definida pela equação: fc = 1 / (2pi * R*C).
Diz-se "segunda ordem", pois para cada AO temos 2 etapas com circuitos RC, isto permite uma melhor filtragem da frequência do sinal de entrada, isto quer dizer que o sinal indesejado (o que se quer filtrar/anular/cancelar/retirar) terá uma melhor atenuação. A diminuição da intensidade do sinal após passar pela frequência de corte do filtro será mais acentuada/brusca quanto maior for a ordem do filtro. Um filtro de segunda ordem é melhor do que um filtro de primeira ordem.
Dois instrumentos de medição podem ser vistos no diagrama da Figura 1, na parte superior. O da direita é um osciloscópio, utilizado para visualizar a amplitude do sinal de entrada (linha azul) e saída (linha vermelha) de áudio no domínio do tempo. O da esquerda é um Bode Plotter, usado aqui para avaliar o funcionamento do filtro. Com ele é possível visualizar a amplitude do sinal variando em função da frequência.
A Figura 2 mostra o conjunto de geradores de ondas senoidais de diferentes frequências utilizados para a simulação/testes do circuito do equalizador de grave e agudo:
- 10 mV/100 Hz;
- 10 mV/1 kHz;
- 10 mV/5 kHz;
- 10 mV/10 kHz;
- 10 mV/20 kHz.
Para o caso de áudio (música) a frequência audível pelo ouvido humano está compreendida entre 20 Hz e 20 kHz.
Figura 2 - Geradores de sinais utilizados para a simulação.
As Figuras a seguir apresentam os resultados dos testes da simulação do circuito do filtro alterando a posição do cursor dos potenciômetros dos equalizadores de grave e agudo.
Figura 3 - Resposta de frequência: 2 pot em 100 %.
A Figura 3 mostra a curva da resposta de frequência do filtro para os 2 potenciômetros na posição de 100 %. A banda varia de 43 Hz a 38 kHz e abrange a faixa completa do filtro.
Figura 4 - Resposta de frequência: grave em 50 %.
Na Figura 4 reduzimos o ajuste do potenciômetro de grave (filtro passa alta) para 50 %, a frequência de corte inferior do filtro passa então de 43 Hz para 71 Hz.
Figura 5 - Resposta de frequência: grave em 0 %.
Reduzindo o potenciômetro de grave (filtro passa alta) para o mínimo (0 %). Agora a frequência de corte inferior do filtro sobe para 933 Hz, conforme a Figura 5.
Figura 6 - Resposta de frequência: agudo em 50 %.
Na Figura 6 reduzimos o ajuste do potenciômetro de agudo (filtro passa baixa) para 50 %, a frequência de corte superior do filtro passa de 38 kHz Hz para 5 kHz.
Figura 7 - Resposta de frequência: agudo em 0 %.
Reduzindo o potenciômetro de agudo (filtro passa baixa) para o mínimo (0 %). Agora a frequência de corte superior do filtro cai para 2,3 kHz, conforme a Figura 7.
Figura 8 - Resposta de frequência: 2 pot em 0 %.
Por fim, deixamos os 2 potenciômetros do nosso filtro, passa alta e passa baixa, ajustes de grave e agudo respectivamente, no mínimo, posição de 0 %. Temos a menor banda de frequência passante no filtro: 760 Hz a 2,6 kHz. A Figura 8 mostra a resposta de frequência do filtro nesta condição.
Os valores de R e C do filtro passa alta ou passa baixa podem ser alterados conforme desejar, para atender a faixa de frequência que se deseja filtrar.
Este circuito atende muito bem a faixa de áudio, para se trabalhar com som e música como um equalizador de grave, agudo ou passa faixa. Também pode ser utilizado para filtrar (limpar) os sinais ruidosos de sensores.
Este
artigo demonstra como elaborar um Filtro
Digital IIR utilizando o microcontrolador PIC32MX 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 (lowpass);
- Passa-alta (highpass);
- Passa-banda (bandpass);
- Rejeita-banda (bandstop).
Funções de Janela são utilizadas em Filtros Digitais FIR podendo ser:
- janela Retangular;
- janela de Hamming;
- janela de Blackman;
- janela de Kaiser.
Filtros Digitais IIR podem utilizar modelagem dos filtros analógicos:
- filtro Butterworth
- filtro Tschebyscheff
- filtro Tschebyscheff inverso
- filtro Elliptic
- filtro Bessel
De um modo geral os Filtros Digitais IIR são representados pela Equação 1.
Equação 1 - Equação básica para um Filtro Digital.
A Função de Transferência H (z) para um Filtro Digital é vista na Equação 2.
Equação 2 - Função de Transferência H (z) de um Filtro Digital. Fonte: ORFANIDS.
Considerando a0 =1 e M=N=2 obtemos a Equação 3 para um FIltro Digital IIR de Segunda Ordem.
Equação 3 - Função de Transferência para um Filtro Digital de Segunda Ordem. Fonte: ORFANIDS.
A Equação 4 mostra a equação diferencial para o FIltro Digital IIR de Segunda Ordem ou Biquadrado.
Equação 4 - Equação Diferencial para o Filtro Digital de Segunda Ordem. Fonte: ORFANIDS.
A equação diferencial do IIR FIlter Biquad é representada pelo Fluxograma 1.
Fluxograma 1 - Realização do Filtro IIR Segunda Ordem na Forma Direta. Fonte: ORFANIDS
Cada seção biquadrada do FIltro IIR da DSP Library da Microchip para o PIC32MX opera segundo o Fluxograma 2 (Second Order Direct Form II Structure Transposed).
Fluxograma 2 - Operação do FIltro IIR da DSP Library da Microchip. Fonte: Microchip.
Criando um Filtro Digital IIR
A Figura 1 mostra os 3 passos para você criar seu Filtro Digital.
Figura 1 - Passos para criar um Filtro Digital.
Este artigo mostra um exemplo para a construção de 4 tipos de Filtros Digitais IIR:
a) filtro passa-baixa de 1000 Hz;
b) filtro passa-alta de 2000 Hz;
c) filtro passa-banda de 1500 Hz à 2000 Hz;
d) filtro rejeita-banda de 2000 Hz à 2500 Hz.
Vamos a algumas considerações do nosso projeto.
Objetivo do circuito:
Filtrar um sinal entre 0 e 3840 Hz. Aplicar os 4 tipos de filtros IIR para verificar a resposta de cada um deles.
Especificações:
- o sinal de entrada é uma onda senoidal gerada pelo próprio microcontrolador através da equação trigonométrica cos(a+b) = 2 cos a cos b - cos(a-b).
- de acordo com o Teorema de Nyquist, a frequência de amostragem do sinal de entrada será 7680 Hz.
-
o microcontrolador escolhido é o PIC32MX, um microcontrolador de 32-bit da Microchip, que possui as funções para o Filtro
Digital IIR disponíveis na DSP Library. Possui 80 MHz, 512 kB de memória Flash e 128 KB High Speed SRAM.
-
será utilizado o dsPIC Filter Design Lite, um programa de Digital Filter Design, para definir os
parâmetros do filtro digital IIR 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 PIC32. O
programa consiste basicamente em declarar as variáveis,
inicializar os ponteiros e variáveis, iniciar a estrutura do filtro com mips_iir16_setup ( ) e executar o cálculo do filtro digital com mips_iir16
( ).
- é aplicada a transformada Rápida de Fourier (FFT) ao sinal filtrado para verificar a resposta do filtro.
-
para teste do nosso circuito o PIC32 varia a frequência do sinal gerado de 0 à 3840 Hz.
- o sinal senoidal gerado e filtrado assim como a FFT são mostrados em um display gráfico.
Digital Filter Design: definindo os parâmetros do Filtro Digital
No
primeiro passo temos que definir alguns parâmetros para poder utilizar
um software capaz de gerar os coeficientes necessários para o cálculo do
filtro digital pelo PIC.
Utilizaremos o Filtro Digital IIR Biquadrado (cascata de segunda ordem). Cada IIR FIlter Biquad possui 2 pólos e 2 zeros.
O FIltro Analógico utilizado foi o Butterworth de 4ª ordem. 2 filtros de segunda ordem (biquadrado) em cascata. No total teremos 4 pólos e 4 zeros. Veja a seguir o Design elaborado para os 4 tipos de Filtros utilizando o dsPIC Filter Design Lite: lowpass, highpass, bandpass e bandstop.
Lowpass IIR FIlter Design
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-baixa.
No
segundo passo utilizaremos o dsPIC FD Lite, o Digital Filter Design
Software, para modelar o nosso filtro digital com estes parâmetros e
gerar os coeficientes para ser utilizado no programa do PIC32.
O método de realização do filtro, quantização, neste caso é "cascated second order sections". Estamos projetando um IIR FIlter Biquad, isto é, com 2 pólos e 2 zeros para cada seção do fiiltro. No menu Design / IIR Design... iniciaremos o design para um Filtro Digital IIR.
Escolheremos o tipo de filtro: lowpass.
Na segunda tela, Figura 3, preencheremos os parâmetros do filtro passa-baixa conforme ilustrado anteriormente na Figura 2.
Figura 3 - Configurando os parâmetros para o filtro passa-baixa.
A Figura 4 mostra o resultado matemático para a modelagem do nosso filtro digital IIR passa-baixa de acordo com os parâmetros fornecidos.
Figura 4 - Resultado da Modelagem do Filtro Digital IIR lowpass.
Highpass IIR FIlter Design
A Figura 5 traz graficamente a representação de cada parâmetro do filtro highpass.
Figura 5 - Especificação do FIltro Digital passa-alta.
Os parâmetros do filtro passa-alta são configurados conforme a Figura 6.
Figura 6 - Configurando os parâmetros para o filtro passa-alta.
A Figura 7 mostra o resultado matemático para a modelagem do filtro digital IIR passa-alta.
Figura 7 - Resultado da Modelagem do Filtro Digital IIR highpass.
Bandpass IIR FIlter Design
A Figura 8 traz graficamente a representação de cada parâmetro do filtro bandpass.
Figura 8 - Especificação do FIltro Digital passa-banda.
Os parâmetros do filtro passa-banda são configurados conforme a Figura 9.
Figura 9 - Configurando os parâmetros para o filtro passa-banda.
A Figura 10 mostra o resultado matemático para a modelagem do filtro digital IIR passa-banda.
Figura 10 - Resultado da Modelagem do Filtro Digital IIR bandpass.
Bandstop IIR FIlter Design
A Figura 11 traz graficamente a representação de cada parâmetro do filtro bandstop.
Figura 11 - Especificação do FIltro Digital rejeita-banda.
Os parâmetros do filtro rejeita-banda são configurados conforme a Figura 12.
Figura 12 - Configurando os parâmetros para o filtro rejeita-banda.
A Figura 13 mostra o resultado matemático para a modelagem do filtro digital IIR rejeita-banda.
Figura 13 - Resultado da Modelagem do Filtro Digital IIR bandstop.
Gerando os coeficientes para o Filtro IIR
Clicando
no botão "Save C File" o software (dsPIC FD Lite - Digital Filter Design) irá gerar um código fonte padrão na
linguagem C para o filtro digital IIR construído, que pode ser visto no Código 1. Com ele você pode construir seu filtro DIgital IIR em outro
compilador C para computador ou outro modelo de microcontrolador.
/***************************************************************************
****************************************************************************
* File: E:\microchip_solutions_v2013-06-15\MyProjects\IIR FIlter\Digital Filter Design\Lowpass\lowpass1000Hz.c
* Created by dsPIC FD Lite Version 1.0.0 Build 1 at 21:20:05 May 04 2015
* C Code Generator - Version 4.0
****************************************************************************
* 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 BiquadSections IIR_lowpass1000Hz;
*
* init_biquad_float (&IIR_lowpass1000Hz); // initialize filter structure
*
* IIR_lowpass1000Hz.filter ( x, y, n, &IIR_lowpass1000Hz); // x is an array of input samples
* // y is an array of output samples
* // n is number of samples to process
* // &IIR_lowpass1000Hz 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' */
float lowpass1000Hz_num[ 6] = {
9.454345703125e-002F, /* b[ 1, 0] */
1.891174316406e-001F, /* b[ 1, 1] */
9.454345703125e-002F, /* b[ 1, 2] */
6.185913085938e-002F, /* b[ 2, 0] */
1.237487792969e-001F, /* b[ 2, 1] */
6.185913085938e-002F}; /* b[ 2, 2] */
float lowpass1000Hz_den[ 6] = {
1.000000000000e+000F, /* a[ 1, 0] */
-8.160400390625e-001F, /* a[ 1, 1] */
1.943054199219e-001F, /* a[ 1, 2] */
5.000000000000e-001F, /* a[ 2, 0] */
-5.340270996094e-001F, /* a[ 2, 1] */
2.815856933594e-001F}; /* a[ 2, 2] */
float lowpass1000Hz_m1[2];
float lowpass1000Hz_m2[2];
float lowpass1000Hz_gain = 1.000000000000e+000F; /* initial gain for cascade realization */
/* also applies to parallel realization */
float lowpass1000Hz_pars = 1.000000000000e+000F; /* scale value for parallel sections */
BiquadSections IIR_lowpass1000Hz = {
2, /* number of sections */
0, /* realization method */
/* 0 Cascaded second order sections */
/* 1 Parallel second order sections */
1, /* quantization: 0 off, 1 on */
1, /* quantization type */
/* 0 Floating point */
/* 1 Fixed point fractional */
0, /* realization type for cascaded sections only */
/* 0 Fixed point - Transposed Canonic biquad sections */
/* 1 Fixed point - Canonic biquad sections */
/* 2 Floating point - 4 multiplies */
/* 3 Floating point - 5 multiplies */
/* 4 Floating point - recursive normal */
0, /* realization type for parallel sections only */
/* 0 Fixed point - Transposed Canonic biquad sections */
/* 1 Floating point - Transposed Canonic biquad sections */
&lowpass1000Hz_gain, /* pointer to gain for cascade/parallel realizations */
&lowpass1000Hz_pars, /* pointer to scale value for parallel sections */
lowpass1000Hz_num, /* pointer to numerator coefficients */
lowpass1000Hz_den, /* pointer to denominator coefficients */
lowpass1000Hz_m1, /* pointer to delay line 1 */
lowpass1000Hz_m2, /* pointer to delay line 2 */
cas_blkfloat_fm1}; /* ptr to filter routine */
/* call the following function first and normally only once */
/* init_biquad_float (&IIR_lowpass1000Hz) */
/* where &IIR_lowpass1000Hz is a pointer to the BiquadSections */
/* structure defining the filter */
/* call the following function to filter n samples */
/* IIR_lowpass1000Hz.filter (pIn, pOut, int n, &IIR_lowpass1000Hz); */
/* 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 */
/* &IIR_lowpass1000Hz 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 float 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_biquad_float (&IIR_lowpass1000Hz);
do {
/* get input samples */
for (in_count = 0; in_count < INSZ1; in_count++) {
file_status = fscanf(fin,"%f",&x[in_count]);
if (file_status != 1)
break;
}
/* filter samples */
if (in_count == 0) break;
IIR_lowpass1000Hz.filter( x, y, in_count, &IIR_lowpass1000Hz);
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
Código 1 - Código C gerado com coeficientes para o Filtro IIR Lowpass.
O que nos interessa neste código são os valores dos coeficientes A1, A2, B1 e B2, que iremos utilizar no programa do PIC32MX. "A" e "B" são os pólos e zeros do Filtro.
Os valores dos coeficientes estão identificados em formato de matriz: Coeficiente [ número da seção Biquadrada , número do coeficiente ]
Exemplo: A [1,1] = coeficiente A1 da primeira seção biquadrada. A [1,2] = coeficiente A2 da primeira seção biquadrada. A [2,1] = coeficiente A1 da segunda seção biquadrada. A [2,2] = coeficiente A2 da segunda seção biquadrada.
B [1,1] = coeficiente B1 da primeira seção biquadrada. B [1,2] = coeficiente B2 da primeira seção biquadrada. B [2,1] = coeficiente B1 da segunda seção biquadrada. B [2,2] = coeficiente B2 da segunda seção biquadrada.
O IIR FIlter Biquad possui 2 pólos e 2 zeros para cada seção (seções de segunda ordem).
Para o Filtro IIR, A0 não é utilizado na função mips_iir16 ( ) da biblioteca DSP Library com o PIC32MX. B0 não é necessário ser informado na função mips_iir16 ( ) da biblioteca DSP Library para o PIC32, pois no IIR FIlter Biquad, B0 = B2.
Por isto, no programa do PIC32MX, iremos utilizar somente os coeficientes A1, A2, B1 e B2 de cada seção.
Estamos modelando um Filtro Analógico Butterworth de 4ª ordem. Temos então 4 pólos e 4 zeros.
No menu Codegen / Microchip / dsPIC30 iremos gerar o código em Assembly com os coeficientes. Este código com os coeficientes para o filtro IIR lowpass é visto no Código 2.
; ..............................................................................
; File lowpass1000Hz.s
; ..............................................................................
.equ lowpass1000HzNumSections, 2
; ..............................................................................
;
; Allocate and initialize filter coefficients
;
; These coefficients have been designed for use in the Transpose filter only
.section .xdata
lowpass1000HzCoefs:
.hword 0x060D ; b( 1,0)/2
.hword 0x0C1A ; b( 1,1)/2
.hword 0x343A ; a( 1,1)/2
.hword 0x060D ; b( 1,2)/2
.hword 0xF391 ; a( 1,2)/2
.hword 0x07EB ; b( 2,0)/2
.hword 0x0FD7 ; b( 2,1)/2
.hword 0x445B ; a( 2,1)/2
.hword 0x07EB ; b( 2,2)/2
.hword 0xDBF5 ; a( 2,2)/2
; ..............................................................................
; Allocate states buffers in (uninitialized) Y data space
.section .ybss, "b"
lowpass1000HzStates1:
.space lowpass1000HzNumSections*2
lowpass1000HzStates2:
.space lowpass1000HzNumSections*2
; ..............................................................................
; Allocate and intialize filter structure
.section .data
.global _lowpass1000HzFilter
_lowpass1000HzFilter:
.hword lowpass1000HzNumSections-1
.hword lowpass1000HzCoefs
.hword 0xFF00
.hword lowpass1000HzStates1
.hword lowpass1000HzStates2
.hword 0x0000
; ..............................................................................
; Sample assembly language calling program
; The following declarations can be cut and pasted as needed into a program
; .extern _IIRTransposeFilterInit
; .extern _BlockIIRTransposeFilter
; .extern _lowpass1000HzFilter
;
; .section .bss
;
; The input and output buffers can be made any desired size
; the value 40 is just an example - however, one must ensure
; that the output buffer is at least as long as the number of samples
; to be filtered (parameter 4)
;input: .space 40
;output: .space 40
; .text
;
;
; This code can be copied and pasted as needed into a program
;
;
; Set up pointers to access input samples, filter taps, delay line and
; output samples.
; mov #_lowpass1000HzFilter, W0 ; Initalize W0 to filter structure
; call _IIRTransposeFilterInit ; call this function once
;
; The next 4 instructions are required prior to each subroutine call
; to _BlockIIRTransposeFilter
; mov #_lowpass1000HzFilter, W0 ; Initalize W0 to filter structure
; mov #input, W1 ; Initalize W1 to input buffer
; mov #output, W2 ; Initalize W2 to output buffer
; mov #20, W3 ; Initialize W3 with number of required output samples
; call _BlockIIRTransposeFilter ; call as many times as needed
Código 2 - Código Assembly gerado com coeficientes para o Filtro IIR Lowpass.
A vantagem de utilizar os coeficientes do código em Assembly é o fato de já estar no formato fracionário. O programa do PIC32 necessita dos coeficientes no formato int16, então basta somente copiá-los para o nosso projeto. O código em C gera os coeficientes em float.
Este procedimento deve ser repetido para os 4 tipos de filtro IIR: lowpass, highpass, bandpass e bandstop. Os coeficientes A1, A2, B1 e B2 são diferentes para cada design elaborado.
O Hardware
Neste projeto utilizaremos:
a) PIC32MX USB Starter Kit II;
b) I/O Expansion Board;
c) GFXv3 Graphic Display.
O PIC32 irá gerar um sinal senoidal de frequência variável, aplicar o filtro digital IIR, calcular a Transformada Rápida de Fourier, a fim de verificar a resposta de cada tipo de filtro e comparar com os dados teóricos obtidos com o dsPIC FD Lite e mostrar no display os respectivos gráficos.
O código fonte do PIC32
No
terceiro passo elaboraremos o programa do PIC no compilador MPLAB C32
da Microchip com o ambiente de desenvolvimento MPLAB X. O Programa foi desenvolvido em linguagem C. Incluímos em
nosso projeto a biblioteca "dsplib_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 3 mostra a inclusão da biblioteca e a declaração dos vetores do Filtro Digital IIR.
#include "dsplib_dsp.h" // library to FFT and IIR FIlter functions
// vetores para iir filter
#define B 2 //2 Biquad Sections
biquad16 bq[B];
int16 coeffs[4*B];
int16 delayline[2*B];
int16 indata, outdata;
int16 sinal_Filtrado [N*2];
Código 3 - Incluindo a biblioteca DSP e declarando os vetores.
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 A1, A2, B1 e B2
foram retirados do código Assembly gerado pelo dsPIC Filter Design Lite. A inicialização das variáveis e coeficientes são vistos no Código 4.
Os coeficientes são carregados para A1, A2, B1 e B2 de acordo com o tipo de filtro selecionado: lowpass, highpass, bandpass ou bandstop.
Còdigo 4 - Carregando os coeficientes e inicializando a estrutura do Filtro IIR.
Primeiro deve-se iniciar com zero o vetor delayline [ ].
Depois carregam-se os valores dos coeficientesem bq [ ], de acordo com o tipo do filtro IIR selecionado.
Agora então podemos chamar a função mips_iir16_setup( ) da biblioteca DSP do PIC32MX que se encarrega de inicializar a estrutura do filtro IIR.
O Código 5 mostra a aplicação do filtro propriamente dito em uma amostra do sinal de entrada.
/* calculate iir filter biquad */
void iir_filter ()
{
int i;
for (i=0;i<N*2;i++)
{
// get input data value into indata
indata = sine_wave_input[i] ;
//calculate iir filter biquad
outdata = mips_iir16(indata, coeffs, delayline, B, 1);
sinal_Filtrado [i] = outdata;
} //end for
}
Código 5 - Função que aplica o FIltro IIR ao sinal de entrada.
A função responsável pelo cálculo do Filtro IIR Biquad é a mips_iir16 ( ), e pertence à DSP Library da Microchip para o PIC32MX.
Nosso programa executa o Código 6 em um loop infinito: gera uma onda senoidal de frequência variável; aplica o filtro IIR ao sinal gerado; calcula a FFT ao sinal Filtrado e atualiza o display com os gráficos.
sineWaveGeneration (signal_freq, 7680.0 ); //gera sinal senoidal
iir_filter (); //aplica o filtro iir ao sinal gerado
moveVectorInputFFT (); //move sinal gerado para entrada do calculo da FFT
fftCalculate (); //calcula a FFT do sinal gerado
updateDisplay (); //atualiza a tela
Código 6 - Loop do programa no código main.
O resultado final
do nosso projeto é visto na Figura 14. Interligando um display gráfico QVGA 320x240 vemos o sinal gerado sendo aplicado ao Filtro Digital
IIR.
Figura 14 - Sinais sendo mostrados no display gráfico.
A Figura 15 mostra a resposta na prática para o nosso filtro passa-baixa de 1000 Hz.
Figura 15 - Resposta do IIR FIlter lowpass.
A Figura 16 mostra a resposta na prática para o nosso filtro passa-alta de 2000 Hz.
Figura 16 - Resposta do IIR FIlter highpass.
A Figura 17 mostra a resposta na prática para o nosso filtro passa-banda de 1500 Hz à 2000 Hz.
Figura 17 - Resposta do IIR FIlter bandpass.
A Figura 18 mostra a resposta na prática para o nosso filtro rejeita-banda de 2000 Hz à 2500 Hz
Figura 18 - Resposta do IIR FIlter bandstop.
Estas curvas podem ser comparadas com aquelas do início deste post, geradas pelo dsPIC FD Lite, a fim de verificar a performance do Filtro Digital IIR da DSP Library com o PIC32MX!
Lembrando que a frequência de amostragem é 7680 Hz e o sinal gerado varia de 0 à 3840 Hz, respeitrando o Teorema de Nyquist.
O Vídeo 1 mostra o projeto do Filtro Digital IIR elaborado no MPLAB X e rodando com o PIC32MX.
Vídeo 1 - IIR FIlter com PIC32MX.
Os cálculos da Fast Fourier Transform (FFT) para o PIC32MX você encontra aqui.
RAMU, B. K. Anantha. Implementing FIR and IIR Digital Filters using PIC18 microcontrollers. Application Note AN852. Microchip Technology Designs. India. 2002.
SKANDA, Vinaya. Sine Wave Generator Using Numerically Controller PIC. Application Note AN1523A. Microchip Technology Inc. 2013.
HAYKIN, Simon S.; VAN VEEN, Barry. Sinais e sistemas. Porto Alegre: Bookman, 2001. 668p.
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.
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.
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.
/***************************************************************************
****************************************************************************
* 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.
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.
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;
//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.
Figura 14 - Sinal de 60 Hz aplicado ao circuito do Filtro DIgital IIR passa-faixa.
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.