-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
[GSoC] Add TransferFunctionMatrix class in physics.control #19761
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[GSoC] Add TransferFunctionMatrix class in physics.control #19761
Conversation
✅ Hi, I am the SymPy bot (v161). I'm here to help you write a release notes entry. Please read the guide on how to write release notes. Your release notes are in good order. Here is what the release notes will look like:
This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.9. Click here to see the pull request description that was parsed.
Update The release notes on the wiki have been updated. |
ping @ishanaj! |
Ready for review! |
Codecov Report
@@ Coverage Diff @@
## master #19761 +/- ##
=============================================
+ Coverage 75.868% 75.877% +0.009%
=============================================
Files 669 669
Lines 173564 173811 +247
Branches 40969 41074 +105
=============================================
+ Hits 131680 131884 +204
- Misses 36147 36171 +24
- Partials 5737 5756 +19 |
I have added a MIMO transfer function object and its important properties. What needs to be done for the interconnection of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we've supported block diagram for SISO systems, I think we should also do the same for MIMO systems.
OK, I will start working on these classes now! |
@moorepants, @sylee957 Can either one of you (or both) also confirm if the work done till now looks fine? Everything else is built on top of |
I am just passing by but I think the class name should be |
Hi @ilayn! Thanks for this suggestion. I just got to know about the control systems toolbox you implemented over the years - harold. My first PR for adding SISO transfer function is merged, here's the documentation. The class was named as |
It is wonderful that you are working on this and it is such a valuable addition. I am indeed using/developing harold but I might add a disclaimer that my wording in harold is highly unconventional so please take it with some salt. It is probably better that others chime in too. My logic is that Transfer function name is like "he is such a gentleman man" that is Transfer function is already a function no need to emphasize it. Same with state space that actually means basically R^n so again redundant wording. Hence the naming Another option is to have a single object |
I think that it's different matter for naming between When I search how many IEEE papers out there for But I don't think that |
What should we name these two classes for series and parallel interconnection? What about |
I don't think IEEE is doing a good job here by returning a couple of thousand results. This terminology should in either case return way more results. And the terminology clash is sufficiently far apart, for example, I was completely immersed in control theory and not once I heard this method. But anyways, my vote goes out for having a single class with SISO/MIMO as special cases. |
Why can't |
raise TypeError("Var must be a Symbol, not {}.".format(type(var))) | ||
|
||
obj = super(TransferFunctionMatrix, cls).__new__(cls, arg) | ||
if all(isinstance(i, (TransferFunction, Series, Parallel)) for i in arg): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This path needs to check that Series
and Parallel
are all is_SISO
, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The special-casing of num_input
and num_outputs
being 1 scares me, and I think it will make this fail:
a1 = TransferFunctionMatrix([-tf4], (1, 1), p)
a11 = TransferFunctionMatrix([[-tf4]], (1, 1), p)
b2 = TransferFunctionMatrix([-tf4, tf4], (2, 1), p)
b21 = TransferFunctionMatrix([[-tf4, tf4]], (2, 1), p)
c = TransferFunctionMatrix([[-tf4], [tf4]], (1, 3), p)
# all of these products should be legal
for a in [a1, a11]:
for b in [b1, b11]:
b * a
a * c
August 31 |
@namannimmo10 can you push the work you have done on the documentation? Also, please respond to @eric-wieser's comments. We have less than 2 days till the deadline. |
Some of the comments are still to be addressed, and class level docstring will be added soon. (Didn't add in this commit because some API design changes are to be made). |
if not isinstance(var, Symbol): | ||
raise TypeError("Var must be a Symbol, not {}.".format(type(var))) | ||
|
||
obj = super(TransferFunctionMatrix, cls).__new__(cls, arg) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm starting to think you really do want to reuse the matrix classes here. So I'd propose __new__
looks like:
def __new__(cls, arg, shape, var):
if var is not None and not isinstance(var, Symbol):
raise TypeError("Var must be a Symbol, not {}.".format(type(var)))
if shape is not None and not isinstance(shape, tuple):
raise TypeError("Shape must be a tuple, not {}.".format(type(shape)))
# let matrix handle conversion from lists
matrix = ImmutableDenseMatrix(arg)
# args[2] is the flattened entries
for entry in matrix.args[2]:
if not isinstance(entry, (TransferFunction, Parallel, Series)):
raise TypeError("Unsupported type for argument of TransferFunctionMatrix.")
if var is not None and entry.var != var:
raise ValueError("All transfer functions should use the same complex"
" variable (var) of the Laplace transform.")
if shape is not None and matrix.shape != shape:
raise ValueError("wrong shape") # or a better message
obj = super(TransferFunctionMatrix, cls).__new__(cls, matrix)
obj._var = var
# etc
return obj
A big advantage of this approach is that TransferFunctionMatrix.subs(some_variable, 0)
will just work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does subs
not work with this class?
There is a basic problem in sympy with allowing non-Expr (even non-Basic) instances in places such as Matrix entries that are clearly written for Expr instances. I intend to eliminate all places where non-Expr instances are used in a Matrix from the codebase and deprecate having non-Expr in a Matrix.
I don't think that it is a big deal to implement something like matrix multiplication which is fairly trivial although perhaps it would be better if there was a reusable function somewhere for doing that calculation. It is still a work in progress and not at all documented but I have implemented various matrix routines in such a way that they can be applied to a standard Python list of lists based on only assuming that the elements support the field operations +
, -
, *
and /
so do not need to Expr or even Basic. My intention was that it should not be necessary to subclass Matrix and insert objects that don't belong there just to reuse the routines for standard matrix operations. Matrix multiplication is handled by this function:
sympy/sympy/polys/domainmatrix.py
Lines 220 to 226 in 500f3c9
def ddm_imatmul(a, b, c): | |
"""a += b @ c""" | |
cT = list(zip(*c)) | |
for bi, ai in zip(b, a): | |
for j, cTj in enumerate(cT): | |
ai[j] = sum(map(mul, bi, cTj), ai[j]) |
That implementation is optimised for large matrices and cheap elementary arithmetic (e.g.
int
or mpz
as the elements).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does subs not work with this class?
My impression was that subs
would not recurse into list arguments, but perhaps I missed a sympify somewhere.
At any rate, my suggestion above is more about letting the matrix constructor handle the normalization, and less about the multiplication itself. The thing I don't like about this PR is how the special cases for TFM([tf])
vs TFM([[tf]])
are in every single method, when they should just be in the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I intend to eliminate all places where non-Expr instances are used in a Matrix from the codebase and deprecate having non-Expr in a Matrix.
If you do this, I'd argue that it might be worth introducing a base class that works over non-exprs too. In my mind, this control stuff is really trying to work with a new TransferFunctionExpr
type, just like matrices work with a Matexpr
type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd argue that it might be worth introducing a base class
The Matrix class is already arranged into a bunch of different base classes:
In [1]: Matrix.mro()
Out[1]:
[sympy.matrices.dense.MutableDenseMatrix,
sympy.matrices.dense.DenseMatrix,
sympy.matrices.matrices.MatrixBase,
sympy.matrices.matrices.MatrixDeprecated,
sympy.matrices.matrices.MatrixCalculus,
sympy.matrices.matrices.MatrixEigen,
sympy.matrices.matrices.MatrixSubspaces,
sympy.matrices.matrices.MatrixReductions,
sympy.matrices.matrices.MatrixDeterminant,
sympy.matrices.common.MatrixCommon,
sympy.matrices.common.MatrixArithmetic,
sympy.matrices.common.MatrixOperations,
sympy.matrices.common.MatrixProperties,
sympy.matrices.common.MatrixSpecial,
sympy.matrices.common.MatrixShaping,
sympy.matrices.common.MatrixRequired,
sympy.printing.defaults.Printable,
object]
It's just not really clear how you could make use of any of those classes separately.
Hey @namannimmo10, @oscarbenjamin is planning to release SymPy 1.7 soon. If you are free and available now, can you finish this PR so that this work can also be included in the release? |
Thanks! Yes, I am planning to complete this PR soon. |
Any progress on this @namannimmo10? |
After a significant delay I'm getting ready for the 1.7 release. Is anything going to happen in this PR soon? |
I'm removing the 1.7 milestone. Let me know if there any changes come soon that should be considered for 1.7 |
@namannimmo10 Can this become a part of next GSoC? |
I would like to work on this issue as my GSoC project. I know basic Git/Github, Python and Control Systems(via NPTEL lectures). Currently I am reading the documentation and code of the the matrix. Please help me get started. |
Sure, please feel free to take over. |
I was going over the document http://www.cds.caltech.edu/~murray/amwiki/index.php/Second_Edition , and I am currently having the following ideas:-
|
@white-peed, I think some small steps can be taken to further develop
All in all, I believe some examples are essential as the development proceeds. |
Can you explain " making TransferFunctionMatrix more robust " ?
…On Sun, Mar 21, 2021 at 2:50 PM Naman Gera ***@***.***> wrote:
@white-peed <https://github.com/white-peed>, I think some small steps can
be taken to further develop sympy.physics.control. That way we can
discuss in detail each step!
1. One task is to complete this outstanding PR; it includes resolving
the merge conflicts, addressing some comments, and making
TransferFunctionMatrix more robust (after some discussion which is
pending by one of the reviewers).
2. Another important task is to add 3-4 working examples in the
documentation showing the users how to exercise this package.
3. After that, we can think of adding graphical analyses to it.
pole_zero and root_locus will simply use .poles() and .zeros() methods
in TransferFunction class. And SymPy's own plotting module will work
fine. bode plot should also be added.
4. Finally, once all the aforementioned tasks are handled, the
StateSpace class can be introduced for creating State Space models. I
would also refer to python-control
<https://github.com/python-control/python-control> and harold
<https://github.com/ilayn/harold> for doing this task.
All in all, I believe some examples are essential as the development
proceeds.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#19761 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/APEYJ2UCGD4JWNMFF47Q4P3TEW24RANCNFSM4OY7KYYQ>
.
|
Please have a look at all the discussions in this PR. There were some suggestions given to improve the existing implementation. |
Hi @namannimmo10 . I am also interested in taking Symbolic Control System as my GSoC project. I am still reviewing the knowledge of Control Theory. It takes a few more days before I can comment on the implementation. Also hello @white-peed . I feel so unlucky as I come here late and you have already come up with some brilliant ideas. Hope there is a chance that we both can contribute to this project. As I am browsing the comment history, I found @white-peed had mentioned using matplotlib and numpy
Then I found that @namannimmo10 was using matplotlib and numpy in I think maybe we should take a look at the Why SymPy section of Introduction to SymPy. It says
We should follow the philosophy of the design. Also the function would become buggy if the dependencies update in the future. The Sympy has already implemented plotting methods in The idea above is just my random thoughts. I haven't come up with other ideas. I have to read the reference book quickly. See you days later. |
References to other Issues or PRs
#19352
Brief description of what is fixed or changed
This PR introduces MIMO transfer functions in
sympy.physics.control
.Other comments
Release Notes
TransferFunctionMatrix
class in physics.control