#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Thu Mar 2 11:26:00 2023
@author: mariano
"""
import numpy as np
import sympy as sp
from .remociones import isFRP, remover_polo_infinito, remover_valor_en_infinito, remover_polo_dc, remover_valor_en_dc, trim_func_s
##########################################
#%% Variables para el análisis simbólico #
##########################################
from .general import s, expr_simb_expr, print_console_alert, print_latex
[docs]def cauer_RC( imm, remover_en_inf=True ):
'''
Realiza una expansión en fracciones continuas sobre una inmitancia (imm),
removiendo en DC o :math:`\\infty` dependiendo de (remover_en_inf). Este
procedimiento se conoce como métodos de Cauer I y II. En el ejemplo de
:math:`Z_{RC}` se remueve en DC y para el caso de :math:`Y_{RC}`
en :math:`\\infty`.
.. math:: Z_{RC}(s)= \\frac{1}{s.C_1} + \\frac{1}{ \\frac{1}{R_1} + \\frac{1}{ \\frac{1}{s.C_2} + \\cdots } } =
R_1 + \\frac{1}{ s.C_1 + \\frac{1}{ R_2 + \\cdots } }
.. math:: Y_{RC}(s)= s.C_1 + \\frac{1}{ R_1 + \\frac{1}{ s.C_2 + \\cdots } } =
\\frac{1}{R_1} + \\frac{1}{ s.C_1 + \\frac{1}{ \\frac{1}{R_2} + \\cdots } }
Parameters
----------
imm : symbolic rational function
La inmitancia a expandir en fracciones continuas..
remover_en_inf : boolean
Determina en qué extremo se realiza la remoción.
Returns
-------
A list k0 with the i-th k0_i resulted from continued fraction expansion.
Raises
------
ValueError
Si y_exc y z_exc no son una instancia de sympy.Expr.
See Also
--------
:func:`cauer_LC`
:func:`dibujar_cauer_RC_RL`
:func:`dibujar_cauer_LC`
Example
-------
>>> import sympy as sp
>>> from pytc2.sintesis_dipolo import cauer_RC
>>> from pytc2.dibujar import dibujar_cauer_RC_RL
>>> s = sp.symbols('s ', complex=True)
>>> # Sea la siguiente función de excitación
>>> ZRC = (s**2 + 4*s + 3)/(s**2 + 2*s)
>>> # Implementaremos FF mediante Cauer 1 o remociones continuas en infinito
>>> koo, ZRC_cauer_oo, rem = cauer_RC(ZRC, remover_en_inf=True)
>>> # Tratamos a nuestra función inmitancia como una Z
>>> dibujar_cauer_RC_RL(koo, z_exc = ZRC_cauer_oo)
>>> # Tratamos a nuestra función inmitancia como una Y
>>> dibujar_cauer_RC_RL(koo, y_exc = ZRC_cauer_oo)
'''
if not isinstance(imm , sp.Expr):
raise ValueError('Hay que definir imm como una expresión simbólica.')
if not isinstance(remover_en_inf, bool):
raise ValueError('remover_en_inf debe ser un booleano.')
ko = []
if remover_en_inf:
rem, koi = remover_polo_infinito(imm)
bRemoverPolo = False
if koi.is_zero:
rem, koi = remover_valor_en_infinito(imm)
bRemoverPolo = True
else:
rem, koi = remover_polo_dc(imm)
bRemoverPolo = False
if koi.is_zero:
rem, koi = remover_valor_en_dc(imm)
bRemoverPolo = True
if isFRP(rem):
bFRP = True
while bFRP and not(rem.is_zero) and not(koi.is_zero):
ko += [koi]
rem = 1/rem
if remover_en_inf:
if bRemoverPolo:
rem_aux, koi = remover_polo_infinito(rem)
bRemoverPolo = False
else:
rem_aux, koi = remover_valor_en_infinito(rem)
bRemoverPolo = True
else:
if bRemoverPolo:
rem_aux, koi = remover_polo_dc(rem)
bRemoverPolo = False
else:
rem_aux, koi = remover_valor_en_dc(rem)
bRemoverPolo = True
bFRP = isFRP(rem_aux)
if bFRP:
rem = rem_aux
if koi.is_zero:
# deshago para entender al resto de la misma
# naturaleza que el último elemento que retiró.
rem = 1/rem
else:
if bFRP:
ko += [koi]
imm_as_cauer = ko[-1]
for ii in np.flipud(np.arange(len(ko)-1)):
imm_as_cauer = ko[ii] + 1/imm_as_cauer
else:
# no se pudo hacer ninguna remoción
imm_as_cauer = imm
ko = [s*0]
rem = s*0
if not (sp.simplify(sp.expand(imm_as_cauer - imm))).is_zero:
# error
print_console_alert('Fallo la expansión')
print_latex(expr_simb_expr(imm, imm_as_cauer, ' \\neq '))
RuntimeWarning('Fallo la expansión Cauer. Revisar!!')
return(ko, imm_as_cauer, rem)
[docs]def cauer_LC( imm, remover_en_inf = True ):
'''
Dibuja una red escalera no disipativa, a partir de la expansión en fracciones
continuas (Método de Cauer). Se remueve en DC o :math:`\\infty` dependiendo
de *remover_en_inf*. En los siguientes ejemplos se expande tanto :math:`Z(s)`
como :math:`Y(s)`, y se remueve a la izquierda en DC y a la derecha en :math:`\\infty`.
La forma matemática será:
.. math:: Z(s)= \\frac{1}{s.C_1} + \\frac{1}{ \\frac{1}{s.L_1} + \\frac{1}{ \\frac{1}{s.C_2} + \\cdots } } =
s.L_1 + \\frac{1}{ s.C_1 + \\frac{1}{ s.L_2 + \\cdots } }
.. math:: Y(s)= \\frac{1}{s.L_1} + \\frac{1}{ \\frac{1}{s.C_1} + \\frac{1}{ \\frac{1}{s.L_2} + \\cdots } } =
s.C_1 + \\frac{1}{ s.L_1 + \\frac{1}{ s.C_2 + \\cdots } }
Parameters
----------
imm : symbolic rational function
La inmitancia a expandir en fracciones continuas..
remover_en_inf : boolean
Determina en qué extremo se realiza la remoción.
Returns
-------
ko : lista de expresiones simbólicas
Conjunto de términos con los residuos de forma :math:`\\frac{k_0}{s}` y :math:`s.k_{\\infty}`
imm_as_cauer : symbolic rational function
La función inmitancia expandida en fracciones contínuas.
rem : symbolic rational function
0 en caso que la expansión sea exitosa, ó una función remanente que no
puede ser expresada en formato Cauer.
Raises
------
ValueError
Si y_exc y z_exc no son una instancia de sympy.Expr.
See Also
--------
:func:`cauer_LC`
:func:`foster_zRC2yRC`
:func:`dibujar_cauer_LC`
Examples
--------
>>> import sympy as sp
>>> from pytc2.sintesis_dipolo import cauer_LC
>>> from pytc2.dibujar import dibujar_cauer_LC
>>> s = sp.symbols('s ', complex=True)
>>> # Sea la siguiente función de excitación
>>> FF = (2*s**4 + 20*s**2 + 18)/(s**3 + 4*s)
>>> # Implementaremos FF mediante Cauer 1 o remociones continuas en infinito
>>> koo, F_cauer_oo, rem = cauer_LC(FF, remover_en_inf=True)
>>> # Tratamos a nuestra función inmitancia como una Z
>>> dibujar_cauer_LC(koo, z_exc = F_cauer_oo)
>>> # Tratamos a nuestra función inmitancia como una Y
>>> dibujar_cauer_LC(koo, y_exc = F_cauer_oo)
'''
if not isinstance(imm , sp.Expr):
raise ValueError('Hay que definir imm como una expresión simbólica.')
if not isinstance(remover_en_inf, bool):
raise ValueError('remover_en_inf debe ser un booleano.')
rem = imm
ko = []
# a veces por problemas numéricos no hay cancelaciones de los términos
# de mayor o menor orden y quedan coeficientes muy bajos.
rem = trim_func_s(sp.simplify(sp.expand(rem)))
if remover_en_inf:
rem_aux, koi = remover_polo_infinito(rem)
else:
rem_aux, koi = remover_polo_dc(rem)
bFRP = isFRP(rem_aux)
if bFRP:
rem = rem_aux
while bFRP and not(rem.is_zero) and not(koi.is_zero):
ko += [koi]
rem = 1/rem
# a veces por problemas numéricos no hay cancelaciones de los términos
# de mayor o menor orden y quedan coeficientes muy bajos.
rem = trim_func_s(sp.simplify(sp.expand(rem)))
if remover_en_inf:
rem_aux, koi = remover_polo_infinito(rem)
else:
rem_aux, koi = remover_polo_dc(rem)
bFRP = isFRP(rem_aux)
if bFRP:
rem = rem_aux
if koi.is_zero:
# deshago para entender al resto de la misma
# naturaleza que el último elemento que retiró.
rem = 1/rem
else:
if bFRP:
# si no salimos por rem NO FRP
ko += [koi]
imm_as_cauer = ko[-1] + rem
for ii in np.flipud(np.arange(len(ko)-1)):
imm_as_cauer = ko[ii] + 1/imm_as_cauer
else:
# no se pudo hacer ninguna remoción
imm_as_cauer = imm
ko = [s*0]
rem = s*0
if not (sp.simplify(sp.expand(imm_as_cauer - imm))).is_zero:
# error
print_console_alert('Fallo la expansión')
print_latex(expr_simb_expr(imm, imm_as_cauer, ' \\neq '))
return(ko, imm_as_cauer, rem)
# TODO: me gustaría documentar y probar mejor esta función
[docs]def foster_zRC2yRC( k0 = sp.Rational(0), koo = sp.Rational(0), ki_wi = sp.Rational(0), kk = sp.Rational(0), ZRC_foster = sp.Rational(0) ):
'''
Permite llegar a la forma foster de una inmitancia :math:`I(s)` (YRC - ZRL),
a partir de la propia función :func:`foster` de expansión en fracciones
simples, y una conversión término-a-término de cada residuo obtenido.
De esa manera se comienza con la expansión foster( I(s)/s ), para luego
realizarel siguiente mapeo de residuos:
+ :math:`k_\\infty = kk`
+ :math:`k_k = k_0`
+ :math:`k_i = ki_wi`
+ :math:`I_F(s) = I(s)*s`
Parameters
----------
k0: simbólica, opcional
Residuo de la función en DC o :math:`s \\to 0`. El valor predeterminado es 0.
koo: simbólica, opcional
Residuo de la función en infinito o :math:`s \\to \\infty`. El valor predeterminado es 0.
ki_wi: simbólica, list o tuple opcional
Residuo de la función en :math:`\\omega_i` o :math:`s^2 \\to -\\omega^2_i`. El valor predeterminado es 0.
kk: simbólica, opcional
Residuo de la función en :math:`\\sigma_i` o :math:`\\omega \\to -\\omega_i`. El valor predeterminado es 0.
ZRC_foster: simbólica
Función inmitancia :math:`I(s)` a expresar como :math:`I_F(s)`
Returns
-------
k0: simbólica, opcional
No está permitido para esta forma el residuo en 0.
koo: simbólica, opcional
Residuo de la función en infinito o :math:`s \\to \\infty`.
ki: simbólica, list o tuple opcional
Residuo de la función en :math:`\\omega_i` o :math:`s \\to -\\sigma_i`.
kk: simbólica, opcional
Residuo de la función en :math:`\\sigma = 0`.
YRC_foster: simbólica
Función YRC expresada como :math:`I_F(s) = I(s)*s`
Raises
------
ValueError
Si cualquiera de los argumentos no son una instancia de sympy.Expr.
See Also
--------
:func:`foster`
:func:`foster_zRC2yRC`
:func:`dibujar_foster_serie`
Examples
--------
>>> import sympy as sp
>>> from pytc2.sintesis_dipolo import foster, foster_zRC2yRC
>>> from pytc2.dibujar import dibujar_foster_derivacion
>>> s = sp.symbols('s ', complex=True)
>>> # Sea la siguiente función de excitación
>>> YRC = 2*(s**2 + 4*s + 3)/(s**2 + 8*s + 12)
>>> k0, koo, ki_wi, kk, YRC_foster = foster(YRC/s)
>>> k0, koo, ki_wi, kk, YRC_foster = foster_zRC2yRC(k0, koo, ki_wi, kk, YRC_foster)
>>> dibujar_foster_derivacion(k0 = k0, koo = koo, ki = ki_wi, y_exc = YRC_foster)
'''
if koo.is_zero:
# koo tiene que ser 0 para ZRC ya que en inf habrá
# o 0 o cte.
if not(kk.is_zero):
koo = kk
kk = sp.Rational(0)
if not(k0.is_zero):
kk = k0
k0 = sp.Rational(0)
if (isinstance(ki_wi, sp.Expr) and not (ki_wi.is_zero)) or isinstance(ki_wi, list):
ki = ki_wi
# ki = []
# for this_ki_wi in ki_wi:
# ki += [[this_ki_wi[1], this_ki_wi[0]]]
YRC_foster = sp.expand(ZRC_foster * s)
return([k0, koo, ki, kk, YRC_foster])
[docs]def foster( imm ):
'''
Expande una función inmitancia :math:`I(s)` en fracciones simples, de acuerdo al método
de Foster. La forma matemática es:
.. math:: I(s)= \\frac{k_0}{s} + k_\\infty.s + \\sum_{i=1}^N\\frac{2.k_i.s}{s^2+\\omega_i^2}
Dependiendo la naturaleza de :math:`I(s)` como impedancia o admitancia,
resultará en los métodos de Foster serie, o paralelo. También existen 3
variantes 1) en caso que se trate de redes no disipativas (LC), y redes
disipativas compuestos solo por dos elementos circuitales: RC - RL. 2) Las
expresiones matemáticas para :math:`Z_{RC}` son las mismas que :math:`Y_{RL}`,
mientras que 3) las de :math:`Z_{RL}` iguales a las de :math:`Y_{RC}`.
Parameters
----------
k0: simbólica, opcional
Residuo de la función en DC o :math:`s \\to 0`. El valor predeterminado es 0.
koo: simbólica, opcional
Residuo de la función en infinito o :math:`s \\to \\infty`. El valor predeterminado es 0.
ki: simbólica, list o tuple opcional
Residuo de la función en :math:`\\omega_i` o :math:`s^2 \\to -\\omega^2_i`. El valor predeterminado es 0.
kk: simbólica, opcional
Residuo de la función en :math:`\\sigma_i` o :math:`\\omega \\to -\\omega_i`. El valor predeterminado es 0.
Returns
-------
k0: simbólica, opcional
El residuo en 0, expresado matemáticamente como :math:`\\frac{k_0}{s}`.
koo: simbólica, opcional
Residuo de la función en infinito o :math:`s \\to \\infty`, que se
corresponde al término :math:`k_\\infty*s`.
ki: simbólica, list o tuple opcional
Residuo de la función en :math:`s^2 \\to -\\omega_i^2`, matemáticamente
:math:`\\frac{2.k_i.s}{s^2+\\omega_i^2}`.
kk: simbólica, opcional
Residuo de la función en :math:`\\sigma = 0`, para funciones disipativas.
foster_form: simbólica
Función YRC expresada como :math:`I_F(s) = I(s)*s`
Raises
------
ValueError
Si cualquiera de los argumentos no son una instancia de sympy.Expr.
See Also
--------
:func:`foster`
:func:`foster_zRC2yRC`
:func:`dibujar_foster_paralelo`
Examples
--------
>>> import sympy as sp
>>> from pytc2.sintesis_dipolo import foster
>>> from pytc2.dibujar import dibujar_foster_serie
>>> s = sp.symbols('s ', complex=True)
>>> # Sea la siguiente función de excitación
>>> FF = (2*s**4 + 20*s**2 + 18)/(s**3 + 4*s)
>>> # Se expande FF a la Foster
>>> k0, koo, ki_wi, _, FF_foster = foster(FF)
>>> # Tratamos a nuestra función imitancia como una Z
>>> dibujar_foster_serie(k0 = k0, koo = koo, ki = ki_wi, z_exc = FF)
'''
if not isinstance(imm , sp.Expr):
raise ValueError('Hay que definir imm como una expresión simbólica.')
num, den = imm.as_numer_denom()
# grados de P y Q
# deg_P = sp.degree(num)
# deg_Q = sp.degree(den)
imm_foster = sp.polys.partfrac.apart(imm)
all_terms = imm_foster.as_ordered_terms()
kk = sp.Rational(0)
k0 = sp.Rational(0)
koo = sp.Rational(0)
ki = []
ii = 0
foster_form = sp.Rational(0)
for this_term in all_terms:
foster_form += this_term
num, den = this_term.as_numer_denom()
if sp.degree(num) == 1 and sp.degree(den) == 0:
koo = num.as_poly(s).LC() / den
elif sp.degree(den) == 1 and sp.degree(num) == 0:
if den.as_poly(s).all_coeffs()[1] == 0:
# red no disipativa
k0 = num / den.as_poly(s).LC()
else:
# red disipativa - tanque RC-RL
# kk_i, koo_i
ki += [[(den / num).expand().as_poly(s).EC(),
(den / num).expand().as_poly(s).LC() ]]
ii += 1
elif sp.degree(den) == 0 and sp.degree(num) == 0:
# constante en redes disipativas
kk = num / den.as_poly(s).LC()
elif sp.degree(num) == 1 and sp.degree(den) == 2:
# tanque
tank_el = (den / num).expand().as_ordered_terms()
koo_i = sp.Rational(0)
k0_i = sp.Rational(0)
for this_el in tank_el:
num, den = this_el.as_numer_denom()
if sp.degree(num) == 1 and sp.degree(den) == 0:
koo_i = num.as_poly(s).LC() / den
elif sp.degree(den) == 1 and sp.degree(num) == 0:
k0_i = num / den.as_poly(s).LC()
ki += [[k0_i, koo_i]]
ii += 1
else:
# error
assert('Error al expandir en fracciones simples.')
if ii == 0:
ki = sp.Rational(0)
if not (sp.simplify(sp.expand(foster_form - imm))).is_zero:
# error
print_console_alert('Fallo la expansión')
print_latex(expr_simb_expr(imm, foster_form, ' \\neq '))
return([k0, koo, ki, kk, foster_form])