7.1.2 Transformada z – Propiedades con Sympy-Python

Luego de intentar obtener la Transformada z con la Tabla de Pares f[n] y F[z], si del resultado sigue siendo None se busca aplicar las reglas descritas en la tabla de propiedades de la Transformada z.

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


1. Propiedad de multiplicación por n de la transformada z

Presentada en la tabla de propiedades y también conocida como Diferenciación en z, se presenta como:

n x[n] u[n] -z \frac{\delta}{\delta z}X(z) R’ = R

Se aplica sobre la señal x[n]=1

x[n] = n \mu[n]

A partir de la tabla de transformadas se tiene que la expresión para μ[n] es

F[z] = \frac{z}{z-1} = (z)\frac{1}{z-1} \frac{\delta}{\delta z}F[z] = \frac{1}{z-1}-\frac{z}{(z-1)^2}

por lo que para X[z] de obtiene como:

X[z] = -z \frac{\delta}{\delta z} F[z] = -z \Big[ \frac{1}{z-1}-\frac{z}{(z-1)^2}\Big] = -z \Big[ -\frac{1}{(z-1)^2}\Big] X[z] = \frac{z}{(z-1)^2}

Algoritmo en Python

El desarrollo del algoritmo es posterior a la búsqueda en la tabla de pares de transformadas z, por lo que se importa el proceso desde telg1001.py. En la tabla, para comprobar el funcionamiento de la propiedad con los resultados del texto, se usa una tabla básica, que luego puede ser ampliada.

El algoritmo se desarrolla para una expresión básica como la de la tabla. Luego los procedimientos se integran en una sola instrucción tal como z_transform(f,n,z) que usa primero la tabla, luego revisa las propiedades y fórmula de la transformada para mostrar un resultado.

u = sym.Heaviside(n)

#f = u
f = n*u

Resultados con el algoritmo:

 k ; func: 1  ;  n*Heaviside(n)
no hubo expresión similar en tabla de transformadas
buscando aplicar una propiedad n*f[n]
  f_powna ; n**a: n  ;  {a_: 1}

 _z_propiedad n*f[n] -------------
  n**a ; func/n, : n  ;  Heaviside(n)
_z_pairs_table match:
  f:           Heaviside(n)
  z_pair f[n]: Heaviside(n)
  z_pair F[z]: z/(z - 1)
  try,check: True -> True
  _z_propiedad n*f[n] <--> -z*diff(Fz):
   (z/(z - 1)**2, Abs(z) > 1, True)
>>> 

Instrucciones en Python

El coeficiente constante k se separa de la expresión para simplificar el análisis de la expresión en func. La constante se reincorpora al resultado al final.

El procedimiento con la tabla de pares de transformadas  z_pairs_properties se obtiene desde telg1001.py , se usa con el parámetro apply_properties=False para mostrar el funcionamiento del algoritmo para el ejercicio. la instrucción z_pairs_properties hace el llamado a una función que analiza la expresión con las propiedades ya implementadas y se omite su escritura en condiciones normales.

Las expresiones pueden tener dos factores con exponentes: an, na, que corresponden a dos propiedades diferentes. El factor  de interés para el ejercicio es na.  La búsqueda de éstos factores se realiza con las instrucciones sym.pow(n,a) y sym.pow(a,n), en la variable f_powna que se inicializan con sym.S.One.

Cuando se encuentra la expresión con f_powna se modifica expresión func_n =func/n, con la que se vuelve a buscar el resultado en la tabla. El proceso para analizar la expresión puede realizarse de forma recursiva hasta obtener una expresión simple como μ[n] y regresar al estado anterior para completar las operaciones. La forma recursiva requiere implementar el procedimiento con def z_propiedades().

La aplicación de la propiedad de multiplicación para n(x[n]) prepara la expresión para aplicar:

n x[n] \longleftrightarrow -z \frac{\delta}{\delta z}X(z)
Fz = (k*(-z)*sym.factor(sym.diff(Fz[0],z,1)),
                  Fz[1], Fz[2])

que contiene las partes de la transformada como el plano de convergencia y condiciones de aplicación que también deben tomarse en cuenta durante el proceso. Aunque para expresiones se sumas, no se toman en cuenta para el resultado final como en los ejercicios de los textos de referencia.

Esta sección expone cómo se implementa la propiedad de transformada z, el resultado final se encuentra en el archivo.py.

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

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

#f = u
f = n*u
#f = sym.cos(2*n)
#f = sym.sin(2*n)

# PROCEDIMIENTO
f = sym.expand(sym.powsimp(f))
a = sym.Wild('a', exclude=[n])
b = sym.Wild('b', exclude=[n])
y = sym.Wild('y')
g = sym.WildFunction('g', nargs=1)

# separa constantes del término
k, func = f.as_independent(n, as_Add=False)
print(' k ; func:',k,' ; ',func)
Fz = z_pairs_properties(func, n, z, apply_properties=False)
if not(Fz==None):
    Fz = k*Fz
    print(' usando tabla de pares: \n ',Fz)

if Fz==None: # no encontrada en tabla
    print('no hubo expresión similar en tabla de transformadas')
    print('buscando aplicar una propiedad n*f[n]')
    # crear una función para aplicar varias veces las propiedades
    # en las expresiones, en forma recursiva.
    
    # busca factores pow(n,a) or pow(a,n)
    f_powna = sym.S.One ; f_powan = sym.S.One
    factor_Mul = sym.Mul.make_args(func)
    for factor_k in factor_Mul:
        ma_powna = factor_k.match(sym.Pow(n,a))
        ma_powan = factor_k.match(sym.Pow(a,n))
        if ma_powna and not(ma_powna[a]==sym.S.Zero) and ma_powna[a].is_integer:
            f_powna = f_powna*factor_k
            print('  f_powna ; n**a:',factor_k,' ; ',ma_powna)
        if ma_powan:
            f_powan = f_powan*factor_k
            print('  f_powan ; a**n:',factor_k,' ; ',ma_powan)

    # otras formas de expresión a revisar
    ma_un = func.match(sym.Heaviside(y))
    ma_gn = func.match(g)
    ma_gu = func.match(g*sym.Heaviside(y))

    # z_propiedad de multipliación n*f[n] <--> -z*dF(z)/dz --------
    if not(f_powna==sym.S.One): # n**a factor encontrado
        ma_powna = f_powna.match(sym.Pow(n,a))
        func_n = func/n # aplicar luego de forma recursiva
        print('\n _z_propiedad n*f[n] -------------')
        print('  n**a ; func/n, :',n,' ; ',func_n)
        Fz = z_pairs_properties(func_n,n,z,
                                apply_properties=False)
        if not(Fz==None):
            Fz = (k*(-z)*sym.factor(sym.diff(Fz[0],z,1)),
                  Fz[1], Fz[2])
            print('  _z_propiedad n*f[n] <--> -z*diff(Fz):\n  ',Fz)

if Fz==None: # no encontrada en tabla, tampoco con la propiedad
    print('propiedad implementada no es suficiente')
    print('implementar otras propiedades.')

Un procedimiento semejante se implementa para la transformada z inversa.

2. Propiedad de multiplicación por n de la transformada z inversa

Se aplica a partir de F(z), donde la expresión será tipo polinomio, por lo que se prepara la expresión para conocer el grado del numerador y de nominador, separar su signo, constante de multiplicación, coeficientes, etc.

Para el resultado del ejercicio anterior f(n) = nμ(n) se obtuvo la expresión:

F[z] = \frac{z}{(z-1)^2}
n x[n] u[n] -z \frac{\delta}{\delta z}X(z) R’ = R

el sentido inverso de la propiedad, se aplica con un integral sobre la expresión con denominador Q=(z-a)b. y a partir de la respuesta F[z] con al menos el grado del numerador P de 1.

El integral se desarrolla con la expresión despejada de la derivada y con un valor F(0)=0 para determinar la constante del integral.

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

usando el valor de para la constante F(0)=0

0 = \frac{1}{(0-1)} + C C = 1 X[z] = \frac{1}{(z-1)} +1 = \frac{1+(z-1)}{(z-1)} X[z] = \frac{z}{(z-1)}

de la tabla la transformada z inversa es μ(n), y al aplicar al resultado la propiedad se tiene:

x[n] = n \mu [n]

resultados con el algoritmo:

 Parametros de P/Q -------------
 P: z
 Q: (z - 1)**2
 P_signo ;k :  1  ;  1
 P_grado, P_ceros: 1  ;  {0: 1}
 Q_grado, Q_polos (real):  2  ;  [1, 1]
 ma_P1 (a*z+ b) :  {a_: 1, b_: 0}
 ma_Q1 (z-a)**b :  {a_: 1, b_: 2}
 ma_Q2 a*z**2+ b*z + r**2:  None
 Fz :  z/(z - 1)**2

 _z_propiedad multiplicación nf[n] <--> -z*diff(F[z])-- 
 Func = integrate(factor(Fz)/z,z):
  z/(z - 1)
_z_pairs_table match:
  k ; F:      1 z/(z - 1)
  z_pair F[z]: z/(z - 1)
         ma_z: {}
  z_pair f[n]: Heaviside(n)
  try,check: True -> True
  _z_propiedad multiplicación nf[n]:
  (n*Heaviside(n), Abs(z) > 1, True)
>>> 

Instrucciones en Python

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

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

# multiplicación nf[n] <--> -z*diff(F[z])
#F = z/(z - 1) #f = u
F = z/(z - 1)**2 #f = n*u
#F = z*(z + 1)/(z - 1)**3 # (n**2)*u

# PROCEDIMIENTO
# separa constantes del término
fn = z_pairs_prop_inverse(F, z, n, apply_properties=False)
if not(fn==None):
    print(' usando tabla de pares: \n ',fn)

if fn==None: # no encontrada en tabla
    Fz = sym.simplify(F) #sym.simplify(F)
    a = sym.Wild('a', exclude=[n,z])
    b = sym.Wild('b', exclude=[n,z])
    r = sym.Wild('r', exclude=[n,z])
    y = sym.Wild('y')
    g = sym.WildFunction('g', nargs=1)
    # analiza como polinomio F[z]:
    # P_signo, constante, F[z] pares
    [P,Q] = F.as_numer_denom()
    # P
    P = sym.Poly(P,z)
    ma_P1 = P.match(a*z+ b)
    P_zeros  = sym.roots(P)
    P_degree = sym.degree(P,z)
    P_leadcoef = sym.LC(P)
    k = sym.Abs(P_leadcoef)
    P_sign = P_leadcoef/k
    P = P/P_leadcoef
    # Q
    Q = sym.factor(Q)
    ma_Q1 = Q.match((z-a)**b)
    ma_Q2 = Q.match(a*z**2+ b*z + r**2)
    Q_poles = sym.real_roots(Q)
    Q_degree = sym.degree(Q,z)
    # separa constante
    Fz = sym.factor(Fz*P_sign/k)
    print('\n Parametros de P/Q -------------')
    print(' P:',P)
    print(' Q:',Q)
    print(' P_signo ;k : ',P_sign,' ; ',k)
    print(' P_grado, P_ceros:',P_degree,' ; ', P_zeros)
    print(' Q_grado, Q_polos (real): ',Q_degree,' ; ',Q_poles)
    print(' ma_P1 (a*z+ b) : ',ma_P1)
    print(' ma_Q1 (z-a)**b : ',ma_Q1)
    print(' ma_Q2 a*z**2+ b*z + r**2: ',ma_Q2)
    print(' Fz : ',Fz)
    
    # _z_property nf[n] <--> -z*diff(F[z])
    if ma_Q1 and ma_Q1[a]==1 and P_degree>0:
        FuncI = sym.factor(Fz/(-z),z)
        Func = sym.integrate(FuncI,z)
        F0 = 0 # para Constante de integral
        C = -Func.subs(z,0)+F0 
        FunC = sym.factor(Func+C)
        print('\n _z_propiedad multiplicación nf[n] <--> -z*diff(F[z])-- ')
        print(' Func = integrate(factor(Fz)/z,z):\n ',FunC)
        fn = z_pairs_prop_inverse(FunC, z, n, apply_properties=True)
        if not(fn==None):
            fn = (P_sign*k*n*fn[0],fn[1],fn[2])
            print('  _z_propiedad multiplicación nf[n]:\n ',fn)

if fn==None: # no encontrada en tabla, tampoco con la propiedad
    print('propiedad implementada no es suficiente')
    print('implementar otras propiedades.')

Si la propiedad debe aplicarse más de una vez, será necesario convertir el bloque a una función para hacer llamadas recursivas a si misma, como es el caso de n2*u

F = z*(z + 1)/(z - 1)**3 # (n**2)*u

o al final de la sección de la propiedad, usar apply_properties=True, para usar el algoritmo implementado en telg1001_z .