alchemyst / Skogestad-Python

Python code for "Multivariable Feedback Control"
111 stars 88 forks source link

Internal delay implementation #344

Closed AlgorithmicAmoeba closed 5 years ago

AlgorithmicAmoeba commented 5 years ago

This PR should close #262 . I have implemented the internal delay functionality using the form used by MATLAB (show here). Everything is contained in the InternalDelay class, which supports instantiation from utils.tf and utils.mimotf objects as well as from an appended standard numerator-denominator form:

num = [[num12, num12], [num21, num22]]
den = [[den12, den12], [den21, den22]]
delay = [[delay12, delay12], [delay21, delay22]]

The class supports cascade/series, parallel, feedback and inverse operations and overloads standard math operators.

SISO Example

I have been able to replicate the SISO example found here (code: siso_code.txt ): image image

MIMO Example

I have also replicated a MIMO example that I built from Example 4.9 in the Skogestad and confirmed the results using an OpenModelica simulation (code mimo_code.txt ):

Screenshot from 2019-04-28 15-11-07

image

alchemyst commented 5 years ago

Give a bit more thought to the way that __init__ works.

I'm torn between the .from_* form which is used by Pandas for DataFrames and the idea of using object instantiation as a "cast". It feels natural to use InternalDelay(G) if G is also a transfer-function-like thing (so perhaps like a mimotf or lti object or a tf) and have the right thing happen. Kind of like int("1") and int(1.0) kind of converts the one type into another. But when you have representations which aren't just one object, it starts making more sense to use a from* method.

I guess I'm asking for a hybrid approach - have "casting" behaviour if you accept just one object and the delays and use from_ methods if you're accepting things like coefficient lists. Come to think of it, it might be easier to drop support for coefficient lists and just always demand one of the other kinds of objects... That conversion code is already in scipy.signal.lti.

Give it some thought - I'll be checking this only this afternoon.

AlgorithmicAmoeba commented 5 years ago

I like the idea of having a casting effect for utils.tf and utils.mimotf objects.

I am a bit skeptical of doing that for lti objects as they do not have MIMO or delay capabilities.

I also really like the ability to build from lists as it allows the class to be constructed independently from any one library (which means that it could in future be added to the other control libraries very easily).

Suggested changes:

Will implement changes once we agree.

alchemyst commented 5 years ago

@darren-roos OK, let's do this: We retain the variadic __input__ with two forms, one which is the "long form" init which directly populates the internal arrays and another where we use the "casting" form for single arguments with the first argument. For other forms we use from_*.