Загрузка данных


% Решение задачи оптимального управления (Вариант 14)
% Метод множителей Лагранжа, сведение к краевой задаче (BVP) с неизвестным временем tf

function solve_optimal_control_v14()
    % Начальное приближение для неизвестного времени tf
    T_guess = 3; 
    
    % Создаем сетку для нормализованного времени tau от 0 до 1
    tau = linspace(0, 1, 100);
    
    % Задаем структуру начального приближения для bvp4c
    solinit = bvpinit(tau, @guess_func, T_guess);

    % Настройки решателя (задаем допуски и увеличиваем макс. число итераций)
    options = bvpset('RelTol', 1e-4, 'AbsTol', 1e-6, 'NMax', 5000);

    disp('Идет поиск оптимального решения...');
    try
        % Решение краевой задачи
        sol = bvp4c(@ode_system, @boundary_conditions, solinit, options);
        
        % Извлечение результатов
        T_opt = sol.parameters; % Найденное оптимальное время tf
        t = 1 + sol.x * (T_opt - 1); % Возврат к реальному времени t (t0 = 1)
        
        x1 = sol.y(1, :);
        x2 = sol.y(2, :);
        psi1 = sol.y(3, :);
        psi2 = sol.y(4, :);
        
        % Расчет оптимального управления по найденным траекториям
        u = zeros(size(t));
        for i = 1:length(t)
            u(i) = (psi2(i) - 2*psi1(i)) / (0.4 * x2(i)^2 + 1e-6);
        end
        
        fprintf('Решение успешно найдено!\n');
        fprintf('Оптимальное конечное время tf = %.4f сек\n', T_opt);
        
        % Построение графиков
        figure('Name', 'Оптимальное управление: Вариант 14', 'Color', 'w');
        
        % 1. Фазовые траектории
        subplot(3,1,1);
        plot(t, x1, 'b-', t, x2, 'r-', 'LineWidth', 1.5);
        title(sprintf('Фазовые траектории (Оптимальное время t_f = %.3f)', T_opt));
        xlabel('Время t'); ylabel('x(t)');
        legend('x_1(t)', 'x_2(t)', 'Location', 'best');
        grid on;
        
        % 2. Сопряженные переменные
        subplot(3,1,2);
        plot(t, psi1, 'b--', t, psi2, 'r--', 'LineWidth', 1.5);
        title('Сопряженные переменные \psi(t)');
        xlabel('Время t'); ylabel('\psi(t)');
        legend('\psi_1(t)', '\psi_2(t)', 'Location', 'best');
        grid on;
        
        % 3. Оптимальное управление
        subplot(3,1,3);
        plot(t, u, 'g', 'LineWidth', 1.5);
        title('Оптимальное управление u(t)');
        xlabel('Время t'); ylabel('u(t)');
        grid on;
        
    catch ME
        disp('Ошибка при решении:');
        disp(ME.message);
        disp('Попробуйте изменить начальное приближение (T_guess или guess_func).');
    end
end

% -----------------------------------------------------------------------
% 1. Система дифференциальных уравнений
% -----------------------------------------------------------------------
function dydtau = ode_system(~, y, T)
    % Переменные состояния и сопряженные переменные
    x1 = y(1); x2 = y(2);
    psi1 = y(3); psi2 = y(4);
    
    % Уравнение управления (с добавлением 1e-6 от деления на 0)
    u = (psi2 - 2*psi1) / (0.4 * x2^2 + 1e-6);
    
    % Производные по реальному времени t
    dx1_dt = -17*x1 - 50*x2 - 2*u;
    dx2_dt = 3*x1 + 8*x2 + u;
    dpsi1_dt = 0.6*x1 + 17*psi1 - 3*psi2;
    dpsi2_dt = 0.4*x2*u^2 + 50*psi1 - 8*psi2;
    
    % Масштабный множитель перехода к нормализованному времени tau:
    % dt = (T - t0) * dtau
    t0 = 1; 
    dt_dtau = T - t0;
    
    % Возвращаем вектор производных по tau
    dydtau = dt_dtau * [dx1_dt; dx2_dt; dpsi1_dt; dpsi2_dt];
end

% -----------------------------------------------------------------------
% 2. Краевые условия и условия трансверсальности
% -----------------------------------------------------------------------
function res = boundary_conditions(ya, yb, T)
    % ya - вектор значений на левом конце (t = 1)
    % yb - вектор значений на правом конце (t = tf)
    
    % На левом конце (t = 1)
    x1_0 = ya(1);
    psi2_0 = ya(4);
    
    % На правом конце (t = tf)
    x1_f = yb(1);
    x2_f = yb(2);
    psi1_f = yb(3);
    psi2_f = yb(4);
    
    % Гамильтониан на правом конце должен быть равен 0
    u_f = (psi2_f - 2*psi1_f) / (0.4 * x2_f^2 + 1e-6);
    H_f = -(0.3*x1_f^2 + 0.2*x2_f^2*u_f^2) + psi1_f*(-17*x1_f - 50*x2_f - 2*u_f) + psi2_f*(3*x1_f + 8*x2_f + u_f);
    
    % Формируем вектор невязок (все они должны быть сведены решателем к 0)
    res = [
        x1_0 - 0;      % 1: x1(1) = 0
        psi2_0 - 0;    % 2: psi2(1) = 0 (условие трансверсальности, т.к. x2(1) свободно)
        x1_f - 1;      % 3: x1(tf) = 1
        x2_f - 1;      % 4: x2(tf) = 1
        H_f            % 5: H(tf) = 0 (условие трансверсальности, т.к. tf свободно)
    ];
end

% -----------------------------------------------------------------------
% 3. Функция начального приближения траекторий
% -----------------------------------------------------------------------
function y_guess = guess_func(tau)
    % tau меняется от 0 до 1.
    % Формируем простейшую линейную интерполяцию от заданных начальных
    % до заданных конечных точек, чтобы помочь решателю сходиться быстрее.
    x1 = tau;           % от 0 до 1
    x2 = 0.5 + 0.5*tau; % от 0.5 до 1 (чтобы x2 не был нулем в начале)
    psi1 = 0;           % костаты начинаем с 0
    psi2 = 0;
    
    y_guess = [x1; x2; psi1; psi2];
end