4.3 FIR – Respuesta de frecuencia y superposición

[ ejercicio bk ] [ algoritmo_bk ] [ ejercicio_xn ] [ algoritmo_xn ]
..

Para sistemas lineales invariantes en el tiempo, LTI, las entradas senoidales complejas tienen como respuesta otra señal senoidal de la misma frecuencia pero con diferente magnitud y fase. TODOS los sistemas LTI tienen la propiedad «entrada-sinusoide» genera una «salida-sinusoide».

Para un filtro FIR LTI, ante una entrada discreta en tiempo tipo señal exponencial compleja, la salida también es una señal discreta en tiempo, tipo exponencial compleja con diferente amplitud, de la misma frecuencia.

|H(e^{j \omega})| = \sum _{k=0}^{M} b_k e^{-j\omega k} = \sum _{k=0}^{M} h[k] e^{-j\omega k} y[n] = |H(e^{j \omega})| x[n] \text{ ; para } x[n] = A e^{j\varphi}e^{-j\omega n}

..


1. Ejercicio bk

Referencia: McClellan Ejemplo 6.1 y 6.2 p217

Considere un sistema LTI con coeficientes de la ecuación de diferencias bk = [1,2,1]. Al convertirlo en la función respuesta de frecuencias del sistema H(ω) se tiene:

H(e^{j \omega}) = 1 + 2 e^{-j\omega} + e^{-j \omega 2}

como bk es simétrico, se obtiene como factor común e(-jω) para simplificar la expresió con un coseno.

= e^{-j \omega} \Big( e^{j \omega} + 2 + e^{-j \omega} \Big) = e^{-j \omega} \Big( 2 +2 \cos(\omega) \Big)

donde la magnitud es:

|H(e^{j \omega})|= \Big( 2 +2 \cos(\omega) \Big)

y la fase:

\angle H(e^{j \omega})= e^{-j \omega}

Al disponer de una señal de entrada con una frecuencia de ω=π/3:

x[n] = 2 e^{j \pi /4} e^{j(\pi /3)n}

se evalúa la magnitud  de |H|:

|H(e^{j \pi /3})|= \Big( 2 +2 \cos(\pi /3) \Big) = 3

y la fase de ∠H:

\angle H(e^{j \pi /3 })= e^{-j \pi/3}

siendo y[n] = (H)(x[n])

y[n] = 3 e^{-j\pi /3}\Big( 2 e^{j \pi /4} e^{j(\pi /3)n} \Big) = (3)(2) e^{j \pi /4-j\pi /3} e^{j\pi /3 n} = 6 e^{-j \pi /12} e^{j\pi /3 n} = 6 e^{j \pi /4} e^{j\pi(n-1) /3}

la salida del sistema es igual a la entrada, multiplicada por 3 y un cambio de fase a -π/3 que es un retraso de una muestra. Recordando que esto aplica cuando bk es simétrico y la entrada es una exponencial compleja.

[ ejercicio bk ] [ algoritmo_bk ] [ ejercicio_xn ] [ algoritmo_xn ]
..


2. Algoritmo bk en Python

Primero se analiza la simetría del vector bk, invirtiendo el vector y restando de su forma original, si todos los resulados son ceros, el vector es simétrico.

Acorde con la simetría de bk se procede a la creación de H y luego yn a partir de xn.

Para xn en el algoritmo, se requiere usar la dsp.euler_args_one_term() para dominio del tiempo contínuo t de la Unidad 1.4 Espectro – Suma de sinusoides y la fórmula de Euler. La función en telg1034.py amplía el uso al dominio de tiempo discreto n al sustituir la variable independiente con las siguientes instrucciones y se obtiene el resultado esperado.

    # revisa si unasenal es discreta con n, Unidad 4 Filtros Digitales
    esdiscreta = False
    varindepend = X.free_symbols
    if (n in varindepend) and not(t in varindepend):
        X = X.subs(n,t)
        esdiscreta = True
    # analiza unasenal con t

El resultado con el algoritmo es:

bk_simetrico: True
H_magn  : exp(I*w) + 2 + exp(-I*w)
H_magcos: 2*cos(w) + 2
H_fase  : -w
  H : (2*cos(w) + 2)*exp(-I*w)
x[n]: 2*exp(I*pi/4)*exp(I*pi*n/3)
wk  : pi/3
y[n]: 6*exp(I*pi/4)*exp(I*pi*(n - 1)/3)
>>>

Instrucciones en Python

# ejemplo 6.1 p217 FIR - Respuesta de frecuencias
# telg1034 DSP fiec-espol edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
import telg1034 as dsp

# variables continuas
from telg1034 import t,A,w,f,p,pi,DosPi,I,equivalentes
# variables discretas
from telg1034 import n

# INGRESO
bk = [1,2,1]
#bk = [1,-2,4,-2,1]

xn = 2*sym.exp(I*pi/4)*sym.exp(I*(pi/3)*n)

# PROCEDIMIENTO
M = len(bk)-1
# revisa simetria bk
bk = np.array(bk)
H_factor = 0
sumainvertida = np.sum(np.abs(bk-np.flip(bk)))
bk_simetrico = False
if sumainvertida == 0 and M>1:
    bk_simetrico = True
    H_factor = sym.sympify(M)/2

# respuesta de frecuencia
H = sym.S.Zero
for k in range(0,M+1,1):
    H = H + bk[k]*sym.exp(-I*w*(k))

# H cuando bk es simetrico.
H_magn = H ; H_magcos = 0 ; H_fase = 0
if bk_simetrico:
    H_magn = sym.expand(H/sym.exp(-I*w*H_factor))
    H_magcos = H_magn.rewrite(sym.cos)
    H_fase = -w*H_factor
    H = H_magcos*sym.exp(I*H_fase)

# señal de entrada x[n]
xn_arg = dsp.euler_args_one_term(xn)
wk = xn_arg['freq_rad']

# señal de salida y[n]
if bk_simetrico:
    n_veces = H_fase/w
    Ampl = H_magcos.subs(w,wk)*xn_arg['amplitud'] 
    yn = Ampl*sym.exp(I*xn_arg['fase'])*sym.exp(I*wk*(n+n_veces))
else:
    yn = xn*H.subs(w,wk)
    
# SALIDA
print('bk_simetrico:',bk_simetrico)
print('H_magn  :',H_magn)
print('H_magcos:',H_magcos)
print('H_fase  :',H_fase)
print('  H :',H)
print('x[n]:',xn)
print('wk  :',wk)
print('y[n]:',yn)

[ ejercicio bk ] [ algoritmo_bk ] [ ejercicio_xn ] [ algoritmo_xn ]
..


3. Ejercicio x[n] de varias sinusoides

Referencia: McClellan Ejemplo 6.4 p220

Para el filtro FIR con coeficientes b[k] = [1,2,1] , encuentre la señal de salida cuando la señal de entrada tiene varios componentes.

x[n] = 4 + 3 \cos \Big( \frac{\pi}{3} n - \frac{pi}{2} \Big) + 3 \cos \Big(\frac{7\pi}{8}n \Big)

El ejercicio se desarrolla término a término por tener diferentes frecuencias. Se aplica el principio de superposición.

[ ejercicio bk ] [ algoritmo_bk ] [ ejercicio_xn ] [ algoritmo_xn ]
..


4. Algoritmo X[n] en Python

Para el ejercicio, xn tiene una señal senoidal mas general y de varios componentes. Por lo que el procedimiento del algoritmo anterior se amplía para cada uno de los componentes.

La señal de entrada se debe revisar sus componentes sumas, procediendo de forma semejante a lo realizado en la Unidad 1.2 Señal – Periodo y Desplazamiento en tiempo. La función dsp.x_list_term_Add() para separar los términos suma entrega su resultado tanto para la variable t ó n.

Sin embargo la obtención de los parámetros de cada término suma de xn con la función dsp.cos_args_one_term(),  debe ampliar la función de t a n, semejante al ejercicio que precede con las siguientes instrucciones.

    # revisa si unasenal es discreta con n, Unidad 4. Filtros digitales
    esdiscreta = False
    varindepend = x.free_symbols
    if (n in varindepend) and not(t in varindepend):
        x = x.subs(n,t)
        esdiscreta = True
    # analiza unasenal con t

Aplicando H en cada término xn acorde a la simetría de bk, se tiene el siguiente resultado con el algoritmo es:

H_magn  : exp(I*w) + 2 + exp(-I*w)
H_magcos: 2*cos(w) + 2
H_fase  : -w
  H : (2*cos(w) + 2)*exp(-I*w)
x[n]: 3*cos(7*pi*n/8) + 3*cos(pi*n/3 - pi/2) + 4
y[n]: 0.456722804932279*cos(pi*(7*n/8 - 7/8)) + 9*cos(pi*(n - 1)/3 - pi/2) + 16
>>>

Instrucciones en Python

# ejemplo 6.4 p220 FIR - Respuesta de frecuencias a varias senoidales
# telg1034 DSP fiec-espol edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
import telg1034 as dsp

# variables continuas
from telg1034 import t,A,w,f,p,pi,DosPi,I,equivalentes
# variables discretas
from telg1034 import n

# INGRESO
bk = [1,2,1]
#bk = [1,-2,4,-2,1]

#xn = 3*sym.cos(n*pi/3 - pi/2)
xn = 4 + 3*sym.cos(n*pi/3 - pi/2) + 3*sym.cos(7*pi*n/8)

# PROCEDIMIENTO
M = len(bk)-1
# revisa simetria bk
bk = np.array(bk)
H_factor = 0
sumainvertida = np.sum(np.abs(bk-np.flip(bk)))
bk_simetrico = False
if sumainvertida == 0 and M>1:
    bk_simetrico = True
    H_factor = sym.sympify(M)/2

# respuesta de frecuencia
H = sym.S.Zero
for k in range(0,M+1,1):
    H = H + bk[k]*sym.exp(-I*w*(k))

# H cuando bk es simetrico.
H_magn = H ; H_magcos = 0 ; H_fase = 0
if bk_simetrico:
    H_magn = sym.expand(H/sym.exp(-I*w*H_factor))
    H_magcos = H_magn.rewrite(sym.cos)
    H_fase = -w*H_factor
    H = H_magcos*sym.exp(I*H_fase)

# señal de entrada x[n]
x_senal = dsp.x_list_term_Add(xn) # términos suma
x_conteo = len(x_senal)
yn = sym.S.Zero
for i in range(0,x_conteo,1):
    unasenal = x_senal[i]
    cond1 = unasenal.has(sym.cos) or unasenal.has(sym.sin)
    cond2 = not(unasenal.has(n))
    if cond1 or cond2:
        xn_arg = dsp.cos_args_one_term(unasenal)
        Ak = xn_arg['amplitud']
        wk = xn_arg['freq_rad']
        fk = xn_arg['fase']
        if bk_simetrico:
            H_magnk = dsp._float_is_int(H_magcos.subs(w,wk).evalf())
            H_fasek = H_fase.subs(w,wk)
            if wk!=sym.S.Zero:
                n_veces = H_fasek/wk
                yk = H_magnk*Ak*sym.cos(wk*(n+n_veces) + fk)
            else:
                yk = H_magnk*Ak
        else:
            yk = H.subs(w,wk)*unasenal
    else: # no es senoidal o constante
        yk = H*unasenal
        print(' ____revisar término:',unasenal.subs(t,n))
    # principio de superposición
    yn = yn +yk

# SALIDA
print('H_magn  :',H_magn)
print('H_magcos:',H_magcos)
print('H_fase  :',H_fase)
print('  H :',H)
print('x[n]:',xn)
print('y[n]:',yn)

[ ejercicio bk ] [ algoritmo_bk ] [ ejercicio_xn ] [ algoritmo_xn ]

4.2 FIR – Filtros y Convolución

[ convolución ] [ ejercicio ] [ algoritmo ]
..


Referencia: McClellan 5.4.3 p181

Una expresión general para salidas de Filtros FIR se obtienen de los términos de respuesta al impulso. Si los coeficientes de bk son los mismos valores de respuesta al impulso se puede expresar como una suma de convolución, que es una operación entre dos secuencias.

y[n] = \sum_{k=0}^{M} h[k] x[n-k] y[n] =h[k] * x[n] =\sum_{k=-\infty}^{\infty} h[k] x[n-k]

Lo que expresa que la secuencia de salida y[n] se obtiene al aplicar la convolución de la respuesta al impulso h[n] con la señal de entrada x[n]

[ convolución ] [ ejercicio ] [ algoritmo ]
..


1. Ejercicio

Referencia: McClellan 5-4.3.3 p184

Evaluar la convolución de hn que es una secuencia de 11 puntos, con xn que es una secuencia de 51 puntos. Use el vector hn como respuesta al impulso de un sistema de medias móviles de 11 puntos.

x[n]= \sin(0.7*\pi*n) \text{ ; } 0 \le n \le 50 h[n]= \begin{cases} 1/11 & 0 \le n \le 40 \\0 & n<0\end{cases}

y[n] = x[n]*h[n]

Al aplicar el algoritmo de media móvil se compara el resultado con el algoritmo de convolución.

muestreo: 51  ; tamaño ki: 73
x[n]: (Heaviside(n) - Heaviside(n - 51))*sin(0.07*pi*n)
h[n]: Heaviside(n)/11 - Heaviside(n - 11)/11
>>>

FIR media movil Convolución[ convolución ] [ ejercicio ] [ algoritmo ]

..


2. Algoritmo en Python

Referencia: [1] LTI DT – Convolución de sumas – Python. Blog Señales y Sistemas. [2] https://numpy.org/doc/stable/reference/generated/numpy.convolve.html

# ejemplo 5-4.3.3 p184 FIR - Media Móvil  y convolución
# telg1034 DSP fiec-espol edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
import telg1034 as dsp

# variables continuas
from telg1034 import t,A,w,f,p,pi,DosPi,I,equivalentes
# variables discretas
from telg1034 import n

# INGRESO
u = sym.Heaviside(n)
# señal como suma de las partes
muestrasN = 50 + 1  # # intervalo [0,50]
gn = (u-u.subs(n,n-muestrasN)) 
xn = sym.sin(0.07*pi*n)*gn

# FIR Media Móvil
ventana = 10 + 1 # intervalo [0,10]
hn = (u-u.subs(n,n-ventana))/ventana 

# PROCEDIMIENTO ----------------
# muestreo x[n]
ki = np.arange(-ventana,muestrasN + ventana,1,dtype=int)
xni = sym.lambdify(n,xn, modules=equivalentes)
xki = xni(ki)

hni = sym.lambdify(n,hn, modules=equivalentes)
hki = hni(ki) 

# FIR Media Móvil
yki = np.convolve(hki,xki)
yki = yki[ventana:len(xki)+ventana] # intervalo ki

# SALIDA
print('muestreo:',muestrasN,' ; tamaño ki:',len(ki))
print('x[n]:',xn)
print('h[n]:',hn)

# GRAFICA FIR
plt.subplot(311) # x[n]
plt.stem(ki,xki,linefmt = 'C0:',
         label='x[n]')
plt.xlabel('n')
plt.ylabel('x[n]')
plt.title('FIR Media Móvil con convolución')
plt.legend()

plt.subplot(312) # h[n]
plt.stem(ki,hki,linefmt = 'C1:',label='h[n]')
plt.xlabel('n')
plt.ylabel('h[n]')
plt.legend()

plt.subplot(313) # y[n]
plt.stem(ki,yki,linefmt = 'C2:',label='y[n]')
plt.xlabel('n')
plt.ylabel('y[n]')
plt.legend()
plt.show()

[ convolución ] [ ejercicio ] [ algoritmo ]

4.1 FIR – Filtro de Medias Móviles

[ media móvil ] | ejercicio: [ rectangular ] [ 2 componentes ] [ algoritmo ]
..


Referencia: McClellan 5 p167

Se introduce el análisis para un sistema discreto en tiempo con respuesta de impulso finita,  FIR (Finite Impulse Response), también conocido como filtros FIR.

Un filtro es un sistema con valores de salida resultantes de la suma ponderada de un número finito de valores de una secuencia de entrada. Se define como una operación también conocida como ecuación de diferencias.

1. El filtro de Medias Móviles

Una señal discreta se modifica por medio de un filtro que se determina como un promedio de un intervalo que se desplaza en el tiempo. Para un sistema tipo causal, se tiene:

y[n] = \sum_{k=n-M}^{n} b_{n-k} x[k] = b_{(M)} x[n-M ] + b_{(M-1)} x[n-M+1] + \text{...} + b_{(0)} x[n]

cuando los coeficientes de bk no son iguales, se dice que el promedio o media  móvil es ponderado.

[ media móvil ] | ejercicio: [ rectangular ] [ 2 componentes ] [ algoritmo ]
..


2. Ejemplo de señal rectangular

Referencia: McClellan ejemplo 5.1 p174

Considere un sistema con media móvil para 3 puntos que se expresa como una ventana que desplaza.

y[n] = \sum_{k=n-2}^{n} \frac{1}{3} x[k]

con entrada rectangular entre [0,10]

x[n]= \begin{cases} 1, & 0 \le n \le 10 \\0 , & en otro caso\end{cases} FIR media móvilRef: Señales Escalón unitario μ(t) e Impulso unitario δ(t). blog de Señales y Sistemas

La señal se define como un escalón que se compone de dos señales escalón:

x[n]= \mu [n] -\mu [n-11]

Para el algoritmo se define a partir de μ[n] que en Sympy es Heaviside. Se indican la cantidad de muestras a observar.

# INGRESO
u = sym.Heaviside(n)
# señal como suma de las partes
muestrasN = 10 + 1  # # intervalo [0,10]
xn = u - u.subs(n,n-muestrasN)

# FIR media móvil
ventana = 2 + 1 # intervalo [0,2]
bk = np.ones(ventana, dtype=float)/ventana
causal = True  # causal o no causal

En la media móvil se requiere M=2, si el sistema es causal y el vector bk que son los valores de ponderación. Se obtienen los siguientes resultados:

muestreo: 11  ; tamaño ki: 17
x[n]: Heaviside(n) - Heaviside(n - 11)
bk: [0.33333333 0.33333333 0.33333333]

[ media móvil ] | ejercicio: [ rectangular ] [ 2 componentes ] [ algoritmo ]
..


3. Ejercicio  con señal de dos componentes

Considere la señal con un componente exponencial y otro componente senoidal que se considera ruido o interferencia que degrada la señal a observar. Se pretende minimizar o remover el efecto del componente senoidal

x[n]= \begin{cases} (1-02)^n + \frac{1}{2}\cos(2 \pi n /8 + \pi/4), & 0 \le n \le 40 \\0 , & n<0\end{cases}

Realice el ejercicio con media móvil que tiene una ventana de 7 puntos o M=6.

Usando el algoritmo se tiene el siguiente resultado:

FIR media movil 02

muestreo: 41  ; tamaño ki: 55
x[n]: (1.02**n + 0.5*cos(pi*n/4 + pi/4))*(Heaviside(n) - Heaviside(n - 40))
bk: [0.14285714 0.14285714 0.14285714 0.14285714 
     0.14285714 0.14285714 0.14285714]

El bloque de ingreso para el algoritmo es:

# INGRESO
u = sym.Heaviside(n)
# señal como suma de las partes
muestrasN = 40 + 1  # # intervalo [0,40]
x0 = u - u.subs(n,n-muestrasN)
x1 = 1.02**n +0.5*sym.cos(2*pi*n/8 + pi/4)
xn = x1*x0

# FIR media móvil
ventana = 6 + 1 # intervalo [0,6]
bk = np.ones(ventana, dtype=float)/ventana
causal=True  # causal o no causal

[ media móvil ] | ejercicio: [ rectangular ] [ 2 componentes ] [ algoritmo ]
..


4. Algoritmo en Python

El modelo de algoritmo para los ejercicios  se presenta para la señal rectangular. Para otros ejercicios se actualiza la señal en el bloque de ingreso.

La variable causal=True establece el signo de la ventana deslizante, si el sistema es causal, el signo es negativo.

# ejemplo 5.1 p174 FIR - Media Móvil general
# telg1034 DSP fiec-espol edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import sympy as sym
import telg1034 as dsp

# variables continuas
from telg1034 import t,A,w,f,p,pi,DosPi,I,equivalentes
# variables discretas
from telg1034 import n

# INGRESO
u = sym.Heaviside(n)
# señal como suma de las partes
muestrasN = 10 + 1  # # intervalo [0,10]
xn = u - u.subs(n,n-muestrasN)

# FIR media móvil
ventana = 2 + 1 # intervalo [0,2]
bk = np.ones(ventana, dtype=float)/ventana
causal = True  # causal o no causal

# PROCEDIMIENTO ----------------
# muestreo x[n]
ki = np.arange(-ventana,muestrasN + ventana,1,dtype=int)
xni = sym.lambdify(n,xn, modules=equivalentes)
xki = xni(ki) 

# FIR Media Móvil
causal_sign = +1 # sistema causal
if not(causal): # sistema no causal
    causal_sign = -1
    
# ajuste de intervalo con ventana
yki = np.zeros(muestrasN + 2*ventana,dtype=float)
for i in range(-ventana,muestrasN + 2*ventana,1):
    unaventana = 0
    for k in range(0,ventana,1):
        if (i-causal_sign*k)>=0 and (i-causal_sign*k)<=(muestrasN+ventana):
            unaventana = unaventana + xki[i-causal_sign*k]*bk[k]
    yki[i] = unaventana

# SALIDA
print('muestreo:',muestrasN,' ; tamaño ki:',len(ki))
print('x[n]:',xn)
print('bk:',bk)

# GRAFICA FIR
plt.subplot(211) # x[n]
plt.stem(ki,xki,linefmt = 'C0:',
         label='x[n]')
plt.xlabel('n')
plt.ylabel('x[n]')
plt.title('FIR Media Móvil')
plt.legend()

plt.subplot(212) # y[n]
plt.stem(ki,yki,linefmt = 'C2:',label='y[n]')
plt.xlabel('n')
plt.ylabel('y[n]')
plt.legend()
plt.show()

[ media móvil ] | ejercicio: [ rectangular ] [ 2 componentes ] [ algoritmo ]