Está en la página 1de 73

Tema 15: Filtros Digitales

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);

delay(2); //Retardo para frecuencia de muestreo


}

...
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

//Bits de DAC y LE en cero


PORTD = 0x00;
PORTB &= ~(1 << PB0) & ~(1 << PB1);
PORTB &= ~(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);

PORTB |= (1 << PB2); //Pulso LE


_delay_us(10);
PORTB &= ~(1 << PB2);
}
Circuito mejorado


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 escribe_dac(uint16_t val_adc);


void init_dac(void);

const int retardo = 2; //Retardo 2 ms, f_muestreo = 500 Hz


boolean estado = LOW;
...
Programa DAC_10 mejorado
...
void setup()
{
init_dac();

MsTimer2::set(retardo, muestreo); //Configura Timer2


MsTimer2::start(); //Habilita la interrupción
}

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

//Bits de DAC y LE en cero


PORTD = 0x00;
PORTB &= ~(1 << PB0) & ~(1 << PB1);
PORTB &= ~(1 << PB2); //LE
}
...
Programa DAC_10 mejorado
...
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);

PORTB |= (1 << PB2); //Pulso LE


_delay_us(10);
PORTB &= ~(1 << PB2);
}
Filtros FIR
Filtros FIR


Filtro de respuesta a impulso finita.

Tiene la forma:
N −1
y (n) = ∑ h(k ) x(n−k )
k=0

y (n): Salida del filtro en el momento n


h(k): coeficiente k del filtro
x (n−k): entrada en el momento n−k

Por ejemplo , para N =4


y (n) = h(0) x(n) + h(1) x (n−1) + h(2) x (n−2) + h(3) x (n−3)
Programa FIR paso bajo
Programa que implementa fitro FIR paso bajo con 15 taps.
/*
Programa filtro_FIR_dac_10_lp_01
-FIR paso bajo con 15 taps
*/
#include <MsTimer2.h>

#define adc_ch 0

void escribe_dac(uint16_t val_adc);


void init_dac(void);

const int retardo = 2; //Retardo 2 ms, f_muestreo = 500 Hz


boolean estado = LOW;
float val_t0; //Valor ADC actual t0
float val_t1 = 0; //Valor ADC t-1
float val_t2 = 0; //Valor ADC t-2
float val_t3 = 0;
...
Programa FIR paso bajo
...
float val_t4 = 0;
float val_t5 = 0;
float val_t6 = 0;
float val_t7 = 0;
float val_t8 = 0;
float val_t9 = 0;
float val_t10 = 0;
float val_t11 = 0;
float val_t12 = 0;
float val_t13 = 0;
float val_t14 = 0;

const float coef[15] = {0.0093741, 0.01524899, 0.0316855,


0.05610993, 0.0839091, 0.10944318,
0.12734291, 0.1337726, 0.12734291,
0.10944318, 0.0839091, 0.05610993,
0.0316855, 0.01524899, 0.0093741};
//fs = 500 Hz, fc = 10Hz, 15 taps
...
Programa FIR paso bajo
...
void setup()
{
init_dac();

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

//Bits de DAC y LE en cero


PORTD = 0x00;
PORTB &= ~(1 << PB0) & ~(1 << PB1);
PORTB &= ~(1 << PB2); //LE
}
...
Programa FIR paso bajo
...
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);

PORTB |= (1 << PB2); //Pulso LE


_delay_us(10);
PORTB &= ~(1 << PB2);
}
Coeficientes para filtros FIR


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 bajo


frec_corte = 10.0 #Frecuencia de corte en Hz

# Usar firwin para crear un filtro FIR paso bajo


#fir_coef = signal.firwin(num_taps, frec_corte/frec_nyq)
fir_coef = signal.firwin(num_taps, frec_corte,
fs=frec_muestreo) #Forma recomendada
print("Coeficientes filtro paso bajo")
print(fir_coef)
...
Coeficientes para filtros FIR

...
# Filtro paso alto
# La frecuencia de corte del filtro: Hz
frec_corte = 8.0 #Frecuencia de corte en Hz

# Usar firwin para crear un filtro FIR paso alto


# No funciona con número de coeficientes par.
#fir_coef = signal.firwin(num_taps, frec_corte/frec_nyq,
pass_zero = False)

fir_coef = signal.firwin(num_taps, frec_corte, pass_zero =


'highpass', fs=frec_muestreo) #Forma recomendada

print("Coeficientes filtro paso alto")


print(fir_coef)

...
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

# Usar firwin para crear un filtro FIR pasa banda


#fir_coef = signal.firwin(num_taps,
[frec_corte_baja/frec_nyq, frec_corte_alta/frec_nyq],
pass_zero = False)
fir_coef = signal.firwin(num_taps, [frec_corte_baja,
frec_corte_alta], pass_zero = 'bandpass', fs=frec_muestreo)

print("Coeficientes filtro pasa banda")


print(fir_coef)
...
Coeficientes para filtros FIR

...
# 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

# Usar firwin para crear un filtro FIR rechaza banda


# No funciona con número de coeficientes par.
#fir_coef = signal.firwin(num_taps,
[frec_corte_baja/frec_nyq, frec_corte_alta/frec_nyq])

fir_coef = signal.firwin(num_taps, [frec_corte_baja,


frec_corte_alta], fs=frec_muestreo) #Forma recomendada
print("Coeficientes filtro rechaza banda")
print(fir_coef)
Filtros IIR

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:

y (n): Salida del filtro en el momento n


y (n−l): Salida del filtro en el momento n−l
x (n−k): entrada en el momento n−k
b k : coeficiente k (entrada) del filtro
al : coeficiente l (salida) del filtro
Programa IIR paso bajo
Programa que implementa fitro IIR paso bajo de orden 2.
/*
Programa filtro_IIR_dac_10_lp_01
-IIR paso bajo de orden 2.
*/
#include <MsTimer2.h>

#define adc_ch 0

void escribe_dac(uint16_t val_adc);


void init_dac(void);

const int retardo = 2; //Retardo 2 ms, f_muestreo = 500 Hz


boolean estado = LOW;
float val_t0; //Valor ADC actual t0
float val_t1 = 0; //Valor ADC t-1
float val_t2 = 0; //Valor ADC t-1
...
Programa IIR paso bajo
...
float y_t1 = 0; //Salida t-1
float y_t2 = 0; //Salida t-2

//fs = 500 Hz, fc = 10 Hz, orden 2


const float coef_b[3] = {0.00362168, 0.00724336, 0.00362168};
const float coef_a[3] = { 1.0, -1.82269493, 0.83718165};

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

//Bits de DAC y LE en cero


PORTD = 0x00;
PORTB &= ~(1 << PB0) & ~(1 << PB1);
PORTB &= ~(1 << PB2); //LE
}
...
Programa IIR paso bajo
...
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);

PORTB |= (1 << PB2); //Pulso LE


_delay_us(10);
PORTB &= ~(1 << PB2);
}
Coeficientes para filtros IIR


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

rp: float, opcional


Para filtros Chebyshev y elípticos, es el rizado
máximo en la banda de paso (dB).

rs: float, opcional
Para filtros Chebyshev y elípticos, es la atenuación
mímima en la bada de rechazo (dB).

btype: {‘bandpass’, ‘lowpass’, ‘highpass’,
‘bandstop’}, opcional

El tipo de filtro. Por defecto es ‘bandpass’.
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.

#Frecuencia de Nyquist de la señal


frec_nyq = frec_muestreo / 2.

# Filtro paso bajo


frec_corte = 10.0 #Frecuencia de corte en Hz

# Usar iirfilter para crear un filtro IIR paso bajo


#coef_b, coef_a = signal.iirfilter(orden,
frec_corte/frec_nyq, btype='low', analog=0,
ftype='butter', output='ba')
...
Coeficientes para filtros IIR


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

# Usar iirfilter para crear un filtro IIR paso alto


#coef_b, coef_a = signal.iirfilter(orden,
frec_corte/frec_nyq, btype='high',
analog=0, ftype='butter', output='ba')

#Forma alternativa, recomendada


coef_b, coef_a = signal.iirfilter(orden, frec_corte,
btype='high', analog=0,
ftype='butter', output='ba',
fs=frec_muestreo)

print("Filtro IIR paso alto")


print("b:", coef_b)
print("a:", coef_a)
...
Coeficientes para filtros IIR
...
# Filtro pasa banda
frec_corte_baja = 12.0 #Frecuencia de corte baja en Hz
frec_corte_alta = 22.0 #Frecuencia de corte alta en Hz

# Usar iirfilter para crear un filtro IIR pasa banda


#coef_b, coef_a = signal.iirfilter(orden,
[frec_corte_baja/frec_nyq, frec_corte_alta/frec_nyq],
btype='band', analog=0, ftype='butter', output='ba')
#Forma alternativa, recomendada
coef_b, coef_a = signal.iirfilter(orden, [frec_corte_baja,
frec_corte_alta],btype='band', analog=0,
ftype='butter', output='ba', fs=frec_muestreo)

print("Filtro IIR pasa banda")


print("b:", coef_b)
print("a:", coef_a)

...
Coeficientes para filtros IIR
...
# Filtro rechaza banda
frec_corte_baja = 8.0 #Frecuencia de corte en Hz
frec_corte_alta = 22.0

# Usar iirfilter para crear un filtro IIR rechaza banda


#coef_b, coef_a = signal.iirfilter(orden,
[frec_corte_baja/frec_nyq, frec_corte_alta/frec_nyq],
btype='stop', analog=0, ftype='butter', output='ba')
#Forma alternativa, recomendada
coef_b, coef_a = signal.iirfilter(orden, [frec_corte_baja,
frec_corte_alta],btype='stop', analog=0,
ftype='butter', output='ba', fs=frec_muestreo)

print("Filtro IIR rechaza banda")


print("b:", coef_b)
print("a:", coef_a)
Filtros IIR - SOS


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

void escribe_dac(uint16_t val_adc);


void init_dac(void);

const int retardo = 2; //Retardo 2 ms, f_muestreo = 500 Hz


boolean estado = LOW;
float val_t0; //Valor ADC actual t0
float val_t1 = 0; //Valor ADC t-1
float val_t2 = 0;
...
Programa IIR rechaza banda
...
float val_t3 = 0;
float val_t4 = 0;
float val_t5 = 0;
float val_t6 = 0;
float val_t7 = 0;
float val_t8 = 0;

float y_t1 = 0; //Salida t-1


float y_t2 = 0; //Salida t-2
float y_t3 = 0;
float y_t4 = 0;
float y_t5 = 0;
float y_t6 = 0;
float y_t7 = 0;
float y_t8 = 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

//Bits de DAC y LE en cero


PORTD = 0x00;
PORTB &= ~(1 << PB0) & ~(1 << PB1);
PORTB &= ~(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);

PORTB |= (1 << PB2); //Pulso LE


_delay_us(10);
PORTB &= ~(1 << PB2);
}
Filtro IIR rechaza banda SOS
Programa que implementa fitro IIR rechaza banda de orden 4 SOS.
/*
Programa filtro_IIR_dac_10_br_sos_02
-IIR rechaza banda de orden 4 con secciones de segundo orden
*/
#include <MsTimer2.h>
#define adc_ch 0
void escribe_dac(uint16_t val_adc);
void init_dac(void);
const int retardo = 2; //Retardo 2 ms, f_muestreo = 500 Hz
boolean estado = LOW;
// Secciones de segundo orden
float x1n = 0;
float x1n_1 = 0;
float x1n_2 = 0;
float y1n = 0;
float y1n_1 = 0;
float y1n_2 = 0;
...
Filtro IIR rechaza banda SOS
...
float x2n = 0;
float x2n_1 = 0;
float x2n_2 = 0;
float y2n = 0;
float y2n_1 = 0;
float y2n_2 = 0;

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

//Bits de DAC y LE en cero


PORTD = 0x00;
PORTB &= ~(1 << PB0) & ~(1 << PB1);
PORTB &= ~(1 << PB2); //LE
}
...
Filtro IIR rechaza banda SOS
...
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);

PORTB |= (1 << PB2); //Pulso LE


_delay_us(10);
PORTB &= ~(1 << PB2);
}
Coeficientes filtros IIR - SOS
import scipy.signal as signal
sample_rate = 500. #Frecuencia de muestreo en Hz.
orden = 4 #Orden del filtro.

# Frecuencia de Nyquist
frec_nyq = frec_muestreo / 2.

# Filtro paso bajo


frec_corte = 10.0 #Frecuencia de corte en Hz

#sos = signal.iirfilter(orden, frec_corte/frec_nyq,


btype='low', analog=0, ftype='butter', output='sos')
sos = signal.iirfilter(orden, frec_corte, btype='low',
analog=0,ftype='butter', output='sos',
fs=frec_muestreo)

print("Filtro IIR paso bajo")


print("sos: ", sos)
...
Coeficientes filtros IIR - SOS
...
# Filtro paso alto
frec_corte = 10.0 #Frecuencia de corte en Hz

# Usar iirfilter para crear un filtro IIR paso alto


#sos = signal.iirfilter(orden, frec_corte/frec_nyq,
btype='high', analog=0, ftype='butter', output='sos')
sos = signal.iirfilter(orden, frec_corte, btype='high',
analog=0,ftype='butter', output='sos',
fs=frec_muestreo)

print("Filtro IIR paso alto SOS")


print("sos: ", sos)
...
Coeficientes filtros IIR - SOS
...
# Filtro pasa banda
frec_corte_baja = 12.0 #Frecuencia de corte en Hz
frec_corte_alta = 22.0

# Usar iirfilter para crear un filtro IIR pasa banda


#sos = signal.iirfilter(orden, [frec_corte_baja/frec_nyq,
frec_corte_alta/frec_nyq], btype='band', analog=0,
ftype='butter', output='sos')
sos = signal.iirfilter(orden, [frec_corte_baja,
frec_corte_alta], btype='band', analog=0,
ftype='butter', output='sos', fs=frec_muestreo)

print("Filtro IIR pasa banda SOS")


print("sos: ", sos)
...
Coeficientes filtros IIR - SOS
...
# Filtro rechaza banda
cutoff_hz_low = 8.0 #Frecuencia de corte en Hz
cutoff_hz_high = 22.0

# Usar iirfilter para crear un filtro IIR rechaza banda


#sos = signal.iirfilter(orden, [frec_corte_baja/frec_nyq,
frec_corte_alta/frec_nyq],btype='stop', analog=0,
ftype='butter', output='sos')
sos = signal.iirfilter(orden, [frec_corte_baja,
frec_corte_alta], btype='stop', analog=0,
ftype='butter', output='sos', fs=frec_muestreo)

print("Filtro IIR rechaza banda SOS")


print("sos: ", sos)
Referencias


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

También podría gustarte