Metoda Eulera

Istota. Metoda Eulera jest najprostszym sposobem aproksymacji rozwiązania równania różniczkowego. W każdym kroku czasowym wykorzystuje jedynie wartość pochodnej w bieżącym punkcie \( \mathbf{x}_n \). Pochodną tę interpretuje się jako wektor wskazujący kierunek i szybkość ruchu punktu. Metoda zakłada więc, że w krótkim przedziale czasu \( \Delta t \) punkt porusza się po linii prostej wyznaczonej przez tę pochodną. Dla układu \( \dot{\mathbf{x}} = f(\mathbf{x}, t, \theta) \) przybliżenie kolejnego punktu ma postać: \( \mathbf{x}_{n+1} = \mathbf{x}_n + \Delta t\, f(\mathbf{x}_n) .\) Oznacza to, że punkt przesuwamy o wartość pochodnej powiększoną o długość kroku czasowego \( \Delta t \). Metoda korzysta wyłącznie z informacji z punktu \( \mathbf{x}_n \), dlatego jest szybka, lecz mało dokładna.

Przykład. Rozważamy równanie \( \dot{x} = -2x \) z warunkiem początkowym \( x_0 = 1 \) i krokiem czasowym \( \Delta t = 0.1 \).
Krok 1: obliczamy pochodną w punkcie \( x_0 = 1 \): \( f(x_0) = -2 \cdot 1 = -2 \).
Nowe przybliżenie: \( x_1 = x_0 + 0.1 \cdot (-2) = 0.8 \).
Krok 2: obliczamy pochodną w punkcie \( x_1 = 0.8 \): \( f(x_1) = -2 \cdot 0.8 = -1.6 \).
Nowe przybliżenie: \( x_2 = 0.8 + 0.1 \cdot (-1.6) = 0.64 \).
Krok 3: pochodna: \( f(x_2) = -1.28 \).
Nowe przybliżenie: \( x_3 = 0.64 + 0.1 \cdot (-1.28) = 0.512 \).
Kolejne kroki przebiegają analogicznie. Przy każdym kroku błąd tworzy się i narasta, ponieważ przyjmujemy liniową aproksymację pochodnej na całym odcinku długości \( \Delta t \).

Zastosowanie. Metoda Eulera sprawdza się jedynie w przypadku bardzo małych kroków czasowych \( \Delta t \) oraz w układach o łagodnej dynamice. W systemach chaotycznych szybko generuje duże błędy numeryczne, co prowadzi do zniekształcenia trajektorii. Z tego powodu traktuje się ją głównie jako metodę edukacyjną lub jako punkt wyjścia do bardziej zaawansowanych metod, takich jak Heun czy RK4.

Implementacja. W dodatku Attractor Builder każdy krok metody Eulera realizuje funkcja step_euler. Przyjmuje ona funkcję prawej strony układu (rhs_func), bieżący wektor stanu p, słownik parametrów params oraz krok czasowy dt: def step_euler(rhs_func, p: Vector, params: dict, dt: float): return p + rhs_func(p, params) * dt

Funkcja rhs_func zwraca wektor pochodnych \( (\dot{x}, \dot{y}, \dot{z}) \) obliczonych w bieżącym punkcie i dla zadanych parametrów \( a, b, c \). Wywołanie step_euler oblicza nowe przybliżenie położenia punktu po upływie jednego kroku czasowego \( \Delta t = dt \). Na przykład gdy w Attractor Builder przyjmiemy (Lorenz):

Równania:
dx/dt = a * (y - x)
dy/dt = x * (b - z) - y
dz/dt = x * y - c * z
Parametry:
| a = 10 | b = 28 | c = 8/3 |
Ustawienia symulacji:
Stan początkowy: x₀ = 0.01, y₀ = 0.01, z₀ = 0.01
Metoda: Euler
Krok czasowy (dt): 0.1
Liczba kroków: 3
Faza rozgrzewki (burn-in): 0
Skala: 1

W każdym kroku algorytm najpierw liczy pochodne \( (\dot{x}, \dot{y}, \dot{z}) \), a następnie aktualizuje współrzędne zgodnie z regułą \( x_{n+1} = x_n + \Delta t \,\dot{x}_n \):

Krok 1. Punkt początkowy:
x0 = 0.01; y0 = 0.01; z0 = 0.01.
Pochodne:
dx0 = 10*(y0-x0) = 10*(0.01-0.01) = 0
dy0 = x0*(28-z0) - y0 ≈ 0.01*(28-0.01) - 0.01 ≈ 0.2699
dz0 = x0*y0 - (8/3)*z0 ≈ 0.01*0.01 - (8/3)*0.01 ≈ -0.02657
Nowy punkt:
x1 = x0 + 0.01*dx0 = 0.01
y1 = y0 + 0.01*dy0 ≈ 0.01270
z1 = z0 + 0.01*dz0 ≈ 0.00973
Krok 2. Punkt wyjściowy:
x1 = 0.01; y1 ≈ 0.01270; z1 ≈ 0.00973.
Pochodne (zaokrąglone):
dx1 = 10*(y1-x1) ≈ 10*(0.01270-0.01) ≈ 0.02699
dy1 = x1*(28-z1) - y1 ≈ 0.01*(28-0.00973) - 0.01270 ≈ 0.26720
dz1 = x1*y1 - (8/3)*z1 ≈ 0.01*0.01270 - (8/3)*0.00973 ≈ -0.02583
Nowy punkt:
x2 = x1 + 0.01*dx1 ≈ 0.01 + 0.01*0.02699 ≈ 0.01027
y2 = y1 + 0.01*dy1 ≈ 0.01270 + 0.01*0.26720 ≈ 0.01537
z2 = z1 + 0.01*dz1 ≈ 0.00973 + 0.01*(-0.02583) ≈ 0.00948
Krok 3. Punkt wyjściowy:
x2 ≈ 0.01027; y2 ≈ 0.01537; z2 ≈ 0.00948.
Pochodne (zaokrąglone):
dx2 = 10*(y2-x2) ≈ 10*(0.01537-0.01027) ≈ 0.05101
dy2 = x2*(28-z2) - y2 ≈ 0.01027*(28-0.00948) - 0.01537 ≈ 0.27209
dz2 = x2*y2 - (8/3)*z2 ≈ 0.01027*0.01537 - (8/3)*0.00948 ≈ -0.02511
Nowy punkt:
x3 = x2 + 0.01*dx2 ≈ 0.01027 + 0.01*0.05101 ≈ 0.01078
y3 = y2 + 0.01*dy2 ≈ 0.01537 + 0.01*0.27209 ≈ 0.01809
z3 = z2 + 0.01*dz2 ≈ 0.00948 + 0.01*(-0.02511) ≈ 0.00922

W kolejnych krokach procedura jest identyczna: w każdym punkcie oblicza się pochodne i stosuje wzór Eulera, aby przesunąć punkt o jeden krok czasowy \( \Delta t \). Przykład ten pokazuje, w jaki sposób ogólny układ Lorenza przechodzi w konkretne obliczenia numeryczne w dodatku.