Solución de sistemas de ecuaciones diferenciales#
Método de Euler#
Considere una Ecuación Diferencial Ordinaria (EDO) de la forma
donde \(f\) es una función. La solución general a la Ec. (83) está dada por la siguiente expresión
donde \(c\) es una constante arbitraria. Para obtener una solución, dependemos de un valor inicial de la forma
Para la mayoría de problemas de valor inicial no es posible encontrar una solución exacta (analítica) ya que las ecuaciones son no lineales, discontinuas, o estocásticas. Por ejemplo, \(\dot{y} = e^{{xy}^{4}}\). Por lo tanto, necesitamos de un método numérico para aproximar la solución.
Es posible aproximar el término del lado izquierdo de un problema de valor inicial \(\frac{\mathrm{d}f}{\mathrm{d}x}\) utilizando el teorema de Taylor alrededor de un punto dado \(x_{0}\)
donde \(\tau\) es el error de truncamiento
Recordando que \(h = x_{1} - x_{0}\), las ecuación anterior queda definida como sigue
Es posible obtener el método de Euler directo utilizando una variación de la interpolación de Lagrange llamada diferencia dividida.
Podemos aproximar cualquier función \(f(x)\) utilizando un polinomio de grado \(P_{n}(x)\) y un término de error
donde
Derivando \(P_{n}(x)\), tenemos
por consiguiente el error se define como sigue
Definimos entonces la primer derivada como sigue
lo que implica
Utilizando el mismo método, obtenemos una aproximación a la segunda derivada como sigue
import numpy as np
import matplotlib.pyplot as plt
# Suprimir advertencias menores de integración durante los bucles de optimización
import warnings
warnings.filterwarnings("ignore")
# Configurar el estilo de graficación para una mejor visualización
plt.style.use('ggplot')
# Parámetros iniciales de la simulación
tfin = 0.5 # Tiempo de simulación
h = 0.001 # Paso de integración
# Se usa np.arange asegurando incluir el punto final tfin.
t = np.arange(0, tfin + h/2, h)
N = len(t) # Número de muestras que se simulan.
# Inicialización del vector de la solución numérica con ceros.
y = np.zeros(N)
y[0] = 5 # Condición inicial (y(0) = 5).
# Ciclo iterativo del Método de Euler para la EDO
# Ecuación diferencial: y' + 20y = 7*exp(-0.5*t) -> y' = -20y + 7*exp(-0.5*t)
for k in range(1, N):
# k-1 representa el índice anterior en la indexación basada en 0 de Python.
f_val = -20 * y[k - 1] + 7 * np.exp(-0.5 * t[k - 1])
y[k] = y[k - 1] + h * f_val
# Solución analítica exacta
y1 = (181 / 39) * np.exp(-20 * t) + (14 / 39) * np.exp(-0.5 * t)
# Gráfica de la solución numérica y analítica
plt.figure(figsize=(8, 5))
# t[::10] y y[::10] equivale a tomar cada 10 elementos (t(1:10:N)) para no saturar los puntos 'or' (círculos rojos).
plt.plot(t[::10], y[::10], 'or', label='Solución numérica')
plt.plot(t, y1, '-b', label='Solución analítica')
# Configuración de etiquetas y leyenda
plt.legend()
plt.xlabel('Tiempo en segundos')
plt.ylabel('Solución en p.u.')
plt.title('Método de Euler vs Solución Analítica')
plt.grid(True)
# Mostrar la gráfica
plt.show()
Ejemplo
Aplique la fórmula de Euler a la ecuación de primer orden con una entrada oscilante
Ejemplo
El crecimiento demográfico simple está descrito por una ecuación diferencial de primer orden de la forma
cuya solución exacta está dada por
Dada la siguiente condición inicial
con una tasa de cambio de \(\varepsilon = 0.5\), la solución analítica queda expresada como sigue
Aplique la fórmula de Euler para obtener una solución aproximada.
Método de Runge-Kutta#
El método de Runge-Kutta (RK) está relacionado con la expansión de la serie de Taylor, con la diferencia de que no es necesaria la diferenciación de \(f\).
Los métodos RK se escriben de la siguiente forma
donde el error de truncamiento está definido por
tal que el error está dado como sigue \(\tau_{n}\left(y\right)\)
Reescribiendo términos, tenemos
Considere el método explícito de un paso
con
donde \(\alpha_{0} + \alpha_{1} = 1\).
Importante
En la formulación del método de Runge-Kutta existe un parámetro libre. En este caso, \(\alpha_{0}\).
Teorema 17
Sea \(f\left(t,y\right)\) y todas sus derivadas parciales de orden menor o igual a \(n+1\) continuas sobre \(D = \left\{ \left(t,y \right) | a \leq t \leq b, c \leq y \leq d \right\}\) y sea \(\left(t_{0}, y_{0}\right)\in D\) para cada \(\left(t, y\right) \in D\), \(\exists \xi \in \left(t, t_{0}\right)\) y \(\mu \in \left(y, y_{0}\right)\) con
donde
Podemos utilizar el Teorema 17 para encontrar los valores \(a_{1}\), \(\alpha_{1}\) y \(\beta_{1}\) considerando que \(\alpha_{1}f\left(t+\alpha_{1}, y + \beta_{1}\right)\) aproxima a Taylor de segundo orden
con un error no mayor a \(O\left(h^{2}\right)\).
Utilizando
la expresión de Taylor de segundo orden se puede escribir como sigue
Expandiendo \(\alpha_{1}f\left(t+\alpha_{1}, y + \beta_{1}\right)\) y su polinomio de Taylor de grado uno alrededor de \(\left(t,y\right)\), tenemos
donde
para algún \(\xi \in \left[t,t + \alpha_{1} \right]\) y \(\mu \in \left[y,y + \beta_{1} \right]\).
Los métodos de orden mayor se obtienen de forma similar. Por ejemplo, Runge-Kutta de tercer orden se expresa como sigue
con
donde
Escogiendo \(\alpha_{2} = 1\), \(\beta_{11} = \frac{1}{2}\), obtenemos la siguiente ecuación
donde
Para obtener el método de Runge-Kutta de cuarto orden, consideramos
# Parámetros iniciales de la simulación
tfin = 5 # Tiempo de observación.
h = 0.01 # Paso de integración.
# Vector de tiempos de integración (equivalente a 0:h:tfin en MATLAB).
t = np.arange(0, tfin + h/2, h)
N = len(t) # Número de muestras que se simulan.
# Inicialización de vectores para la solución y los coeficientes RK4.
y = np.zeros(N)
k1 = np.zeros(N)
k2 = np.zeros(N)
k3 = np.zeros(N)
k4 = np.zeros(N)
# Condición inicial (y(0) = 1).
y[0] = 1
# Ciclo iterativo del Método de Runge-Kutta de 4to Orden
# Ecuación diferencial: y' + 2y = 0 -> y' = -2y
for k in range(1, N):
k1[k] = h * (-2 * y[k - 1])
k2[k] = h * (-2 * (y[k - 1] + 0.5 * h * k1[k]))
k3[k] = h * (-2 * (y[k - 1] + 0.5 * h * k2[k]))
k4[k] = h * (-2 * (y[k - 1] + h * k3[k]))
# Cálculo del siguiente valor de y usando el promedio ponderado de los coeficientes
y[k] = y[k - 1] + (1 / 6) * (k1[k] + 2 * k2[k] + 2 * k3[k] + k4[k])
# Solución analítica exacta
y1 = np.exp(-2 * t)
# Gráfica de la solución numérica y analítica
plt.figure(figsize=(8, 5))
# t[::10] y y[::10] seleccionan uno de cada diez puntos para graficar círculos rojos sin saturar.
plt.plot(t[::10], y[::10], 'or', label='Solución numérica')
plt.plot(t, y1, '-b', label='Solución analítica')
# Configuración de ejes, leyenda y etiquetas
plt.legend()
plt.xlabel('Tiempo en segundos')
plt.ylabel('Solución en p.u.')
plt.title('Método de Runge-Kutta (4to Orden) vs Solución Analítica')
plt.grid(True)
# Mostrar la gráfica
plt.show()