68 lines
1.5 KiB
Python
68 lines
1.5 KiB
Python
|
import numpy as np
|
||
|
import matplotlib.pyplot as plt
|
||
|
from matplotlib.scale import FuncScale
|
||
|
|
||
|
# f: (t, y) -> R, dy/dt = f
|
||
|
def euler(f, a, b, y0, h):
|
||
|
xs = [a]
|
||
|
ys = [y0]
|
||
|
x = a
|
||
|
y = y0
|
||
|
while x < b:
|
||
|
y += h * f(x, y)
|
||
|
x += h
|
||
|
if abs(y) > threshold:
|
||
|
break
|
||
|
xs.append(x)
|
||
|
ys.append(y)
|
||
|
return xs, ys
|
||
|
|
||
|
def improvedEuler(f, a, b, y0, h):
|
||
|
xs = [a]
|
||
|
ys = [y0]
|
||
|
|
||
|
x = a
|
||
|
y = y0
|
||
|
while x <= b:
|
||
|
slope1 = f(x, y)
|
||
|
y_predictor = y + h * slope1
|
||
|
slope2 = f(x + h, y_predictor)
|
||
|
y = y + (h/2) * (slope1 + slope2)
|
||
|
x = x + h
|
||
|
if abs(y) > threshold:
|
||
|
break
|
||
|
xs.append(x)
|
||
|
ys.append(y)
|
||
|
return xs, ys
|
||
|
|
||
|
f = lambda t, y: t**3 + y**3
|
||
|
threshold = 100
|
||
|
a = 0
|
||
|
b = 2
|
||
|
|
||
|
lims = [
|
||
|
(0, 1.4, 1.8, 1, threshold),
|
||
|
(1, 0.4, 0.6, 1, threshold),
|
||
|
(-1, 0.4, 0.6, -threshold, -1),
|
||
|
]
|
||
|
|
||
|
y0, xm, xM, ym, yM = lims[0]
|
||
|
|
||
|
fig, ax= plt.subplots(1, 2)
|
||
|
for h in [0.1, 0.01, 0.001, 0.0001]:
|
||
|
ax[0].plot(*euler(f, a, b, y0, h), label=f'$\\Delta t$={h}', linewidth=1)
|
||
|
T, Y = improvedEuler(f, a, b, y0, h)
|
||
|
ax[1].plot(T, Y, label=f'$\\Delta t$={h}', linewidth=1)
|
||
|
print(f"Max x: {T[-1]}")
|
||
|
|
||
|
for axe in ax:
|
||
|
axe.legend()
|
||
|
axe.set_xlim(xm, xM)
|
||
|
axe.set_ylim(ym, yM)
|
||
|
#axe.set_yscale(FuncScale(axe, (lambda y: np.log(-y), lambda y: -np.exp(y))))
|
||
|
|
||
|
ax[0].set_title("Euler Method")
|
||
|
ax[1].set_title("Improved Euler Method")
|
||
|
|
||
|
#fig.suptitle(r"Numerically solving $y'=y^3 + t^3$ starting at (0, 0)")
|
||
|
plt.show()
|