JuliaControl / JuliaControl/ModelPredictiveControl.jl

Support online parameter estimation with an API (a.k.a. adaptive state estimation)

Open
#432 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Julia
Stars
135
Forks
9
Avg merge
17h 35m
Merged PRs (30d)
16

Description

Supporting adaptive state estimation is quite straightforward on any state estimator that works with NonLinModel: you just augment the state vector with the estimated parameters $p_1$, $p_2$, etc. and augment the $\mathbf{f}$ equation with a time-invariant assumption $dp_1/dt = 0$, $dp_2/dt = 0$, etc.

Because of this, I first thought that adding an explicit API that would do this automatically is a very low priority feature. But, while writing this simple example of online parameter estimation with the MHE on the inverted pendulum:

using ModelPredictiveControl, Plots, JuMP
theme(:dark); default(fontfamily="Computer Modern"); scalefontsizes(1.1)
function f!(ẋ, x, u, _ , p)
    g, L, m = p                 # [m/s²], [m], [kg]
    θ, ω, K = x[1], x[2], x[3]  # [rad], [rad/s], [kg/s]
    τ  = u[1]                   # [Nm]
    ẋ[1] = ω
    ẋ[2] = -g/L*sin(θ) - K/m*ω + τ/m/L^2
    ẋ[3] = 0                    # dK/dt = 0 (the estimated parameter)
end
h!(y, x, _ , _ ) = (y[1] = 180/π*x[1]; nothing) # [°]
p = [9.8, 0.4, 0.3]
nu, nx, ny, Ts = 1, 3, 1, 0.1
vu, vx, vy = ["\$τ\$ (Nm)"], ["\$θ\$ (rad)", "\$ω\$ (rad/s)", "\$K\$ (kg/s)"], ["\$θ\$ (°)"]
model = setname!(NonLinModel(f!, h!, Ts, nu, nx, ny; p=p); u=vu, x=vx, y=vy)
σQ=[0.1, 1.0, 1.0]; σR=[5.0]; nint_ym=0; nint_u=0; 
transcription = OrthogonalCollocation(); hessian = true;
mhe = MovingHorizonEstimator(model; σQ, σR, nint_ym, nint_u, He=10, transcription, hessian)
setconstraint!(mhe, x̂min=[-Inf, -Inf, 1.0], x̂max=[+Inf, +Inf, 2.0], v̂min=[-2.5], v̂max=[2.5])
mhe |> display
N = 30; u = [1.10];
unset_time_limit_sec(mhe.optim)
res = sim!(mhe, N, u, x_0=[0, 0, 1.5], x̂_0=[0, 0, 1.2], y_noise=[0.5])
T = @elapsed sim!(mhe, N, u, x_0=[0, 0, 1.5], x̂_0=[0, 0, 1.2], y_noise=[0.5])
println("Sampling time: $Ts s, Average compute time: $(T/N) s")
plot(res, plotu=false, plotxwithx̂=true) |> display

I noticed that the states associated to the estimated parameter are in fact LTI models (the 0 in the RHS, that is, an integrator). It means that we could specialized the equality constraint as linear one on these states, for non-SingleShooting transcription. This is very similar to what is already done with the generic integrating states from nint_ym and nint_u options. The goal is to reduces the dimensions of the Jacobian thus more efficient AD. So this feature is more interesting to implement than I initially thought.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing how NonLinModel states and MovingHorizonEstimator build equality constraints for OrthogonalCollocation, then compare the existing nint_ym and nint_u handling. Check how SingleShooting is excluded and identify where an API for parameter states would fit. Done means parameter estimation can be configured explicitly and non-SingleShooting Jacobian dimensions are reduced without changing the illustrated behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
julia
Domain
backend-api-design, performance
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.