1.6 Espectro – Formato Euler a coseno(t) con Sympy-Python

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]

Como resultado del producto de sinusoides usando la fórmula de Euler se obtienen términos exponenciales para las partes de frecuencia y fase.

El proceso inverso requiere reagrupar las expresiones de la lista Xe_senales por cada término suma.

unaSenal = sym.powsimp(unaSenal,combine='exp')

Luego simplificar sus exponentes tomando como factor común el número complejo I. En éste último paso es necesario tomar en cuenta el signo del término que contiene t.

factor_I = I
if t1<sym.S.Zero:
    factor_I = -I
exponente = factor_I*(sym.expand(exponente/factor_I))

Este proceso se debe aplicar a cada término suma de la expresión, requiriendo un análisis detallado de cada término como se muestra en el algoritmo.

Al terminar de reordenar la expresión se convierte nuevamente a la forma coseno usando la instrucción:

Xe_to_cos = Xe_sum.rewrite(sym.cos)

El proceso de inverso se agrupa en la función euler_to_cos_list(Xe_senales).

La mejor forma de escribir el algoritmo paso a paso es usando un ejemplo, con el que si usa el algoritmo básico desarrollado en Producto de sinusoides , podrá observar que el resultado debe considerar mas casos de los presentados.

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]
..


1. Ejemplo

Referencia: McClellan ejemplo 3.3 p77

La señal x(t) es el producto de dos señales de frecuencias 9 y 200 Hz según la expresión mostrada, realice el espectro de frecuencias correspondiente.  muestre la expresión de cosenos más simples usando las fórmulas de Euler.

x(t) = 2 \cos (2 \pi 9 t) \cos( 2 \pi*200*t)

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]
..


2. Desarrollo analítico

Se usa la fórmula de Euler para cada parte de la expresión:

2 \cos (2 \pi (9) t) = e^{j 2\pi (9) t} +e^{-j 2\pi (9)t} \cos( 2 \pi (200) t) = \frac{1}{2} e^{j 2\pi (200) t} +\frac{1}{2}e^{-j 2\pi (200)t} x(t) = 2 \cos (2 \pi 9 t) \cos( 2 \pi*200*t) x(t) = \Big(e^{j 2\pi (9) t} +e^{-j 2\pi (9)t} \Big) \Big( \frac{1}{2} e^{j 2\pi (200) t} + \frac{1}{2}e^{-j 2\pi (200)t} \Big) = \frac{1}{2} e^{j 2\pi (9) t} e^{j 2\pi (200) t} + \frac{1}{2} e^{j 2\pi (9) t}e^{-j 2\pi (200)t} +\frac{1}{2} e^{-j 2\pi (9)t} e^{j 2\pi (200) t} + \frac{1}{2}e^{-j 2\pi (9)t} e^{-j 2\pi (200)t} = \frac{1}{2}e^{j 2\pi (200) t + j 2\pi (9) t} + \frac{1}{2} e^{-j 2\pi (200) t + j 2\pi (9) t} +\frac{1}{2} e^{j 2\pi (200) t -j 2\pi (9)t} + \frac{1}{2}e^{-j 2\pi (200)t -j 2\pi (9)t} = \frac{1}{2}e^{j 2\pi (209) t } + \frac{1}{2} e^{-j 2\pi (191) t} +\frac{1}{2} e^{j 2\pi (191) t} + \frac{1}{2} e^{-j 2\pi (209)t} x(t) = \cos (2\pi(191)t) + \cos (2 \pi (209)t)

El resultado obtenido usando la función euler_to_cos_list() es:

x(t): 2*cos(9*t*(2*pi))*cos(200*t*(2*pi))
x_senales: 
senal:   2*cos(9*t*(2*pi))*cos(200*t*(2*pi))
  euler: exp(-209*I*t*2*pi)/2 + exp(-191*I*t*2*pi)/2 + exp(191*I*t*(2*pi))/2 + exp(209*I*t*(2*pi))/2
x_expand: 
  cos(382*pi*t) + cos(418*pi*t)
x_espectro:
freq : [-209. -191.  191.  209.]
ampl : [1/2 1/2 1/2 1/2]
fase : [0 0 0 0]
etiq : ['1/2' '1/2' '1/2' '1/2']

La gráfica de espectro muestra las señales desplazadas en frecuencia resultado del producto de senoidales.

espectro Senales Producto Cos 03Se adjunta la gráfica de tiempo como complemento

espectro Senales Producto Cos t 04

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]

..


3. Algoritmo con Python

El algoritmo en Python incluye la función euler_to_cos_list(Xe_senales) que se añade a telg1034.py para el uso en los otros ejercicios cuando se busca simplificar las expresiones de x_senales.

# ejemplo 3.3 p77 Disminuir la diferencia entre 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
from telg1034 import t,A,w,f,p,pi,DosPi,I,equivalentes

# INGRESO
x1 = 2*sym.cos(DosPi*9*t)
x2 = sym.cos(DosPi*200*t)
x  = x1*x2

# PROCEDIMIENTO
x_senales = dsp.x_list_term_Add(x)
x_conteo = len(x_senales)
Xe_senales = dsp.cos_to_euler_one_term(x_senales)
Xe_espectro = dsp.cos_spectrum_list(x_senales)

def euler_to_cos_list(Xe_senales):
    '''Xe_senales a coseno, simplifica x(t) en formato Euler
    '''
    Xe_conteo = len(Xe_senales)
    x_expand = sym.S.Zero
    for i in range(Xe_conteo):
        unaSenal = Xe_senales[i]
        if unaSenal.has(sym.UnevaluatedExpr):
            unaSenal = unaSenal.doit()
        unaSenal = sym.powsimp(unaSenal,combine='exp')
        if unaSenal.is_Add:
            term_sum = unaSenal.args
            Xe_sum = sym.S.Zero
            for unterm in term_sum:
                factor_mul = unterm.args
                if len(factor_mul)>0: # unterm no es constante
                    Xe_term = sym.S.One
                    for unfactor in factor_mul:
                        if unfactor.has(t) and unfactor.has(sym.exp):
                            exponente = unfactor.args[0]
                            expresion = sym.expand(exponente/I)
                            constante = expresion.subs(t,0)
                            expresion = expresion - constante
                            t1 = expresion.subs(t,1)
                            factor_I = I
                            if t1<sym.S.Zero:
                                factor_I = -I
                            exponente = factor_I*(sym.expand(exponente/factor_I))
                            el_factor = sym.exp(exponente)
                        else: # el factor es constante
                            el_factor = unfactor
                        Xe_term = Xe_term*el_factor
                else: # unterm es constante
                    Xe_term = unterm
                Xe_sum = Xe_sum + Xe_term
            Xe_to_cos = Xe_sum.rewrite(sym.cos)
        else:
            Xe_to_cos = unaSenal
        x_expand = x_expand + Xe_to_cos
    return(x_expand)
x_expand = euler_to_cos_list(Xe_senales)

# SALIDA
print('x(t):',x)
print('x_senales: ')
for i in range(x_conteo):
    print('senal:  ',x_senales[i])
    print('  euler:',Xe_senales[i])
print('x_expand: ')
print(' ',x_expand)
print('x_espectro:')
for unparam in Xe_espectro:
    print(unparam,':',Xe_espectro[unparam])

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]
..


4. Gráficas de espectro de frecuencias y señal en tiempo

La parte gráfica es la usada en la sección de Producto de señales

# GRAFICAS de espectro de frecuencias ---------
freq = Xe_espectro['freq']
magnitud = Xe_espectro['ampl']
etiqueta = Xe_espectro['etiq']
mag_max = float(max(magnitud))
freq_max = float(max(freq))

# grafica 
graf_dx = 0.12
fig_espectro = plt.figure()
graf_fasor = fig_espectro.add_subplot()
# grafica magnitud
graf_fasor.set_xlim([-freq_max*(1+graf_dx),freq_max*(1+graf_dx)])
graf_fasor.set_ylim([0,mag_max*(1+graf_dx*2)])
graf_fasor.axhline(0,color='black')
graf_fasor.axvline(0,linestyle='dotted',color='grey')
graf_fasor.stem(freq,magnitud)
# etiquetas de fasor
for k in range(0,len(freq),1):
    texto = etiqueta[k]
    x_text = freq[k]
    y_text = magnitud[k]
    plt.annotate(texto,xy=(x_text,y_text), xytext=(0,5),
                 textcoords='offset points',ha='center')
graf_fasor.grid()
graf_fasor.set_xlabel('freq Hz')
graf_fasor.set_ylabel('amplitud')
graf_fasor.set_title('Espectro: x_senales')

#plt.show()

# GRAFICAR x(t) ---------------------------
# INGRESO
x_senales_graf = [x1,x2,x] # para graficar
x_etiqueta = ['x1(t)','x2(t)','x1(t)x2(t)']
x_tipolinea = ['dashed','dotted','solid']

tramos_T = 20       # tramos por periodo
periodos_graf = 2   # periodos en una grafica

# PROCEDIMIENTO GRAFICA
x_conteo_graf = len(x_senales_graf)
# etiquetas si están vacias
if len(x_etiqueta)==0: 
    if x_conteo_graf > 1:
        for i in range(0,x_conteo_graf-1,1):
            x_etiqueta.append('x'+str(i)+'(t)')
            x_tipolinea.append('dotted')
    x_etiqueta.append('x(t)')
    x_tipolinea.append('solid')
    
[T_min,T_max] = dsp.periodo_minmax(freq)
x_conteo = len(x_senales_graf)

muestras_T = tramos_T + 1
# intervalo de t entre [a,b] en pasos dt
a = 0
b = T_max*periodos_graf
dt = T_min/tramos_T # tamaño de paso,tramo, muestreo
ti = np.arange(a,b+dt,dt)

xi_k = [] # muestras de cada señal x
for unasenal in x_senales_graf:
    # x(t) a forma numérica lambda t:
    if unasenal.has(t):
        xk = sym.lambdify(t,unasenal)
    else: # es constante
        xk = lambda t: unasenal + 0*t
    xki = xk(ti) # evalúa en intervalo
    xi_k.append(np.copy(xki))

# graficar
fig_x = plt.figure()
graf_x = fig_x.add_subplot()
for i in range(0,x_conteo_graf,1):
    color_i = dsp._graf_lineacolor_i(i)
    graf_x.plot(ti,xi_k[i], color=color_i,
                linestyle=x_tipolinea[i],
                label=x_etiqueta[i])
    graf_x.axhline(0,color='black')
graf_x.set_title('Señales xk(t)')
graf_x.set_xlabel('t (segundos)')
graf_x.set_ylabel('x_senales')
graf_x.grid()
graf_x.legend()
plt.show()

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]


5. Tarea

Referencia: McClellan ejercicio 3.1 p75

Verificar el algoritmo con

x(t) = \sin ^2 (10 \pi t)

que debe dar resultado:

x(t): sin(10*pi*t)**2
x_senales: 
senal:   sin(10*pi*t)**2
  euler: -exp(20*I*pi*t)/4 + 1/2 - exp(-20*I*pi*t)/4
x_expand: 
  1/2 - cos(20*pi*t)/2
   freq_min: 10.0
freq_centro: 10.0
   freq_max: 10.0
ancho de banda BW: 0.0
x_espectro:
freq : [-10.   0.  10.]
ampl : [1/4 1/2 1/4]
fase : [pi 0 pi]
etiq : ['1/4$ e^j(\\pi)$' '1/2' '1/4$ e^j(\\pi)$']

[ ejercicio ] [ analítico ][ algoritmo ] [ gráfica ]