Un modelo que describe el comportamiento del sistema mecánico anterior es
\begin{equation} m\frac{d^2 x}{dt^2}=-c\frac{dx}{dt}-kx \end{equation}donde $c$ es la constante de amortiguamiento y $k$ es la constante de elasticidad. Revisar modelado
Documentación de los paquetes que utilizaremos hoy.
En python
existe una función llamada _odeint_ del paquete _integrate_ de la libreria _scipy_, que permite integrar sistemas vectoriales de primer orden, del tipo
con condiciones iniciales $\boldsymbol{y}(0) = \boldsymbol{y}_{0}$. Notar que $\boldsymbol{y}$ representa un vector de $n$ componentes.
Ahora, si nos fijamos bien, el modelo del oscilador armónico amortiguado que obtuvimos es una ecuación diferencial ordinaria (EDO) de segundo orden. No hay problema. La podemos convertir en un sistema de ecuaciones de primer orden de la siguiente manera:
In [1]:
# Primero importamos todas las librerias, paquetes y/o funciones que vamos a utlizar
import matplotlib.pyplot as plt # ¿Para qué sirve?
import numpy as np # ¿Para qué sirve?
from scipy.integrate import odeint # Función para integrar EDO vectoriales de primer orden
%matplotlib inline # ¿Para qué sirve?
In [2]:
# Definimos los parámetros
k = 3.0 # Constante del muelle
m = 1.0 # Masa
B = .5 # Constante de amortiguación
# Función f(t,y) que vamos a integrar
def armonico(y, t):
y1, y2 = y
return [y2, -k * y1 / m - B / m * y2]
y0 = [0.6, 0.4] # Vector de posición inicial y velocidad inicial
# condiciones iniciales y1(0)=0.6 [m] y2(0)=0.4 [m/s]
# Especificamos los puntos de tiempo donde queremos la solución
#tiempo = np.linspace(0, 15) # Dominio temporal de 0 a 15 (por defecto 50 puntos)
tt = np.arange(0, 20, .01) # Dominio temporal de 0 a 20 con paso de 0.01
yy = odeint(armonico, y0, tt)
#El sistema se resuelve con
#odeint(funcion_sistema, condiciones_iniciales, dominio_tiempo)
In [3]:
# Veamos como nos entrega las soluciones la funcion odeint
np.shape(yy) # shape es una función de numpy que nos entrega las dimensiones del objeto
Out[3]:
In [4]:
yy
Out[4]:
¿Cómo extraemos los resultados $y_1$ y $y_2$ independientemente?
In [5]:
## Una forma
#yy1 = yy[:,0] # tome de yy todas las filas (:) y la primer columna
#yy2 = yy[:,1] # tome de yy todas las filas (:) y la segunda columna
# Otra forma (más compacta)
yy1, yy2 = yy.T # transponemos la matriz yy y extraemos los resultados.
In [6]:
# Comandos para hacer los números de los ejes más grandes
import matplotlib as mpl
label_size = 14
mpl.rcParams['xtick.labelsize'] = label_size
mpl.rcParams['ytick.labelsize'] = label_size
In [7]:
# Graficamos
plt.plot(tt, yy1, c = 'r', label="Posicion")
plt.plot(tt, yy2, c = 'k', label="Velocidad")
plt.legend(loc = 'best', prop={'size': 14})
plt.xlabel('$t$', fontsize = 14)
plt.ylabel('$y_1$, $y_2$', fontsize = 14)
plt.show()
In [8]:
# Frecuencia natural
omega0 = k/m
# Graficamos el espacio fase
plt.figure(figsize = (6,6))
plt.scatter(yy1, yy2/omega0, lw = 0, s = 3, cmap = 'viridis', c = yy1)
plt.show()
Teníamos \begin{equation} m\frac{d^2 x}{dt^2} + c\frac{dx}{dt} + kx = 0 \end{equation}
si recordamos que $\omega_0 ^2 = \frac{k}{m}$ y definimos $\frac{c}{m}\equiv 2\Gamma$, tendremos
\begin{equation} \frac{d^2 x}{dt^2} + 2\Gamma \frac{dx}{dt}+ \omega_0^2 x = 0 \end{equation}Si $\omega_0^2 > \Gamma^2$ se tiene movimiento oscilatorio subamortiguado.
In [13]:
omega0 = k/m
Gamma = B/(2*m)
In [14]:
omega0**2, Gamma**2
Out[14]:
In [15]:
omega0**2 > Gamma**2
Out[15]:
Entonces, el primer caso que ya habíamos presentado corresponde a movimiento amortiguado.
In [18]:
plt.figure()
plt.plot(tt, yy1, c = 'r', label="Posicion")
plt.plot(tt, yy2, c = 'k', label="Velocidad")
plt.legend(loc = 'best', prop={'size': 14})
plt.xlabel('t', fontsize = 14)
plt.show()
Si $\omega_0^2 < \Gamma^2$ se tiene movimiento oscilatorio sobreamortiguado.
In [19]:
k = .1 # Constante del muelle
m = 1.0 # Masa
B = .5 # Constante de amortiguación
In [20]:
omega0 = k/m
Gamma = B/(2*m)
In [21]:
omega0**2, Gamma**2
Out[21]:
In [22]:
omega0**2 < Gamma**2
Out[22]:
In [24]:
y0 = [0.6, 0.4]
tt = np.arange(0, 20, .01)
yy = odeint(armonico, y0, tt)
In [25]:
yy1s, yy2s = yy.T # extraer posición y velocidad.
In [26]:
plt.plot(tt, yy1s, c = 'r', label="Posicion")
plt.plot(tt, yy2s, c = 'k', label="Velocidad")
plt.legend(loc = 'best', prop={'size': 14})
plt.xlabel('tiempo', fontsize = 14)
plt.show()
Si $\omega_0^2 = \Gamma^2$ se tiene movimiento críticamente amortiguado.
In [27]:
k = np.sqrt(.0625) # Constante del muelle
m = 1.0 # Masa
B = .5 # Constante de amortiguación
In [28]:
omega0 = k/m
Gamma = B/(2*m)
In [29]:
omega0**2, Gamma**2
Out[29]:
In [30]:
omega0**2 == Gamma**2
Out[30]:
In [31]:
y0 = [0.6, 0.4]
tt = np.arange(0, 20, .01)
yy = odeint(armonico, y0, tt)
In [33]:
yy1c, yy2c = yy.T # extraer posición y velocidad.
In [35]:
plt.plot(tt, yy1c, c = 'r', label="Posicion")
plt.plot(tt, yy2c, c = 'k', label="Velocidad")
plt.legend(loc = 'best',prop={'size': 14})
plt.xlabel('tiempo', fontsize = 14)
plt.show()
En resumen, se tiene entonces:
In [36]:
fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2, 3, sharex='col',
sharey='row',figsize =(10,6))
ax1.plot(tt, yy1, c = 'k')
ax1.set_title('Amortiguado', fontsize = 14)
ax1.set_ylabel('Posición', fontsize = 14)
ax2.plot(tt, yy1s, c = 'b')
ax2.set_title('Sobreamortiguado', fontsize = 14)
ax3.plot(tt, yy1c, c = 'r')
ax3.set_title('Crítico', fontsize = 16)
ax4.plot(tt, yy2, c = 'k')
ax4.set_ylabel('Velocidad', fontsize = 14)
ax4.set_xlabel('tiempo', fontsize = 14)
ax5.plot(tt, yy2s, c = 'b')
ax5.set_xlabel('tiempo', fontsize = 14)
ax6.plot(tt, yy2c, c = 'r')
ax6.set_xlabel('tiempo', fontsize = 14)
plt.show()
Actividad. ¿Cómo se ve el espacio fase para los diferentes casos así como para diferentes condiciones iniciales?
In [ ]: