Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Support for binary operations between MIMO and SISO LTI systems #1081

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

Merged
merged 42 commits into from
Jan 20, 2025

Conversation

sdahdah
Copy link
Contributor

@sdahdah sdahdah commented Dec 19, 2024

Resolves #1076 and #939

This PR implements binary operations (__add__, __mul__, etc.) between MIMO and SISO LTI systems.

Specifically, it

  • implements TransferFunction.append() and FrequencyResponseData.append(),
  • changes control.append() to return the type of the first argument,
  • implements MIMO-SISO __mul__, __rmul__, __truediv__ and __rtruediv__ for MIMO and SISO LTI systems using the updated control.append(),
  • implements MIMO-SISO __add__, __radd__, __sub__, and __rsub__ using the updated multiplication and division operations,
  • implements inversion of biproper state-space systems via __pow__, and
  • fixes a bug (?) where StateSpace.minreal() drops the dt

I would recommend reviewing the changes in that order.

See also #459

@coveralls
Copy link

coveralls commented Dec 19, 2024

Coverage Status

coverage: 94.645% (-0.04%) from 94.687%
when pulling ccf9ce1 on sdahdah:main
into 0ff0452 on python-control:main.

@murrayrm
Copy link
Member

I'll try to review this in the coming days. In the meantime, there is a typo in a docstring ("ct.ombine_tf" should be "ct.combine_tf") that is causing a failure in the doctest check.

@murrayrm murrayrm self-assigned this Dec 19, 2024
@murrayrm murrayrm self-requested a review December 19, 2024 22:41
@murrayrm murrayrm removed their assignment Dec 19, 2024
@sdahdah
Copy link
Contributor Author

sdahdah commented Dec 20, 2024

I'll try to review this in the coming days. In the meantime, there is a typo in a docstring ("ct.ombine_tf" should be "ct.combine_tf") that is causing a failure in the doctest check.

Thank you! Is there a way to run the doctests locally? make html in the doc/ folder I think? I have not been able to figure that out

@murrayrm
Copy link
Member

murrayrm commented Dec 20, 2024

Is there a way to run the doctests locally? make html in the doc/ folder I think? I have not been able to figure that out

make doctest in the doc/ directory will run the tests.

Copy link
Member

@murrayrm murrayrm left a comment

Choose a reason for hiding this comment

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

Preliminary comments. I haven't gone through to make sure the everything is correct, but wanted to pass on some higher level comments first. OK to ignore the code style ones, but I would fix up some of the Numpydoc ones (which I eventually need to check in tests/docstrings_tests.py.

@sdahdah
Copy link
Contributor Author

sdahdah commented Dec 21, 2024

Thanks for taking a look. Would you like me to fix these before you continue the review? I might not be able to until the new year unfortunately.

Copy link
Member

@murrayrm murrayrm left a comment

Choose a reason for hiding this comment

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

As currently written, the new systems that are being created are non-minimal. For example:

s = ct.tf('s')
ct.config.defaults['xferfcn.display_format'] = 'zpk'  # simpler output format
siso = (s+1) / ((s+2) * (s+3))
mimo = ct.combine_tf([
  [1/s,         1/(s+4)], 
  [1/(s+5), (s+6)/(s**2 + 2*s + 2)]
])
print(siso * mimo)

<TransferFunction>: sys[219]
Inputs (2): ['u[0]', 'u[1]']
Outputs (2): ['y[0]', 'y[1]']

Input 1 to output 1:
      (s + 1) (s + 5)
---------------------------
(s) (s + 2) (s + 3) (s + 5)

Input 1 to output 2:
        (s) (s + 1)
---------------------------
(s) (s + 2) (s + 3) (s + 5)

Input 2 to output 1:
        (s + 1) (s + (1-1j)) (s + (1+1j))
-------------------------------------------------
(s + (1-1j)) (s + (1+1j)) (s + 2) (s + 3) (s + 4)

Input 2 to output 2:
             (s + 1) (s + 4) (s + 6)
-------------------------------------------------
(s + (1-1j)) (s + (1+1j)) (s + 2) (s + 3) (s + 4)

Note the various pole/zero cancellations that appear. It seems to me that these are spurious and shouldn't show up (eg, (s+4) in the [2, 2] transfer function).

This same type of situation occurs in state space and is consistent with the results that occur if you convert the SISO system to a matrix system by hand. I'm not sure (yet) what is gong on, but this seems like something we should fix, either for this specific case or for the more general case of multiplying MIMO systems.

I need to think a bit more about what is causing this, but wanted to flag it here in case someone else has some insights. It seems to me that perfect pole/zero cancellations (and the equivalent in state space) should get sorted out ahead of time, either by not creating them or by removing them before we send things back to the user.

@sdahdah
Copy link
Contributor Author

sdahdah commented Jan 17, 2025

As currently written, the new systems that are being created are non-minimal. For example:

s = ct.tf('s')
ct.config.defaults['xferfcn.display_format'] = 'zpk'  # simpler output format
siso = (s+1) / ((s+2) * (s+3))
mimo = ct.combine_tf([
  [1/s,         1/(s+4)], 
  [1/(s+5), (s+6)/(s**2 + 2*s + 2)]
])
print(siso * mimo)

<TransferFunction>: sys[219]
Inputs (2): ['u[0]', 'u[1]']
Outputs (2): ['y[0]', 'y[1]']

Input 1 to output 1:
      (s + 1) (s + 5)
---------------------------
(s) (s + 2) (s + 3) (s + 5)

Input 1 to output 2:
        (s) (s + 1)
---------------------------
(s) (s + 2) (s + 3) (s + 5)

Input 2 to output 1:
        (s + 1) (s + (1-1j)) (s + (1+1j))
-------------------------------------------------
(s + (1-1j)) (s + (1+1j)) (s + 2) (s + 3) (s + 4)

Input 2 to output 2:
             (s + 1) (s + 4) (s + 6)
-------------------------------------------------
(s + (1-1j)) (s + (1+1j)) (s + 2) (s + 3) (s + 4)

Note the various pole/zero cancellations that appear. It seems to me that these are spurious and shouldn't show up (eg, (s+4) in the [2, 2] transfer function).

This same type of situation occurs in state space and is consistent with the results that occur if you convert the SISO system to a matrix system by hand. I'm not sure (yet) what is gong on, but this seems like something we should fix, either for this specific case or for the more general case of multiplying MIMO systems.

I need to think a bit more about what is causing this, but wanted to flag it here in case someone else has some insights. It seems to me that perfect pole/zero cancellations (and the equivalent in state space) should get sorted out ahead of time, either by not creating them or by removing them before we send things back to the user.

I took a quick look but I'm not sure. It's definitely happening inside xferfcn.TransferFunction.__mul__. I think roots need to be cancelled in xferfcn._add_siso(), but I'm not sure whether minreal() should just be used?

@sdahdah
Copy link
Contributor Author

sdahdah commented Jan 17, 2025

Happy new year @murrayrm . I fixed some of your initial comments (and also tried to look for other instances of nonstandard docstrings and indentation along the way). I'm not 100% sure what's going on with the spurious poles and zeros, buy maybe another issue should be raised to track that?

@sdahdah sdahdah requested a review from murrayrm January 17, 2025 21:57
@sdahdah
Copy link
Contributor Author

sdahdah commented Jan 17, 2025

Not sure why the Py3.12; conda Slycot; conda Pandas; conda CVXOPT ; QtAgg check is failing during setup:

error    libmamba Error when extracting package: Could not stat include/event2/keyvalq_struct.h
libevent-2.1.12-hf998b51_1.conda extraction failed
Found incorrect download: libevent. Aborting

I don't think it's related to the PR

@murrayrm murrayrm merged commit 71bd731 into python-control:main Jan 20, 2025
23 checks passed
@murrayrm murrayrm added this to the 0.10.2 milestone Feb 19, 2025
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.

Proposal for multiplying a NumPy array by a scalar TransferFunction
3 participants