Skip to content

Conversation

abhiphile
Copy link
Contributor

@abhiphile abhiphile commented Mar 1, 2024

References to other Issues or PRs

Fixes Discussion in #26228
Fixes Issue #26161

Brief description of what is fixed or changed

  1. Feedback in Control Systems will now be used with TransferFunctions easily without affecting the system's overall structure.
  2. Added method to find out the numerator and denominator of TransferFunction.
  3. Added a method to convert the Feedback system to expression.

Other comments

Release Notes

  • physics.control
    • Added support for using Feedback as a TransferFunction.
    • Added methods to get the numerator and denominator of TransferFunction.
    • Added function to get the expression for the Feedback object.

@sympy-bot
Copy link

sympy-bot commented Mar 1, 2024

Hi, I am the SymPy bot. 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:

  • physics.control
    • Added support for using Feedback as a TransferFunction. (#26293 by @abhiphile)

    • Added methods to get the numerator and denominator of TransferFunction. (#26293 by @abhiphile)

    • Added function to get the expression for the Feedback object. (#26293 by @abhiphile)

This will be added to https://github.com/sympy/sympy/wiki/Release-Notes-for-1.13.

Click here to see the pull request description that was parsed.
<!-- Your title above should be a short description of what
was changed. Do not include the issue number in the title. -->

#### References to other Issues or PRs
Fixes Discussion in https://github.com/sympy/sympy/pull/26228
Fixes Issue https://github.com/sympy/sympy/issues/26161

<!-- If this pull request fixes an issue, write "Fixes #NNNN" in that exact
format, e.g. "Fixes #1234" (see
https://tinyurl.com/auto-closing for more information). Also, please
write a comment on that issue linking back to this pull request once it is
open. -->


#### Brief description of what is fixed or changed
1. Feedback in Control Systems will now be used with TransferFunctions easily without affecting the system's overall structure.
2. Added method to find out the numerator and denominator of TransferFunction.
3. Added a method to convert the Feedback system to expression.

#### Other comments


#### Release Notes

<!-- Write the release notes for this release below between the BEGIN and END
statements. The basic format is a bulleted list with the name of the subpackage
and the release note for this PR. For example:

* solvers
  * Added a new solver for logarithmic equations.

* functions
  * Fixed a bug with log of integers. Formerly, `log(-x)` incorrectly gave `-log(x)`.

* physics.units
  * Corrected a semantical error in the conversion between volt and statvolt which
    reported the volt as being larger than the statvolt.

or if no release note(s) should be included use:

NO ENTRY

See https://github.com/sympy/sympy/wiki/Writing-Release-Notes for more
information on how to write release notes. The bot will check your release
notes automatically to see if they are formatted correctly. -->

<!-- BEGIN RELEASE NOTES -->
* physics.control
  * Added support for using Feedback as a TransferFunction.
  * Added methods to get the numerator and denominator of TransferFunction.
  * Added function to get the expression for the Feedback object.
<!-- END RELEASE NOTES -->

Update

The release notes on the wiki have been updated.

@abhiphile abhiphile marked this pull request as ready for review March 1, 2024 16:52
@abhiphile
Copy link
Contributor Author

@moorepants, Sir, can you please review this PR? I've made sure that everything is correct here.
This can possibly close the issue.

@moorepants
Copy link
Member

It would be good to have a test showing that you can combine with another transfer function (like putting two a feedback in series with a tf) and show that is works in regular assembly operations.

@abhiphile
Copy link
Contributor Author

It would be good to have a test showing that you can combine with another transfer function (like putting two a feedback in series with a tf) and show that is works in regular assembly operations.

Sir, Are you talking about this?
tf3 = TransferFunction(tf1 * fd1, tf2, s)

@moorepants
Copy link
Member

Sir, Are you talking about this?

I was thinking just Series(Feedback(tf1, tf2), tf3) then check the num and den are correct and maybe that doit works.

@abhiphile
Copy link
Contributor Author

abhiphile commented Mar 3, 2024

I was thinking just Series(Feedback(tf1, tf2), tf3)

I can see that num and den property are not available in Series so do I've to implement them inside of Series?
I think that will be lots of work and out of scope for this PR and reviewing everything will be difficult, maybe I can work on it by opening a new PR.

I've just used doit() and written the tests.

@abhiphile abhiphile force-pushed the Feedback-as-TransferFunction branch from 0ec9f42 to e356578 Compare March 3, 2024 09:23
@abhiphile abhiphile force-pushed the Feedback-as-TransferFunction branch from e356578 to d3ecdcf Compare March 3, 2024 09:27
@moorepants
Copy link
Member

I can see that num and den property are not available in Series so do I've to implement them inside of Series?

If making Feedback work as a transfer function means that other things have to be fixed too, then we need to do that. This PR doesn't address the primary issue if you can't use Feedback as a transfer function.

@moorepants
Copy link
Member

My original example does seem to work with this PR:

In [1]: %paste
import sympy as sm
import sympy.physics.control as cn

Ib, Is, c, m, h, g, l2, l1 = sm.symbols('I_b, I_s, c, m, h, g, l2, l1',
                                        real=True, nonnegative=True)
KD, KP, v = sm.symbols('K_D, K_P, v', real=True)
s = sm.symbols('s')

tau1_sq = (Ib + m*h**2)/m/g/h
tau2 = l2/v
tau3 = v/(l1 + l2)
K = v**2/g/(l1 + l2)

Gtheta = cn.TransferFunction(-K*(tau2*s + 1), tau1_sq*s**2 - 1, s)
Gdelta = cn.TransferFunction(1, Is*s**2 + c*s, s)
Gpsi = cn.TransferFunction(1, tau3*s, s)
Dcont = cn.TransferFunction(KD*s, 1, s)
PIcont = cn.TransferFunction(KP, s, s)
Gunity = cn.TransferFunction(1, 1, s)

Ginner = cn.Feedback(Dcont*Gdelta, Gtheta)

Gouter = cn.Feedback(PIcont*Ginner*Gpsi, Gunity)

## -- End pasted text --

In [2]: Gouter
Out[2]: Feedback(Series(TransferFunction(K_P, s, s), Feedback(Series(TransferFunction(K_D*s, 1, s), TransferFunction(1, I_s*s**2 + c*s, s)), TransferFunction(-v**2*(l2*s/v + 1)/(g*(l1 + l2)), -1 + s**2*(I_b + h**2*m)/(g*h*m), s), -1), TransferFunction(1, s*v/(l1 + l2), s)), TransferFunction(1, 1, s), -1)

In [3]: Gouter.num
Out[3]: Series(TransferFunction(K_P, s, s), Feedback(Series(TransferFunction(K_D*s, 1, s), TransferFunction(1, I_s*s**2 + c*s, s)), TransferFunction(-v**2*(l2*s/v + 1)/(g*(l1 + l2)), -1 + s**2*(I_b + h**2*m)/(g*h*m), s), -1), TransferFunction(1, s*v/(l1 + l2), s))

In [4]: Gouter.doit()
Out[4]: TransferFunction(K_D*K_P*g*s**3*v**2*(l1 + l2)*(I_s*s**2 + c*s)**2*(-g*h*m + s**2*(I_b + h**2*m))*(-K_D*g*h*m*s*v**2*(l2*s + v) + g*v*(l1 + l2)*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m))), s**2*v*(I_s*s**2 + c*s)*(-K_D*g*h*m*s*v**2*(l2*s + v) + g*v*(l1 + l2)*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m)))*(K_D*K_P*g*s*v*(l1 + l2)**2*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m)) + s**2*v*(I_s*s**2 + c*s)*(-K_D*g*h*m*s*v**2*(l2*s + v) + g*v*(l1 + l2)*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m))))/(l1 + l2), s)

In [5]: Gouter.doit().to_expr()
Out[5]: (K_D*K_P*g*s**3*v**2*(l1 + l2)*(I_s*s**2 + c*s)**2*(-g*h*m + s**2*(I_b + h**2*m))*(-K_D*g*h*m*s*v**2*(l2*s + v) + g*v*(l1 + l2)*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m))))/((s**2*v*(I_s*s**2 + c*s)*(-K_D*g*h*m*s*v**2*(l2*s + v) + g*v*(l1 + l2)*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m)))*(K_D*K_P*g*s*v*(l1 + l2)**2*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m)) + s**2*v*(I_s*s**2 + c*s)*(-K_D*g*h*m*s*v**2*(l2*s + v) + g*v*(l1 + l2)*(I_s*s**2 + c*s)*(-g*h*m + s**2*(I_b + h**2*m))))/(l1 + l2)))

In [6]: Gouter.doit().to_expr().simplify()
Out[6]: K_D*K_P*(l1 + l2)**2*(g*h*m - s**2*(I_b + h**2*m))/(K_D*K_P*(l1 + l2)**2*(g*h*m - s**2*(I_b + h**2*m)) + s**2*v*(K_D*h*m*v*(l2*s + v) - (l1 + l2)*(I_s*s + c)*(-g*h*m + s**2*(I_b + h**2*m))))

which is nice. It is also a useful test case for the unit tests.

So I guess we can merge this without making Series and Parallel act like a transfer function also. It can be solved separately.

@abhiphile
Copy link
Contributor Author

abhiphile commented Mar 3, 2024

tau1_sq = (Ib + m*h2)/m/g/h
tau2 = l2/v
tau3 = v/(l1 + l2)
K = v
2/g/(l1 + l2)

Thank you for your time. I will also write a unit test for this.
But I've already included a similar test here https://github.com/sympy/sympy/pull/26293/files#diff-f148f25c5f8d301ec215df3efcee817b486b0a760284872c93395c19d2a08e29R1036
If it is still needed, I'll include this in the unit test

@abhiphile abhiphile force-pushed the Feedback-as-TransferFunction branch from d0d951c to e1d59db Compare March 4, 2024 06:19
Copy link
Contributor

@faze-geek faze-geek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great reviews and work here @abhiphile. I'll wait for Jason to merge this when he feels appropriate. Thanks !

@moorepants
Copy link
Member

LGTM, nice work!

@faze-geek
Copy link
Contributor

faze-geek commented Mar 4, 2024

Failing test here doesn't seem to be related. Thanks for your contributions, merging !

@faze-geek faze-geek merged commit 8a619fc into sympy:master Mar 4, 2024
@oscarbenjamin
Copy link
Collaborator

Failing test here doesn't seem to be unrelated.

That particular pypy test just fails randomly since some recent pypy release (a few months ago?). I can't reproduce the failure outside of CI so I haven't opened a PyPy issue about it. The problem is something to do with pytest's assertion rewriting which presumably messes with PyPy's AST.

pypy/pypy#3959
pytest-dev/pytest#11168

@faze-geek
Copy link
Contributor

Sorry, mentioned "doesn't" and "unrelated" together by mistake. Did not mean to cause a confusion 😄

@abhiphile abhiphile deleted the Feedback-as-TransferFunction branch March 16, 2024 16:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants