From 9acbfbbbf3b4e2c9e8453c0cc18d21df88d6230b Mon Sep 17 00:00:00 2001 From: Richard Murray Date: Fri, 6 Dec 2024 17:36:37 -0800 Subject: [PATCH 1/4] fix issue with multiplying MIMO LTI system by scalar --- control/frdata.py | 15 +++++++++++++-- control/tests/lti_test.py | 18 ++++++++++++++++++ control/xferfcn.py | 17 ++++++++--------- 3 files changed, 39 insertions(+), 11 deletions(-) diff --git a/control/frdata.py b/control/frdata.py index 1bdf28528..ac032d3f7 100644 --- a/control/frdata.py +++ b/control/frdata.py @@ -261,6 +261,11 @@ def __init__(self, *args, **kwargs): # create interpolation functions if smooth: + # Set the order of the fit + if self.omega.size < 2: + raise ValueError("can't smooth with only 1 frequency") + degree = 3 if self.omega.size > 3 else self.omega.size - 1 + self.ifunc = empty((self.fresp.shape[0], self.fresp.shape[1]), dtype=tuple) for i in range(self.fresp.shape[0]): @@ -268,7 +273,8 @@ def __init__(self, *args, **kwargs): self.ifunc[i, j], u = splprep( u=self.omega, x=[real(self.fresp[i, j, :]), imag(self.fresp[i, j, :])], - w=1.0/(absolute(self.fresp[i, j, :]) + 0.001), s=0.0) + w=1.0/(absolute(self.fresp[i, j, :]) + 0.001), + s=0.0, k=degree) else: self.ifunc = None @@ -392,7 +398,12 @@ def __add__(self, other): # Convert the second argument to a frequency response function. # or re-base the frd to the current omega (if needed) - other = _convert_to_frd(other, omega=self.omega) + if isinstance(other, (int, float, complex, np.number)): + other = _convert_to_frd( + other, omega=self.omega, + inputs=self.ninputs, outputs=self.noutputs) + else: + other = _convert_to_frd(other, omega=self.omega) # Check that the input-output sizes are consistent. if self.ninputs != other.ninputs: diff --git a/control/tests/lti_test.py b/control/tests/lti_test.py index 3f001c17b..5359ceea3 100644 --- a/control/tests/lti_test.py +++ b/control/tests/lti_test.py @@ -350,3 +350,21 @@ def test_subsys_indexing(fcn, outdx, inpdx, key): np.testing.assert_almost_equal( subsys_fcn.frequency_response(omega).response, subsys_chk.frequency_response(omega).response) + + +@slycotonly +@pytest.mark.parametrize("op", [ + '__mul__', '__rmul__', '__add__', '__radd__', '__sub__', '__rsub__']) +@pytest.mark.parametrize("fcn", [ct.ss, ct.tf, ct.frd]) +def test_scalar_algebra(op, fcn): + sys_ss = ct.rss(4, 2, 2) + match fcn: + case ct.ss: + sys = sys_ss + case ct.tf: + sys = ct.tf(sys_ss) + case ct.frd: + sys = ct.frd(sys_ss, [0.1, 1, 10]) + + scaled = getattr(sys, op)(2) + np.testing.assert_almost_equal(getattr(sys(1j), op)(2), scaled(1j)) diff --git a/control/xferfcn.py b/control/xferfcn.py index 56ec7395f..b7daa9a2d 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -634,11 +634,11 @@ def __mul__(self, other): from .statesp import StateSpace # Convert the second argument to a transfer function. - if isinstance(other, StateSpace): + if isinstance(other, (StateSpace, np.ndarray)): other = _convert_to_transfer_function(other) - elif isinstance(other, (int, float, complex, np.number, np.ndarray)): - other = _convert_to_transfer_function(other, inputs=self.ninputs, - outputs=self.noutputs) + elif isinstance(other, (int, float, complex, np.number)): + # Multiply by a scaled identify matrix (transfer function) + other = _convert_to_transfer_function(np.eye(self.ninputs) * other) if not isinstance(other, TransferFunction): return NotImplemented @@ -681,8 +681,8 @@ def __rmul__(self, other): # Convert the second argument to a transfer function. if isinstance(other, (int, float, complex, np.number)): - other = _convert_to_transfer_function(other, inputs=self.ninputs, - outputs=self.ninputs) + # Multiply by a scaled identify matrix (transfer function) + other = _convert_to_transfer_function(np.eye(self.noutputs) * other) else: other = _convert_to_transfer_function(other) @@ -723,9 +723,8 @@ def __truediv__(self, other): """Divide two LTI objects.""" if isinstance(other, (int, float, complex, np.number)): - other = _convert_to_transfer_function( - other, inputs=self.ninputs, - outputs=self.ninputs) + # Multiply by a scaled identify matrix (transfer function) + other = _convert_to_transfer_function(np.eye(self.ninputs) * other) else: other = _convert_to_transfer_function(other) From 0b9be7a845fc6fcc62dd667d4c2d932debe363db Mon Sep 17 00:00:00 2001 From: "Scott C. Livingston" Date: Tue, 10 Dec 2024 16:03:04 -0800 Subject: [PATCH 2/4] fix misprint --- control/xferfcn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/xferfcn.py b/control/xferfcn.py index b7daa9a2d..ba8712aea 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -681,7 +681,7 @@ def __rmul__(self, other): # Convert the second argument to a transfer function. if isinstance(other, (int, float, complex, np.number)): - # Multiply by a scaled identify matrix (transfer function) + # Multiply by a scaled identity matrix (transfer function) other = _convert_to_transfer_function(np.eye(self.noutputs) * other) else: other = _convert_to_transfer_function(other) From f514f7c0064f214aa1be0917086f01833f6af490 Mon Sep 17 00:00:00 2001 From: "Scott C. Livingston" Date: Tue, 10 Dec 2024 16:03:11 -0800 Subject: [PATCH 3/4] fix misprint --- control/xferfcn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/xferfcn.py b/control/xferfcn.py index ba8712aea..43b99cc07 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -637,7 +637,7 @@ def __mul__(self, other): if isinstance(other, (StateSpace, np.ndarray)): other = _convert_to_transfer_function(other) elif isinstance(other, (int, float, complex, np.number)): - # Multiply by a scaled identify matrix (transfer function) + # Multiply by a scaled identity matrix (transfer function) other = _convert_to_transfer_function(np.eye(self.ninputs) * other) if not isinstance(other, TransferFunction): return NotImplemented From 3165881f23f917a9ed1c211b4b3f1497ac0e8c0d Mon Sep 17 00:00:00 2001 From: "Scott C. Livingston" Date: Tue, 10 Dec 2024 16:03:19 -0800 Subject: [PATCH 4/4] fix misprint --- control/xferfcn.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control/xferfcn.py b/control/xferfcn.py index 43b99cc07..5304ea636 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -723,7 +723,7 @@ def __truediv__(self, other): """Divide two LTI objects.""" if isinstance(other, (int, float, complex, np.number)): - # Multiply by a scaled identify matrix (transfer function) + # Multiply by a scaled identity matrix (transfer function) other = _convert_to_transfer_function(np.eye(self.ninputs) * other) else: other = _convert_to_transfer_function(other) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy