Adaptive control and online parameter estimation

Since control systems modeling questions tend to pop up on here quite a bit, I figured I’d share the approach I’ve been taking for these kinds of things using ControlSystems.jl to build linear components for nonlinear DifferentialEquations.jl simulations and ComponentArrays.jl to glue it all together. I made an example of model reference adaptive control which I think is a good one to show off this approach for a few reasons:

  1. Adaptive control is inherently nonlinear. For purely linear problems, it makes most sense to work direcly in ControlSystems.jl. This will show how you can build up linear components from transfer functions and pretty easily use them in a nonlinear model.
  2. Its just complex enough to show the type of workflow you would need for larger models (which can have hundreds of deeply nested components).
  3. It requires us to swap out components that don’t have the same number of internal state variables. For typical flat vector systems of equations, this type of thing is a bit of a headache to deal with because you have to make sure you update the view indices for the whole array. This usually turns into a mess of view(u, num_previous_states+1 : num_previous_states+num_this_component_states) and can be pretty error-prone.
  4. It shows online parameter estimation, which is just fun. While we aren’t learning the model parameters directly (i.e. direct adaptive control), we are learning the control parameters needed to drive the model tracking error to zero. Direct parameter estimation uses the same technique though.
  5. It shows Rohr’s example of parameter drift leading to instability due to insufficient excitation conditions, which is a pretty important topic if you want to implement this kind of thing.

So why not just use modeling language? Don’t get me wrong, modeling languages are great and I still use them often, but it’s nice knowing that I have the freedom to do whatever I want without having to wait for someone to add a feature. If I want to put a empirically learned model in my simulation as a subcomponent, I can do that pretty easily.

But anyway, here is the example. If you catch any mistakes, please point them out.

6 Likes

Awesome! Looks like a great direction.

dx .= A*x + BB*u you might want to do a 5-arg mul! here. Dθ .= -γ*e*w could be @. Dθ = -γ*e*w.

You can also just @register in ModelingToolkit, but I think those are two separate issues. We might want to make ModelingToolkit build a model in ComponentArrays form.

1 Like

Oh nice, I didn’t even realize that was a thing.

Yeah, that’s true. ModelingToolkit is also a lot more flexible than what I tend have in mind when I think of modeling languages.

I’ve also had some plans to go the other direction to take advantage of symbolic Jacobian derivation and such. With the stuff I did for plot labeling, it might not be too hard now.

julia> ca = ComponentArray(a=5, b=(a=zeros(4,4), b=0), c=(a=[(a=1, b=2), (a=3, b=1), (a=1, b=2), (a=3, b=1)], b=[1., 2., 4]))
ComponentVector{Float64}(a = 5.0, b = (a = [0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0; 0.0 0.0 0.0 0.0], b = 0.0), c = (a = [(a = 1.0, b = 2.0), (a = 3.0, b = 1.0), (a = 1.0, b = 2.0), (a = 3.0, b = 1.0)], b = [1.0, 2.0, 4.0]))

julia> ComponentArrays.plot_labels(ca)
29-element Array{String,1}:
 "a"
 "b.a[1,1]"
 "b.a[2,1]"
 "b.a[3,1]"
 "b.a[4,1]"
 "b.a[1,2]"
 "b.a[2,2]"
 "b.a[3,2]"
 "b.a[4,2]"
 "b.a[1,3]"
 "b.a[2,3]"
 "b.a[3,3]"
 "b.a[4,3]"
 "b.a[1,4]"
 "b.a[2,4]"
 "b.a[3,4]"
 "b.a[4,4]"
 "b.b"
 "c.a[1].a"
 "c.a[1].b"
 "c.a[2].a"
 "c.a[2].b"
 "c.a[3].a"
 "c.a[3].b"
 "c.a[4].a"
 "c.a[4].b"
 "c.b[1]"
 "c.b[2]"
 "c.b[3]"