Tema 15 Filtros Digitales PDF
Tema 15 Filtros Digitales PDF
Tema 15 Filtros Digitales PDF
Muestreo y reconstrucción
●
Muestreo con ADC de 10 bits
●
Reconstrucción con DAC genérico de 10 bits
Muestreo y reconstrucción
Programa DAC_10
Programa que lee señal de ADC y saca por DAC_10.
/* Programa dac_10_02.ino
- Conxión con DAC_10, dac generico de 10 bits de Proteus.
- Lee canal de ADC y saca por DAC.
- PORTD 8 bits menos significativos.
- PB0 y PB1 bits 8 y 9.
- PB2 Latch Enable - LE.
*/
#define adc_ch 0
void escribe_dac(uint16_t val_adc);
void init_dac(void);
void setup()
{
init_dac();
}
...
Programa DAC_10
...
void loop()
{
static uint16_t val_adc;
val_adc = analogRead(adc_ch);
escribe_dac(val_adc);
...
Programa DAC_10
...
void init_dac(void)
{
//Bits de DAC y LE como salidas
DDRD = 0xFF;
DDRB |= (1 << PB0) | (1 << PB1);
DDRB |= (1 << PB2); //LE
...
Programa DAC_10
...
void escribe_dac(uint16_t val_adc)
{
uint8_t aux1;
PORTD = lowByte(val_adc); // Bits 0 a 7 del DAC
aux1 = highByte(val_adc) & ((1 << 0) | (1 << 1));
//Bit 8 del DAC
if((aux1 & (1 << 0)) != 0)
PORTB |= (1 << PB0);
else
PORTB &= ~(1 << PB0);
//Bit 9 del DAC
if((aux1 & (1 << 1)) != 0)
PORTB |= (1 << PB1);
else
PORTB &= ~(1 << PB1);
●
Frecuencia de muestreo de 500 Hz.
●
Frecuencia máxima de la señal a muestrear 250
Hz.
●
Filtro de reconstrucción. Sallen Key, Butterworth,
segundo orden, frecuencia de corte 250 Hz.
●
Suma de señales de entrada.
Circuito mejorado
Programa DAC_10 mejorado
Programa que lee ADC y saca por DAC_10 a una frecuencia de 500 Hz.
/*
Programa dac_10_timer_01.ino
- Control de tiempo usando Timer2.
*/
#include <MsTimer2.h>
#define adc_ch 0
void loop()
{
static uint16_t val_adc;
if(estado == HIGH)
{
estado = LOW;
val_adc = analogRead(adc_ch);
escribe_dac(val_adc);
}
}
...
Programa DAC_10 mejorado
...
void muestreo()
{
estado = HIGH; //Variable estado
}
void init_dac(void)
{
//Bits de DAC y LE como salidas
DDRD = 0xFF;
DDRB |= (1 << PB0) | (1 << PB1);
DDRB |= (1 << PB2); //LE
●
Filtro de respuesta a impulso finita.
●
Tiene la forma:
N −1
y (n) = ∑ h(k ) x(n−k )
k=0
#define adc_ch 0
MsTimer2::set(retardo, muestreo);
MsTimer2::start(); //Habilita la interrupción
}
void loop()
{
uint16_t val_out;
uint8_t aux1;
float val_filt;
...
Programa FIR paso bajo
...
if (estado == HIGH)
{
//Filtro FIR
val_t0 = analogRead(adc_ch);
val_filt = coef[0] * val_t0 + coef[1] * val_t1 +
coef[2] * val_t2 + coef[3] * val_t3 +
coef[4] * val_t4 + coef[5] * val_t5 +
coef[6] * val_t6 + coef[7] * val_t7 +
coef[8] * val_t8 + coef[9] * val_t9 +
coef[10] * val_t10 + coef[11] * val_t11 +
coef[12] * val_t12 + coef[13] * val_t13 +
coef[14] * val_t14;
//Recorrer posiciones
val_t14 = val_t13;
val_t13 = val_t12;
val_t12 = val_t11;
val_t11 = val_t10;
val_t10 = val_t9;
val_t9 = val_t8;
...
Programa FIR paso bajo
...
val_t8 = val_t7;
val_t7 = val_t6;
val_t6 = val_t5;
val_t5 = val_t4;
val_t4 = val_t3;
val_t3 = val_t2;
val_t2 = val_t1;
val_t1 = val_t0;
// escribir valor de salida en DAC_10
val_out = int(val_filt); //Salida del filtro
//escribe_dac(val_t0); //Salida directa, del ADC
escribe_dac(val_out);
estado = LOW;
}
}
...
Programa FIR paso bajo
...
void muestreo()
{
estado = HIGH; //Variable estado
}
void init_dac(void)
{
//Bits de DAC y LE como salidas
DDRD = 0xFF;
DDRB |= (1 << PB0) | (1 << PB1);
DDRB |= (1 << PB2); //LE
●
Coeficientes con módulo scipy.signal de Python
● scipy.signal.firwin(numtaps, cutoff,
width=None, window='hamming',
pass_zero=True, scale=True, nyq=None,
fs=None)
●
cutoff: float
Frecuencia de corte del filtro (en las mismas
unidades que fs) o un arreglo de frecuencias de
corte (bordes de banda).
Coeficientes para filtros FIR
●
pass_zero: {True, False, ‘bandpass’, ‘lowpass’,
‘highpass’, ‘bandstop’}, opcional
Si es True, la ganancia a frecuencia 0 (la “ganancia
en DC”) es 1. Si es False, the la ganancia en DC 0.
También puede ser una cadana de caracteres que
indique el tipo de filtro deseado.
●
window: string o tupla de strings y valores de
parámetros, opcional
(boxcar, triang, blackman, hamming, hann, bartlett,
flattop, parzen, bohman, blackmanharris, nuttall,
barthann, cosine, exponential, tukey, entre otros).
Coeficientes para filtros FIR
●
nyq: float, opcional
Obsoleta. Usar fs. Es la frecuencia de Nyquist.
Cada frecuencia en cutoff debe estar entre 0 y nyq.
Por defecto es 1.
●
fs: float, opcional
La frecuencia de muestreo de la señal. Cada
frecuencia en cutoff debe estar entre 0 y fs/2. Por
defecto es 2.
●
Devuelve h: (numtaps,) ndarray
Coeficientes de filtro FIR de longitud numtaps.
Coeficientes para filtros FIR
●
Coeficientes con módulo scipy.signal de Python
from scipy import signal
frec_muestreo = 500. #Frecuencia de muestreo en Hz.
num_taps = 15 #Número de coeficientas del filtro.
# Frecuencia de Nyquist
frec_nyq = frec_muestreo / 2.
...
# Filtro paso alto
# La frecuencia de corte del filtro: Hz
frec_corte = 8.0 #Frecuencia de corte en Hz
...
Coeficientes para filtros FIR
...
# Filtro pasa banda
# La frecuencia de corte del filtro: Hz
frec_corte_baja = 8.0 #Frecuencia de corte en Hz
frec_corte_alta = 18.0
...
# Filtro rechaza banda
# La frecuencia de corte del filtro: Hz
frec_corte_baja = 8.0 #Frecuencia de corte en Hz
frec_corte_alta = 22.0
Forma
Directa I
Filtros IIR
Forma
Directa II
Filtros IIR
●
Filtro de respuesta a impulso infinita. Usa valores
previos de la entrada y la salida.
●
Tiene la forma:
M N
y (n) = ∑ b k x (n−k) −∑ al y (n−l)
k =0 l=1
De otra forma :
y (n) = b 0 x (n) + b1 x (n−1) + b2 x (n−2) +... +b M x (n−M )
− a 1 y (n−1) − a2 y (n−2) − a3 y (n−3) −... −a n y (n−N )
Filtros IIR
●
Donde:
#define adc_ch 0
void setup()
{
init_dac();
MsTimer2::set(retardo, muestreo);
MsTimer2::start(); //Habilita la interrupción
}
...
Programa IIR paso bajo
...
void loop()
{
uint16_t val_out;
uint8_t aux1;
float val_filt;
if (estado == HIGH)
{
//Filtro FIR
val_t2 = val_t1;
val_t1 = val_t0;
val_t0 = analogRead(adc_ch);
val_filt = coef_b[0] * val_t0 + coef_b[1] * val_t1 +
coef_b[2] * val_t2 - (coef_a[1] * y_t1 +
coef_a[2] * y_t2);
y_t2 = y_t1;
y_t1 = val_filt;
...
Programa IIR paso bajo
...
// escribir valor de salida en DAC_10
val_out = int(val_filt); //Salida del filtro
//escribe_dac(val_t0); //Salida directa, del ADC
escribe_dac(val_out);
estado = LOW;
}
}
void muestreo()
{
estado = HIGH; //Variable estado
}
...
Programa IIR paso bajo
...
void init_dac(void)
{
//Bits de DAC y LE como salidas
DDRD = 0xFF;
DDRB |= (1 << PB0) | (1 << PB1);
DDRB |= (1 << PB2); //LE
●
Coeficientes con módulo scipy.signal de Python
scipy.signal.iirfilter(N, Wn, rp=None,
rs=None, btype='band', analog=False,
ftype='butter', output='ba', fs=None)
●
N: int
El orden del filtro.
●
Wn: arreglo o lista
Un escalar o una lista de dos valores, que indican
las frecuencias críticas.
Coeficientes para filtros IIR
●
analog: bool, opcional
Cuando es True, devuelve los coeficientes para un
filtro analógico, si no, para un filtro digital.
●
ftype: str, opcional
El tipo de filtro IIR filter a diseñar:
Butterworth : ‘butter’, Chebyshev I : ‘cheby1’,
Chebyshev II : ‘cheby2’, Cauer/elliptic: ‘ellip’,
Bessel/Thomson: ‘bessel’.
Coeficientes para filtros IIR
●
output: {‘ba’, ‘zpk’, ‘sos’}, opcional
Formato de salidad del filtro:
Secciones de segundo orden (recomendado): ‘sos’
Numerador/denominador (default): ‘ba’
Polo-cero : ‘zpk’
●
fs: float, opcional
La frecuencia de muestreo de un sistema digital.
Coeficientes para filtros IIR
●
Devuelve.
●
b, a: ndarray, ndarray
Coeficientes de polinimios para numerador (b) y
denominador (a) del IIR. Si output='ba'.
●
z, p, k: ndarray, ndarray, float
Ceros, polos, y ganancia del sistema para la
función de transferencia del IIR. Si output='zpk'.
●
sos: ndarray
●
Secciones de segundo orden para el IIR. Si
output=='sos'.
Coeficientes para filtros IIR
●
Coeficientes con módulo scipy.signal de Python
import scipy.signal as signal
frec_muestreo = 500. #Frecuencia de muestreo en Hz.
orden = 6 #Orden del filtro.
●
Coeficientes con módulo scipy.signal de Python
...
#Forma alternativa, recomendable
coef_b, coef_a = signal.iirfilter(orden, frec_corte,
btype='low', analog=0,
ftype='butter', output='ba',
fs = frec_muestreo)
print("Filtro IIR paso bajo")
print("b:", coef_b)
print("a:", coef_a)
...
Coeficientes para filtros IIR
...
# Filtro paso alto
cutoff_hz = 10.0 #Frecuencia de corte en Hz
...
Coeficientes para filtros IIR
...
# Filtro rechaza banda
frec_corte_baja = 8.0 #Frecuencia de corte en Hz
frec_corte_alta = 22.0
●
Directa II en cascada,
dos secciones SOS
Filtros IIR - SOS
●
IIR de orden elevado, se vuelve inestable debido a
errores de redondeo.
●
Solución: secciones de segundo orden - SOS.
Programa IIR rechaza banda
Programa que implementa fitro IIR rechaza banda de orden 4.
/*
Programa filtro_IIR_dac_10_br_02
-IIR rechaza banda de orden 4. No funciona.
*/
#include <MsTimer2.h>
#define adc_ch 0
...
Programa IIR rechaza banda
...
//fs = 500 Hz, fcl = 8 Hz, fch = 22 Hz, orden 4, rechaza banda
const float coef_b[9] = {0.79436603, -6.26659408, 21.71592747,
-43.17415134, 53.86090432, -43.17415134,
21.71592747, -6.26659408, 0.79436603};
const float coef_a[9] = {1.0, -7.43574447, 24.29723327,
-45.56997062, 53.65490541, -40.61192091,
19.29833524, -5.26385483, 0.63101739};
void setup()
{
init_dac();
MsTimer2::set(retardo, muestreo);
MsTimer2::start(); //Habilita la interrupción
}
...
Programa IIR rechaza banda
...
void loop()
{
uint16_t val_out;
uint8_t aux1;
float val_filt;
if (estado == HIGH){
//Filtro IIR
val_t8 = val_t7;
val_t7 = val_t6;
val_t6 = val_t5;
val_t5 = val_t4;
val_t4 = val_t3;
val_t3 = val_t2;
val_t2 = val_t1;
val_t1 = val_t0;
val_t0 = analogRead(adc_ch);
...
Programa IIR rechaza banda
...
val_filt = coef_b[0] * val_t0 + coef_b[1] * val_t1 +
coef_b[2] * val_t2 + coef_b[3] * val_t3 +
coef_b[4] * val_t4 + coef_b[5] * val_t5 +
coef_b[6] * val_t6 + coef_b[7] * val_t7 +
coef_b[8] * val_t8 - (coef_a[1] * y_t1 +
coef_a[2] * y_t2 + coef_a[3] * y_t3 +
coef_a[4] * y_t4 + coef_a[5] * y_t5 +
coef_a[6] * y_t6 + coef_a[7] * y_t7 +
coef_a[8] * y_t8);
y_t8 = y_t7;
y_t7 = y_t6;
y_t6 = y_t5;
y_t5 = y_t4;
y_t4 = y_t3;
y_t3 = y_t2;
y_t2 = y_t1;
y_t1 = val_filt;
...
Programa IIR rechaza banda
...
// escribir valor de salida en DAC_10
val_out = int(val_filt); //Salida del filtro
//escribe_dac(val_t0); //Salida directa, del ADC
escribe_dac(val_out);
estado = LOW;
}
}
void muestreo()
{
estado = HIGH; //Variable estado
}
...
Programa IIR rechaza banda
...
void init_dac(void)
{
//Bits de DAC y LE como salidas
DDRD = 0xFF;
DDRB |= (1 << PB0) | (1 << PB1);
DDRB |= (1 << PB2); //LE
...
Programa IIR rechaza banda
...
void escribe_dac(uint16_t val_adc)
{
uint8_t aux1;
PORTD = lowByte(val_adc); // Bits 0 a 7 del DAC
aux1 = highByte(val_adc) & ((1 << 0) | (1 << 1));
//Bit 8 del DAC
if((aux1 & (1 << 0)) != 0)
PORTB |= (1 << PB0);
else
PORTB &= ~(1 << PB0);
//Bit 9 del DAC
if((aux1 & (1 << 1)) != 0)
PORTB |= (1 << PB1);
else
PORTB &= ~(1 << PB1);
float x3n = 0;
float x3n_1 = 0;
float x3n_2 = 0;
float y3n = 0;
float y3n_1 = 0;
float y3n_2 = 0;
float x4n = 0;
float x4n_1 = 0;
float x4n_2 = 0;
float y4n = 0;
float y4n_1 = 0;
float y4n_2 = 0;
...
Filtro IIR rechaza banda SOS
...
//fs=500Hz, fcl=8Hz, fch=22Hz, orden 4, BR, Butter, SOS, IIR
const float sos0[6] = {0.79436603, -1.56664852, 0.79436603,
1.0, -1.77928987, 0.81912041};
const float sos1[6] = { 1.0, -1.9721998, 1.0, 1.0, -1.86438897,
0.88096273};
const float sos2[6] = { 1.0, -1.9721998, 1.0, 1.0, -1.83940362,
0.90790429};
const float sos3[6] = { 1.0, -1.9721998, 1.0, 1.0, -1.95266201,
0.96315455};
void setup()
{
init_dac();
MsTimer2::set(retardo, muestreo);
MsTimer2::start(); //Habilita la interrupción
}
...
Filtro IIR rechaza banda SOS
...
void loop()
{
uint16_t val_out;
uint8_t aux1;
float val_filt;
if (estado == HIGH)
{
//Filtro IIR
x1n_2 = x1n_1; //Primera sección
x1n_1 = x1n;
x1n = analogRead(adc_ch);
y1n = sos0[0] * x1n + sos0[1] * x1n_1 + sos0[2] * x1n_2
- (sos0[4] * y1n_1 + sos0[5] * y1n_2);
y1n_2 = y1n_1;
y1n_1 = y1n;
...
Filtro IIR rechaza banda SOS
...
x2n_2 = x2n_1;
x2n_1 = x2n;
x2n = y1n; //Salida de la sección anterior,
//entrada del módulo actual
y2n = sos1[0] * x2n + sos1[1] * x2n_1 + sos1[2] * x2n_2
- (sos1[4] * y2n_1 + sos1[5] * y2n_2);
y2n_2 = y2n_1;
y2n_1 = y2n;
x3n_2 = x3n_1;
x3n_1 = x3n;
x3n = y2n; //Salida de la sección anterior,
//entrada del módulo actual
y3n = sos2[0] * x3n + sos2[1] * x3n_1 + sos2[2] * x3n_2
- (sos2[4] * y3n_1 + sos2[5] * y3n_2);
y3n_2 = y3n_1;
y3n_1 = y3n;
...
Filtro IIR rechaza banda SOS
...
x4n_2 = x4n_1;
x4n_1 = x4n;
x4n = y3n; //Salida de la sección anterior,
//entrada del módulo actual
y4n = sos3[0] * x4n + sos3[1] * x4n_1 + sos3[2] * x4n_2
- (sos3[4] * y4n_1 + sos3[5] * y4n_2);
y4n_2 = y4n_1;
y4n_1 = y4n;
// escribir valor de salida en DAC_10
val_out = int(y4n); //Salida del filtro
//val_out = int(val_t0); //Salida directa, del ADC
escribe_dac(val_out);
estado = LOW;
}
}
...
Filtro IIR rechaza banda SOS
...
void muestreo()
{
estado = HIGH; //Variable estado
}
void init_dac(void)
{
//Bits de DAC y LE como salidas
DDRD = 0xFF;
DDRB |= (1 << PB0) | (1 << PB1);
DDRB |= (1 << PB2); //LE
# Frecuencia de Nyquist
frec_nyq = frec_muestreo / 2.
●
Reay, D. S. (2016). Digital signal processing using the
ARM® cortex®-M4. Wiley.
https://doi.org/10.1002/9781119078227
●
Weckesser, W (2016). Signal Processing with SciPy:
Linear Filters.
https://warrenweckesser.github.io/papers/weckesser-sci
py-linear-filters.pdf
●
Palacherla, A. (1997). AN540. Implementing IIR Digital
Filters. Microchip Technology Inc.
Referencias
●
Quezada, E. A. (2022).Procesamiento Digital de
Señales en Tiempo Real Usando Microcontroladores
STM32 y Python. Univalle.
https://www.academia.edu/79826525/Procesamiento_D
igital_de_SeC3%B1ales_en_Tiempo_Real_Usando_Mi
crocontroladores_STM32_y_Python
●
Signal processing (scipy.signal).
https://docs.scipy.org/doc/scipy/reference/signal.html