Badanie koncentruje się na porównaniu dwóch metod rozwiązywania układów Lotki-Volterry i Lorenza: implementacji metody Eulera oraz wykorzystaniu pakietu scipy.
W pierwszej części przeprowadzono symulacje za pomocą metody Eulera. Dokonano porównania wyników dla różnych wartości kroku czasowego (dt). Wyniki zostały przeanalizowane i przedstawione graficznie w celu umożliwienia porównania zachowania układu dla różnych wartości dt.
W kolejnej części raportu wykorzystano inną metodę, korzystając z funkcji odeint z pakietu scipy.integrate. Dodatkowo, dla każdej wartości kroku czasowego użytej w metodzie Eulera, obliczono średni błąd aproksymacji względem wartości referencyjnych uzyskanych za pomocą metody odeint.
Ostateczne wnioski z niniejszego sprawozdania pozwolą na ocenę skuteczności obu metod symulacji oraz ich odporność na dobór kroku czasowego, co jest istotnym czynnikiem wpływającym na dokładność wyników.
$$ {\frac{dx}{dt} = ax - bxy} $$
$$ {\frac{dy}{dt} = (cx - d)y} $$
import numpy as np
import matplotlib.pyplot as plt
def euler_method(a, b, c, d, x0, y0, dt, steps):
= [x0]
x_values = [y0]
y_values for _ in range(steps):
= a * x_values[-1] - b * x_values[-1] * y_values[-1]
dx_dt = c * x_values[-1] * y_values[-1] - d * y_values[-1]
dy_dt = x_values[-1] + dx_dt * dt
x_new = y_values[-1] + dy_dt * dt
y_new
x_values.append(x_new)
y_values.append(y_new)return x_values, y_values
# Funkcja obliczająca średni błąd aproksymacji
def calculate_average_error(true_values, approx_values):
= np.abs(true_values - approx_values)
errors return np.mean(errors)
# Parametry
= 1.2
a = 0.6
b = 0.3
c = 0.8
d
# Populacje początkowe
= 2
x0 = 1
y0
# Lista różnych wartości kroku dt
= [0.1, 0.05, 0.01]
dt_values
# Wyniki metody Eulera dla różnych wartości kroku dt
for dt in dt_values:
= int(80 / dt)
steps = euler_method(a, b, c, d, x0, y0, dt, steps)
x_values, y_values
=(10, 6))
plt.figure(figsize='Euler - x(t)')
plt.plot(x_values, label='Euler - y(t)')
plt.plot(y_values, labelf'Symulacja populacji dla dt={dt}')
plt.title('Czas')
plt.xlabel('Populacja')
plt.ylabel(
plt.legend()True)
plt.grid(
plt.show()
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
def euler_method(a, b, c, d, x0, y0, dt, steps):
= [x0]
x_values = [y0]
y_values for _ in range(steps):
= a * x_values[-1] - b * x_values[-1] * y_values[-1]
dx_dt = c * x_values[-1] * y_values[-1] - d * y_values[-1]
dy_dt = x_values[-1] + dx_dt * dt
x_new = y_values[-1] + dy_dt * dt
y_new
x_values.append(x_new)
y_values.append(y_new)return x_values, y_values
# Funkcja obliczająca średni błąd aproksymacji
def calculate_average_error(true_values, approx_values):
= np.abs(true_values - approx_values)
errors return np.mean(errors)
# Parametry
= 1.2
a = 0.6
b = 0.3
c = 0.8
d
# Początkowe populacje
= 2
x0 = 1
y0
# Lista różnych wartości kroków dt
= [0.05, 0.01, 0.001]
dt_values
# Wyniki metody Eulera dla różnych wartości kroku dt
for dt in dt_values:
= int(80 / dt)
steps = euler_method(a, b, c, d, x0, y0, dt, steps)
x_values_euler, y_values_euler
# Rozwiązanie z pomocą odeint
def model(z, t):
= z
x, y = a * x - b * x * y
dx_dt = c * x * y - d * y
dy_dt return [dx_dt, dy_dt]
= np.linspace(0, 80, steps + 1)
t = [x0, y0]
z0 = odeint(model, z0, t)
z_odeint = z_odeint[:, 0]
x_values_odeint = z_odeint[:, 1]
y_values_odeint
=(10, 6))
plt.figure(figsize='Euler - x(t)')
plt.plot(x_values_euler, label='Euler - y(t)')
plt.plot(y_values_euler, label='odeint - x(t)', linestyle='--')
plt.plot(x_values_odeint, label='odeint - y(t)', linestyle='--')
plt.plot(y_values_odeint, labelf'Population simulation for dt={dt}')
plt.title('Time')
plt.xlabel('Population')
plt.ylabel(
plt.legend()True)
plt.grid(
plt.show()
= calculate_average_error(x_values_odeint, x_values_euler)
error_x = calculate_average_error(y_values_odeint, y_values_euler)
error_y print(f"dt={dt}, Average Error for x(t): {error_x}, Average Error for y(t): {error_y}")
dt=0.09, Average error for x(t): 4.5386523875719575, Average error for y(t): 2.1322796713960326
dt=0.075, Average error for x(t): 2.699332651223852, Average error for y(t): 1.9305765727495827
dt=0.05, Average Error for x(t): 2.4437596140948665, Average Error for y(t): 1.583412638014361
dt=0.01, Average Error for x(t): 0.8149373464424021, Average Error for y(t): 0.5055264320468017
dt=0.001, Average Error for x(t): 0.06583244461491997, Average Error for y(t): 0.04060824939869479
dt | Średni błąd dla x(t) | Średni błąd dla y(t) | Średnia (x(t), y(t)) |
---|---|---|---|
0.09 | 4.5386523875719575 | 2.1322796713960326 | 3.335466029484995 |
0.075 | 2.699332651223852 | 1.9305765727495827 | 2.3149546119867175 |
0.05 | 2.4437596140948665 | 1.583412638014361 | 2.013586126054614 |
0.01 | 0.8149373464424021 | 0.5055264320468017 | 0.6602318892446019 |
0.001 | 0.06583244461491997 | 0.04060824939869479 | 0.05322034700680738 |
import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint
def euler_method(sigma, rho, beta, x0, y0, z0, dt, steps):
= [x0]
x_values = [y0]
y_values = [z0]
z_values for _ in range(steps):
= sigma * (y_values[-1] - x_values[-1])
dx_dt = x_values[-1] * (rho - z_values[-1]) - y_values[-1]
dy_dt = x_values[-1] * y_values[-1] - beta * z_values[-1]
dz_dt = x_values[-1] + dx_dt * dt
x_new = y_values[-1] + dy_dt * dt
y_new = z_values[-1] + dz_dt * dt
z_new
x_values.append(x_new)
y_values.append(y_new)
z_values.append(z_new)return x_values, y_values, z_values
# Funkcja obliczająca średni błąd aproksymacji
def calculate_average_error(true_values, approx_values):
= np.abs(true_values - approx_values)
errors return np.mean(errors)
# Parametry modelu Lorenza
= 10
sigma = 28
rho = 8/3
beta
# Początkowe warunki
= 0
x0 = 1
y0 = 1.05
z0
# Lista różnych wartości kroku czasowego dt
= [ 0.04, 0.02, 0.01, 0.001]
dt_values
# Wyniki dla metody Eulera dla różnych wartości dt
for dt in dt_values:
= int(80 / dt)
steps = euler_method(sigma, rho, beta, x0, y0, z0, dt, steps)
x_values_euler, y_values_euler, z_values_euler
# Rozwiązanie za pomocą odeint
def model(state, t):
= state
x, y, z = sigma * (y - x)
dx_dt = x * (rho - z) - y
dy_dt = x * y - beta * z
dz_dt return [dx_dt, dy_dt, dz_dt]
= np.linspace(0, 80, steps + 1)
t = [x0, y0, z0]
state0 = odeint(model, state0, t)
state_odeint = state_odeint[:, 0]
x_values_odeint = state_odeint[:, 1]
y_values_odeint = state_odeint[:, 2]
z_values_odeint
= plt.figure(figsize=(16, 5))
fig
# Wykres y(x)
1, 3, 1)
plt.subplot(='Euler', color='blue')
plt.plot(x_values_euler, y_values_euler, label='odeint', color='red', linestyle='--')
plt.plot(x_values_odeint, y_values_odeint, labelf'y(x) - Simulation, dt={dt}')
plt.title('X')
plt.xlabel('Y')
plt.ylabel(
plt.legend()True)
plt.grid(
# Wykres z(x)
1, 3, 2)
plt.subplot(='Euler', color='blue')
plt.plot(x_values_euler, z_values_euler, label='odeint', color='red', linestyle='--')
plt.plot(x_values_odeint, z_values_odeint, labelf'z(x) - Simulation, dt={dt}')
plt.title('X')
plt.xlabel('Z')
plt.ylabel(
plt.legend()True)
plt.grid(
# Wykres z(y)
1, 3, 3)
plt.subplot(='Euler', color='blue')
plt.plot(y_values_euler, z_values_euler, label='odeint', color='red', linestyle='--')
plt.plot(y_values_odeint, z_values_odeint, labelf'z(y) - Simulation, dt={dt}')
plt.title('Y')
plt.xlabel('Z')
plt.ylabel(
plt.legend()True)
plt.grid(
plt.tight_layout()
plt.show()
= plt.figure(figsize=(12, 8))
fig = fig.add_subplot(111, projection='3d')
ax ='Euler', color='blue')
ax.plot(x_values_euler, y_values_euler, z_values_euler, label='odeint', color='red', linestyle='--')
ax.plot(x_values_odeint, y_values_odeint, z_values_odeint, labelf'Simulation for dt={dt}')
ax.set_title('X')
ax.set_xlabel('Y')
ax.set_ylabel('Z')
ax.set_zlabel(
ax.legend()
plt.show()
= calculate_average_error(x_values_odeint, x_values_euler)
error_x = calculate_average_error(y_values_odeint, y_values_euler)
error_y = calculate_average_error(z_values_odeint, z_values_euler)
error_z print(f"dt={dt}, Average Error for X: {error_x}, Average Error for Y: {error_y}, Average Error for Z: {error_z}")
dt=0.04, Average Error for X: nan, Average Error for Y: nan, Average Error for Z: nan
dt=0.02, Average Error for X: 9.160473319570897, Average Error for Y: 10.394051377529555, Average Error for Z: 9.452990585686898
dt=0.01, Average Error for X: 8.581482374633888, Average Error for Y: 9.601881745806123, Average Error for Z: 9.22120213881979
dt=0.001, Average Error for X: 6.946460771812238, Average Error for Y: 7.857654961620313, Average Error for Z: 7.920956509955428
dt | Średni błąd dla X | Średni błąd dla Y | Średni błąd dla Z | Średnia (x, y, z) |
---|---|---|---|---|
0.02 | 9.160473319570897 | 10.394051377529555 | 9.452990585686898 | 9.33583876059685 |
0.01 | 8.581482374633888 | 9.601881745806123 | 9.22120213881979 | 9.134522419753267 |
0.001 | 6.946460771812238 | 7.857654961620313 | 7.920956509955428 | 7.575357414462326 |
Analizując dane dotyczące średnich błędów dla różnych wartości kroku czasowego dt dla metod symulacji przy użyciu metody Eulera i odeint, można wyciągnąć następujące wnioski:
Na podstawie danych dotyczących średnich błędów dla różnych wartości kroku czasowego dt w symulacji systemu Lorenza, można wyciągnąć następujące wnioski:
Metoda odeint jest bardziej dokładną metodą numeryczną niż metoda Eulera w przypadku symulacji dynamiki układów fizycznych, szczególnie dla większych wartości kroku czasowego. Dla małych wartości dt, różnice pomiędzy obiema metodami są mniejsze, ale nadal metoda odeint może zapewniać lepszą dokładność i stabilność.