Sigma-Delta con audio en Python

Usando los conceptos descritos para abrir un archivo de audio .wav, realice en python lo siguiente:

a) Codificador: Realice la codificación en ∑Δ para el audio del ejemplo, y crear el archivo correspondiente al resultado.

b) Decodificador: Reconstruya la señal de audio a partir del archivo del literal anterior, de ∑Δ a .wav, y pruebe su resultado ejecutando el archivo con un programa como windows media player.

c) Realice las observaciones correspondientes al proceso realizado.

Trabajo extra, opcional

d) Cree un archivo de audio en formato .wav dictando una frase como la mostrada, y repita el proceso anterior.

e) Realice las observaciones correspondientes al proceso realizado.


Codificador Sigma-Delta

Se adjunta un algoritmo en python de referencia al que hay que añadir la parte de manejo del audio.

– En el bloque de ingreso complete las instrucciones para leer el archivo. Observe los nombres de las variables.

# Modulacion Delta - Codificador de audio
# entrada x(t), salida: ysalida[n]
# propuesta: edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as waves
import scipy.signal as senal

# INGRESO
# archivo=......
# fsonido, sonido = ......

# PROCEDIMIENTO

# Analógica de referencia
deltaT  = 1/(2*np.pi*fsonido)
xanalog = sonido[:,0] # Canal izquierdo
xmax    = np.max(xanalog)
nsonido = len(xanalog)
t0 = 0
tn = nsonido*deltaT
t  = np.arange(0,tn,deltaT)

# Codificacion Sigma-Delta
salto  = 1 #usa todas las muestras sin saltar
deltaY = xmax//10
nd = nsonido//salto
td = np.arange(0,nd,1) # eje tiempo[n] digital
xdigital = np.zeros(nd,dtype=float)
ysalida  = np.zeros(nd,dtype=int)
muestra  = xanalog[0]
i = 1
while not(i >= nd):
    muestra = xanalog[i*salto] # referencia analógica
    diferencia = muestra-xdigital[i-1]
    if (diferencia>0):
        bit = 1
    else:
        bit = -1
    xdigital[i] = xdigital[i-1]+bit*deltaY
    ysalida[i]  = bit
    i = i + 1
fsalida = fsonido/salto
parametros = np.array([deltaT,deltaY,fsalida])

# SALIDA
print(ysalida)
print(parametros)

# Graba archivo
np.savetxt('sigmadelta_datos.txt',ysalida,fmt='%i')
np.savetxt('sigmadelta_parametros.txt',parametros)

# Grafico
# Escala y RANGO ejex del gráfico
a = int(nsonido*0.35)
b = int(nsonido*0.355)

plt.figure(1)       # define la grafica
plt.suptitle('Codificador Sigma-Delta Audio.wav')

# grafica de 3x1 y subgrafica 1
plt.subplot(311)
plt.ylabel('x(t)')
# rango en el eje y
xmax = np.max(xanalog)+0.1*np.max(xanalog)
xmin = np.min(xanalog)-0.1*np.max(xanalog)
plt.axis((a*deltaT, b*deltaT, xmin, xmax))
plt.plot(t[a:b],xanalog[a:b], 'g')
plt.ylabel('xanalogica[n]')

# grafica de 3x1 y subgrafica 2
plt.subplot(312) 
plt.ylabel('xdigital[n]')
# rango en el eje
mxa=np.max(xdigital[a:b])
mna=np.min(xdigital[a:b])
plt.axis((a,b,mxa,mna))
#plt.plot(td,xdigital,'bo')
plt.step(td[a:b],xdigital[a:b], where='post',color='m')

# grafica de 3x1 y subgrafica 3
plt.subplot(313) 
plt.ylabel('ysalida[n]')
plt.axis((a,b,-1.1,1.1))
plt.step(td[a:b],ysalida[a:b], where='post',color='b')
plt.show()

Decodificador Sigma-Delta

El resultado gráfico al decodificar el archivo de ∑Δ se muestra, se debe añadir la instrucción para generar el archivo de audio y poder escucharlo.

modifique la seccion de #Salida para crear el arhivo de audio con nombre: ‘sigmadeltaaudio.wav’.

# Modulacion Sigma-Delta Decodificador
# entrada yentrada[n], salida: x[t]
# propuesta:edelros@espol.edu.ec
import numpy as np
import matplotlib.pyplot as plt
import scipy.io.wavfile as waves

# INGRESO
archivodatos = 'sigmadelta_datos.txt'
archivoparam = 'sigmadelta_parametros.txt'

# PROCEDIMIENTO
# lectura de archivo
yentrada = np.loadtxt(archivodatos,dtype=int)
datos    = np.loadtxt(archivoparam,dtype=float)
deltaD   = datos[0]
deltaY   = datos[1]
fsonido  = datos[2]
# muestras para gráfica
k = len(yentrada) 

# Arreglos para datos
xdigital = np.zeros(k, dtype='int16')
punto    = np.zeros(k, dtype=int)
td       = np.zeros(k, dtype=float) # eje n digital

# calcula los valores para digital
xdigital[0] = yentrada[0]
punto[0] = 0
td[0]    = 0
for i in range(1,k):
    punto[i] = i
    td[i]    = deltaD*i
    xdigital[i] = xdigital[i-1]+yentrada[i]*deltaY

# SALIDA
print(xdigital)
#Archivo de audio
# CREAR EL ARCHIVO DE AUDIO ***********************

#Gráfico
a = int(k*0.25) # RANGO ejex del gráfico
b = int(k*0.252)

plt.figure(1) # define la grafica
plt.suptitle('Decodifica Sigma_Delta')

plt.subplot(211) # grafica de 2x1 y subgrafica 1
plt.ylabel('entrada: y[n]')
plt.axis((a,b,-1.1,1.1))
#plt.plot(punto[a:b],yentrada[a:b],'b')
plt.step(punto[a:b],yentrada[a:b], where='post', color='b')

plt.subplot(212) # grafica de 2x1 y subgrafica 2
plt.ylabel('salida: x[t]')
xmax = np.max(xdigital[a:b]) # rango en el eje
xmin = np.min(xdigital[a:b])
plt.axis((a*deltaD,b*deltaD,xmin,xmax))
#plt.plot(td[a:b],xdigital[a:b],'m')
plt.step(td[a:b],xdigital[a:b], where='post', color='m')
plt.show()

La gráfica muestra solo el intervalo de tiempo entre a=0.25 y b=0.252 del total de tiempo del audio, el propósito es la observacion visual complementará a la de escuchar el audio resultante.

Transformada z – Tabla de Propiedades

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

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: Lathi Tabla 5.1 Transformada z p492. Oppenheim tabla 10.2 p776, Schaum Hsu Tabla 4-1 p170.

Tabla de Transformada z
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} |z|>γ
11b |γ|n sin(βn) μ[n] \frac{ z |\gamma | \sin (\beta )}{z^2-(2|\gamma | \cos (\beta ))z +|\gamma |^2} |z|>γ
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 – Ejercicios resueltos con sistemas discretos

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

 

7.3 LTI DT Transformada z – Y[z]=ZIR+ZSR con Sympy-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), aqui se usa la transformada_z inversa con Sympy:

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

Yz_ZIR_ZSR_graf01


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.

 Hz {polos:veces} :  {3: 1, 2: 1}
 Hz {ceros:veces} :  {-5/3: 1}

 termino condiciones iniciales: 
z*(11 - 3*z)
termino entrada x[n]:  
2*z*(3*z + 5)
-------------
   2*z - 1   

 Yz = ZIR_z + ZSR_z:
  z*(11 - 3*z)        2*z*(3*z + 5)      
- ------------ + ------------------------
   2                       / 2          \
  z  - 5*z + 6   (2*z - 1)*\z  - 5*z + 6/

 Yz en fracciones parciales z:
    26*z          7*z         18*z  
------------ - --------- + ---------
15*(z - 1/2)   3*(z - 2)   5*(z - 3)

 y[n]:
/      n      n       n\             
|26*0.5    7*2    18*3 |             
|------- - ---- + -----|*Heaviside(n)
\   15      3       5  /             
>>> 

Instrucciones Python

# Transformada z - Fracciones parciales
# Y(z) = -condicion0+entradaxn = ZIR+ZSR
# Lathi Ejemplo 5.5 p510
import sympy as sym
import telg1001 as fcnm
sym.SYMPY_DEBUG=True
# INGRESO
z = sym.Symbol('z')
n = sym.Symbol('n', real=True)

# coeficientes como racional en dominio 'ZZ' enteros
a0 = sym.Rational(1/2).limit_denominator(1000)
# señal de entrada Xz
Xz = z/(z-a0)

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

# condiciones iniciales ascendente ...,y[-2],y[-1]
a1 = sym.Rational(37,36)
a2 = sym.Rational(11,6)
cond_inicio = [a1, a2]

# PROCEDIMIENTO
Fz = sym.simplify(Hz)
# polos y ceros de Fz
[P,Q] = Fz.as_numer_denom()
P = sym.poly(P,z)
Q = sym.poly(Q,z)
P_ceros = sym.roots(P)
Q_polos = sym.roots(Q)

# coeficientes QD
Q_coef  = Q.coeffs()
Q_grado = Q.degree()

# Términos de condiciones iniciales
m0 = len(cond_inicio)
term_0 = 0 
for j in range(0,Q_grado,1):
    term_grado = 0
    for i in range(m0-1-j,m0,1):
        term_cond0 = cond_inicio[i]*(z**((m0-1-j)-i ))
        term_grado = term_grado + term_cond0
    term_0 = term_0 + term_grado*Q_coef[j+1]
    
# salida y(t) a entrada x(t)
term_0  = sym.simplify(term_0*(z**2))
term_xn = sym.simplify(Pz*Xz)
ZIR_z = -sym.simplify(term_0/Q)
ZSR_z = sym.simplify(term_xn/Q)

# Y[z] = entrada0 + estado0
Yz = ZIR_z + ZSR_z

# Y[z] en fracciones parciales y parametros cuadraticos
Yzp = fcnm.apart_z(Yz)
Qs2 = fcnm.Q_cuad_z_parametros(Yzp)

# Inversa de transformada z
yn = 0*n ; Fz_revisar = []
term_sum = sym.Add.make_args(Yzp)
for term_k in term_sum:
    term_kn = fcnm.inverse_z_transform(term_k,z,n)
    if type(term_kn)==tuple:
        yn = yn + term_kn[0]
    else:
        yn = yn + term_kn
yn = yn.collect(sym.Heaviside(n))
yn = yn.collect(sym.DiracDelta(n))
yn = fcnm._round_float_is_int(yn)

# SALIDA
print(' Hz {polos:veces} : ',Q_polos)
print(' Hz {ceros:veces} : ',P_ceros)
print('\n termino condiciones iniciales: ')
sym.pprint(term_0)
print(' termino entrada x[n]:  ')
sym.pprint(term_xn)
print('\n Yz = ZIR_z + ZSR_z:')
sym.pprint(Yz)
print('\n Yz en fracciones parciales z:')
sym.pprint(Yzp)
if len(Qs2)>0:
    print('Y[z] parametros cuadraticos: ')
    for Qs2_k in Qs2:
        print(Qs2_k,':')
        for cadauno in Qs2[Qs2_k].keys():
            print(cadauno,'\t',Qs2[Qs2_k][cadauno])
print('\n y[n]:')
sym.pprint(yn)
if len(Fz_revisar)>0:
    print('\n --- revisar terminos sin transformada en tabla: ---')
    for un_term in Fz_revisar:
        print(un_term)

7.2.1 LTI DT Transformada z – y[n] ecuación 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]

Yz_ZIR_ZSR_graf01

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 rápidamente 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 ítems 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 numerador y 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 

>>> 

Instrucciones en Python

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

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

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

# PROCEDIMIENTO
Fz = sym.simplify(Xz)
# fracciones parciales modificadas
Fzz = (Fz)/z
Fzm = Fzz.apart()
# fracciones parciales restaurada
terminos = Fzm.args
Fzp = 0*z
for untermino in terminos:
    Fzp = Fzp + untermino*z

# SALIDA
print('\n Xz:')
sym.pprint(Xz)
print('\n Xz/z:')
sym.pprint(Fzz)
print('\n Xz/z.apart:')
sym.pprint(Fzm)
print('\n Xz = (Xz/z)*z')
sym.pprint(Fzp)

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 raíz del denominador, en cada caso se obvia el término de la raíz 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:
   2            
2*z  - 11*z + 12
----------------
       3        
(z - 2) *(z - 1)

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

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 ítems 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 en fracciones parciales
   2*z*(z - 8)     2*z 
- ------------- + -----
   2              z - 1
  z  - 6*z + 25        
parametros cuadraticos: 
-2*z*(z - 8)/(z**2 - 6*z + 25) :
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.3a 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)
Qz = (z-1)*(z**2-6*z+25)

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

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

# PROCEDIMIENTO
def apart_z(Fz):
    ''' fracciones parciales en dominio z
        modifica con factor 1/z
    '''
    Fz = sym.simplify(Fz)
    # fracciones parciales modificadas con 1/z
    Fzz = (Fz)/z
    Fzm = sym.apart(Fzz,z)
    # restaura z
    term_suma = sym.Add.make_args(Fzm)
    Fzp = 0*z
    for term_k in term_suma:
        Fzp = Fzp + term_k*z
    return(Fzp)

def Q_cuad_z_parametros(Fz):
    ''' parametros cuadraticos en dominio z
    '''

    def Q_cuad_z_term(untermino):
        ''' parametros cuadraticos en dominio z
            de un termino de fraccin parcial
        '''
        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)

    Fz = apart_z(Fz)
    # parametros denominador cuadratico
    Qs2 = {}
    term_suma = sym.Add.make_args(Fz)
    for term_k in term_suma:
        Qs2_k = Q_cuad_z_term(term_k)
        if len(Qs2_k)>0:
            Qs2[term_k] = Qs2_k
    return(Qs2)

Fz  = apart_z(Xz)
Qs2 = Q_cuad_z_parametros(Fz)

# SALIDA
print('\n Xz:')
sym.pprint(Xz)
print('\n Xz en fracciones parciales')
sym.pprint(Fz)
if len(Qs2)>0:
    print('parametros cuadraticos: ')
    for Qs2_k in Qs2:
        print(Qs2_k,':')
        for cadauno in Qs2[Qs2_k].keys():
            print(cadauno,'\t',Qs2[Qs2_k][cadauno])

7.1.6 LTI DT – H[z] Diagrama de bloques con «1/z» – ejercicios

Referencia: Lathi 5.4 p519. Oppenheim 10.8 p783, Hsu Ejercicio 4.34 p201

Dada la similitud entre sistemas LTIC y LTID, las convenciones para diagramas de bloques  y las reglas de interconexión son idénticas a los sistemas contínuos. Los diagramas mostrados se realizan con el programa Xcos de SciLab.

Una función de transferencia general se expresa como:

H(z) = \frac{b_0 z^N +b_1 z^{N-1} + \text{ ... } + b_{N-1} z + b_N}{z^N + a_1 z^{N-1} +\text{ ... } + a_{N-1}z +a_N}

Ejemplo 1. H(z)

Referencia : Lathi 5.8a p522

H(z) =\frac{2}{z+5}

La función de transferencia es de primer orden (N=1), por lo que solo se usará un retraso para el diagrama. Los coeficientes de retroalimentación de retraso y adelanto son:

a1= 5 y b0 = 0, b1=2

La imagen presenta dos formas de realizar los diagramas

Ejemplo 2. H(z)

Referencia : Lathi 5.8b p522

H(z) =\frac{4z+28}{z+1}

la función de transferencia también es de primer orden (N=1), los coeficientes de retraso y adelanto son:

a1= 1 y b0 = 4, b1=28

La imagen presenta dos formas de realizar el diagrama de bloques

Ejemplo 3. H(z)

Referencia : Lathi 5.8c p522

H(z) =\frac{z}{z+7}

la función de transferencia también es de primer orden (N=1), los coeficientes de retraso y adelanto son:

a1= 7 y b0 = 1, b1=0

Ejemplo 4. H(z)

Referencia : Lathi 5.8d p522

H(z) =\frac{4z+28}{z^2+6z+5}

la función de transferencia también es de segundo orden (N=2), los coeficientes de retraso y adelanto son:

a1= 6, a2= 5 y b0 = 0, b1=4, b2=28

Ejemplo 5. Sistema LTI D

Referencia: Ejemplo Openheim 10.28 p784

Considere el sistema LTI causal descrito mediante:

y[n] - \frac{1}{4} y[n-1] = x[n]

con función del sistema:

H(z) =\frac{1}{1- \frac{1}{4} z^{-1} }

Aqui z-1 es la función del sistema con retraso unitario. El diagrama de bloques en la figura contiene un lazo de retroalimentación.

y[n] -\frac{1}{4} z^{-1} y[n] = x[n] y[n] = x[n] + \frac{1}{4} z^{-1} y[n]


Ejemplo 6. Función H(z)

Referencia: Ejemplo Openheim 10.29 p785

Considere un sistema LTI causal con función del sistema:

H(z) = \frac{ 1 - 2 z^{-1} }{ 1 - \frac{1}{4} z^{-1} }

La función se puede separar en bloque de denominador y numerador, semejante a los polinomios Q(E)  y P(E).

= \Bigg[\frac{1}{1 - \frac{1}{4}z^{-1}} \Bigg] \Bigg[ 1 - 2z^{-1} \Bigg]

Se observa en el diagrama (a) que z-1 se encuentra duplicado pues ambos bloques toman la misma señal para aplicarle un atraso, cada uno le da a una ganancia diferente. Por lo que un solo bloque z-1 puede realizar la misma operación.

En el mundo de los circuito digitales y componentes, la situación se interpreta como un componente duplicado, lo que tiene implicaciones de costos de implementación, recuerde el tema cuando construye un circuito digital usando puertas lógicas y registros.

7.1.5 Transformada z Inversa con Sympy-Python

La Transformada z  inversa, usa la Tabla de Pares f[n] y F[z] y los algoritmos para buscar una expresión semejante F.match() en conjunto con la tabla de propiedades y los algoritmos desarrollados en la sección anterior. El resultado se integra desde telg1001.py y se muestra en los siguientes ejemplos:

Ejemplo 1.  Transformada z inversa de una fracción X[1/z]

Referencia: Oppenheim Ejemplo 10.13 p761, Lathi Ejemplo 5.1 p490

Continuando con el ejercicio presentado para convertir x[n] a X[z], se tiene que:

X[z] = \frac{1}{1-a z^{-1}}\text{ , } |z|>|a| X[z] = \frac{z}{z-a}\text{ , } \Big|z|>|a|

siendo la expresión de ingreso al algoritmo:

F = z/(z - 2)

el resultado es:

f[n] : (2**n*Heaviside(n), Abs(z) > 2, True)
>>> 

Ejemplo 1a. Instrucciones Python

# transformada z propiedades con Sympy
# aplicar luego de buscar en tabla de pares
import sympy as sym
import telg1001 as fcnm

# INGRESO
n = sym.Symbol('n', real=True)
z = sym.Symbol('z')
u = sym.Heaviside(n)

# (a**n)*f[n] <--> F(z/a)
F = z/(z - 2)  #f = (2**n)*u

# PROCEDIMIENTO
fn = fcnm.inverse_z_transform(F,z,n)

# SALIDA
print('f[n] :',fn)

El algoritmo presentado puede ser tomado como punto de partida para los siguientes ejercicios. Realizado para explicación conceptual.

Ejemplo 2. Transformada z inversa usando expansión en fracciones parciales

Referencia: Lathi 5.3 a

Encuentre la transformada z inversa para:

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

el ingreso para el algoritmo del ejercicio anterior es:

F = (8*z-19)/((z-2)*(z-3))

con el resultado siguiente:

f[n] : (9*2**n + 10*3**n)*Heaviside(n)/6 - 19*DiracDelta(n)/6

activando la variable sym.SYMPY_DEBUG=True, se observa el proceso de fracción parcial modificada, la búsqueda en la tabla, y aplicación de una propiedad de la transformada z.

inverse_z_transform(F,z,n): (8*z - 19)/((z - 3)*(z - 2))

apart_z(F) : (8*z - 19)/((z - 3)*(z - 2))
_simplify_z: (8*z - 19)/((z - 3)*(z - 2))
  P_leadcoef: 8  ; P_zc: 1  ; P: z - 19/8
  _simplify_z k_sign: 1  ; k: 8  ; P_zc: 1  ; Q_zc: 1
    F[z]: (z - 19/8)/((z - 3)*(z - 2))
_simplify_z: (z - 19/8)/(z*(z - 3)*(z - 2))
  P_leadcoef: 8  ; P_zc: 1  ; P: z - 19/8
  Q_leadcoef: 8  ; Q_zc: z  ; Q: (z - 3)*(z - 2)
  _simplify_z k_sign: 1  ; k: 1  ; P_zc: 1  ; Q_zc: z
    F[z]: (z - 19/8)/((z - 3)*(z - 2))
  P: (8*z - 19)/8 
  Q: (z - 3)*(z - 2) 
  P_degree: 1  ; P_zeros: {19/8: 1} 
  Q_degree: 3  ; Q_poles: {3: 1, 2: 1, 0: 1}
  apart(F/z): 3/(16*(z - 2)) + 5/(24*(z - 3)) - 19/(48*z)
  ma_Qk: {a_: 48, b_: 0, c_: 1}  ; ma_Qk2: {b_: 48, a_: 0, c_: 0}
_simplify_z: -19/(48*z)
  P_leadcoef: -19  ; P_zc: 1  ; P: 1
  Q_leadcoef: 48  ; Q_zc: z  ; Q: 1
  _simplify_z k_sign: -1  ; k: 19/48  ; P_zc: 1  ; Q_zc: z
    F[z]: 1
  ma_Qk: {a_: 16, b_: -32, c_: 1}  ; ma_Qk2: {b_: 16, c_: -32, a_: 0}
_simplify_z: 3/(16*(z - 2))
  P_leadcoef: 3  ; P_zc: 1  ; P: 1
  Q_leadcoef: 16  ; Q_zc: 1  ; Q: z - 2
  _simplify_z k_sign: 1  ; k: 3/16  ; P_zc: 1  ; Q_zc: 1
    F[z]: 1/(z - 2)
  ma_Qk: {a_: 24, b_: -72, c_: 1}  ; ma_Qk2: {b_: 24, c_: -72, a_: 0}
_simplify_z: 5/(24*(z - 3))
  P_leadcoef: 5  ; P_zc: 1  ; P: 1
  Q_leadcoef: 24  ; Q_zc: 1  ; Q: z - 3
  _simplify_z k_sign: 1  ; k: 5/24  ; P_zc: 1  ; Q_zc: 1
    F[z]: 1/(z - 3)

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

 apart_z(F) as partial fractions: (-19/6, 3*z/(2*(z - 2)), 5*z/(3*(z - 3)))
  term_k[z]: -19/6
[0] _z_pairs_prop_inverse ----
_simplify_z: -19/6
  P_leadcoef: -19  ; P_zc: 1  ; P: 1
  Q_leadcoef: 6  ; Q_zc: 1  ; Q: 1
  _simplify_z k_sign: -1  ; k: 19/6  ; P_zc: 1  ; Q_zc: 1
    F[z]: 1
 _z_pairs_table match: 
  F: 1
  z_pair F[z]: 1  ; ma_z: {}
  z_pair f[n]: DiracDelta(n)
  try,check  : True -> True
[0]   pair f[n]: (-19*DiracDelta(n)/6, True, True)
  term_k[n]: (-19*DiracDelta(n)/6, True, True)
  term_k[z]: 3*z/(2*(z - 2))
[0] _z_pairs_prop_inverse ----
_simplify_z: 3*z/(2*(z - 2))
  P_leadcoef: 3  ; P_zc: 1  ; P: z
  Q_leadcoef: 2  ; Q_zc: 1  ; Q: z - 2
  _simplify_z k_sign: 1  ; k: 3/2  ; P_zc: 1  ; Q_zc: 1
    F[z]: z/(z - 2)

[1] z_properties_inverse_z_transform
  P: z 
  Q: z - 2 
  P_degree: 1  ; P_zeros: {0: 1} 
  Q_degree: 1  ; Q_poles: {2: 1}
  ma_P1 (a*z+ b):    {a_: 1, b_: 0}
  ma_Q1 (a*z-b)**c : {a_: 1, b_: 2, c_: 1}

 _z_property multiply (a**n)*f[n] <--> F(z/a) 
 k_sign: 1 ; k: 3/2  ; k_b: 2
 F[z]: z/(z - 1)
[2] _z_pairs_prop_inverse ----
_simplify_z: z/(z - 1)
    F[z]: z/(z - 1)
 _z_pairs_table match: 
  F: z/(z - 1)
  z_pair F[z]: z/(z - 1)  ; ma_z: {}
  z_pair f[n]: Heaviside(n)
  try,check  : True -> True
[2]   pair f[n]: (Heaviside(n), Abs(z) > 1, True)

  _z_property multiply (a**n)*f[n]:
  (3*2**n*Heaviside(n)/2, Abs(z) > 2, True)
[1]  _z_properties_inverse f[n]: (3*2**n*Heaviside(n)/2, Abs(z) > 2, True)
[0]   prop f[n]: (3*2**n*Heaviside(n)/2, Abs(z) > 2, True)
  term_k[n]: (3*2**n*Heaviside(n)/2, Abs(z) > 2, True)
  term_k[z]: 5*z/(3*(z - 3))
[0] _z_pairs_prop_inverse ----
_simplify_z: 5*z/(3*(z - 3))
  P_leadcoef: 5  ; P_zc: 1  ; P: z
  Q_leadcoef: 3  ; Q_zc: 1  ; Q: z - 3
  _simplify_z k_sign: 1  ; k: 5/3  ; P_zc: 1  ; Q_zc: 1
    F[z]: z/(z - 3)

[1] z_properties_inverse_z_transform
  P: z 
  Q: z - 3 
  P_degree: 1  ; P_zeros: {0: 1} 
  Q_degree: 1  ; Q_poles: {3: 1}
  ma_P1 (a*z+ b):    {a_: 1, b_: 0}
  ma_Q1 (a*z-b)**c : {a_: 1, b_: 3, c_: 1}

 _z_property multiply (a**n)*f[n] <--> F(z/a) 
 k_sign: 1 ; k: 5/3  ; k_b: 3
 F[z]: z/(z - 1)
[2] _z_pairs_prop_inverse ----
_simplify_z: z/(z - 1)
    F[z]: z/(z - 1)
 _z_pairs_table match: 
  F: z/(z - 1)
  z_pair F[z]: z/(z - 1)  ; ma_z: {}
  z_pair f[n]: Heaviside(n)
  try,check  : True -> True
[2]   pair f[n]: (Heaviside(n), Abs(z) > 1, True)

  _z_property multiply (a**n)*f[n]:
  (5*3**n*Heaviside(n)/3, Abs(z) > 3, True)
[1]  _z_properties_inverse f[n]: (5*3**n*Heaviside(n)/3, Abs(z) > 3, True)
[0]   prop f[n]: (5*3**n*Heaviside(n)/3, Abs(z) > 3, True)
  term_k[n]: (5*3**n*Heaviside(n)/3, Abs(z) > 3, True)

 f[n]: 3*2**n*Heaviside(n)/2 + 5*3**n*Heaviside(n)/3 - 19*DiracDelta(n)/6
 f[n]: (9*2**n + 10*3**n)*Heaviside(n)/6 - 19*DiracDelta(n)/6
f[n] : (9*2**n + 10*3**n)*Heaviside(n)/6 - 19*DiracDelta(n)/6
>>>