JuliaControl / ControlSystems.jl

A Control Systems Toolbox for Julia
https://juliacontrol.github.io/ControlSystems.jl/stable/
Other
508 stars 85 forks source link

Luenberger/Ackermann pole placement for MIMO systems. #456

Open tfoliva opened 3 years ago

tfoliva commented 3 years ago

I was in need of a function to perform state observers pole placement, so I wrote a wrapper function around the place(A, B, p) function as luenberger(A, C, p) which returns the observer gain matrix L. It makes use of the dual property between observability and controllability. I don't know if it is of any use, if it is I can push the code. Otherwise, if the decision to have only the place command was a deliberate project choice, please disregard.

On the other hand, I noticed that the ackermann function is only implemented for SISO systems. Is implementing it for MIMO systems on the roadmap? If it is, I can try to work on that...

tfoliva commented 3 years ago

I now noticed that #384 already mentions the second part of the issue.

albheim commented 3 years ago

For me personally I find it easy enough to use place(A, B, p) and place(A', C', p) so I don't really feel the need for a specific wrapper for that, but I'm not against it either.

For the second part we most certainly would like a MIMO place function, though I don't think ackermann works for MIMO so we have to look to other algorithms.

Connected to the issue you mentioned I actually started #402 a while ago. I implemented the basic version of the place that MATLAB uses, and was a bit dissappointed when I realised it only handled real poles and I didn't understand how to make it more general as MATLAB has. Haven't had time to look at it again since I lost motivation back then so it is just sitting there for now, think it is pretty much working but as I said, just real poles.

I had a quick look at robpole which seemed reasonable, and there are existing implementations in both python and matlab to get help with understanding the algorithm, so could maybe be a good option. But if you decide to take a look I think you can have a go at anything you think looks interesting.

baggepinnen commented 3 years ago

We could at the very least document how to place poles for an observer in the Docstring to place, don't forget to transpose the resulting matrix as well

albheim commented 3 years ago

We could at the very least document how to place poles for an observer in the Docstring to place, don't forget to transpose the resulting matrix as well

Agreed, and maybe I need a wrapper given how well I remember to use it... As I said, not against it :)

tfoliva commented 3 years ago

We could at the very least document how to place poles for an observer in the Docstring to place, don't forget to transpose the resulting matrix as well

I did transpose the resulting matrix. This seems like a reasonable solution to me, one less function to "clunk" the library but the documentation should suffice in aiding anyone in need of such function. As for the documentation, I already wrote this piece of docstring (and adaptation of place's docstring) when writing my implementation of luenberger, so I think it could be repurposed

"""
    luenberger(A, C, p)
    luenberger(sys::StateSpace, p)

Calculate gain matrix `L` such that the poles of `(A - LC)` are in `p`.
Uses sytem's dual form (Controllability-Observability duality) applied to Ackermann's formula.
That is, `(A - BK)` is indentic to `(A' - C'L') == (A - LC)`.
"""
tfoliva commented 3 years ago

I am new to contributing on Github so I don't have much practice with pull requests and the whole workflow needed to get them approved, but I could try pushing the wrapper and the documentation...

baggepinnen commented 3 years ago

This change would be so simple that you could probably try editing the file directly in github's web editor, just click the pen symbol when viewing the file.

tfoliva commented 3 years ago

For me personally I find it easy enough to use place(A, B, p) and place(A', C', p) so I don't really feel the need for a specific wrapper for that, but I'm not against it either.

For the second part we most certainly would like a MIMO place function, though I don't think ackermann works for MIMO so we have to look to other algorithms.

Connected to the issue you mentioned I actually started #402 a while ago. I implemented the basic version of the place that MATLAB uses, and was a bit dissappointed when I realised it only handled real poles and I didn't understand how to make it more general as MATLAB has. Haven't had time to look at it again since I lost motivation back then so it is just sitting there for now, think it is pretty much working but as I said, just real poles.

I had a quick look at robpole which seemed reasonable, and there are existing implementations in both python and matlab to get help with understanding the algorithm, so could maybe be a good option. But if you decide to take a look I think you can have a go at anything you think looks interesting.

I did take a look on your code yesterday and thought it seems promising. As for a more general version like the one MATLAB implements, I also looked over to the python control systems library and saw that their version wraps around a scipy.signal similar function which uses the algorithm you mentioned.

However, when using it today for the first time I had some trouble placing repeated poles on the same location... So I don't know yet if I did something wrong or if it is a limitation of the algorithm.

olof3 commented 3 years ago

I thought the conclusion was that there should be no added function, but an update to the docs, which I agree would be useful.

However it seems like this wrapper luenberger was indeed added in #457 ?!

The naming of luenberger and place is not symmetrical and quite confusing. And as @albheim wrote above

For me personally I find it easy enough to use place(A, B, p) and place(A', C', p) so I don't really feel the need for a specific wrapper for that, but I'm not against it either.

I see absolutely no need for it either. I think that we should revert this, but update the docs as was suggested above.

tfoliva commented 3 years ago

We could at the very least document how to place poles for an observer in the Docstring to place, don't forget to transpose the resulting matrix as well

Agreed, and maybe I need a wrapper given how well I remember to use it... As I said, not against it :)

I thought the conclusion was that the wrapper function would be useful, so I made the PR. But I agree that the naming convention is not symmetric either, it was just that I could not thing of a better name.

However, I think that reverting the change and just updating the documentation is OK as well...

Perhaps another option would be to make place take an optional argument (:c for control and :o for observer) like

place(A, B, p, :c)
place(A, C, p, :o)

Which would inform the function if the user intended to place observer poles or control poles. This way the naming convention is preserved, the user gets the added comfort of having an observer pole placement function and it's one less function. I think it could even default to :c.

olof3 commented 3 years ago

However, I think that reverting the change and just updating the documentation is OK as well...

Perhaps another option would be to make place take an optional argument (:c for control and :o for observer) like

Yes, both options would be improvements. I think that I prefer your idea with :c/:o.

stephans3 commented 3 years ago

You can find three simple methods of pole placement for MIMO systems in the Wikibooks about Control Systems.

Recently I have found the preprint Refined Transformation Approach for Stabilization of MIMO System by Pole Placement which seems to be a simple approach as well but I haven't had time to evaluate it.

As far as I understand the problem of pole placement for MIMO systems is that it strongly depends on the "special needs" (e.g. robustness, repeated poles, minimum gain, etc.) of the closed-loop.

I have found some articles covering these topics:

However, I have no implementation of one of them yet.

Probably it would make sense to have a common interface for a catalogue of possible methods covering certain flavors like robust or minimum gain pole placement.