Sistema masa resorte amortiguador#

Ecuaciones de movimiento#

Supongamos que el resorte no cumple la ley de Hook, sino que produce una fuerza que es:

\[f_k = Kx^3\]

Entonces las ecuaciones de movimiento son

\[ ma(t) = F+mg - f_b - f_k \implies m \ddot x(t) = F + mg - b \dot x(t) - K x^3(t)\]

Podemos escribir las ecuaciones de estado, suponiendo los estados son \(\dot x = x_1\) y \(x = x_2\). Entonces resultan:

\[\begin{split} \left\{ \begin{array}{ll} \dot x_1(t) = & -\dfrac{b}{m} x_1(t) - \dfrac{K} {m} x_2^3(t) +\dfrac{F(t)}{m} + g\\ \dot x_2(t) = & x_1(t) \end{array} \right. \end{split}\]

El objetivo es linealizar el sistema en torno al punto de operaci贸n. Vamos a obtener el punto de operaci贸n para \(F=0\).

Usaremos para este trabajo SymPy para que nos ayude con la matem谩tica simb贸lica.

SymPy para la linealizaci贸n#

Primero importamos el paquete de c谩lculo simb贸lico e inicializamos la forma en que este paquete mostrar谩 las formulas en pantalla.

import sympy as sp
sp.init_printing()

Ahora definimos los s铆mbolos que estar谩 presentes en las ecuaciones y luego las ecuaciones usando estos s铆mbolos

F, m,  g, K, b, x1, x2 = sp.symbols('F, m,  g, K, b, x1, x2')
dx1 = -b/m*x1-K/m*x2**3+F/m+g
dx2 = x1

Ahora vemos como muestra SymPy las ecuaciones

dx1
../../../../_images/f2c19eafdbd6c8d6c57bc15b6f07b2995c75bd8515da660fce73229f6a4a0547.png
ec_est=sp.Matrix([dx1,dx2])
x=sp.Matrix([x1,x2])
u = sp.Matrix([F])

Recordando un poco lo visto en teor铆a, podemos resolver la linealizaci贸n r谩pidamente obteniendo el Jacobiano de las ecuaciones de estado.

A = ec_est.jacobian(x)
B = ec_est.jacobian(u)

Veamos el resultado:

A
\[\begin{split}\displaystyle \left[\begin{matrix}- \frac{b}{m} & - \frac{3 K x_{2}^{2}}{m}\\1 & 0\end{matrix}\right]\end{split}\]
B
\[\begin{split}\displaystyle \left[\begin{matrix}\frac{1}{m}\\0\end{matrix}\right]\end{split}\]

El punto de equilibrio de un sistema es donde el sistema est谩 quieto o permanece si variar nada. Para obtener el punto de equilibrio, por lo tanto tenemos que hacer que las variables de estados \(x_1\) y\( x_2\) permanezcan constantes. Esto ocurre cuando todas las derivadas \(\dot x_1\) y \(\dot x_2\) son igual a 0 (el sistema esta quieto). Vamos a considerar en un primer momento \(F=0\).

ec_est_f0 = ec_est.subs([(F,0)]) # substitu铆mos F con 0
sol0 = sp.solve(ec_est_f0,(x1,x2), dict=True) # resolvemos X1, y x2
sol0
../../../../_images/942cb7ee6865d2ffa89f6705f519f1969bb2fa4f52bcb2e2767110f4bdb643b3.png

Me quedo solo con la soluci贸n real, por ser la 煤nica con sentido f铆sico

sol0 = sol0[0]
sol0
../../../../_images/9bad687226dd82011a8f72cea52ccf7120eb95d0db1d9f1a0ecc0628bb89543a.png
A.subs(sol0)
B.subs(sol0)
\[\begin{split}\displaystyle \left[\begin{matrix}\frac{1}{m}\\0\end{matrix}\right]\end{split}\]

Podemos resolver tambi茅n ahora si ponemos una \(F=1\)

ec_est_f1 = ec_est.subs([(F,1)]) 
sol1 = sp.solve(ec_est_f1,(x1,x2),dict=True)
sol1
../../../../_images/2e3b70acc64f2a2ee67bf3402305579b6b93a95febf055366e58ad4102cbb4c3.png

Me quedo con la 煤nica soluci贸n real posible que es la primera (recodar que python indexa de 0).

sol1 = sol1[0]
A.subs(sol1), B.subs(sol1) 
\[\begin{split}\displaystyle \left( \left[\begin{matrix}- \frac{b}{m} & - \frac{3 K \left(\frac{g m}{K} + \frac{1}{K}\right)^{\frac{2}{3}}}{m}\\1 & 0\end{matrix}\right], \ \left[\begin{matrix}\frac{1}{m}\\0\end{matrix}\right]\right)\end{split}\]

Vemos que esta es una matriz que posee s铆mbolos. Para poder usarla con el paquete de control, debemos pasarla a una matriz puramente num茅rica. esto lo haremos substituyendo los s铆mbolos por valores

An=A.subs(sol1).subs([(b,1),(K,2),(m,3),(g,9.8)])
Bn=B.subs(sol1).subs([(b,1),(K,2),(m,3),(g,9.8)])

Ahora veamos los resultados

An
\[\begin{split}\displaystyle \left[\begin{matrix}- \frac{1}{3} & -12.2722931550313\\1 & 0\end{matrix}\right]\end{split}\]
Bn
\[\begin{split}\displaystyle \left[\begin{matrix}\frac{1}{3}\\0\end{matrix}\right]\end{split}\]

Analicemos un poco que son Bn y An

type(An)
sympy.matrices.dense.MutableDenseMatrix

Esto nos dice que es un objeto de tipo simb贸lico. Para poder usarlo a煤n debemos pasarlo a un tipo num茅rico.

Utilizaci贸n num茅rica de los resultados simb贸licos#

Hide code cell source
import numpy as np
import control as ctrl
import matplotlib.pyplot as plt
# descomentar la siguiente linea para ver la imagen e una ventana emergente
# %matplotlib qt5
A1 = np.float64(An)
B1 = np.float64(Bn)

Chequeemos ahora el tipo de datos de la matriz A1:

type(A1)
numpy.ndarray

Vemos que ahora es de tipo ndarray de numpy, que es software de algebra num茅rico (no simb贸lico). Este tipo de datos es aceptado por el paquete de control, por lo que podemos usar las matrices A1 y B1 para definir nuestro sistema en espacio de estados.

sys = ctrl.ss(A1,B1,[0,1],0)

Con este modelo podemos f谩cilmente simular la respuesta al escal贸n

t,y = ctrl.step_response(sys, T=np.linspace(0,40,1000))

Ahora utilizaremos lo visto en el cuaderno de figuras

Hide code cell source
fig = plt.figure(figsize=(10, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(t,y)
ax.set_title('Respuesta al escal贸n')
ax.set_xlabel('Tiempo [s]')
ax.set_ylabel('Posici贸n $x$');
ax.grid()
../../../../_images/503e8f023fc2cb178d70a76ea2912c40b748b53242d8b989d07b2addde482a49.png

Simulaci贸n No-Lineal#

Primero debemos definir el sistema no lineal en una funci贸n para que despu茅s podamos integrarlo con los m茅todos de integraci贸n del paquete scipy (otro paquete m谩s de Python).

def resorte_no_lineal(t, x, b=1, m=3, K=2, g=9.8, step_amp=1):
    F=1+step_amp # Hacemos la entrada igual a 2 ya que al sistema lineal le aplicamos 
                 # un escal贸n unitario sobre el punto de trabajo que era F=1
    x1,x2 = x
    dx1 = -b/m*x1-K/m*x2**3+F/m+g
    dx2 = x1
    return dx1, dx2

Para comenzar necesitamos tambi茅n los valores num茅ricos de las condiciones iniciales

x0 = np.float64(sol1[x1].subs([(b,1),(K,2),(m,3),(g,9.8)])), np.float64(sol1[x2].subs([(b,1),(K,2),(m,3),(g,9.8)]))
x0
../../../../_images/fe93e60cc3a896d8006424efa7ce18c0e886115f908f0f7c085545f03a8aafcf.png
import scipy.integrate as integ
tspan = (0, 40)
t1= np.linspace(*tspan, 1000)

def simulate():
    r = integ.solve_ivp(resorte_no_lineal, tspan, x0, t_eval=t1)
    return r.y

x1,x2 = simulate()

Ahora veamos los resultados de la simulaci贸n del sistema no lineal

Hide code cell source
fig = plt.figure(figsize=(10, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(t1,x2, label='$x$')
ax.set_title('Respuesta al escal贸n')
ax.set_xlabel('Tiempo [s]')
ax.set_ylabel('Posici贸n $x$')
ax.legend()
ax.grid();
../../../../_images/289aebee1d23948c84b04c05b3499c35ec48efcc729f3a66af16866fe73181c9.png

Para poder evaluar las diferencias me falta agregarle a la salida del sistema lineal el valor de equilibrio.

yc = y+x0[1]
Hide code cell source
fig = plt.figure(figsize=(10, 4))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8])
ax.plot(t,yc, label=r'$x$ del sistema linealizado')
ax.plot(t1, x2, label=r'$x$ del sistema no lienal', alpha=0.6)
ax.set_title('Respuesta al escal贸n')
ax.set_xlabel('Tiempo [s]')
ax.set_ylabel('Posici贸n $x$')
ax.legend()
ax.grid();
../../../../_images/ef72e3c628a94ce6f60322647596c0541d190c30e5626daf198e55f49be08d27.png

Podemos ver que la respuesta al escal贸n del sistema lineal y del sistema no lineal dan bastante parecidos.

Dejamos como ejercicio al lector evaluar que sucede si el escal贸n es m谩s grande (5 o 10 veces m谩s grande).