%% Численное решение обыкновенных дифференциальных уравнений % *Анализ жёсткой и нежёсткой задач с использованием различных методов* % % В этой работе рассматриваются два дифференциальных уравнения: % % # *Нежёсткая задача*: нелинейное уравнение типа Риккати % # *Жёсткая задача*: линейное уравнение с большим коэффициентом жёсткости % % Для каждой задачи применяются 6 численных методов и проводится сравнительный анализ. clear; clc; close all; %% ЧАСТЬ 1: НЕЖЁСТКАЯ ЗАДАЧА % %% Постановка задачи % % Рассматривается задача Коши для нелинейного ОДУ первого порядка: % % $$\frac{dy}{dt} = y^2 - t, \quad y(0) = 1, \quad t \in [0, 1.5]$$ % % Это уравнение типа Риккати, которое не имеет аналитического решения в % замкнутой форме. Поэтому для проверки точности численных методов мы % используем высокоточное численное решение, полученное с помощью % адаптивного метода Рунге-Кутта |ode45|. %% 1.1 Определение параметров задачи f4 = @(t, y) y.^2 - t; % Правая часть уравнения y0_4 = 1; % Начальное условие t0_4 = 0; % Начальное время t_end_4 = 1.5; % Конечное время h_4 = 0.05; % Шаг интегрирования N_4 = (t_end_4 - t0_4) / h_4; % Число шагов t_grid_4 = linspace(t0_4, t_end_4, N_4+1); % Сетка времени fprintf('═══════════════════════════════════════════════════════\n'); fprintf(' ЧАСТЬ 1: НЕЖЁСТКАЯ ЗАДАЧА (РИККАТИ) \n'); fprintf('═══════════════════════════════════════════════════════\n\n'); fprintf('Уравнение: dy/dt = y² - t\n'); fprintf('Начальное условие: y(0) = 1\n'); fprintf('Интервал интегрирования: [0, 1.5]\n'); fprintf('Шаг интегрирования: h = %.3f\n', h_4); fprintf('Число шагов: N = %d\n\n', N_4); %% 1.2 Построение эталонного решения % % Для получения эталонного решения используется встроенный решатель |ode45| % с очень жёсткими допусками на погрешность. Это обеспечивает точность, % достаточную для использования в качестве "точного" решения при анализе % погрешностей тестируемых методов. [t_ref4, y_ref4] = ode45(f4, [t0_4, t_end_4], y0_4, ... odeset('RelTol', 1e-12, 'AbsTol', 1e-14)); y_ref_4 = @(t) interp1(t_ref4, y_ref4, t, 'spline'); y_exact_4 = y_ref_4(t_grid_4); fprintf('✓ Эталонное решение построено с помощью ode45\n'); fprintf(' Параметры точности: RelTol = 1e-12, AbsTol = 1e-14\n'); fprintf(' Число точек адаптивной сетки: %d\n\n', length(t_ref4)); %% 1.3 Реализация численных методов % % Реализуем 6 различных численных методов: % % # *Явный метод Эйлера* (1-й порядок точности) % # *Явный метод трапеций* (улучшенный Эйлер, 2-й порядок) % # *Классический метод Рунге-Кутта 4-го порядка* (RK4) % # *Неявный метод Эйлера* (обратный Эйлер, 1-й порядок) % # *Неявный метод трапеций* (A-устойчивый, 2-й порядок) % # *Неявный метод Рунге-Кутта 4-го порядка* (метод Гаусса) %% Метод 1: Явный метод Эйлера % Простейший явный метод первого порядка точности. % Итерационная формула: $y_{n+1} = y_n + h \cdot f(t_n, y_n)$ fprintf('→ Вычисление методом Эйлера...\n'); y_euler_4 = zeros(1, N_4+1); y_euler_4(1) = y0_4; for n = 1:N_4 y_euler_4(n+1) = y_euler_4(n) + h_4 * f4(t_grid_4(n), y_euler_4(n)); end err_euler_4 = norm(y_euler_4 - y_exact_4); fprintf(' Глобальная погрешность: %.2e\n', err_euler_4); %% Метод 2: Явный метод трапеций (улучшенный Эйлер) % Метод второго порядка точности с двумя вычислениями функции на шаг. % % $$y_{n+1} = y_n + \frac{h}{2}(k_1 + k_2)$$ % % где $k_1 = f(t_n, y_n)$, $k_2 = f(t_n + h, y_n + h \cdot k_1)$ fprintf('→ Вычисление явным методом трапеций...\n'); y_trap_expl_4 = zeros(1, N_4+1); y_trap_expl_4(1) = y0_4; for n = 1:N_4 k1 = f4(t_grid_4(n), y_trap_expl_4(n)); k2 = f4(t_grid_4(n) + h_4, y_trap_expl_4(n) + h_4 * k1); y_trap_expl_4(n+1) = y_trap_expl_4(n) + (h_4/2) * (k1 + k2); end err_trap_expl_4 = norm(y_trap_expl_4 - y_exact_4); fprintf(' Глобальная погрешность: %.2e (улучшение в %.1f раз)\n', ... err_trap_expl_4, err_euler_4/err_trap_expl_4); %% Метод 3: Классический метод Рунге-Кутта 4-го порядка (RK4) % Наиболее популярный явный метод четвёртого порядка точности. % Требует 4 вычисления функции на шаг, обеспечивает высокую точность. fprintf('→ Вычисление методом RK4...\n'); y_rk4_4 = zeros(1, N_4+1); y_rk4_4(1) = y0_4; for n = 1:N_4 k1 = f4(t_grid_4(n), y_rk4_4(n)); k2 = f4(t_grid_4(n) + h_4/2, y_rk4_4(n) + h_4/2 * k1); k3 = f4(t_grid_4(n) + h_4/2, y_rk4_4(n) + h_4/2 * k2); k4 = f4(t_grid_4(n) + h_4, y_rk4_4(n) + h_4 * k3); y_rk4_4(n+1) = y_rk4_4(n) + h_4/6 * (k1 + 2*k2 + 2*k3 + k4); end err_rk4_4 = norm(y_rk4_4 - y_exact_4); fprintf(' Глобальная погрешность: %.2e (улучшение в %.1f раз)\n', ... err_rk4_4, err_euler_4/err_rk4_4); %% Метод 4: Неявный метод Эйлера (обратный Эйлер) % Неявный метод первого порядка, безусловно устойчивый. % На каждом шаге требуется решение нелинейного уравнения: % % $$y_{n+1} = y_n + h \cdot f(t_{n+1}, y_{n+1})$$ fprintf('→ Вычисление обратным методом Эйлера...\n'); y_beuler_4 = zeros(1, N_4+1); y_beuler_4(1) = y0_4; for n = 1:N_4 t_next = t_grid_4(n+1); G = @(z) z - h_4 * f4(t_next, z) - y_beuler_4(n); y_beuler_4(n+1) = fzero(G, y_beuler_4(n)); end err_beuler_4 = norm(y_beuler_4 - y_exact_4); fprintf(' Глобальная погрешность: %.2e\n', err_beuler_4); %% Метод 5: Неявный метод трапеций % A-устойчивый метод второго порядка точности. % Особенно эффективен для жёстких задач. % % $$y_{n+1} = y_n + \frac{h}{2}[f(t_n, y_n) + f(t_{n+1}, y_{n+1})]$$ fprintf('→ Вычисление неявным методом трапеций...\n'); y_trap_impl_4 = zeros(1, N_4+1); y_trap_impl_4(1) = y0_4; for n = 1:N_4 t_n = t_grid_4(n); t_np1 = t_grid_4(n+1); y_n = y_trap_impl_4(n); G = @(z) z - y_n - (h_4/2) * (f4(t_n, y_n) + f4(t_np1, z)); y_trap_impl_4(n+1) = fzero(G, y_n); end err_trap_impl_4 = norm(y_trap_impl_4 - y_exact_4); fprintf(' Глобальная погрешность: %.2e\n', err_trap_impl_4); %% Метод 6: Неявный метод Рунге-Кутта 4-го порядка (метод Гаусса) % Двухстадийный метод Гаусса с четвёртым порядком точности. % A-устойчив и симплектичен, идеален для гамильтоновых систем. fprintf('→ Вычисление неявным методом RK4 (Гаусс)...\n'); % Коэффициенты метода Гаусса c = [1/2 - sqrt(3)/6; 1/2 + sqrt(3)/6]; A = [1/4, 1/4 - sqrt(3)/6; 1/4 + sqrt(3)/6, 1/4]; b = [1/2, 1/2]; y_irk4_4 = zeros(1, N_4+1); y_irk4_4(1) = y0_4; options = optimoptions('fsolve', 'Display', 'off'); for n = 1:N_4 t_n = t_grid_4(n); y_n = y_irk4_4(n); % Система уравнений для стадий K1, K2 stage_eq = @(K) [ K(1) - f4(t_n + c(1)*h_4, y_n + h_4*(A(1,1)*K(1) + A(1,2)*K(2))); K(2) - f4(t_n + c(2)*h_4, y_n + h_4*(A(2,1)*K(1) + A(2,2)*K(2))) ]; K0 = [f4(t_n, y_n); f4(t_n, y_n)]; % Начальное приближение K = fsolve(stage_eq, K0, options); y_irk4_4(n+1) = y_n + h_4 * (b(1)*K(1) + b(2)*K(2)); end err_irk4_4 = norm(y_irk4_4 - y_exact_4); fprintf(' Глобальная погрешность: %.2e\n\n', err_irk4_4); %% 1.4 Сравнение результатов % % Выводим сводную таблицу погрешностей всех методов. fprintf('╔════════════════════════════════════════════════════╗\n'); fprintf('║ СРАВНЕНИЕ МЕТОДОВ (h = %.3f) ║\n', h_4); fprintf('╠════════════════════════════════════════════════════╣\n'); fprintf('║ Метод │ Погрешность │ Улучшение ║\n'); fprintf('╠════════════════════════════════════════════════════╣\n'); fprintf('║ Явный Эйлер │ %.2e │ — ║\n', err_euler_4); fprintf('║ Явная трапеция │ %.2e │ ×%.1f ║\n', err_trap_expl_4, err_euler_4/err_trap_expl_4); fprintf('║ RK4 (явный) │ %.2e │ ×%.0f ║\n', err_rk4_4, err_euler_4/err_rk4_4); fprintf('║ Обратный Эйлер │ %.2e │ ×%.1f ║\n', err_beuler_4, err_euler_4/err_beuler_4); fprintf('║ Неявная трапеция │ %.2e │ ×%.1f ║\n', err_trap_impl_4, err_euler_4/err_trap_impl_4); fprintf('║ Неявный RK4 (Гаусс) │ %.2e │ ×%.0f ║\n', err_irk4_4, err_euler_4/err_irk4_4); fprintf('╚════════════════════════════════════════════════════╝\n\n'); %% 1.5 Визуализация решений % % Построим график сравнения всех методов с эталонным решением. figure('Position', [100, 100, 1200, 700]); t_plot_4 = linspace(t0_4, t_end_4, 500); y_plot_4 = y_ref_4(t_plot_4); plot(t_plot_4, y_plot_4, 'k-', 'LineWidth', 3, 'DisplayName', 'Эталон (ode45)'); hold on; plot(t_grid_4, y_euler_4, 'b.-', 'LineWidth', 1.5, 'MarkerSize', 10, ... 'DisplayName', sprintf('Эйлер (погр. %.1e)', err_euler_4)); plot(t_grid_4, y_trap_expl_4, 'c*-', 'LineWidth', 1.5, 'MarkerSize', 8, ... 'DisplayName', sprintf('Явн. трапеция (%.1e)', err_trap_expl_4)); plot(t_grid_4, y_rk4_4, 'rs-', 'LineWidth', 1.5, 'MarkerSize', 8, ... 'DisplayName', sprintf('RK4 (%.1e)', err_rk4_4)); plot(t_grid_4, y_beuler_4, 'g^-', 'LineWidth', 1.5, 'MarkerSize', 8, ... 'DisplayName', sprintf('Обр. Эйлер (%.1e)', err_beuler_4)); plot(t_grid_4, y_trap_impl_4, 'md-', 'LineWidth', 1.5, 'MarkerSize', 8, ... 'DisplayName', sprintf('Неявн. трапеция (%.1e)', err_trap_impl_4)); plot(t_grid_4, y_irk4_4, 'kx-', 'LineWidth', 1.5, 'MarkerSize', 10, ... 'DisplayName', sprintf('Неявн. RK4 (%.1e)', err_irk4_4)); xlabel('Время t', 'FontSize', 14, 'FontWeight', 'bold'); ylabel('Решение y(t)', 'FontSize', 14, 'FontWeight', 'bold'); title('Часть 1: Сравнение всех методов (dy/dt = y² - t)', ... 'FontSize', 16, 'FontWeight', 'bold'); legend('Location', 'northwest', 'FontSize', 11); grid on; grid minor; set(gca, 'FontSize', 12, 'LineWidth', 1.5); hold off; %% 1.6 Анализ сходимости % % Исследуем, как погрешность зависит от величины шага интегрирования. % Для методов p-го порядка точности ожидается: $\text{погрешность} \sim h^p$ fprintf('→ Выполняется анализ сходимости...\n'); h_values_4 = [0.1, 0.05, 0.025, 0.0125, 0.00625]; n_h = length(h_values_4); errors_p1 = zeros(6, n_h); for idx = 1:n_h h_temp = h_values_4(idx); N_temp = (t_end_4 - t0_4) / h_temp; t_temp = linspace(t0_4, t_end_4, N_temp+1); y_exact_temp = y_ref_4(t_temp); % Явный Эйлер y_temp = zeros(1, N_temp+1); y_temp(1) = y0_4; for n = 1:N_temp y_temp(n+1) = y_temp(n) + h_temp * f4(t_temp(n), y_temp(n)); end errors_p1(1,idx) = norm(y_temp - y_exact_temp); % Явная трапеция y_temp = zeros(1, N_temp+1); y_temp(1) = y0_4; for n = 1:N_temp k1 = f4(t_temp(n), y_temp(n)); k2 = f4(t_temp(n) + h_temp, y_temp(n) + h_temp * k1); y_temp(n+1) = y_temp(n) + (h_temp/2) * (k1 + k2); end errors_p1(2,idx) = norm(y_temp - y_exact_temp); % RK4 y_temp = zeros(1, N_temp+1); y_temp(1) = y0_4; for n = 1:N_temp k1 = f4(t_temp(n), y_temp(n)); k2 = f4(t_temp(n) + h_temp/2, y_temp(n) + h_temp/2 * k1); k3 = f4(t_temp(n) + h_temp/2, y_temp(n) + h_temp/2 * k2); k4 = f4(t_temp(n) + h_temp, y_temp(n) + h_temp * k3); y_temp(n+1) = y_temp(n) + h_temp/6 * (k1 + 2*k2 + 2*k3 + k4); end errors_p1(3,idx) = norm(y_temp - y_exact_temp); % Обратный Эйлер y_temp = zeros(1, N_temp+1); y_temp(1) = y0_4; for n = 1:N_temp G = @(z) z - h_temp * f4(t_temp(n+1), z) - y_temp(n); y_temp(n+1) = fzero(G, y_temp(n)); end errors_p1(4,idx) = norm(y_temp - y_exact_temp); % Неявная трапеция y_temp = zeros(1, N_temp+1); y_temp(1) = y0_4; for n = 1:N_temp G = @(z) z - y_temp(n) - (h_temp/2) * ... (f4(t_temp(n), y_temp(n)) + f4(t_temp(n+1), z)); y_temp(n+1) = fzero(G, y_temp(n)); end errors_p1(5,idx) = norm(y_temp - y_exact_temp); % Неявный RK4 y_temp = zeros(1, N_temp+1); y_temp(1) = y0_4; for n = 1:N_temp t_n = t_temp(n); y_n = y_temp(n); stage_eq = @(K) [ K(1) - f4(t_n + c(1)*h_temp, y_n + h_temp*(A(1,1)*K(1) + A(1,2)*K(2))); K(2) - f4(t_n + c(2)*h_temp, y_n + h_temp*(A(2,1)*K(1) + A(2,2)*K(2))) ]; K0 = [f4(t_n, y_n); f4(t_n, y_n)]; K = fsolve(stage_eq, K0, options); y_temp(n+1) = y_n + h_temp * (b(1)*K(1) + b(2)*K(2)); end errors_p1(6,idx) = norm(y_temp - y_exact_temp); end fprintf(' Анализ завершён для %d значений шага\n\n', n_h); %% Таблица сходимости fprintf('┌──────────────────────────────────────────────────────────────────────────┐\n'); fprintf('│ ТАБЛИЦА СХОДИМОСТИ (ЧАСТЬ 1) │\n'); fprintf('├──────────┬────────────┬────────────┬────────────┬────────────┬───────────┤\n'); fprintf('│ h │ Эйлер │ Явн.трап. │ RK4 │ Обр.Эйлер │ Неяв.трап.│\n'); fprintf('├──────────┼────────────┼────────────┼────────────┼────────────┼───────────┤\n'); for i = 1:n_h fprintf('│ %.6f │ %.2e │ %.2e │ %.2e │ %.2e │ %.2e │\n', ... h_values_4(i), errors_p1(1,i), errors_p1(2,i), errors_p1(3,i), ... errors_p1(4,i), errors_p1(5,i)); end fprintf('└──────────┴────────────┴────────────┴────────────┴────────────┴───────────┘\n\n'); %% График сходимости figure('Position', [100, 100, 1200, 800]); [sorted_h, idx_sort] = sort(h_values_4); method_names = {'Явный Эйлер', 'Явная трапеция', 'RK4', ... 'Обратный Эйлер', 'Неявная трапеция', 'Неявный RK4'}; markers = {'o', '*', 's', '^', 'd', 'x'}; colors = {'b', 'c', 'r', 'g', 'm', 'k'}; for m = 1:6 loglog(sorted_h, errors_p1(m,idx_sort), [colors{m} '-' markers{m}], ... 'LineWidth', 2, 'MarkerSize', 12, 'DisplayName', method_names{m}); hold on; end % Добавим линии теоретического порядка h_ref = sorted_h(2:end); loglog(h_ref, 2*h_ref, 'k--', 'LineWidth', 1, 'DisplayName', 'O(h)'); loglog(h_ref, 0.5*h_ref.^2, 'k:', 'LineWidth', 1, 'DisplayName', 'O(h²)'); loglog(h_ref, 0.01*h_ref.^4, 'k-.', 'LineWidth', 1, 'DisplayName', 'O(h⁴)'); xlabel('Шаг интегрирования h', 'FontSize', 14, 'FontWeight', 'bold'); ylabel('Глобальная погрешность ||y_{num} - y_{ref}||', 'FontSize', 14, 'FontWeight', 'bold'); title('Часть 1: Анализ сходимости (нежёсткая задача)', ... 'FontSize', 16, 'FontWeight', 'bold'); legend('Location', 'southeast', 'FontSize', 11); grid on; grid minor; set(gca, 'FontSize', 12, 'LineWidth', 1.5); hold off; %% Оценка порядка сходимости fprintf('┌────────────────────────────────────────────────────┐\n'); fprintf('│ ОЦЕНКИ ПОРЯДКА СХОДИМОСТИ (ЧАСТЬ 1) │\n'); fprintf('├────────────────────────────────┬───────────────────┤\n'); fprintf('│ Метод │ Порядок (теория) │\n'); fprintf('├────────────────────────────────┼───────────────────┤\n'); h_sub = sorted_h(3:end); for m = 1:6 err_sub = errors_p1(m,idx_sort(3:end)); if length(err_sub) >= 2 && all(err_sub > 0) p_est = log(err_sub(1)/err_sub(end)) / log(h_sub(1)/h_sub(end)); % Теоретический порядок if m == 1 || m == 4 p_theory = 1; elseif m == 2 || m == 5 p_theory = 2; else p_theory = 4; end fprintf('│ %-30s │ %.3f (≈ %d) │\n', method_names{m}, p_est, p_theory); end end fprintf('└────────────────────────────────┴───────────────────┘\n\n'); %% ЧАСТЬ 2: ЖЁСТКАЯ ЗАДАЧА % %% Постановка задачи % % Рассматривается линейное ОДУ с большим коэффициентом жёсткости: % % $$\frac{dy}{dt} = -2000y + t, \quad y(0) = 0, \quad t \in [0, 1]$$ % % Параметр жёсткости $\lambda = -2000$ делает эту задачу *жёсткой* (stiff). % Это означает, что явные методы требуют очень малого шага для устойчивости, % в то время как неявные методы остаются устойчивыми при больших шагах. fprintf('═══════════════════════════════════════════════════════\n'); fprintf(' ЧАСТЬ 2: ЖЁСТКАЯ ЗАДАЧА (λ = -2000) \n'); fprintf('═══════════════════════════════════════════════════════\n\n'); %% 2.1 Определение параметров задачи lambda = 2000; f9 = @(t, y) -lambda * y + t; y0_9 = 0; t0_9 = 0; t_end_9 = 1; h_9 = 0.01; % Шаг интегрирования N_9 = (t_end_9 - t0_9) / h_9; t_grid_9 = linspace(t0_9, t_end_9, N_9+1); fprintf('Уравнение: dy/dt = -2000y + t\n'); fprintf('Начальное условие: y(0) = 0\n'); fprintf('Интервал интегрирования: [0, 1]\n'); fprintf('Параметр жёсткости: λ = -2000\n'); fprintf('Шаг интегрирования: h = %.3f\n\n', h_9); fprintf('ТЕОРЕТИЧЕСКИЙ АНАЛИЗ УСТОЙЧИВОСТИ:\n'); fprintf('─────────────────────────────────────────────────────\n'); fprintf('Для явного метода Эйлера условие устойчивости:\n'); fprintf(' |1 + h·λ| ≤ 1\n'); fprintf(' |1 - 2000h| ≤ 1\n'); fprintf(' => h ≤ 2/2000 = 0.001\n\n'); fprintf('Наш шаг h = %.3f > 0.001, поэтому явные методы\n', h_9); fprintf('будут НЕУСТОЙЧИВЫМИ!\n\n'); %% 2.2 Аналитическое решение % % Для этого линейного уравнения существует аналитическое решение: % % $y(t) = \frac{t - 1/\lambda}{\lambda} + C \cdot e^{-\lambda t}$ % % где константа $C$ определяется из начального условия. fprintf('АНАЛИТИЧЕСКОЕ РЕШЕНИЕ:\n'); fprintf('─────────────────────────────────────────────────────\n'); fprintf('Для линейного ОДУ dy/dt = -λy + t существует точное решение:\n'); fprintf(' y(t) = (t - 1/λ)/λ + C·exp(-λt)\n'); fprintf('С учётом y(0) = 0: C = 1/λ²\n\n'); C_analytical = 1/(lambda^2); y_analytical = @(t) (t - 1/lambda)/lambda + C_analytical * exp(-lambda*t); fprintf('Особенность: решение содержит быстро затухающую компоненту\n'); fprintf('exp(-2000t), которая практически исчезает при t > 0.005\n'); fprintf('Именно эта быстрая динамика создаёт ЖЁСТКОСТЬ задачи!\n\n'); %% 2.3 Эталонное решение с помощью ode15s % % Для жёстких задач используется специализированный решатель |ode15s|, % основанный на неявных методах с численным дифференцированием. [t_ref9, y_ref9] = ode15s(f9, [t0_9, t_end_9], y0_9, ... odeset('RelTol', 1e-12, 'AbsTol', 1e-14)); y_ref_9 = @(t) interp1(t_ref9, y_ref9, t, 'spline'); y_exact_9 = y_ref_9(t_grid_9); fprintf('✓ Эталонное решение построено с помощью ode15s\n'); fprintf(' (специализированный решатель для жёстких задач)\n'); fprintf(' Параметры: RelTol = 1e-12, AbsTol = 1e-14\n\n'); % Проверка согласованности с аналитическим решением y_analytical_grid = y_analytical(t_grid_9); err_analytical = norm(y_analytical_grid - y_exact_9); fprintf('✓ Проверка: ||y_аналит - y_ode15s|| = %.2e\n', err_analytical); fprintf(' (отличное совпадение!)\n\n'); %% 2.4 Реализация численных методов % % Вычислим решение всеми шестью методами. Для явных методов ожидаем % неустойчивость из-за нарушения условия устойчивости. %% Метод 1: Явный Эйлер (ожидается неустойчивость!) fprintf('→ Вычисление явным методом Эйлера...\n'); try y_euler_9 = zeros(1, N_9+1); y_euler_9(1) = y0_9; stable_euler = true; for n = 1:N_9 y_euler_9(n+1) = y_euler_9(n) + h_9 * f9(t_grid_9(n), y_euler_9(n)); % Проверка на численную неустойчивость if abs(y_euler_9(n+1)) > 1e10 fprintf(' ⚠ НЕУСТОЙЧИВОСТЬ на шаге n=%d (t=%.3f)\n', n, t_grid_9(n+1)); fprintf(' |y| = %.2e >> 1e10\n', abs(y_euler_9(n+1))); stable_euler = false; break; end end if stable_euler err_euler_9 = norm(y_euler_9 - y_exact_9); fprintf(' Метод сошёлся. Погрешность: %.2e\n', err_euler_9); else err_euler_9 = inf; fprintf(' ✗ Метод НЕУСТОЙЧИВ\n'); end catch err_euler_9 = inf; y_euler_9 = nan(size(t_grid_9)); fprintf(' ✗ ОШИБКА при вычислении\n'); end %% Метод 2: Явная трапеция (также неустойчива) fprintf('→ Вычисление явным методом трапеций...\n'); try y_trap_expl_9 = zeros(1, N_9+1); y_trap_expl_9(1) = y0_9; stable_trap_expl = true; for n = 1:N_9 k1 = f9(t_grid_9(n), y_trap_expl_9(n)); k2 = f9(t_grid_9(n) + h_9, y_trap_expl_9(n) + h_9 * k1); y_trap_expl_9(n+1) = y_trap_expl_9(n) + (h_9/2) * (k1 + k2); if abs(y_trap_expl_9(n+1)) > 1e10 fprintf(' ⚠ НЕУСТОЙЧИВОСТЬ на шаге n=%d (t=%.3f)\n', n, t_grid_9(n+1)); stable_trap_expl = false; break; end end if stable_trap_expl err_trap_expl_9 = norm(y_trap_expl_9 - y_exact_9); fprintf(' Метод сошёлся. Погрешность: %.2e\n', err_trap_expl_9); else err_trap_expl_9 = inf; fprintf(' ✗ Метод НЕУСТОЙЧИВ\n'); end catch err_trap_expl_9 = inf; y_trap_expl_9 = nan(size(t_grid_9)); fprintf(' ✗ ОШИБКА при вычислении\n'); end %% Метод 3: RK4 (также неустойчив) fprintf('→ Вычисление методом RK4...\n'); try y_rk4_9 = zeros(1, N_9+1); y_rk4_9(1) = y0_9; stable_rk4 = true; for n = 1:N_9 k1 = f9(t_grid_9(n), y_rk4_9(n)); k2 = f9(t_grid_9(n) + h_9/2, y_rk4_9(n) + h_9/2 * k1); k3 = f9(t_grid_9(n) + h_9/2, y_rk4_9(n) + h_9/2 * k2); k4 = f9(t_grid_9(n) + h_9, y_rk4_9(n) + h_9 * k3); y_rk4_9(n+1) = y_rk4_9(n) + h_9/6 * (k1 + 2*k2 + 2*k3 + k4); if abs(y_rk4_9(n+1)) > 1e10 fprintf(' ⚠ НЕУСТОЙЧИВОСТЬ на шаге n=%d (t=%.3f)\n', n, t_grid_9(n+1)); stable_rk4 = false; break; end end if stable_rk4 err_rk4_9 = norm(y_rk4_9 - y_exact_9); fprintf(' Метод сошёлся. Погрешность: %.2e\n', err_rk4_9); else err_rk4_9 = inf; fprintf(' ✗ Метод НЕУСТОЙЧИВ\n'); end catch err_rk4_9 = inf; y_rk4_9 = nan(size(t_grid_9)); fprintf(' ✗ ОШИБКА при вычислении\n'); end %% Метод 4: Обратный Эйлер (УСТОЙЧИВ!) fprintf('→ Вычисление обратным методом Эйлера...\n'); y_beuler_9 = zeros(1, N_9+1); y_beuler_9(1) = y0_9; for n = 1:N_9 t_next = t_grid_9(n+1); G = @(z) z - h_9 * f9(t_next, z) - y_beuler_9(n); y_beuler_9(n+1) = fzero(G, y_beuler_9(n)); end err_beuler_9 = norm(y_beuler_9 - y_exact_9); fprintf(' ✓ Метод УСТОЙЧИВ. Погрешность: %.2e\n', err_beuler_9); %% Метод 5: Неявная трапеция (A-УСТОЙЧИВА!) fprintf('→ Вычисление неявным методом трапеций...\n'); y_trap_impl_9 = zeros(1, N_9+1); y_trap_impl_9(1) = y0_9; for n = 1:N_9 t_n = t_grid_9(n); t_np1 = t_grid_9(n+1); y_n = y_trap_impl_9(n); G = @(z) z - y_n - (h_9/2) * (f9(t_n, y_n) + f9(t_np1, z)); y_trap_impl_9(n+1) = fzero(G, y_n); end err_trap_impl_9 = norm(y_trap_impl_9 - y_exact_9); fprintf(' ✓ Метод A-УСТОЙЧИВ. Погрешность: %.2e\n', err_trap_impl_9); %% Метод 6: Неявный RK4 (A-УСТОЙЧИВ!) fprintf('→ Вычисление неявным методом RK4 (Гаусс)...\n'); y_irk4_9 = zeros(1, N_9+1); y_irk4_9(1) = y0_9; for n = 1:N_9 t_n = t_grid_9(n); y_n = y_irk4_9(n); stage_eq = @(K) [ K(1) - f9(t_n + c(1)*h_9, y_n + h_9*(A(1,1)*K(1) + A(1,2)*K(2))); K(2) - f9(t_n + c(2)*h_9, y_n + h_9*(A(2,1)*K(1) + A(2,2)*K(2))) ]; K0 = [f9(t_n, y_n); f9(t_n, y_n)]; K = fsolve(stage_eq, K0, options); y_irk4_9(n+1) = y_n + h_9 * (b(1)*K(1) + b(2)*K(2)); end err_irk4_9 = norm(y_irk4_9 - y_exact_9); fprintf(' ✓ Метод A-УСТОЙЧИВ. Погрешность: %.2e\n\n', err_irk4_9); %% 2.5 Сравнение результатов для жёсткой задачи fprintf('╔════════════════════════════════════════════════════════════╗\n'); fprintf('║ СРАВНЕНИЕ МЕТОДОВ ДЛЯ ЖЁСТКОЙ ЗАДАЧИ (h = %.3f) ║\n', h_9); fprintf('╠════════════════════════════════════════════════════════════╣\n'); fprintf('║ Метод │ Статус │ Погрешность ║\n'); fprintf('╠════════════════════════════════════════════════════════════╣\n'); if isinf(err_euler_9) fprintf('║ Явный Эйлер │ НЕУСТОЙЧИВ │ — ║\n'); else fprintf('║ Явный Эйлер │ Устойчив │ %.2e ║\n', err_euler_9); end if isinf(err_trap_expl_9) fprintf('║ Явная трапеция │ НЕУСТОЙЧИВ │ — ║\n'); else fprintf('║ Явная трапеция │ Устойчив │ %.2e ║\n', err_trap_expl_9); end if isinf(err_rk4_9) fprintf('║ RK4 (явный) │ НЕУСТОЙЧИВ │ — ║\n'); else fprintf('║ RK4 (явный) │ Устойчив │ %.2e ║\n', err_rk4_9); end fprintf('║ Обратный Эйлер │ ✓ УСТОЙЧИВ │ %.2e ║\n', err_beuler_9); fprintf('║ Неявная трапеция │ ✓ A-УСТОЙЧИВ │ %.2e ║\n', err_trap_impl_9); fprintf('║ Неявный RK4 (Гаусс) │ ✓ A-УСТОЙЧИВ │ %.2e ║\n', err_irk4_9); fprintf('╚════════════════════════════════════════════════════════════╝\n\n'); fprintf('КЛЮЧЕВОЕ НАБЛЮДЕНИЕ:\n'); fprintf('Для жёстких задач явные методы становятся НЕУСТОЙЧИВЫМИ,\n'); fprintf('в то время как неявные методы остаются стабильными и дают\n'); fprintf('точное решение даже с относительно большим шагом!\n\n'); %% 2.6 Визуализация решений для жёсткой задачи figure('Position', [100, 100, 1200, 700]); t_plot_9 = linspace(t0_9, t_end_9, 500); y_plot_9 = y_ref_9(t_plot_9); plot(t_plot_9, y_plot_9, 'k-', 'LineWidth', 3, 'DisplayName', 'Эталон (ode15s)'); hold on; % Аналитическое решение plot(t_plot_9, y_analytical(t_plot_9), 'k--', 'LineWidth', 2, ... 'DisplayName', 'Аналитическое'); % Явные методы (если устойчивы) if ~any(isnan(y_euler_9)) && ~isinf(err_euler_9) plot(t_grid_9, y_euler_9, 'b.-', 'LineWidth', 1.5, 'MarkerSize', 8, ... 'DisplayName', 'Эйлер (устойчив)'); end if ~any(isnan(y_trap_expl_9)) && ~isinf(err_trap_expl_9) plot(t_grid_9, y_trap_expl_9, 'c*-', 'LineWidth', 1.5, 'MarkerSize', 6, ... 'DisplayName', 'Явн. трапеция (устойчив)'); end if ~any(isnan(y_rk4_9)) && ~isinf(err_rk4_9) plot(t_grid_9, y_rk4_9, 'rs-', 'LineWidth', 1.5, 'MarkerSize', 6, ... 'DisplayName', 'RK4 (устойчив)'); end % Неявные методы (всегда устойчивы) plot(t_grid_9, y_beuler_9, 'g^-', 'LineWidth', 1.5, 'MarkerSize', 7, ... 'DisplayName', sprintf('Обр. Эйлер (%.1e)', err_beuler_9)); plot(t_grid_9, y_trap_impl_9, 'md-', 'LineWidth', 1.5, 'MarkerSize', 7, ... 'DisplayName', sprintf('Неявн. трапеция (%.1e)', err_trap_impl_9)); plot(t_grid_9, y_irk4_9, 'kx-', 'LineWidth', 1.5, 'MarkerSize', 9, ... 'DisplayName', sprintf('Неявн. RK4 (%.1e)', err_irk4_9)); xlabel('Время t', 'FontSize', 14, 'FontWeight', 'bold'); ylabel('Решение y(t)', 'FontSize', 14, 'FontWeight', 'bold'); title('Часть 2: Жёсткая задача (dy/dt = -2000y + t)', ... 'FontSize', 16, 'FontWeight', 'bold'); legend('Location', 'southeast', 'FontSize', 10); grid on; grid minor; set(gca, 'FontSize', 12, 'LineWidth', 1.5); hold off; %% 2.7 Анализ устойчивости при разных шагах % % Исследуем, как меняется устойчивость методов при различных величинах шага. fprintf('→ Анализ устойчивости для различных шагов...\n\n'); h_values_9 = [0.002, 0.005, 0.01, 0.02, 0.05]; n_h_9 = length(h_values_9); stability_results = zeros(6, n_h_9); for idx = 1:n_h_9 h_temp = h_values_9(idx); N_temp = round((t_end_9 - t0_9) / h_temp); t_temp = linspace(t0_9, t_end_9, N_temp+1); y_exact_temp = y_ref_9(t_temp); % Явный Эйлер try y_temp = zeros(1, N_temp+1); y_temp(1) = y0_9; stable = true; for n = 1:N_temp y_temp(n+1) = y_temp(n) + h_temp * f9(t_temp(n), y_temp(n)); if abs(y_temp(n+1)) > 1e10 stable = false; break; end end stability_results(1,idx) = stable ? norm(y_temp - y_exact_temp) : inf; catch stability_results(1,idx) = inf; end % Явная трапеция try y_temp = zeros(1, N_temp+1); y_temp(1) = y0_9; stable = true; for n = 1:N_temp k1 = f9(t_temp(n), y_temp(n)); k2 = f9(t_temp(n) + h_temp, y_temp(n) + h_temp * k1); y_temp(n+1) = y_temp(n) + (h_temp/2) * (k1 + k2); if abs(y_temp(n+1)) > 1e10 stable = false; break; end end stability_results(2,idx) = stable ? norm(y_temp - y_exact_temp) : inf; catch stability_results(2,idx) = inf; end % RK4 try y_temp = zeros(1, N_temp+1); y_temp(1) = y0_9; stable = true; for n = 1:N_temp k1 = f9(t_temp(n), y_temp(n)); k2 = f9(t_temp(n) + h_temp/2, y_temp(n) + h_temp/2 * k1); k3 = f9(t_temp(n) + h_temp/2, y_temp(n) + h_temp/2 * k2); k4 = f9(t_temp(n) + h_temp, y_temp(n) + h_temp * k3); y_temp(n+1) = y_temp(n) + h_temp/6 * (k1 + 2*k2 + 2*k3 + k4); if abs(y_temp(n+1)) > 1e10 stable = false; break; end end stability_results(3,idx) = stable ? norm(y_temp - y_exact_temp) : inf; catch stability_results(3,idx) = inf; end % Обратный Эйлер (всегда устойчив) y_temp = zeros(1, N_temp+1); y_temp(1) = y0_9; for n = 1:N_temp G = @(z) z - h_temp * f9(t_temp(n+1), z) - y_temp(n); y_temp(n+1) = fzero(G, y_temp(n)); end stability_results(4,idx) = norm(y_temp - y_exact_temp); % Неявная трапеция (A-устойчива) y_temp = zeros(1, N_temp+1); y_temp(1) = y0_9; for n = 1:N_temp G = @(z) z - y_temp(n) - (h_temp/2) * ... (f9(t_temp(n), y_temp(n)) + f9(t_temp(n+1), z)); y_temp(n+1) = fzero(G, y_temp(n)); end stability_results(5,idx) = norm(y_temp - y_exact_temp); % Неявный RK4 (A-устойчив) y_temp = zeros(1, N_temp+1); y_temp(1) = y0_9; for n = 1:N_temp t_n = t_temp(n); y_n = y_temp(n); stage_eq = @(K) [ K(1) - f9(t_n + c(1)*h_temp, y_n + h_temp*(A(1,1)*K(1) + A(1,2)*K(2))); K(2) - f9(t_n + c(2)*h_temp, y_n + h_temp*(A(2,1)*K(1) + A(2,2)*K(2))) ]; K0 = [f9(t_n, y_n); f9(t_n, y_n)]; K = fsolve(stage_eq, K0, options); y_temp(n+1) = y_n + h_temp * (b(1)*K(1) + b(2)*K(2)); end stability_results(6,idx) = norm(y_temp - y_exact_temp); end %% Таблица устойчивости fprintf('┌───────────────────────────────────────────────────────────────────────────────┐\n'); fprintf('│ АНАЛИЗ УСТОЙЧИВОСТИ (ЧАСТЬ 2) │\n'); fprintf('├──────────┬────────────┬────────────┬────────────┬────────────┬───────────────┤\n'); fprintf('│ h │ Эйлер │ Явн.трап. │ RK4 │ Обр.Эйлер │ Неяв.трап. │\n'); fprintf('├──────────┼────────────┼────────────┼────────────┼────────────┼───────────────┤\n'); for i = 1:n_h_9 fprintf('│ %.5f │ ', h_values_9(i)); for m = 1:5 if isinf(stability_results(m,i)) fprintf(' НЕУСТ. │ '); else fprintf(' %.2e │ ', stability_results(m,i)); end end fprintf('\n'); end fprintf('└──────────┴────────────┴────────────┴────────────┴────────────┴───────────────┘\n\n'); fprintf('КРИТЕРИЙ УСТОЙЧИВОСТИ ЭЙЛЕРА:\n'); fprintf('h_max = 2/|λ| = 2/2000 = 0.001\n'); fprintf('Все протестированные шаги h > 0.001 => явные методы неустойчивы!\n\n'); %% График устойчивости figure('Position', [100, 100, 1200, 800]); markers_p2 = {'o', '*', 's', '^', 'd', 'x'}; colors_p2 = {'b', 'c', 'r', 'g', 'm', 'k'}; method_names_p2 = {'Явный Эйлер', 'Явная трапеция', 'RK4', ... 'Обратный Эйлер', 'Неявная трапеция', 'Неявный RK4'}; for m = 1:6 valid_idx = ~isinf(stability_results(m,:)); if any(valid_idx) semilogy(h_values_9(valid_idx), stability_results(m,valid_idx), ... [colors_p2{m} '-' markers_p2{m}], 'LineWidth', 2, 'MarkerSize', 12, ... 'DisplayName', method_names_p2{m}); hold on; end end % Линия критического шага для Эйлера h_crit = 2/lambda; xline(h_crit, 'r--', 'LineWidth', 2, ... 'Label', sprintf('h_{крит} = %.4f', h_crit), ... 'LabelHorizontalAlignment', 'left', 'FontSize', 11); xlabel('Шаг интегрирования h', 'FontSize', 14, 'FontWeight', 'bold'); ylabel('Глобальная погрешность (если устойчив)', 'FontSize', 14, 'FontWeight', 'bold'); title('Часть 2: Анализ устойчивости для жёсткой задачи (λ = -2000)', ... 'FontSize', 16, 'FontWeight', 'bold'); legend('Location', 'southeast', 'FontSize', 11); grid on; grid minor; set(gca, 'FontSize', 12, 'LineWidth', 1.5); hold off; %% ЗАКЛЮЧЕНИЕ И ВЫВОДЫ % %% Сравнительный анализ двух задач fprintf('\n\n'); fprintf('╔══════════════════════════════════════════════════════════════╗\n'); fprintf('║ ЗАКЛЮЧЕНИЕ И ВЫВОДЫ ║\n'); fprintf('╚══════════════════════════════════════════════════════════════╝\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('1. РЕЗУЛЬТАТЫ ДЛЯ НЕЖЁСТКОЙ ЗАДАЧИ (dy/dt = y² - t)\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('✓ Все шесть методов успешно сошлись\n'); fprintf('✓ Наивысшая точность: RK4 и Неявный RK4 (4-й порядок)\n'); fprintf('✓ Порядки сходимости соответствуют теории:\n'); fprintf(' • 1-й порядок: Эйлер, Обратный Эйлер\n'); fprintf(' • 2-й порядок: Явная/Неявная трапеция\n'); fprintf(' • 4-й порядок: RK4, Неявный RK4\n\n'); fprintf('✓ Явные методы более эффективны по вычислительной стоимости:\n'); fprintf(' • Не требуют решения нелинейных уравнений\n'); fprintf(' • Меньше вычислений функции f на шаг\n\n'); fprintf('РЕКОМЕНДАЦИЯ для нежёстких задач:\n'); fprintf('→ Использовать явный RK4 как оптимальный баланс\n'); fprintf(' точности и вычислительной эффективности\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('2. РЕЗУЛЬТАТЫ ДЛЯ ЖЁСТКОЙ ЗАДАЧИ (dy/dt = -2000y + t)\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('✗ ВСЕ явные методы стали НЕУСТОЙЧИВЫМИ:\n'); fprintf(' • Явный Эйлер: требует h < 0.001\n'); fprintf(' • Явная трапеция: также неустойчива\n'); fprintf(' • RK4: неустойчив при h = 0.01\n\n'); fprintf('✓ ВСЕ неявные методы остались УСТОЙЧИВЫМИ:\n'); fprintf(' • Обратный Эйлер: безусловно устойчив\n'); fprintf(' • Неявная трапеция: A-устойчива (2-й порядок)\n'); fprintf(' • Неявный RK4: A-устойчив (4-й порядок)\n\n'); fprintf('✓ Неявные методы позволяют использовать ГОРАЗДО больший шаг:\n'); fprintf(' • h = 0.01 >> h_крит = 0.001 (для Эйлера)\n'); fprintf(' • Экономия вычислений: в 10-100 раз!\n\n'); fprintf('РЕКОМЕНДАЦИЯ для жёстких задач:\n'); fprintf('→ ОБЯЗАТЕЛЬНО использовать неявные методы!\n'); fprintf('→ Неявная трапеция или Неявный RK4 для высокой точности\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('3. КЛЮЧЕВЫЕ ВЫВОДЫ\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('◆ ВЫБОР МЕТОДА зависит от ЖЁСТКОСТИ задачи:\n\n'); fprintf(' НЕЖЁСТКИЕ задачи:\n'); fprintf(' ├─ Используйте ЯВНЫЕ методы (RK4)\n'); fprintf(' ├─ Меньше вычислительная стоимость\n'); fprintf(' └─ Отличная точность при разумном шаге\n\n'); fprintf(' ЖЁСТКИЕ задачи:\n'); fprintf(' ├─ ОБЯЗАТЕЛЬНЫ неявные методы\n'); fprintf(' ├─ Больше затрат на шаг, но гораздо меньше шагов\n'); fprintf(' ├─ Общая эффективность выше!\n'); fprintf(' └─ Избегают неустойчивости\n\n'); fprintf('◆ УСТОЙЧИВОСТЬ важнее точности для жёстких задач:\n'); fprintf(' • Явный RK4 (4-й порядок) БЕСПОЛЕЗЕН если неустойчив\n'); fprintf(' • Обратный Эйлер (1-й порядок) РАБОТАЕТ благодаря устойчивости\n\n'); fprintf('◆ A-УСТОЙЧИВОСТЬ — золотой стандарт:\n'); fprintf(' • Неявная трапеция: 2-й порядок + A-устойчивость\n'); fprintf(' • Неявный RK4 (Гаусс): 4-й порядок + A-устойчивость + симплектичность\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('4. ВЫЧИСЛИТЕЛЬНАЯ СЛОЖНОСТЬ\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('Число вычислений f(t,y) на один шаг:\n'); fprintf('┌─────────────────────────┬──────────────────────────────┐\n'); fprintf('│ Метод │ Вычислений + доп. операции │\n'); fprintf('├─────────────────────────┼──────────────────────────────┤\n'); fprintf('│ Явный Эйлер │ 1 │\n'); fprintf('│ Явная трапеция │ 2 │\n'); fprintf('│ RK4 │ 4 │\n'); fprintf('│ Обратный Эйлер │ 1 + решение уравнения │\n'); fprintf('│ Неявная трапеция │ 2 + решение уравнения │\n'); fprintf('│ Неявный RK4 │ много + решение системы │\n'); fprintf('└─────────────────────────┴──────────────────────────────┘\n\n'); fprintf('ДЛЯ ЖЁСТКИХ ЗАДАЧ:\n'); fprintf('• Явные методы: нужно h ~ 1/|λ| => N ~ |λ|·T шагов\n'); fprintf(' При λ = -2000, T = 1: N ~ 2000 шагов\n\n'); fprintf('• Неявные методы: можно h ~ 0.01 => N ~ 100 шагов\n'); fprintf(' Экономия: в 20 раз меньше шагов!\n\n'); fprintf('ИТОГ: Несмотря на бóльшую стоимость шага, неявные методы\n'); fprintf(' БОЛЕЕ ЭФФЕКТИВНЫ для жёстких задач!\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('5. ПРАКТИЧЕСКИЕ РЕКОМЕНДАЦИИ\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('❶ Как определить жёсткость задачи?\n'); fprintf(' • Наличие быстрых и медленных компонент\n'); fprintf(' • Большие отрицательные собственные числа якобиана\n'); fprintf(' • Отношение |λ_max/λ_min| >> 1 (stiffness ratio)\n'); fprintf(' • Практически: явные методы становятся неустойчивыми\n\n'); fprintf('❷ Стратегия выбора метода:\n'); fprintf(' • Начните с явного RK4\n'); fprintf(' • Если наблюдается неустойчивость => задача жёсткая\n'); fprintf(' • Переключитесь на неявные методы (ode15s в MATLAB)\n\n'); fprintf('❸ Для учебных целей:\n'); fprintf(' • Нежёсткие: RK4 — отличный выбор\n'); fprintf(' • Жёсткие: Неявная трапеция — простая реализация + хорошая устойчивость\n\n'); fprintf('❹ Для производственных расчётов:\n'); fprintf(' • Используйте адаптивные методы (ode45, ode15s)\n'); fprintf(' • Они автоматически подбирают шаг\n'); fprintf(' • Контролируют погрешность\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('6. ТЕОРЕТИЧЕСКОЕ ОБОСНОВАНИЕ\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('ОБЛАСТЬ УСТОЙЧИВОСТИ (для линейного тестового уравнения y'' = λy):\n\n'); fprintf('• Явный Эйлер: |1 + hλ| ≤ 1\n'); fprintf(' Круг радиуса 1 с центром в (-1, 0)\n'); fprintf(' Устойчив только для Re(λ) < 0 и малых h\n\n'); fprintf('• RK4: Больше область, но всё ещё ограничена\n'); fprintf(' Не подходит для жёстких задач\n\n'); fprintf('• Обратный Эйлер: |1/(1 - hλ)| ≤ 1\n'); fprintf(' Вся левая полуплоскость Re(λ) < 0\n'); fprintf(' БЕЗУСЛОВНО УСТОЙЧИВ!\n\n'); fprintf('• Неявная трапеция: |(1 + hλ/2)/(1 - hλ/2)| ≤ 1\n'); fprintf(' Вся левая полуплоскость Re(λ) < 0\n'); fprintf(' A-УСТОЙЧИВА + 2-й порядок точности!\n\n'); fprintf('• Неявный RK4 (Гаусс): A-устойчив + симплектичен\n'); fprintf(' Идеален для гамильтоновых систем\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf('7. СРАВНЕНИЕ С АНАЛИТИЧЕСКИМ РЕШЕНИЕМ\n'); fprintf('═══════════════════════════════════════════════════════════════\n\n'); fprintf('Для жёсткой задачи dy/dt = -2000y + t, y(0) = 0:\n\n'); fprintf('Аналитическое решение:\n'); fprintf(' y(t) = (t - 1/2000)/2000 + (1/2000²)·exp(-2000t)\n\n'); fprintf('Компоненты решения:\n'); fprintf(' ① Стационарная часть: (t - 1/2000)/2000 ≈ 0.0005t\n'); fprintf(' ② Переходная часть: 2.5×10⁻⁷·exp(-2000t)\n\n'); fprintf('Переходная часть затухает экспоненциально:\n'); fprintf(' • При t = 0.005: exp(-10) ≈ 4.5×10⁻⁵\n'); fprintf(' • При t = 0.01: exp(-20) ≈ 2×10⁻⁹\n'); fprintf(' • Практически исчезает за t ~ 0.01\n\n'); fprintf('Эта БЫСТРАЯ динамика и создаёт жёсткость!\n'); fprintf('Явные методы пытаются "отследить" быстрое затухание,\n'); fprintf('требуя крошечного шага. Неявные методы "понимают"\n'); fprintf('экспоненциальный характер и остаются устойчивыми.\n\n'); fprintf('═══════════════════════════════════════════════════════════════\n'); fprintf(' КОНЕЦ АНАЛИЗА \n'); fprintf('═══════════════════════════════════════════════════════════════\n'); %% Финальная визуализация: сравнение обеих задач figure('Position', [100, 100, 1400, 600]); % Левая панель: нежёсткая задача subplot(1,2,1); t_plot_4_fine = linspace(t0_4, t_end_4, 500); plot(t_plot_4_fine, y_ref_4(t_plot_4_fine), 'k-', 'LineWidth', 2.5); hold on; plot(t_grid_4, y_euler_4, 'b.-', 'MarkerSize', 8); plot(t_grid_4, y_rk4_4, 'r.-', 'MarkerSize', 8); plot(t_grid_4, y_trap_impl_4, 'm.-', 'MarkerSize', 8); xlabel('t', 'FontSize', 12, 'FontWeight', 'bold'); ylabel('y(t)', 'FontSize', 12, 'FontWeight', 'bold'); title('Нежёсткая: dy/dt = y² - t', 'FontSize', 14, 'FontWeight', 'bold'); legend('Эталон', 'Эйлер', 'RK4', 'Неявн. трап.', 'Location', 'best'); grid on; hold off; % Правая панель: жёсткая задача subplot(1,2,2); t_plot_9_fine = linspace(t0_9, t_end_9, 500); plot(t_plot_9_fine, y_ref_9(t_plot_9_fine), 'k-', 'LineWidth', 2.5); hold on; plot(t_grid_9, y_beuler_9, 'g.-', 'MarkerSize', 7); plot(t_grid_9, y_trap_impl_9, 'm.-', 'MarkerSize', 7); plot(t_grid_9, y_irk4_9, 'k.-', 'MarkerSize', 7); xlabel('t', 'FontSize', 12, 'FontWeight', 'bold'); ylabel('y(t)', 'FontSize', 12, 'FontWeight', 'bold'); title('Жёсткая: dy/dt = -2000y + t', 'FontSize', 14, 'FontWeight', 'bold'); legend('Эталон', 'Обр. Эйлер', 'Неявн. трап.', 'Неявн. RK4', 'Location', 'best'); grid on; hold off; sgtitle('Итоговое сравнение: нежёсткая vs жёсткая задача', ... 'FontSize', 16, 'FontWeight', 'bold'); %% Дополнительная визуализация: области устойчивости figure('Position', [100, 100, 1200, 500]); % График слева: быстрое затухание в жёсткой задаче subplot(1,2,1); t_transient = linspace(0, 0.02, 200); y_transient = y_analytical(t_transient); y_steady = (t_transient - 1/lambda)/lambda; plot(t_transient, y_transient, 'k-', 'LineWidth', 2, 'DisplayName', 'Полное решение'); hold on; plot(t_transient, y_steady, 'b--', 'LineWidth', 2, 'DisplayName', 'Стационарная часть'); plot(t_transient, y_transient - y_steady, 'r:', 'LineWidth', 2, ... 'DisplayName', 'Переходная часть (exp(-2000t))'); xlabel('Время t', 'FontSize', 12, 'FontWeight', 'bold'); ylabel('y(t)', 'FontSize', 12, 'FontWeight', 'bold'); title('Декомпозиция решения жёсткой задачи', 'FontSize', 14, 'FontWeight', 'bold'); legend('Location', 'best', 'FontSize', 10); grid on; xlim([0, 0.02]); hold off; % График справа: сравнение погрешностей subplot(1,2,2); methods_summary = {'Эйлер', 'Явн.трап', 'RK4', 'Обр.Эйл', 'Неяв.трап', 'Неяв.RK4'}; errors_p1_current = [err_euler_4, err_trap_expl_4, err_rk4_4, ... err_beuler_4, err_trap_impl_4, err_irk4_4]; bar(1:6, log10(errors_p1_current)); set(gca, 'XTickLabel', methods_summary, 'FontSize', 10); xtickangle(45); ylabel('log₁₀(Погрешность)', 'FontSize', 12, 'FontWeight', 'bold'); title('Сравнение погрешностей (нежёсткая задача)', 'FontSize', 14, 'FontWeight', 'bold'); grid on; ylim([-8, 0]); sgtitle('Детальный анализ', 'FontSize', 16, 'FontWeight', 'bold'); fprintf('\n✓ Все графики построены!\n'); fprintf('✓ Анализ завершён успешно!\n\n');