quinta-feira, 22 de maio de 2025

Métodos pseudo-espectral (parte 3)

Untitled
Dando continuidade ao método pseudo-espectral (discutido em detalhes aqui e aqui). A formulação do problema de controle ótimo anteriormente proposto, pode ser reescrita como um problema de programação não-linear, da seguinte forma:
01.jpg
sujeito a:
02.jpg
Neste problema, o vetor de decisão y, com dimensão , composto pelos seguintes elementos:
03.jpg
sendo e vetor-coluna formados através do empilhamento vertical das colunas de e , respectivamente. A função de custo F pode ser reescrita por meio de:
g223.png
e a função de restrições G, com , dada por:
06.png
Os limites inferiores e superiores ( e , respectivamente) para são dados por:
07.png
em que denota um vetor-coluna de n zeros e representa um vetor-coluna formado pelo empilhamento de n cópidas do vetor-coluna x . Os limites inferiores e superiores ( e , respectivamente) para o vetor de decisão y são dados por:
08.png
Pode ter ficado confuso, mas nas secões a seguir a gente fará alguns exemplos numéricos com exemplos comumente apresentados no formato de um problema de controle ótimo e vamos solucioná-los.
Exemplo 1
Deseja-se encontrar um controle , de modo a minimizar o funcional de custo:
01.png
sujeito a:
02.png
em que e , sendo uma matriz positivo-semidefinida e uma matriz positivo-definida. O valor inicial dos estados é . Reescrevendo o problema como um problema de programação não linear resultante da discretização pseudo-espectral com nós, o vetor de decisão corresponde a:
03.png
Isso se dá porque não há parâmetro adicional, o tempo inicial e final são fixados (o valor de será especificado a seguir). Não há limites de excursão para os estados e controles (são variáveis livres). E por outro lado, a função de restrições é dada por:
0.png
com os limites inferiores e superiores dados por:
05.png
Isso decorre pelo fato de que não há restrições de trajetória () para os estados e controle, e há restrição inicial para o estado no instante inicial (). Suponha que as matrizes do sistema dado () , o estado inicial e o tempo final sejam dados por:
06.png
Vamos resolver por meio de código em Matlab. Para os dados propostos, tem-se que:
clear all; close all; clc;
 
% Matrizes do problema
A = [0 1;
0 0];
B = [0;
1];
Q = eye(2);
R = 10;
t0 = 0;
tf = 10;
Definição da quantidade de nós N para a discretização pseudo-espectral:
N = 39;
Parâmetros derivados a serem utilizados na formulação da otimização pseudo-espectral (já foram definidos anteriormente em aqui e aqui):
% Parâmetros derivados a partir de 'N'
nos = tau(N);
D = matriz_D(N, nos);
wk = pesos_wk(N, nos);
Para a execução do restante do código, é fundamental que sejam definidas as seguintes funções de custo:
function J = funcao_custo(y, Q, R, N, peso, t0, tf)
%%% Alocação inicial de memória.
persistent u x1 x2 X
 
%%% Criação das dimensões dos vetores (uma única vez)
if isempty(u) || length(u) ~= (N+1)
u = zeros(1, N+1);
x1 = zeros(1, N+1);
x2 = zeros(1, N+1);
X = zeros(2, N+1);
end
 
%%% Separa as variáveis para uso (mantendo área alocada)
u(:) = y(1, 0*(N+1) + 1 : 1*(N+1)); % Controle u
x1(:) = y(1, 1*(N+1) + 1 : 2*(N+1)); % Estado x1
x2(:) = y(1, 2*(N+1) + 1 : 3*(N+1)); % Estado x2
 
% Vetor X atualizado
X(1,:) = x1;
X(2,:) = x2;
 
%%% Função de custo
integral = 0;
for k = 1:(N+1)
Lk = X(:,k)' * Q * X(:,k) + u(k)' * R * u(k);
 
integral = integral + Lk * peso(k);
end
 
J = ((tf-t0)/2) * integral;
end
e a função de constraints (restrições):
function [c, ceq] = constraints(y, N, D, A, B)
%%% Para alocação de memória
persistent u x1 x2 X FN chiN
 
if isempty(u) || length(u) ~= (N+1)
u = zeros(1, N+1);
x1 = zeros(1, N+1);
x2 = zeros(1, N+1);
X = zeros(2, N+1);
FN = zeros(2, N+1);
chiN = zeros(2, N+1);
end
 
%%% Separa as variáveis para uso (mantendo área alocada)
u(:) = y(1, 0*(N+1) + 1 : 1*(N+1)); % Controle u
x1(:) = y(1, 1*(N+1) + 1 : 2*(N+1)); % Estado x1
x2(:) = y(1, 2*(N+1) + 1 : 3*(N+1)); % Estado x2
X = [x1; x2];
 
% Cálculo do FN
FN = matriz_FN(y, N, A, B);
 
% Determinação do vetor chi^(N)
chiN = X * D' - FN;
% Restrições de desigualdade
rest_0 = [x1(1); x2(1)] - [1; 1];
 
c = [ chiN(:);
-chiN(:);
rest_0(:);
-rest_0(:);];
% Restrições de igualdade
ceq = [];
 
end
Dentro dessas funções de constraints, é chamada a função matriz_FN, que é dada por:
function FN = matriz_FN(y, N, A, B)
%%% Alocação de memória
persistent u x1 x2 X X_dot
 
if isempty(u) || length(u) ~= (N+1)
u = zeros(1, N+1);
x1 = zeros(1, N+1);
x2 = zeros(1, N+1);
X = zeros(2, N+1);
X_dot = zeros(2, N+1);
end
 
%%% Separa as variáveis para uso (mantendo área alocada)
u(:) = y(1, 0*(N+1) + 1 : 1*(N+1)); % Controle u
x1(:) = y(1, 1*(N+1) + 1 : 2*(N+1)); % Estado x1
x2(:) = y(1, 2*(N+1) + 1 : 3*(N+1)); % Estado x2
 
X(1,:) = x1;
X(2,:) = x2;
 
% Tempo inicia e final
t0 = 0;
tf = 10;
 
%%% Inicialização dos parâmetros a se resolverem.
X_dot = zeros(2, N+1);
for k = 1:(N+1)
X_dot(:,k) = A * X(:,k) + B * u(k);
end
 
FN = ((tf-t0)/2) * X_dot;
end
De posse dessas funções, a gente consegue configurar o restante do código para emprego da função fmincon, do Matlab:
% Instância da função de custo
Fy = @(y)funcao_custo(y, Q, R, N, wk, t0, tf);
 
% Instância de restrições
nonlcon = @(y)constraints(y, N, D, A, B);
 
% Demais parâmetros para a função fmincon
Aa = []; % Não há restrição do tipo 'Aa.x <= bb';
bb = []; % Não há restrição do tipo 'Aa.x <= bb';
Aeq = []; % Não há restrição do tipo 'A.x = b';
beq = []; % Não há restrição do tipo 'A.x = b';
lb = []; % Não há, inicialmente, restrições do tipo 'lb <= x'; e
lu = []; % Não há, inicialmente, restrições do tipo 'x <= ub'.
 
% Opções do otimizador
options = optimoptions('fmincon', ...
'Display', 'iter', ...
'Algorithm','SQP', ...
'MaxFunEvals', 5000, ...
'TolX', 1e-6);
 
% Chute inicial para as variáveis do otimizador.
u = zeros(1, N+1);
x1 = zeros(1, N+1);
x2 = zeros(1, N+1);
y0 = [u, x1, x2];
 
% Roda o otimizador.
solution = fmincon(Fy, y0, Aa, bb, Aeq, beq, lb, lu, nonlcon, options);
Iter Func-count Fval Feasibility Step Length Norm of First-order step optimality 0 121 0.000000e+00 1.000e+00 1.000e+00 0.000e+00 5.922e-08 1 243 1.082734e+01 3.000e-01 7.000e-01 4.238e+00 2.502e+00 2 365 1.547283e+01 9.000e-02 7.000e-01 2.429e+00 2.000e+00 3 488 1.627929e+01 4.590e-02 4.900e-01 8.652e-01 7.847e-01 4 610 1.732777e+01 1.377e-02 7.000e-01 7.005e-01 5.967e-01 5 732 1.753941e+01 4.131e-03 7.000e-01 3.660e-01 3.660e-01 6 855 1.755446e+01 2.107e-03 4.900e-01 2.609e-01 2.298e-01 7 978 1.757484e+01 1.074e-03 4.900e-01 1.518e-01 1.615e-01 8 1100 1.759285e+01 3.223e-04 7.000e-01 1.470e-01 1.038e-01 9 1222 1.759382e+01 9.670e-05 7.000e-01 1.525e-01 1.284e-01 10 1344 1.759060e+01 2.901e-05 7.000e-01 1.316e-01 1.246e-01 11 1466 1.758441e+01 8.703e-06 7.000e-01 1.197e-01 7.028e-02 12 1588 1.758220e+01 2.611e-06 7.000e-01 1.191e-01 9.027e-02 13 1710 1.757834e+01 7.833e-07 7.000e-01 9.368e-02 6.893e-02 14 1832 1.757675e+01 2.350e-07 7.000e-01 9.847e-02 6.817e-02 15 1954 1.757500e+01 7.050e-08 7.000e-01 6.562e-02 5.328e-02 16 2076 1.757366e+01 2.115e-08 7.000e-01 5.783e-02 3.731e-02 17 2198 1.757348e+01 1.135e-08 7.000e-01 4.598e-02 4.766e-02 18 2320 1.757260e+01 3.987e-09 7.000e-01 3.494e-02 3.359e-02 19 2443 1.757226e+01 2.964e-09 4.900e-01 2.595e-02 1.900e-02 20 2565 1.757209e+01 1.573e-09 7.000e-01 2.107e-02 2.176e-02 21 2687 1.757201e+01 1.837e-09 7.000e-01 1.645e-02 1.404e-02 22 2809 1.757194e+01 2.630e-09 7.000e-01 1.440e-02 1.316e-02 23 2931 1.757189e+01 1.456e-09 7.000e-01 1.015e-02 1.208e-02 24 3054 1.757185e+01 5.118e-10 4.900e-01 7.443e-03 5.515e-03 25 3176 1.757184e+01 2.874e-10 7.000e-01 5.849e-03 6.863e-03 26 3299 1.757183e+01 4.589e-10 4.900e-01 4.178e-03 4.257e-03 27 3421 1.757182e+01 5.074e-10 7.000e-01 3.605e-03 2.515e-03 28 3542 1.757182e+01 5.333e-10 1.000e+00 4.144e-03 2.617e-03 29 3663 1.757182e+01 2.943e-10 1.000e+00 2.999e-03 2.914e-03 Iter Func-count Fval Feasibility Step Length Norm of First-order step optimality 30 3786 1.757182e+01 2.353e-10 4.900e-01 2.026e-03 1.798e-03 31 3908 1.757182e+01 2.227e-10 7.000e-01 1.604e-03 1.685e-03 32 4030 1.757181e+01 3.240e-10 7.000e-01 1.623e-03 1.489e-03 33 4151 1.757181e+01 5.876e-11 1.000e+00 1.451e-03 1.276e-03 34 4273 1.757181e+01 4.567e-11 7.000e-01 1.080e-03 1.019e-03 35 4396 1.757181e+01 1.984e-11 4.900e-01 6.960e-04 8.906e-04 36 4518 1.757181e+01 6.183e-11 7.000e-01 7.091e-04 6.417e-04 37 4639 1.757181e+01 4.204e-11 1.000e+00 7.222e-04 9.197e-04 38 4761 1.757181e+01 8.962e-11 7.000e-01 4.867e-04 3.933e-04 39 4883 1.757181e+01 1.083e-10 7.000e-01 4.688e-04 2.862e-04 40 5005 1.757181e+01 1.103e-11 7.000e-01 2.855e-04 2.434e-04 Solver stopped prematurely. fmincon stopped because it exceeded the function evaluation limit, options.MaxFunctionEvaluations = 5.000000e+03.
Depois da resolução do problema, a gente consegue plotar o resultado por meio dos seguintes códigos:
% Extrai os valores do sistema
t_original = ((tf - t0) / 2) * nos + ((tf + t0) / 2);
u(:) = solution(1, 0*(N+1) + 1 : 1*(N+1)); % Controle u
x1(:) = solution(1, 1*(N+1) + 1 : 2*(N+1)); % Estado x1
x2(:) = solution(1, 2*(N+1) + 1 : 3*(N+1)); % Estado x2
 
% Plota os resultados das variáveis de estados.
subplot(2,1,1);
plot(t_original, x1); hold on;
plot(t_original, x2, 'r');
ylim([-0.5 2]);
grid;
xlabel("t");
legend('x_1(t)', 'x_2(t)');
 
% Variáveis de controle.
subplot(2,1,2);
plot(t_original, u);
grid;
ylim([-1.5 0.5]);
xlabel("t");
ylabel("u(t)");