Algoritmos y funciones: telg1001.py

Resumen de algoritmos y funciones del curso señales y sistemas. Descargue una copia del archivo como telg1001.py en el directorio de trabajo, importe las funciones y use llamando con fcnm.funcion().

import telg1001 as fcnm

respuesta = fcnm.funcion(parametros)

El contenido de telg1001.py se actualiza cuando al desarrollar un ejercicio se encuentra que se puede mejorar una función manteniendo compatibilidad con lo realizado anteriormente. Se incorpora la referencia al ejercicio como comentario.

# Transformadas de Laplace, funciones
# http://blog.espol.edu.ec/telg1001/
import numpy as np
import sympy as sym
import matplotlib.pyplot as plt
equivalentes = [{'DiracDelta': lambda x: 1*(x==0)},
                {'Heaviside': lambda x,y: np.heaviside(x, 1)},
                'numpy',]
s = sym.Symbol('s')
t = sym.Symbol('t',real=True)

# Transformada de Laplace para f(t) con Sympy-Python
# http://blog.espol.edu.ec/telg1001/transformada-de-laplace-para-ft-con-sympy-python/
def separa_constante(termino):
    ''' separa constante antes de usar
        sym.laplace_transform(term_suma,t,s)
        para incorporarla luego de la transformada
        inconveniente revisado en version 1.11.1
    '''
    constante = 1
    if termino.is_Mul:
        for term_mul in termino.args:
            if not(term_mul.has(t)):
                constante = term_mul
        termino = termino/constante
    return([termino,constante])

...

4.4.5 LTI Laplace – Circuitos electrónicos Activos «Op Amp»

Referencia: Lathi 4.4-1 p382,  Oppenheim 11.50 p896

Se amplian los conceptos de circuitos pasivos analizados con transformadas e Laplace, aplicando a circuitos activos. Se obtienen los circuitos equivalentes o modelos matemáticos y se repiten los procedimientos anteriores.

El elemento activo más conocido es el amplificador operacional  (op amp) que tienen ganancia «muy alta». El  voltaje de salida v2 = – A v1, donde A es del orden de 105 o 106. Un factor importante es que la impedancia de entrada es muy alta del orden de 1012Ω y la impedancia de salida es muy baja (50-100Ω)

La configuración de la ganancia se establece con los resistores Ra y Rb y la forma de conectar las entradas y salidas.

K = 1+\frac{R_a}{R_b} v_2 = K v_1 v_2 = (R_b + R_a) i_o = R_b i_o + R_a i_o v_2 = v_s = Ra i_o = R_a i_o \frac{v_2}{v_1} =\frac{R_b+R_a}{R_a} = 1+\frac{R_b}{R_a} = K

1. Amplificador Operacional en el dominio s

Referencia: Lathi 4.6-5 p399

Dada la alta impedancia del op amp, la corriente de retroalimentación  I(s) fluye solo por los resistores. El voltaje de entrada es cero o muy pequeño dada la ganancia muy grande del op amp. Dadas estas simplificaciones, se aproxima con mucha precisión que:

Y(s) = - I(s) Z_f(s) I(s) = \frac{X(s)}{Z(s)} Y(s) = -\frac{Z_f(s)}{Z(s)} H(s) = -\frac{Z_f(s)}{Z(s)}

1,1 Amplificador Operacional como multiplicador escalar

H(s) = -\frac{R_f}{R}

1,2 Amplificador Operacional como Integrador

Referencia: Oppenheim 11.52 p898

H(s) = \Big(-\frac{1}{RC}\Big) \frac{1}{s}

1,3 Amplificador Operacional como Sumador

Y(s) = - \Big[\frac{R_f}{R_1}X_1(s)+\frac{R_f}{R_2}X_2(s)+\frac{R_f}{R_3}X_3(s) \Big]

Observe que las ganancias del sumador son siempre negativas, hay una inversión de signo en cada señal de entrada.

Y(s) = K_1 X_1(s)+K_2 X_2(s)+K_3 X_3(s)


Ejemplo 1. Implementación con Op-Amp

Referencia: Lathi 4.25 p401

Realizar la implementación de un sistema dado por la función de transferencia H(s)

H(s) = \frac{2s+5}{s^2+4s+10}

El diagrama de bloques de la función de transferencia H(s) es,

Se agrupan algunos elementos como sumadores y sus factores de multiplicación. Para referencia se etiqueta cada punto como señal W(s) en cada punto donde el orden del exponente de ‘s’ es diferente.

Se considera la inversión de signo de la señal de entrada por la configuración del amplificador operacional y el factor K de cada rama a usar.

Se identifica el tipo de op amp a usar y se establecen los valores de los resistores en múltiplos de 10KΩ y los capacitores en el orden de 10 μF.


Ejemplo 1. Desarrollo analítico

Para revisar el comportamiento del circuito, en caso de implementarlo con OpAmps, el resultado de la función de transferencia para el impulso usando el algoritmo de la sección LTI CT Laplace – Ejercicio resuelto para Y(s)=H(s)X(s) con Sympy-Python

 H(s) = P(s)/Q(s):
   2*s + 5   
-------------
 2           
s  + 4*s + 10
 H(s) en factores:
   2*s + 5   
-------------
 2           
s  + 4*s + 10

H(s) parámetros cuadraticos:
(2*s + 5)/(s**2 + 4*s + 10) : 
 {'A': 2.0, 'B': 5.0, 'a': 2.0, 'c': 10.0,
  'r': 2.041241452319315, 'b': 2.449489742783178,
  'theta': -0.20135792079033082}

 h(t) :
/  ___  -2*t    /  ___  \                       \             
|\/ 6 *e    *sin\\/ 6 *t/      -2*t    /  ___  \|             
|------------------------ + 2*e    *cos\\/ 6 *t/|*Heaviside(t)
\           6                                   /             

polosceros:
Q_polos : {-2 - sqrt(6)*I: 1, -2 + sqrt(6)*I: 1}
P_ceros : {-5/2: 1}

Estabilidad de H(s):
 n_polos_real : 0
 n_polos_imag : 2
 enRHP : 0
 unicos : 0
 repetidos : 0
 asintota : estable

 X(s): 
1

Respuesta entrada cero ZIR H(s) y condiciones iniciales
term_cero : 0
ZIR :
0
yt_ZIR :
0

 ZSR respuesta estado cero:
ZSR :
   2*s + 5   
-------------
 2           
s  + 4*s + 10

 ZSR_Qs2 :
 (2*s + 5)/(s**2 + 4*s + 10) :
  {'A': 2.0, 'B': 5.0, 'a': 2.0, 'c': 10.0,
   'r': 2.041241452319315, 'b': 2.449489742783178,
   'theta': -0.20135792079033082}
yt_ZSR :
/  ___  -2*t    /  ___  \                       \             
|\/ 6 *e    *sin\\/ 6 *t/      -2*t    /  ___  \|             
|------------------------ + 2*e    *cos\\/ 6 *t/|*Heaviside(t)
\           6                                   /             

 Y(s)_total = ZIR + ZSR:
   2*s + 5   
-------------
 2           
s  + 4*s + 10

 y(t)_total = ZIR + ZSR:
/  ___  -2*t    /  ___  \                       \             
|\/ 6 *e    *sin\\/ 6 *t/      -2*t    /  ___  \|             
|------------------------ + 2*e    *cos\\/ 6 *t/|*Heaviside(t)
\           6                                   /             
>>>

donde la gráfica de polos muestra que se encuentran todos del lado izquierdo del plano

OpAmpEj01 H(s) Polos

También se muestra la respuesta al impulso h(t) del circuito

Las respuestas fueron obtenidas al usar como bloque de entrada,

# H(s) respuesta impulso
Ps = 2*s+5
Qs = s**2 + 4*s + 10
Hs = Ps/Qs

# X(s) Señal de entrada
xt = d

# condiciones iniciales, [y'(0),y(0)] orden descendente
t0 = 0
cond_inicio = [0, 0] # estado cero no se usan

# Grafica, intervalo tiempo [t_a,t_b]
t_a = -1 ; t_b = 10
muestras = 101  # 51 resolucion grafica

Transformada z – Tabla de Propiedades

Referencia: Schaum Hsu Tabla 4-2 p173. Lathi Tabla 5.2 p509. Oppenheim Tabla 10.3 p793 pdf821,

 

Propiedad señal Transformada z ROC
x[n]
x1[n]
x2[n]
X[z]
X1[z]
X2[z]
R
R1
R2
Aditiva x1[n] + x2[n] X1[z] + X2[z]
Escalabilidad a x[n] a X[z]
Linealidad a_1 x_1[n] + a_2 x_2[n] a_1 X_1[z] + a_2 X_2[z] R’ ⊃R1∩R2
Desplazamiento
en tiempo
x[n-n0] z-n0 X[z] R’ ⊃ R∩{0<|z|<∞}
Multiplicación
por z0n
z0n x[n] X \big(\frac{z}{z_0}\big) R’ = |z0|R
Multiplicación
por ejβn
ejβn x[n] X(e-jβ z) R’ = R
Inversión en tiempo x[-n] X \big(\frac{1}{z}\big) R’ = 1/R
Multiplicación
por n
n x[n] -z \frac{\delta}{\delta z}X(z) R’ = R
Acumulativa \sum_{k=-\infty}^n x[n] \frac{1}{1-z^{-1}} X(z) R’ ⊃ R∩{|z|>1}
Convolución x_1 \circledast z_2 X1[z]X2[z] R’ ⊃R1∩R2
Valor inicial x[0] \lim _{z \rightarrow \infty} X[z]
Valor Final \lim _{N \rightarrow \infty} x[N] \lim _{z \rightarrow 1} (z-1) X[z]
polos de (z-1)X[z] dentro de círculo unitario

Transformadas z – Tabla

Transformada z – Tabla

Referencia: Schaum Hsu Tabla 4-1 p170. Lathi Tabla 5.1 Transformada z p492. Oppenheim tabla 10.2 p776 pdf807

No. x[n] X[z] ROC
1a δ[n] 1 Toda z
1b δ[n-m] z-m Toda z excepto
0 (si m>0) ó
∞ (si m<0)
2a μ[n] \frac{z}{z-1} \frac{1}{1-z^{-1}} |z|>1
2b -μ[-n-1] \frac{z}{z-1} \frac{1}{1-z^{-1}} |z|<1
3 n μ[n] \frac{z}{(z-1)^2} \frac{z^{-1}}{(1- z^{-1})^2} |z|>1
4 n2 μ[n] \frac{z(z+1)}{(z-1)^3}
5 n3 μ[n] \frac{z(z^2 + 4z + 1)}{(z-1)^4}
6a γn μ[n] \frac{z}{z-\gamma} \frac{1}{1-\gamma z^{-1}} |z|>|γ|
6b n μ[-n-1] \frac{z}{z-\gamma} \frac{1}{1-\gamma z^{-1}} |z|<|γ|
7 γn-1 μ[n-1] \frac{1}{z-\gamma}
8a n γn μ[n] \frac{\gamma z}{(z-\gamma)^2} \frac{\gamma z^{-1}}{(1- \gamma z^{-1})^2} |z|>|γ|
8b -n γn μ[-n-1] \frac{\gamma z}{(z-\gamma)^2} \frac{\gamma z^{-1}}{(1- \gamma z^{-1})^2} |z|<|γ|
8c (n+1) γn μ[n] \Big[ \frac{z}{z-\gamma}\Big]^2 \frac{1}{(1- \gamma z^{-1})^2} |z|>|γ|
9 n2 γn μ[n] \frac{\gamma z (z + \gamma)}{(z - \gamma)^3 }
10 \frac{n(n-1)(n-2) \text{...} (n-m+1)}{\gamma^m m!}\gamma^n \mu[n] \frac{ z}{(z-\gamma)^{m+1}}
11a |γ|n cos(βn) μ[n] \frac{ z \big(z-|\gamma | \cos (\beta ) \big)}{z^2-(2|\gamma | \cos (\beta ))z +|\gamma |^2}
11b |γ|n sin(βn) μ[n] \frac{ z |\gamma | \sin (\beta )}{z^2-(2|\gamma | \cos (\beta ))z +|\gamma |^2}
12a r|γ|n cos(βn+θ) μ[n] \frac{ rz[z \cos (\theta) - |\gamma | \cos (\beta -\theta)]}{z^2-(2|\gamma | \cos (\beta ))z +|\gamma |^2}
12b r|γ|n cos(βn+θ) μ[n]
γ = |γ| e
\frac{\big(0.5r e^{j \theta} \big)z}{z - \gamma} + \frac{\big(0.5r e^{-j \theta} \big)z}{z - \gamma^{*}}
12c r|γ|n cos(βn+θ) μ[n] \frac{z(Az +B)}{z^2 + 2az + |\gamma|2}
r = \sqrt{\frac{A^2|\gamma |^2 + B^2 - 2AaB}{|\gamma |^2 - a^2}} \beta = \cos ^{-1} \frac{-a}{|\gamma |}

\theta = tan^{-1} \frac{ Aa - B}{A \sqrt{|\gamma |^2 - a^2}}

13 {an ; 0≤ n ≤ N-1
{0  ; otro caso
\frac{1-a^N z^{-n}}{1-az^{-1}} |z|>0

Transformada z – Tabla de propiedades

7.4 LTI DT Transformada z – Ejemplos con sistemas discretos

2Eva2009TII_T2 LTI DT Dado h[n], y[n] determine x[n]

 

7.3 LTI DT Transformada z – Y[z] componentes de entrada cero y estado cero con Python

Referencia: Lathi Ejemplo 5.5 p510

continuando con la solución del ejercicio de condiciones iniciales,

y[n+2] – 5 y[n+1] + 6 y[n] = 3 x[n+1] + 5 x[n]

con las condiciones iniciales y[-1]=11/16, y[-2]=37/36,
ante una entrada x[n]=(-2)-nμ[n]

Respuesta
total
= respuesta a
entrada cero
+ respuesta a
estado cero

En el ejemplo se encuentra que la solución total de la ecuación de diferencias se puede separar en dos componentes. El primero es generado por las condiciones iniciales y el segundo por la entrada x[n]

\Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] + \Bigg(-3 + \frac{11}{z} \Bigg) = 3\frac{1}{z-0.5}+5\frac{1}{z(z-0.5)} \Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] = - \Bigg(-3 + \frac{11}{z} \Bigg) + \frac{3z+5}{z(z-0.5)} \Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] = -\text{condiciones iniciales} + \text{entrada x[n]}

para simplificar, se multiplica ambos lados por z2

(z^2 - 5 z + 6 ) Y[z] = - z(-3z +11) + \frac{z(3z+5)}{(z-0.5)} (z^2 - 5 z + 6 ) Y[z] = - \text{condiciones iniciales} + \text{entrada x[n]} Y[z] = \frac{- z(-3z +11)}{(z^2 - 5 z + 6 )} + \frac{z(3z+5)}{(z-0.5)(z^2 - 5 z + 6 ) }

respuesta total = (respuesta a entrada cero) + (respuesta estado cero)

continuando luego con el proceso de fracciones parciales y cambio al dominio de tiempo discreto. (realizado en desarrollo analítico).


Instrucciones en Python

Se reutilizan los algoritmos de la sección LTID Transformada z – Fracciones parciales con Python a lo que se añaden las instrucciones de los pasos anteriores.

termino entrada cero:  z**2*(-3.0 + 11.0/z)
termino estado cero:   z*(3*z + 5)/(z - 0.5)

 Yz = (-entrada0 +estado0)/Qz:
   2 /       11.0\   z*(3*z + 5)
- z *|-3.0 + ----| + -----------
     \        z  /     z - 0.5  
--------------------------------
           2                    
          z  - 5*z + 6          

 Yz en fracción:
   /     2               \  
 z*\3.0*z  - 9.5*z + 10.5/  
----------------------------
              / 2          \
(1.0*z - 0.5)*\z  - 5*z + 6/

 Yz en fracciones parciales:
1.73333333333333*z   1.16666666666667*z             1.2*z          
------------------ - ------------------ + -------------------------
   1.0*z - 0.5          0.5*z - 1.0       0.333333333333333*z - 1.0
 
{polos:veces}:  {3: 1, 2: 1}
>>> 

Instrucciones Python

# Transformada z- Fracciones parciales
# Y(z) componentes entrada0 y estado0
# Polos únicos, repetidos y complejos
# Lathi Ejemplo 5.5 p510
import sympy as sym

# INGRESO
z = sym.Symbol('z')

# Hz = Pz/Qz
Pz = 3*z+5
Qz = z**2-5*z+6

# condiciones iniciales ascendente ...,y[-2],y[-1]
inicial = [37/36, 11/6]

# señal de entrada Xz
Xz = z/(z-0.5)

# PROCEDIMIENTO
# coeficientes QD
P = Pz.as_poly(z)
Q = Qz.as_poly(z)
Q_raiz  = sym.roots(Q)
Q_coef  = Q.coeffs()
Q_grado = Q.degree()

Hz = Pz/Qz

# Términos de condiciones iniciales
m0 = len(inicial)
termino0 = 0 
for j in range(0,Q_grado,1):
    terminogrado = 0
    for i in range(m0-1-j,m0,1):
        terminogrado = terminogrado + inicial[i]*(z**((m0-1-j)-i ))
    termino0 = termino0 + terminogrado*Q_coef[j+1]
    
# salida y(t) a entrada x(t)
entrada0 = termino0*(z**2)
estado0  = sym.simplify(Pz*Xz)

# ecuación lado derecho
derecha = sym.simplify(-entrada0 + estado0)
fraccion = derecha.as_numer_denom()
numerador = sym.simplify(fraccion[0])
denominador = sym.simplify(fraccion[1])

# senal resultante
Yzf = (numerador/denominador)/Qz

# fracciones parciales modificadas
Yzz = sym.simplify(Yzf/z)
Yzm = Yzz.apart()

# fracciones parciales restaurada
terminos = Yzm.args
Yzp = 0
parametros = [] # denominador cuadratico
for untermino in terminos:
    Yzp = Yzp + untermino*z

    # revisa denominador cuadratico
    [numerador,denominador] = (untermino*z).as_numer_denom()
    if not(denominador.is_constant()):
        denominador = denominador.as_poly()
        numerador = numerador.as_poly()
        gradoD = denominador.degree()
        gradoN = numerador.degree()
        coeficientesD = denominador.coeffs()
        coeficientesN = numerador.coeffs()
        if gradoD == 2 and gradoN==2:
            a = float(coeficientesD[1])/2
            gamma2 = float(coeficientesD[2])
            gamma = np.sqrt(gamma2)
            A = float(coeficientesN[0])
            B = float(coeficientesN[1])
            rN = (A**2)*gamma2 + B**2 - 2*A*a*B
            rD = gamma2 - a**2
            r = np.sqrt(rN/rD)
            beta = np.arccos(-a/gamma)
            thetaN = A*a-B
            thetaD = A*np.sqrt(gamma2-a**2)
            theta = np.arctan(thetaN/thetaD)
            parametros.append({'r':r,
                               'beta':beta,
                               'theta':theta})

# SALIDA
print('termino entrada cero: ',entrada0)
print('termino estado cero:  ',estado0)
print('\n Yz = (-entrada0 +estado0)/Qz:')
sym.pprint((-entrada0 + estado0)/Qz)

print('\n Yz en fracción:')
sym.pprint(Yzf)
print('\n Yz en fracciones parciales:')
sym.pprint(Yzp)
print('\n {polos:veces} Hz: ',Q_raiz)
if len(parametros)>0:
    print('parametros cuadraticos: ')
    print(parametros)

7.2.1 LTI DT Transformada z – Y[n] ecuacion lineal de diferencias en z con condiciones iniciales

La transformada z convierte las ecuaciones de diferencias en expresiones algebraicas que permiten encontrar soluciones en el dominio z. A partir de las soluciones en el dominio z, se aplica la transformada inversa z que lleva a la solución en el dominio del tiempo


Ejercicio1

Referencia: Lathi Ejemplo 5.5 p510

Resolver

y[n+2] – 5 y[n+1] + 6 y[n]  = 3 x[n+1] + 5 x[n]

con las condiciones iniciales y[-1]=11/16, y[-2]=37/36,
ante una entrada x[n]=(2)-nμ[n]

Desarrollo analítico

Usando la propiedad de desplazamiento de 2 unidades a la derecha.

y[n] – 5 y[n-1] +6 y[n-2]  = 3 x[n-1] + 5 x[n-2]

se aplica la transformada z, teniendo en cuenta que y[n-k] significa y[n-k]μ[n], pues consideramos solamente la situación de n≥0, y[n] esta presente incluso antes de n=0.

Teniendo así que,

y[n] μ[n] \Leftrightarrow Y[z] y[n-1] μ[n] \Leftrightarrow \frac{1}{z} Y[z] + y[-1] = \frac{1}{z} Y[z] + \frac{11}{6} y[n-1] μ[n] \Leftrightarrow \frac{1}{z} Y[z] + \frac{11}{6} y[n-2] μ[n] \Leftrightarrow \frac{1}{z^2} Y[z] + \frac{1}{z}y[-1] + y[-2] y[n-2] \mu [n] \Leftrightarrow \frac{1}{z^2} Y[z] + \frac{1}{z}\frac{11}{6} +\frac{37}{36}

Conociendo que para una entrada causal x[n]

x[-1] = x[-2] = … = x[-n] = 0

se tiene que:

x[n] = (2)^{-n} \mu [n] = (2^{-1})^n \mu [n] = (0.5)^n \mu [n] \Leftrightarrow \frac{z}{z-0.5} x[n-1] \mu [n] \Leftrightarrow \frac{1}{z}X[z] +x[-1] = \frac{1}{z}\frac{z}{z-0.5} +0= \frac{1}{z-0.5} x[n-2] \mu [n] \Leftrightarrow \frac{1}{z^2}X[z] + \frac{1}{z}x[-1] + x[-2] = = \frac{1}{z^2} \frac{z}{z-0.5} + (0) + (0) = \frac{1}{z(z-0.5)}

en general, para una entrada causal:

x[n-r] \mu [n] \Leftrightarrow \frac{1}{z^r}X[z]

tomando los resultados anteriores y reemplazado en la ecuacion inicial, de tiene

Y[z] - 5 \Bigg[ \frac{1}{z} Y[z] + \frac{11}{6}\Bigg] + 6 \Bigg[\frac{1}{z^2} Y[z] + \frac{1}{z}\frac{11}{6} +\frac{37}{36} \Bigg] = = 3\frac{1}{z-0.5}+5\frac{1}{z(z-0.5)}

reagrupando términos Y[z] y reordenando,

\Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] +\Bigg(-5\frac{11}{6}+ \frac{1}{z}\frac{11}{6}6 +6\frac{37}{36} \Bigg) = = 3\frac{1}{z-0.5}+5\frac{1}{z(z-0.5)} \Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] + \Bigg(-3 + \frac{11}{z} \Bigg) = 3\frac{1}{z-0.5}+5\frac{1}{z(z-0.5)} \Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] = -\Bigg(-3 + \frac{11}{z} \Bigg) + 3\frac{1}{z-0.5}+5\frac{1}{z(z-0.5)}

En el lado derecho se muestran términos generados por una respuesta natural y una respuesta forzada. Dicho de otra forma, se muestran términos generados por las condiciones iniciales y por la señal x[n].

reagrupando el lado derecho en forma de numerador y denominador

\Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] = \frac{3z^2 -9.5z +10.5}{z(z-0.5)}

se puede reescribir, multiplicando cada lado por z2

z^2\Bigg(1 - 5 \frac{1}{z} + 6 \frac{1}{z^2}\Bigg) Y[z] = z^2 \Bigg[\frac{3z^2 -9.5z +10.5}{z(z-0.5)} \Bigg] (z^2 - 5 z + 6) Y[z] = \frac{z(3z^2 -9.5z +10.5)}{(z-0.5)} Y[z] = \frac{z(3z^2 -9.5z +10.5)}{(z-0.5)(z^2 - 5 z + 6)}

se aplica fracciones parciales, usando el algoritmo de la sección Transformada z-fracciones parciales

Y[z] = \frac{26}{15}\frac{z}{z-0.5} - \frac{7}{3}\frac{z}{z-2} + \frac{18}{5}\frac{z}{z-3}

usando la tabla de transformadas z, se obtiene como respuesta en el tiempo discreto

y[n] = \Bigg[ \frac{26}{15}(0.5)^n - \frac{7}{3}(2)^n + \frac{18}{5}(3)^n \Bigg] \mu [n]

7.2 LTI DT Transformada z – X[z] Fracciones parciales modificadas con Python

Referencia: Lathi 5.1-1 p495, Oppenheim 10.3 p757, Hsu 4.5.D p174

Muchas de las transformadas X(z) de interés en la práctica son funciones racionales, que pueden ser expresadas como la suma de fracciones parciales, cuyas transformadas inversas pueden ser encontradas rapidamente en la tabla de transformadas.

Se busca evitar realizar el integral en el plano complejo requerido para encontrar la transformada inversa de z.

El método de las fracciones parciales es práctico porque cada x[n] transformable se define para n≥0, existe  su correspondiente X[z] definida para |z|>r0 y viceversa. (r0 es constante)

Para desarrollar y probar el algoritmo con Sympy-Python, se usará el desarrollo de los tres ejercicios siguientes, con polos únicos, repetidos y complejos. El algoritmo final del literal c integra las soluciones anteriores.


Ejercicio 1. Polos diferentes

Referencia: Lathi Ejercicio 5.3a p495. Hsu. ejercicio 4.29 p198

Realice la expansión en fracciones parciales de,

X[z] = \frac{8z-19}{(z-2)(z-3)}

Se puede encontrar que,

X[z] = \frac{3}{(z-2)}+\frac{5}{(z-3)}

de la tabla de transformadas z se tiene,

x[n] = [3(2)^{n-1} +5(3)^{n-1}] \mu [n-1]

Que tiene una entrada  con términos multiplicadas por μ[n-1], que es un inconveniente y no deseable. Se prefieren las transformadas respecto a μ[n].

Observando la tabla de transformadas z entre los items 6a y 7, se tiene que si la señal X[n] es multiplicada por u[n], el numerador tiene un factor z. Esto se consigue expandiendo en fracciones parciales X[z]/z  que son fracciones parciales modificadas cuando se tiene un factor z en el numeradory luego se restauran multiplicando el todo el resultado por z.

\frac{X[z]}{z} = \frac{8z-19}{z(z-2)(z-3)} =\frac{-19/6}{z} + \frac{3/2}{z-2} + \frac{5/3}{z-3}

que al multiplicar ambos lados por z, se obtiene,

X[z] =\frac{-19}{6} + \frac{3}{2}\frac{z}{z-2} + \frac{5}{3}\frac{z}{z-3}

y usando la tabla de transformadas z se obtiene:

x[n] = \frac{-19}{6} \delta [n] + \Big[ \frac{3}{2}(2)^n + \frac{5}{3}(3)^n \Big] \mu[n]

que es el resultado esperado y con respuesta equivalente al resolver con algoritmo iterativo para n=0,1,2,3,…

Por este motivo, es recomendable siempre expandir en fracciones parciales X[z]/z en lugar de solo X[z], pues tiene un factor z en el numerador.

Algoritmo en Python

Para realizar el ejercicio, debemos considerar usar Sympy. Las operaciones se realizan al dividir X[x]/z y simplificar la nueva expresión Xzz, luego una expansión Xzp. El resultado se multiplica término a término por z y de añaden a la expresión total Xzfp.

El bloque de ingreso que se modifica para cada caso es:

Pz = 8*z-19
Qz = (z-2)*(z-3)

El resultado obtenido es:

 Xz:
    8*z - 19   
---------------
(z - 3)*(z - 2)

 Xz/z:
    8*z - 19    
----------------
  / 2          \
z*\z  - 5*z + 6/

 Xz/z.apart:
    3           5        19
--------- + --------- - ---
2*(z - 2)   3*(z - 3)   6*z

 Xz = (Xz/z)*z
   3*z         5*z      19
--------- + --------- - --
2*(z - 2)   3*(z - 3)   6 

{polos:veces}:  {3: 1, 2: 1}
>>> 

Instrucciones en Python

# Transformada z- Fracciones parciales
# Polos únicos, repetidos y complejos
# Lathi Ejercicio 5.3a pdf495
# blog.espol.edu.ec/telg1001
import numpy as np
import sympy as sym

# INGRESO
z = sym.Symbol('z')

Pz = 8*z-19
Qz = (z-2)*(z-3)

# PROCEDIMIENTO
P = Pz.as_poly(z)
Q = Qz.as_poly(z)
Xz = Pz/Qz

# Raices Denominador
Q_raiz = sym.roots(Q)
Q_raizRe = sym.real_roots(Q)
rcompleja = len(Q_raiz)-len(Q_raizRe)

# Raices reales, únicas y repetidas
if (rcompleja<=0 and len(Q_raizRe)>0):
    # fracciones parciales modificadas
    Xzz = (P/Q)/z
    Xzm = Xzz.apart()
    # fracciones parciales restaurada
    terminos = Xzm.args
    Xzp = 0*z
    for untermino in terminos:
        Xzp = Xzp + untermino*z


# SALIDA
print('\n Xz:')
sym.pprint(Xz)
if (len(Q_raizRe)>0):
    print('\n Xz/z:')
    sym.pprint(Xzz)
    print('\n Xz/z.apart:')
    sym.pprint(Xzm)
    print('\n Xz = (Xz/z)*z')
    sym.pprint(Xzp)
    print('\n {polos:veces}:    ', Q_raiz)
print('\n polos Re: ', Q_raizRe)
if (rcompleja>0):
    print( ' Existen raíces complejas en denominador')
    print( ' Revisar la sección correspondiente')

Ejercicio 2. Polos repetidos

Referencia: Lathi Ejercicio 5.3b p495

Realice la expansión en fracciones parciales de,

X[z] = \frac{z(2z^2-11z+12)}{(z-1)(z-2)^{3}}

Antes de realizar la expansión en fracciones parciales, se divide ambos lados de la expresión para z. Es decir se usa fracciones parciales modificadas

\frac{X[z]}{z} = \frac{1}{z}\frac{z(2z^2-11z+12)}{(z-1)(z-2)^{3}} \frac{X[z]}{z} = \frac{(2z^2-11z+12)}{(z-1)(z-2)^{3}}

donde el modelo de las fracciones parciales a aplicar es:

\frac{(2z^2-11z+12)}{(z-1)(z-2)^{3}} = \frac{k}{z-1} + \frac{a_0}{(z-2)^3} + \frac{a_1}{(z-2)^2} + \frac{a_2}{(z-2)}

Para encontrar las constantes, se evalúa la expresión de la izquierda con los valores de cada raiz del denominador, en cada caso se obvia el término de la raiz en el denominador,

k = \frac{(2z^2-11z+12)}{\cancel{z-1}(z-2)^{3}} \Bigg|_{z=1} = \frac{(2(1)^2-11(1)+12)}{((1)-2)^{3}} = -3 a_0 = \frac{(2z^2-11z+12)}{(z-1)\cancel{(z-2)^{3}}}\Bigg|_{z=2} = \frac{(2(2)^2-11(2)+12)}{((2)-1)} = -2

con lo que la expresión modelo se convierte en:

\frac{(2z^2-11z+12)}{(z-1)(z-2)^{3}} = \frac{-3}{z-1} + \frac{-2}{(z-2)^3} + \frac{a_1}{(z-2)^2} + \frac{a_2}{(z-2)}

Una forma de resolver es por ejemplo para a2, multiplicar ambos lados por z y hacer que z→∞

\frac{(2z^2-11z+12)}{(z-1)(z-2)^{3}} z = z \Big[\frac{-3}{z-1} + \frac{-2}{(z-2)^3} + \frac{a_1}{(z-2)^2} + \frac{a_2}{(z-2)}\Big] \frac{(2z^2-11z+12)}{(z-1)(z-2)^{3}} z = \frac{-3z}{z-1} + \frac{-2z}{(z-2)^3} + \frac{a_1z}{(z-2)^2} + \frac{a_2z}{(z-2)}\Big] 0 = \frac{-3}{1-1/z} + \frac{-2z}{(z-2)^3} + \frac{a_1z}{(z-2)^2} + \frac{a_2}{(1-2/z)}\Big] 0 = -3 + (0) + (0) + a_2 a_2 =3

quedando solamente una incógnita a1 por resolver,

\frac{(2z^2-11z+12)}{(z-1)(z-2)^{3}} = \frac{-3}{z-1} + \frac{-2}{(z-2)^3} + \frac{a_1}{(z-2)^2} + \frac{3}{(z-2)}

El valor de a1 se puede determinar haciendo z tomar un valor conveniente, es decir z=0 en ambos lados de la ecuación

\frac{(2(0)^2-11(0)+12)}{((0)-1)((0)-2)^{3}} = \frac{-3}{(0)-1} + \frac{-2}{((0)-2)^3} + \frac{a_1}{((0)-2)^2} + \frac{3}{((0)-2)} \frac{12}{(-1)(-8)} = \frac{-3}{-1} + \frac{-2}{-8} + \frac{a_1}{4} + \frac{-3}{-2} \frac{3}{2} = 3 + \frac{1}{4} + \frac{a_1}{4} - \frac{3}{2} \frac{6}{2} - \frac{13}{4}= \frac{a_1}{4} -\frac{1}{4}= \frac{a_1}{4} a_1 = -1

completando la expresión:

\frac{X[z]}{z} = \frac{-3}{z-1} + \frac{-2}{(z-2)^3} + \frac{-1}{(z-2)^2} + \frac{3}{(z-2)}

teniendo finalmente X[z] al multiplicar ambos lados por z,

X[z] = \frac{-3z}{z-1} + \frac{-2z}{(z-2)^3} + \frac{-1z}{(z-2)^2} + \frac{3z}{(z-2)}

y usando la tabla de transformadas z se obtiene:

x[n] = \Big[-3 -2 \frac{n(n-1)}{8}(2)^n - \frac{n}{2}(2)^n + 3(2)^n \Big] \mu [n]

simplificando un poco:

x[n] = \Big[-3 -\Big(\frac{n(n-1)}{4} + \frac{n}{2} - 3\Big)(2)^n \Big] \mu [n] x[n] = -\Big[3 +\frac{1}{4}(n^2 + n-12)(2)^n \Big] \mu [n]

Usando el algoritmo en Python anterior, el bloque de ingreso cambia a:

Pz = z*(2*z**2-11*z+12)
Qz = (z-1)*(z-2)**3

con el resultado:

 Xz:
  /   2            \
z*\2*z  - 11*z + 12/
--------------------
         3          
  (z - 2) *(z - 1)  

 Xz/z:
         3       2              
      2*z  - 11*z  + 12*z       
--------------------------------
  / 4      3       2           \
z*\z  - 7*z  + 18*z  - 20*z + 8/

 Xz/z.apart:
    3       3        1          2    
- ----- + ----- - -------- - --------
  z - 1   z - 2          2          3
                  (z - 2)    (z - 2) 

 Xz = (Xz/z)*z
   3*z     3*z       z         2*z   
- ----- + ----- - -------- - --------
  z - 1   z - 2          2          3
                  (z - 2)    (z - 2) 
{polos:veces}:  {1: 1, 2: 3}
>>> 

comparando con el resultado analítico es el mismo.


Ejercicio 3. Polos complejos

Referencia: Lathi Ejercicio 5.3c p495

Realice la expansión en fracciones parciales de,

X[z] = \frac{2 z(3z+17)}{(z-1)(z^2 - 6z+25)}

Se realiza la separación en fracciones parciales modificadas

\frac{X[z]}{z} = \frac{2(3z+17)}{(z-1)(z^2 - 6z+25)}

usando el método «cubrir» de Heaviside se tiene que :

k = \frac{2(3z+17)}{\cancel{(z-1)}(z^2 - 6z+25)} \Big|_{z=1}=2

queda por resolver la segunda parte de la fracción.

\frac{X[z]}{z} = \frac{2}{(z-1)}+\frac{Az+B}{z^2 - 6z+25}

Usando el método de los factores cuadráticos, se multiplica ambos lados por z y z→∞

\frac{X[z]}{z}z= z\frac{2}{(z-1)}+z\frac{Az+B}{z^2 - 6z+25} 0 = \frac{2}{(1-1/z)}+\frac{Az^2+Bz}{(z^2 - 6z+25)} 0 = \frac{2}{(1-1/z)}+\frac{A+B\frac{1}{z}}{\frac{1}{z^2}(z^2 - 6z+25)} 0 = \frac{2}{(1-1/z)}+\frac{A+B\frac{1}{z}}{1 - 6\frac{1}{z}+25\frac{1}{z^2}} 0 = 2+A

con lo que A = -2 , para encontrar B se usa un valor conveniente de z=0

\frac{2 z(3z+17)}{(z-1)(z^2 - 6z+25)} = \frac{2}{(z-1)}+\frac{Az+B}{z^2 - 6z+25} \frac{2 (0+17)}{(0-1)(0^2 - 6(0)+25)} = \frac{2}{((0)-1)}+\frac{-2(0)+B}{(0^2 - 6(0)+25)} \frac{34}{-25} = +\frac{2}{-1}+\frac{B}{25} -\frac{34}{25} + 2=\frac{B}{25} -34+ 2(25) = B

con lo que B=16

\frac{X[z]}{z}= \frac{2}{(z-1)}+\frac{-2z+16}{z^2 - 6z+25} X[z]= \frac{2}{(z-1)}+\frac{z(-2z+16)}{z^2 - 6z+25}

con lo que es posible usar la tabla de transformadas z usando los items 2a y 12c. Para 12c los valores de A = -2, B = 16, |γ| =5 y a=-3.

r = \sqrt{\frac{(-2)^2 (5)^2+(16)^2-2(-2)(-3)(16)}{(5^2 -(-3)^2}} = \sqrt{\frac{100+256-192}{25-9}} =3.2

\beta = \cos^{-1} \Big(\frac{-(-3)}{5} \Big) = 0.927 \theta = \tan^{-1} \Bigg(\frac{(-2)(-3)-16}{(-2)\sqrt{(5^2 -(-3)^2}}\Bigg) = \tan^{-1}\Big( \frac{-10}{-8}\Big) = -2.246

reemplazando en la transformada, se encuentra x[n].

x[n] = [2+3.2(5)^n \cos(0.927n-2.246)] \mu [n]

pasamos a probar el algoritmo, donde se encuentra que para el denominador hay raíces complejas. Otra forma de observar es que las funciones parciales aún entregan resultados con términos que tienen el denominador con grado 2. Donde hay que usar expresiones de la tabla de transformadas.

 Xz:
     2*z*(3*z + 17)    
-----------------------
        / 2           \
(z - 1)*\z  - 6*z + 25/

 Xz/z:
          2              
       6*z  + 34*z       
-------------------------
  / 3      2            \
z*\z  - 7*z  + 31*z - 25/

 Xz/z.apart:
    2*(z - 8)       2  
- ------------- + -----
   2              z - 1
  z  - 6*z + 25        

 Xz = (Xz/z)*z
   2*z*(z - 8)     2*z 
- ------------- + -----
   2              z - 1
  z  - 6*z + 25        

{polos:veces}:     {1: 1, 3 - 4*I: 1, 3 + 4*I: 1}

 polos Re:  [1]
parametros cuadraticos: 
r 	 3.2015621187164243
gamma 	 5.0
beta 	 0.9272952180016123
theta 	 0.8960553845713439
>>> 

Instrucciones en Python

El algoritmo inicia de la misma forma que en la sección anterior. Ahora hay que revisar el grado del denominador en cada término. Si es de grado 2, se calculan los valores de r, β y θ para armar las transformada a partir de la tabla.

# Transformada z- Fracciones parciales
# Polos únicos, repetidos y complejos
# Lathi Ejercicio 5.3c pdf495
# blog.espol.edu.ec/telg1001
import numpy as np
import sympy as sym

# INGRESO
z = sym.Symbol('z')

Pz = 2*z*(3*z+17) #z*(2*z**2-11*z+12) #8*z-19
Qz = (z-1)*(z**2-6*z+25) #(z-1)*(z-2)**3 #(z-2)*(z-3)

# PROCEDIMIENTO
P = Pz.as_poly(z)
Q = Qz.as_poly(z)
Xz = Pz/Qz

# Raices Denominador
Q_raiz = sym.roots(Q)
Q_raizRe = sym.real_roots(Q)
rcompleja = len(Q_raiz)-len(Q_raizRe)

# Raices reales, únicas y repetidas
if (rcompleja<=0 and len(Q_raizRe)>0):
    # fracciones parciales modificadas
    Xzz = (P/Q)/z
    Xzm = Xzz.apart()
    # fracciones parciales restaurada
    terminos = Xzm.args
    Xzp = 0*z
    for untermino in terminos:
        Xzp = Xzp + untermino*z

def parametro_cuadratico(untermino):
    unparametro ={}
    # revisa denominador cuadratico
    [numerador,denominador] = (untermino).as_numer_denom()
    gradoD = 0
    coeficientesD = denominador
    gradoN = 0
    coeficientesN = numerador
    if not(denominador.is_constant()):
        denominador = denominador.as_poly()
        gradoD = denominador.degree()
        coeficientesD = denominador.coeffs()
    if not(numerador.is_constant()):
        numerador = numerador.as_poly()
        gradoN = numerador.degree()
        coeficientesN = numerador.coeffs()
    if gradoD == 2 and gradoN==2:
        a = float(coeficientesD[1])/2
        gamma2 = float(coeficientesD[2])
        gamma = np.sqrt(gamma2)
        A = float(coeficientesN[0])
        B = float(coeficientesN[1])
        rN = (A**2)*gamma2 + B**2 - 2*A*a*B
        rD = gamma2 - a**2
        r = np.sqrt(rN/rD)
        beta = np.arccos(-a/gamma)
        thetaN = A*a-B
        thetaD = A*np.sqrt(gamma2-a**2)
        theta = np.arctan(thetaN/thetaD)
        unparametro = {'r':r,
                       'gamma':gamma,
                       'beta':beta,
                       'theta':theta}
    return (unparametro)

# Terminos cuadraticos
parametros = [] # denominador cuadratico
if (rcompleja>0 and len(Q_raizRe)>0):
    # fracciones parciales modificadas
    Xzz = (P/Q)/z
    Xzm = Xzz.apart()
    # fracciones parciales restaurada
    terminos = Xzm.args
    Xzp = 0*z
    for untermino in terminos:
        Xzp = Xzp + untermino*z
        unparam = parametro_cuadratico(untermino*z)
        if len(unparam)>0:
            parametros.append(unparam)
if (rcompleja>0 and len(Q_raizRe)==0):
    Xzp = P/Q
    parametros.append(parametro_cuadratico(P/Q))

# SALIDA
print('\n Xz:')
sym.pprint(Xz)
if (len(Q_raizRe)>0):
    print('\n Xz/z:')
    sym.pprint(Xzz)
    print('\n Xz/z.apart:')
    sym.pprint(Xzm)
    print('\n Xz = (Xz/z)*z')
    sym.pprint(Xzp)
    print('\n {polos:veces}: ', Q_raiz)
print('\n polos Re: ', Q_raizRe)
if len(parametros)>0:
    for unparam in parametros:
        print('parametros cuadraticos: ')
        for cadauno in unparam.keys():
            print(cadauno,'\t',unparam[cadauno])