State Feedback: Double Intergrator with Unknown Sign

This recreates the controller from A. Rantzer, “Minimax adaptive control for a finite set of linear systems,” in Proc. 3th Annu. Learning Dyn. Control Conf., vol. 144, Jun. 07 – 08 2021, pp. 893–904. See the arXiv version.

We consider a discrete-time double integrator with unknown input direction

\[ \begin{aligned} x_{t+1} & = \begin{bmatrix} 2 & -1 & -1 \\ 1 & 0 & 0 \\ 0 & 0 & 0 \end{bmatrix} + x_t \pm \begin{bmatrix} 0 \\ 0 \\ 1 \end{bmatrix} u_t + I w_t \end{aligned}\]

Preamble

We load the packages

using MinimaxAdaptiveControl 
using LinearAlgebra
using JuMP
using Plots
using Clarabel # Open source SDP solver

We use Clarabel here, but any JuMP compatible SDP solver will do.

Switch this out with whatever optimizer you are using

optimizer_factory = () -> Clarabel.Optimizer

System definition

We define the system matrices, and the cost function

\[ \sum_{t = 0}^\infty \left( |x_t|^2_Q + |u_t|^2_R - \gamma^2 |w_t|^2 \right),\]

where $Q = I$ and $R = I$.

A0 = [
    2.0 -1.0 1.0;
    1.0 0.0 0.0;
    0.0 0.0 0.0
   ]
B0 = [0.0; 0.0; 1.0;;]
Q = Matrix(1.0I, 3, 3)
R = Matrix(1.0I, 1, 1)
γ = 19.0
sys1 = SSLinMod(A0, B0, Q, R)
sys2 = SSLinMod(A0, -B0, Q, R)
sys = [sys1, sys2]

Reduction to principal problem

We reduce the uncertain system sys to principal model form using reduceSys

models = [Model(optimizer_factory()), Model(optimizer_factory())]
(A, B, G, Ks, Hs) = reduceSys(sys, γ, models)

Here we get the matrices

\[A = 0, \quad B = 0, \quad G = I\]

The feedback gains are

\[\begin{aligned} K_1 & = \begin{bmatrix} 1.8 & -1.3 & 1.3 \end{bmatrix} \\ K_2& = \begin{bmatrix} -1.8 & 1.3 & -1.3 \end{bmatrix} \end{aligned}\]

The cost matrices become

\[H_1 = \begin{bmatrix} -1804.0 & 722.0 & -722.0 & 0.0 & 722.0 & 361.0 & 0.0\\ 722.0 & -360.0 & 361.0 & 0.0 & -361.0 & 0.0 & 0.0\\ -722.0 & 361.0 & -360.0 & 0.0 & 361.0 & 0.0 & 0.0\\ 0.0 & 0.0 & 0.0 & -360.0 & 0.0 & 0.0 & 361.0\\ 722.0 & -361.0 & 361.0 & 0.0 & -361.0 & 0.0 & 0.0\\ 361.0 & 0.0 & 0.0 & 0.0 & 0.0 & -361.0 & 0.0\\ 0.0 & 0.0 & 0.0 & 361.0 & 0.0 & 0.0 & -361.0 \end{bmatrix}\]

and

\[H_2 = \begin{bmatrix} -1804.0 & 722.0 & -722.0 & 0.0 & 722.0 & 361.0 & 0.0\\ 722.0 & -360.0 & 361.0 & 0.0 & -361.0 & 0.0 & 0.0\\ -722.0 & 361.0 & -360.0 & 0.0 & 361.0 & 0.0 & 0.0\\ 0.0 & 0.0 & 0.0 & -360.0 & 0.0 & 0.0 & -361.0\\ 722.0 & -361.0 & 361.0 & 0.0 & -361.0 & 0.0 & 0.0\\ 361.0 & 0.0 & 0.0 & 0.0 & 0.0 & -361.0 & 0.0\\ 0.0 & 0.0 & 0.0 & -361.0 & 0.0 & 0.0 & -361.0 \end{bmatrix}\]

They differ only in the elemets on the (4, 7)th and (7, 4)th elements.

Controller synthesis

We first ensure that the associated performance level and feedback gains solves the Bellman inequalities using MACLMIs

model = Model(optimizer_factory())
period = 1
Ps0, Psplus= MACLMIs(A, B, G, Ks, Hs, period, model)

and verify the termination status of the optimization routine

julia>
termination_status(model)
OPTIMAL::TerminationStatusCode = 1

Next we construct the selection rule and controller objects using getPeriodicSelectionRule and MAController:

selectionRule = getPeriodicSelectionRule(period)
N = length(Hs)
mac = MAController(zeros(3), A, B, G, Ks, Hs, zeros(N), selectionRule)

Simulation

We first set up the matrices holding the states, outputs, control signal and disturbances

Tdur = 2000
states = zeros(Tdur + 1, 3)
outputs = zeros(Tdur + 1, 3)
controls = zeros(Tdur, 1)
processDisturbances = randn(Tdur, 3)
measurementDisturbances = zeros(Tdur, 3)

We also want to track the time-evolution of the value-function and the empirical $\ell_2$-gain using getValueFunction and InducedlpGain

vfun = getValueFunction(mac, Ps0, N)
dc= InducedlpGain(0.0, 0.0, 0.0, 2)
metrics = [vfun, dc]
metricResults = zeros(Tdur + 1, length(metrics))

Next we construct the SSPlant for data generation and simulate!

plant = SSPlant(A0, -B0, zeros(3))
simulate!(states, outputs, controls, processDisturbances, measurementDisturbances, metricResults, metrics, plant, mac, Tdur)

and plot the results

plot(
     [states[1:Tdur, 1] controls[1:Tdur] metricResults[1:Tdur, :]], layout = (2, 2),
     xlabel = "Timestep",
     ylabel = ["State 1" "Control" "Value Function" "Induced Lp Gain"],
     legend = false,
     linewidth = 2
    )

image