This commit is contained in:
2025-12-10 18:33:31 +03:00
commit 4d95efa95e
17 changed files with 20559 additions and 0 deletions

0
README.md Normal file
View File

File diff suppressed because it is too large Load Diff

189
labs/lab1/code/main.py Normal file
View File

@@ -0,0 +1,189 @@
import matplotlib.pyplot as plt
import math
import numpy as np
from scipy.integrate import solve_ivp
from scipy.optimize import fsolve
class ODESolver:
def euler_method(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
y[i + 1] = y[i] + h * f(t[i], y[i])
return t, y
def explicit_trapezoid(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
k1 = f(t[i], y[i])
k2 = f(t[i] + h, y[i] + h * k1)
y[i + 1] = y[i] + (h / 2) * (k1 + k2)
return t, y
def rk4_method(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
k1 = f(t[i], y[i])
k2 = f(t[i] + h/2, y[i] + h/2 * k1)
k3 = f(t[i] + h/2, y[i] + h/2 * k2)
k4 = f(t[i] + h, y[i] + h * k3)
y[i + 1] = y[i] + h/6 * (k1 + 2*k2 + 2*k3 + k4)
return t, y
def backward_euler(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
t_next = t[i + 1]
def equation(z):
return z - h * f(t_next, z) - y[i]
y[i + 1] = fsolve(equation, y[i])[0]
return t, y
def implicit_trapezoid(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
t_n = t[i]
t_np1 = t[i + 1]
y_n = y[i]
def equation(z):
return z - y_n - (h/2) * (f(t_n, y_n) + f(t_np1, z))
y[i + 1] = fsolve(equation, y_n)[0]
return t, y
def problem_1_4():
print("=== ЗАДАЧА 1.4: y' = y² - t, y(0) = 1 ===")
def f(t, y):
return y**2 - t
t_span = [0, 1.0]
y0 = 1
h = 0.25
solver = ODESolver()
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
t_trap, y_trap = solver.explicit_trapezoid(f, t_span, y0, h)
t_rk4, y_rk4 = solver.rk4_method(f, t_span, y0, h)
sol_ref = solve_ivp(f, t_span, [y0], method='RK45',
rtol=1e-10, atol=1e-12, dense_output=True)
t_ref = np.linspace(t_span[0], t_span[1], 100)
y_ref = sol_ref.sol(t_ref)[0]
y_ref_euler = sol_ref.sol(t_euler)[0]
y_ref_trap = sol_ref.sol(t_trap)[0]
y_ref_rk4 = sol_ref.sol(t_rk4)[0]
err_euler = np.linalg.norm(y_euler - y_ref_euler)
err_trap = np.linalg.norm(y_trap - y_ref_trap)
err_rk4 = np.linalg.norm(y_rk4 - y_ref_rk4)
print(f"Ошибка метода Эйлера: {err_euler:.2e}")
print(f"Ошибка явного метода трапеций: {err_trap:.2e}")
print(f"Ошибка метода РК4: {err_rk4:.2e}")
plt.figure(figsize=(12, 8))
plt.plot(t_ref, y_ref, 'k-', linewidth=5, label='Эталонное решение (solve_ivp)')
plt.plot(t_euler, y_euler, 'bo-', markersize=10, label='Метод Эйлера')
plt.plot(t_trap, y_trap, 'c*-', markersize=15, label='Явный метод трапеций')
plt.plot(t_rk4, y_rk4, 'rs-', markersize=5, label='Метод РК4')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('Задача 1.4: y\' = y² - t, y(0) = 1')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
return t_euler, y_euler, t_trap, y_trap, t_rk4, y_rk4, t_ref, y_ref
if __name__ == "__main__":
result1 = problem_1_4()
def problem_2_4():
print("\n=== ЗАДАЧА 2.4: y' = -2000y + t, y(0) = 0 ===")
def f(t, y):
return -2000 * y + t
t_span = [0, 1]
y0 = 0
h = 1
solver = ODESolver()
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
t_beuler, y_beuler = solver.backward_euler(f, t_span, y0, h)
t_itrap, y_itrap = solver.implicit_trapezoid(f, t_span, y0, h)
sol_ref = solve_ivp(f, t_span, [y0], method='Radau',
rtol=1e-10, atol=1e-12, dense_output=True)
t_ref = np.linspace(t_span[0], t_span[1], 100)
y_ref = sol_ref.sol(t_ref)[0]
y_ref_euler = sol_ref.sol(t_euler)[0]
y_ref_beuler = sol_ref.sol(t_beuler)[0]
y_ref_itrap = sol_ref.sol(t_itrap)[0]
err_euler = np.linalg.norm(y_euler - y_ref_euler)
err_beuler = np.linalg.norm(y_beuler - y_ref_beuler)
err_itrap = np.linalg.norm(y_itrap - y_ref_itrap)
print(f"Ошибка явного метода Эйлера: {err_euler:.2e}")
print(f"Ошибка неявного метода Эйлера: {err_beuler:.2e}")
print(f"Ошибка неявного метода трапеций: {err_itrap:.2e}")
plt.figure(figsize=(12, 8))
plt.plot(t_ref, y_ref, 'k-', linewidth=5, label='Эталонное решение (solve_ivp)')
plt.plot(t_euler, y_euler, 'bo-', markersize=4, label='Явный метод Эйлера')
plt.plot(t_beuler, y_beuler, 'g^-', markersize=4, label='Неявный метод Эйлера')
plt.plot(t_itrap, y_itrap, 'm*-',linewidth=2.2, markersize=4, label='Неявный метод трапеций')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('Задача 2.4: y\' = -2000y + t, y(0) = 0 (жесткая система)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
return t_euler, y_euler, t_beuler, y_beuler, t_itrap, y_itrap, t_ref, y_ref
if __name__ == "__main__":
result2 = problem_2_4()

BIN
labs/lab1/master.pdf Normal file

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

9625
labs/lab1/report/res.pdf Normal file

File diff suppressed because it is too large Load Diff

643
labs/lab1/report/res.typ Normal file
View File

@@ -0,0 +1,643 @@
#set text(size: 1.3em)
#show link: underline
#set page(footer: context {
if counter(page).get().first() > 1 [
#align(center)[
#counter(page).display("1")
]
]
if counter(page).get().first() == 1 [
#align(center)[
Санкт-Петербург \ 2025
]
]
})
#set page(header: context {
if counter(page).get().first() == 1 [
#align(center)[
Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики
]
]
})
#show raw.where(block: false): box.with(
fill: luma(240),
inset: (x: 3pt, y: 0pt),
outset: (y: 3pt),
radius: 2pt,
)
#show raw.where(block: true): block.with(
fill: luma(240),
inset: 10pt,
radius: 4pt,
)
// title
#for _ in range(5) { linebreak() }
#align(center)[Расчетно графическая работа №1]
#for _ in range(15) { linebreak() }
#align(right)[Выполнили:]
#align(right)[Левахин Лев]
#align(right)[Останин Андрей]
#align(right)[Дощенников Никита]
#align(right)[Группы: К3221, К3240]
#align(right)[Проверил:]
#align(right)[Владимир Владимирович Беспалов]
#pagebreak()
=== Цель
Изучение и практическое применение численных методов решения обыкновенных дифференциальных уравнений, сравнение их точности и устойчивости на различных типах задач.
=== Задачи
1. Реализовать следующие численные методы решения ОДУ:
- Явный метод Эйлера (1-го порядка)
- Явный метод трапеций (улучшенный Эйлер, 2-го порядка)
- Классический метод Рунге-Кутты 4-го порядка (RK4)
- Неявный метод Эйлера (1-го порядка)
- Неявный метод трапеций (2-го порядка)
2. Решить две задачи:
- Нежесткое нелинейное уравнение типа Риккати (`1.4`): исследование точности и сходимости явных методов
- Жесткое линейное уравнение (`2.4`): исследование устойчивости неявных методов
3. Провести анализ погрешностей и построить графики решений
4. Сформулировать выводы о применимости различных методов
=== Теоретические основы
==== Постановка задачи Коши
Рассматривается начальная задача для обыкновенного дифференциального уравнения первого порядка:
$
frac(d y, d x) eq f(t, y), space.quad y(t_0) eq y_0
$
где
- $t$ - независимая переменная (время)
- $y(t)$ - искомая функция
- $f(t, y)$ - правая часть уравнения
- $y_0$ - начальное условие
==== Классификация численных методов
*Явные методы* - значение решения на следующем шаге вычисляется непосредственно из известных значений:
- Просты в реализации
- Требуют малого шага для жестких систем
- Примеры: явный Эйлер, RK4
*Неявные методы* - значение решения на следующем шаге находится из неявного уравнения:
- Требуют решения нелинейных уравнений на каждом шаге
- Обладают лучшей устойчивостью для жестких систем
- Примеры: неявный Эйлер, неявная трапеция
=== Описание реализованных методов
==== Явный метод Эйлера
$
y_(n + 1) eq y_n plus h dot f(t_n, y_n)
$
Имеет первый порядок точности $O(h)$.
```python
def euler_method(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
y[i + 1] = y[i] + h * f(t[i], y[i])
return t, y
```
Метод использует линейную аппроксимацию решения на основе производной в начале интервала. Это самый простой, но наименее точный метод.
==== Явный метод трапеций
$
k_1 eq f(t_n, y_n) \
k_2 eq f(t_n plus h, y_n plus h dot k_1) \
y_(n plus 1) eq y_n plus frac(h, 2) dot (k_1 plus k_2)
$
Имеет второй порядок точности $O(h^2)$.
```python
def explicit_trapezoid(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
k1 = f(t[i], y[i])
k2 = f(t[i] + h, y[i] + h * k1)
y[i + 1] = y[i] + (h / 2) * (k1 + k2)
return t, y
```
Метод сначала делает предсказание решения в конце интервала (явным Эйлером), затем усредняет производные в начале и конце интервала.
==== Метод Рунге-Кутты 4-го порядка (RK4)
$
k_1 eq f(t_n, y_n) \
k_2 eq f(t_n plus frac(h, 2), y_n plus h dot frac(k_1, 2)) \
k_3 eq f(t_n plus frac(h, 2), y_n plus h dot frac(k_2, 2)) \
k_4 eq f(t_n plus h, y_n plus h dot k_3) \
y_(n plus 1) = y_n + frac(h, 6) dot (k_1 plus 2 k_2 plus 2 k_3 plus k_4)
$
Имеет четвертый порядок точности $O(h^4)$
```python
def rk4_method(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
k1 = f(t[i], y[i])
k2 = f(t[i] + h/2, y[i] + h/2 * k1)
k3 = f(t[i] + h/2, y[i] + h/2 * k2)
k4 = f(t[i] + h, y[i] + h * k3)
y[i + 1] = y[i] + h/6 * (k1 + 2*k2 + 2*k3 + k4)
return t, y
```
Метод вычисляет четыре промежуточных значения производной внутри интервала и формирует взвешенное среднее. Это обеспечивает высокую точность.
==== Неявный метод Эйлера
$
y_(n plus 1) eq y_n plus h dot f(t_(n plus 1), y_(n plus 1))
$
Имеет первый порядок точности $O(h)$
```python
def backward_euler(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
t_next = t[i + 1]
def equation(z):
return z - h * f(t_next, z) - y[i]
y[i + 1] = fsolve(equation, y[i])[0]
return t, y
```
Метод использует производную в конце интервала, что требует решения нелинейного уравнения на каждом шаге с помощью `fsolve`. Это обеспечивает безусловную устойчивость для линейных задач.
==== Неявный метод трапеций
$
y_(n plus 1) eq y_n plus frac(h, 2) dot [f(t_n, y_n) plus f(t_(n plus 1), t_(n + 1)]
$
Имеет второй порядок точности $O(h^2)$
```python
def implicit_trapezoid(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
t_n = t[i]
t_np1 = t[i + 1]
y_n = y[i]
def equation(z):
return z - y_n - (h/2) * (f(t_n, y_n) + f(t_np1, z))
y[i + 1] = fsolve(equation, y_n)[0]
return t, y
```
Метод усредняет производные в начале и конце интервала (как явная трапеция), но использует неизвестное значение $y_(n+1)$, что требует решения нелинейного уравнения. Метод A-устойчив.
=== Задачи
==== 1.4
$
y' eq y^2 - t, space.quad y(0) eq 1, space.quad t in [0, 1.5], space.quad h eq 0.25
$
- Нелинейное уравнение типа Риккати
- Не имеет аналитического решения
- Нежесткая система - подходит для явных методов
- Используется для анализа точности и сходимости
```python
def problem_1_4():
def f(t, y):
return y**2 - t
t_span = [0, 1.5]
y0 = 1
h = 0.25
solver = ODESolver()
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
t_trap, y_trap = solver.explicit_trapezoid(f, t_span, y0, h)
t_rk4, y_rk4 = solver.rk4_method(f, t_span, y0, h)
sol_ref = solve_ivp(f, t_span, [y0], method='RK45',
rtol=1e-10, atol=1e-12, dense_output=True)
```
==== 2.4
$
y' eq -2000y plus t, space.quad y(0) eq 0, space.quad t in [0, 1], space.quad h eq 1
$
- Линейное уравнение с большим отрицательным коэффициентом $lambda = -2000$
- Жесткая система
- Явный метод Эйлера неустойчив при больших шагах
- Требует неявных методов для устойчивости
```python
def problem_2_4():
def f(t, y):
return -2000 * y + t
t_span = [0, 1]
y0 = 0
h = 1
solver = ODESolver()
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
t_beuler, y_beuler = solver.backward_euler(f, t_span, y0, h)
t_itrap, y_itrap = solver.implicit_trapezoid(f, t_span, y0, h)
sol_ref = solve_ivp(f, t_span, [y0], method='Radau',
rtol=1e-10, atol=1e-12, dense_output=True)
```
=== Результаты
==== 1.4
Мы уменьшили интервал с $[0, 1.5]$ до $[0, 1]$ для того, чтобы избежать "взрыва решения", так как уравнение нелинейно.
Результаты программы:
```bash
=== ЗАДАЧА 1.4: y' = y² - t, y(0) = 1 ===
Ошибка метода Эйлера: 6.44e+00
Ошибка явного метода трапеций: 3.76e+00
Ошибка метода РК4: 6.45e-01
```
Ошибка получилась порядка $10^(-1)$.
#align(center)[
#figure(
image("assets/1.png"),
supplement: [Рис.],
caption: [График решения задачи 1.4]
) <g1>
]
- RK4 самый точный. Ошибка $tilde 10^(-1)$ в разы меньше остальных. На графике траектория почти совпадает с эталоном.
- Явная трапеция имеет среднюю точность. Ошибка меньше, чем у Эйлера, но заметно хуже RK4.
- Метод эйлера самый неточный. Ошибка огромная, отклонение от эталона быстро растёт.
==== 2.4
Результаты программы:
```bash
=== ЗАДАЧА 2.4: y' = -2000y + t, y(0) = 0 ===
Ошибка явного метода Эйлера: 5.00e-04
Ошибка неявного метода Эйлера: 1.25e-10
Ошибка неявного метода трапеций: 2.50e-07
```
#align(center)[
#figure(
image("assets/2.png"),
supplement: [Рис.],
caption: [График решения задачи 2.4]
) <g2>
]
- Неявный Эйлер самый точный и устойчивый. Ошибка $tilde 10^(-10)$.
- Неявная трапеция тоже устойчива, но точность хуже. Ошибка $tilde 10^(-7)$.
- Явный Эйлер нестабилен, даёт неправильную форму решения.
=== Структура программы
==== Класс `ODESolver`
Класс инкапсулирует все численные методы:
```python
class ODESolver:
def euler_method(self, f, t_span, y0, h): ...
def explicit_trapezoid(self, f, t_span, y0, h): ...
def rk4_method(self, f, t_span, y0, h): ...
def backward_euler(self, f, t_span, y0, h): ...
def implicit_trapezoid(self, f, t_span, y0, h): ...
```
==== Функция решения задач
Каждая задача решается в отдельной функции:
- `problem_1_4()` - для нежесткой задачи
- `problem_2_4()` - для жесткой задачи
Функции выполняют:
1. Определение правой части ОДУ
2. Задание параметров интегрирования
3. Вызов численных методов
4. Получение эталонного решения
5. Вычисление погрешностей
6. Построение графиков
==== Вычисление эталонного решения
Используются высокоточные методы из библиотеки SciPy:
- `solve_ivp` с методом RK45 для нежестких систем
- `solve_ivp` с методом Radau для жестких систем
- Строгие допуски: `rtol=1e-10`, `atol=1e-12`
==== Анализ погрешности
Глобальная погрешность вычисляется как норма разности:
```python
err = np.linalg.norm(y_numerical - y_reference)
```
где используется евклидова норма $L_2$.
=== Выводы
О порядке точности:
- Порядок метода существенно влияет на точность при одинаковом шаге
- Для достижения заданной точности метод более высокого порядка требует меньше вычислений
- RK4 является оптимальным выбором для нежестких задач
О явных и неявных методах:
- Явные методы просты в реализации, но имеют ограничения по устойчивости
- Неявные методы требуют решения нелинейных уравнений, но обеспечивают устойчивость
- Для жестких систем неявные методы необходимы
О жесткости:
- Жесткие системы характеризуются наличием сильно различающихся масштабов времени
- Явные методы требуют непрактично малых шагов для жестких систем
- A-устойчивые неявные методы позволяют использовать большие шаги
=== Приложение
Полный код программы:
```python
import matplotlib.pyplot as plt
import math
import numpy as np
from scipy.integrate import solve_ivp
from scipy.optimize import fsolve
class ODESolver:
def euler_method(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
y[i + 1] = y[i] + h * f(t[i], y[i])
return t, y
def explicit_trapezoid(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
k1 = f(t[i], y[i])
k2 = f(t[i] + h, y[i] + h * k1)
y[i + 1] = y[i] + (h / 2) * (k1 + k2)
return t, y
def rk4_method(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
k1 = f(t[i], y[i])
k2 = f(t[i] + h/2, y[i] + h/2 * k1)
k3 = f(t[i] + h/2, y[i] + h/2 * k2)
k4 = f(t[i] + h, y[i] + h * k3)
y[i + 1] = y[i] + h/6 * (k1 + 2*k2 + 2*k3 + k4)
return t, y
def backward_euler(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
t_next = t[i + 1]
def equation(z):
return z - h * f(t_next, z) - y[i]
y[i + 1] = fsolve(equation, y[i])[0]
return t, y
def implicit_trapezoid(self, f, t_span, y0, h):
t0, t_end = t_span
N = int((t_end - t0) / h)
t = np.linspace(t0, t_end, N + 1)
y = np.zeros(N + 1)
y[0] = y0
for i in range(N):
t_n = t[i]
t_np1 = t[i + 1]
y_n = y[i]
def equation(z):
return z - y_n - (h/2) * (f(t_n, y_n) + f(t_np1, z))
y[i + 1] = fsolve(equation, y_n)[0]
return t, y
def problem_1_4():
print("=== ЗАДАЧА 1.4: y' = y² - t, y(0) = 1 ===")
def f(t, y):
return y**2 - t
t_span = [0, 1.0]
y0 = 1
h = 0.25
solver = ODESolver()
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
t_trap, y_trap = solver.explicit_trapezoid(f, t_span, y0, h)
t_rk4, y_rk4 = solver.rk4_method(f, t_span, y0, h)
sol_ref = solve_ivp(f, t_span, [y0], method='RK45',
rtol=1e-10, atol=1e-12, dense_output=True)
t_ref = np.linspace(t_span[0], t_span[1], 100)
y_ref = sol_ref.sol(t_ref)[0]
y_ref_euler = sol_ref.sol(t_euler)[0]
y_ref_trap = sol_ref.sol(t_trap)[0]
y_ref_rk4 = sol_ref.sol(t_rk4)[0]
err_euler = np.linalg.norm(y_euler - y_ref_euler)
err_trap = np.linalg.norm(y_trap - y_ref_trap)
err_rk4 = np.linalg.norm(y_rk4 - y_ref_rk4)
print(f"Ошибка метода Эйлера: {err_euler:.2e}")
print(f"Ошибка явного метода трапеций: {err_trap:.2e}")
print(f"Ошибка метода РК4: {err_rk4:.2e}")
plt.figure(figsize=(12, 8))
plt.plot(t_ref, y_ref, 'k-', linewidth=5, label='Эталонное решение (solve_ivp)')
plt.plot(t_euler, y_euler, 'bo-', markersize=10, label='Метод Эйлера')
plt.plot(t_trap, y_trap, 'c*-', markersize=15, label='Явный метод трапеций')
plt.plot(t_rk4, y_rk4, 'rs-', markersize=5, label='Метод РК4')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('Задача 1.4: y\' = y² - t, y(0) = 1')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
return t_euler, y_euler, t_trap, y_trap, t_rk4, y_rk4, t_ref, y_ref
if __name__ == "__main__":
result1 = problem_1_4()
def problem_2_4():
print("\n=== ЗАДАЧА 2.4: y' = -2000y + t, y(0) = 0 ===")
def f(t, y):
return -2000 * y + t
t_span = [0, 1]
y0 = 0
h = 1
solver = ODESolver()
t_euler, y_euler = solver.euler_method(f, t_span, y0, h)
t_beuler, y_beuler = solver.backward_euler(f, t_span, y0, h)
t_itrap, y_itrap = solver.implicit_trapezoid(f, t_span, y0, h)
sol_ref = solve_ivp(f, t_span, [y0], method='Radau',
rtol=1e-10, atol=1e-12, dense_output=True)
t_ref = np.linspace(t_span[0], t_span[1], 100)
y_ref = sol_ref.sol(t_ref)[0]
y_ref_euler = sol_ref.sol(t_euler)[0]
y_ref_beuler = sol_ref.sol(t_beuler)[0]
y_ref_itrap = sol_ref.sol(t_itrap)[0]
err_euler = np.linalg.norm(y_euler - y_ref_euler)
err_beuler = np.linalg.norm(y_beuler - y_ref_beuler)
err_itrap = np.linalg.norm(y_itrap - y_ref_itrap)
print(f"Ошибка явного метода Эйлера: {err_euler:.2e}")
print(f"Ошибка неявного метода Эйлера: {err_beuler:.2e}")
print(f"Ошибка неявного метода трапеций: {err_itrap:.2e}")
plt.figure(figsize=(12, 8))
plt.plot(t_ref, y_ref, 'k-', linewidth=5, label='Эталонное решение (solve_ivp)')
plt.plot(t_euler, y_euler, 'bo-', markersize=4, label='Явный метод Эйлера')
plt.plot(t_beuler, y_beuler, 'g^-', markersize=4, label='Неявный метод Эйлера')
plt.plot(t_itrap, y_itrap, 'm*-',linewidth=2.2, markersize=4, label='Неявный метод трапеций')
plt.xlabel('t')
plt.ylabel('y(t)')
plt.title('Задача 2.4: y\' = -2000y + t, y(0) = 0 (жесткая система)')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
return t_euler, y_euler, t_beuler, y_beuler, t_itrap, y_itrap, t_ref, y_ref
if __name__ == "__main__":
result2 = problem_2_4()
```

View File

@@ -0,0 +1,7 @@
f = @(t,y) y.^2 - t;
y0 = 1;
tspan = [0 1.05]; % tspan = [0 1.5];
opts = odeset('RelTol',1e-12,'AbsTol',1e-14);
[t1,y1] = ode45(f,tspan,y0,opts);
plot(t1,y1)
print -dpng "plot.png"

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -0,0 +1,9 @@
lambda = 2000;
f = @(t,y) -lambda*y + t;
y0 = 0;
tspan = [0 1];
opts = odeset('RelTol',1e-12,'AbsTol',1e-14);
[t2,y2] = ode15s(f,tspan,y0,opts);
plot(t2,y2)
print -dpng "plot.png"

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
labs/lab1/variants.pdf Normal file

Binary file not shown.

82
practice/lab1/main.py Normal file
View File

@@ -0,0 +1,82 @@
import sys
import matplotlib.pyplot as plt
def f(x: float, y: float) -> float:
# f(x, y) = x^2 - 2y
return x**2 - 2 * y
def euler(h: float, x_min: float, x_max: float, y_0: float):
# y_(n + 1) = y_n + h * f(x_n, y_n)
x_i: list[float] = [x_min]
y_i: list[float] = [y_0]
f_i = f(x_i[-1], y_i[-1])
h_f_i = h * f_i
for i in range(int((x_max - x_min) / h)):
y_i.append(y_i[-1] + h_f_i)
x_i.append(x_i[-1] + h)
f_i = f(x_i[-1], y_i[-1])
h_f_i = h * f_i
return x_i, y_i
def trapezoid(h: float, x_min: float, x_max: float, y_0: float):
# y_(n + 1) = y_n + h * (f(x_n, y_n) + f(x_(n + 1), y~_(n + 1)))/2
# y~_(n + 1) = y_n + h * f(x_n, y_n)
x_i: list[float] = [x_min]
y_i: list[float] = [y_0]
y_tilde = y_i[-1] + h * f(x_i[-1], y_i[-1])
for i in range(int((x_max - x_min) / h)):
y = y_i[-1] + h * (f(x_i[-1], y_i[-1]) + f(x_i[-1] + h, y_tilde)) / 2
y_i.append(y)
x_i.append(x_i[-1] + h)
y_tilde = y_i[-1] + h * f(x_i[-1], y_i[-1])
return x_i, y_i
def rk4(h: float, x_min: float, x_max: float, y_0: float):
# k_1 = f(x_n, y_n)
# k_2 = f(x_n + h/2, y_n + h/2 k_1)
# k_3 = f(x_n + h/2, y_n + h/2 k_2)
# k_4 = f(x_n + h, y_n + hk_3)
# y_(n + 1) = y_n + h/6 (k_1 + 2k_2 + 2k_3 + k_4)
x_i: list[float] = [x_min]
y_i: list[float] = [y_0]
for i in range(int((x_max - x_min) / h)):
k_1 = f(x_i[-1], y_i[-1])
k_2 = f(x_i[-1] + h/2, y_i[-1] + h/2 * k_1)
k_3 = f(x_i[-1] + h/2, y_i[-1] + h/2 * k_2)
k_4 = f(x_i[-1] + h, y_i[-1] + h * k_3)
y = y_i[-1] + h/6 * (k_1 + 2 * k_2 + 2 * k_3 + k_4)
y_i.append(y)
x_i.append(x_i[-1] + h)
return x_i, y_i
def draw_graph(x: list, y: list):
plt.plot(x, y)
plt.show()
def main() -> None:
# y' = t^2 - 2y, y(0) = 1, t in [0, 1]
methods = {"euler": euler,
"trapezoid": trapezoid,
"rk4": rk4}
if sys.argv[1] in methods.keys():
x, y = methods[sys.argv[1]](0.01, 0, 1, 1)
draw_graph(x, y)
if __name__ == "__main__":
main()

BIN
theory/lectures.pdf Normal file

Binary file not shown.