From f81b6d2617c14c0ca18b317bd92916b6ded5a71f Mon Sep 17 00:00:00 2001 From: Rory Yorke Date: Sat, 10 Dec 2022 11:59:25 +0200 Subject: [PATCH 1/3] Allow division by scalar for StateSpace & InputOutputSystem Attempt division by any non-LTI and non-NameIOSystem by translating G / k to G * (1/k). Division of StateSpace by TransferFunction, etc., unchanged. --- control/iosys.py | 11 +++++++++++ control/statesp.py | 19 ++++++++----------- control/tests/statesp_test.py | 11 +++++++++++ control/tests/type_conversion_test.py | 6 +++--- 4 files changed, 33 insertions(+), 14 deletions(-) diff --git a/control/iosys.py b/control/iosys.py index cbbd4cecc..b6b665030 100644 --- a/control/iosys.py +++ b/control/iosys.py @@ -346,6 +346,17 @@ def __neg__(sys): # Return the newly created system return newsys + def __truediv__(sys2, sys1): + """Multiply two input/output systems (series interconnection)""" + # Note: order of arguments is flipped so that self = sys2, + # corresponding to the ordering convention of sys2 * sys1 + + if not isinstance(sys1, (LTI, NamedIOSystem)): + return sys2 * (1/sys1) + else: + return NotImplemented + + # Update parameters used for _rhs, _out (used by subclasses) def _update_params(self, params, warning=False): if warning: diff --git a/control/statesp.py b/control/statesp.py index 7843cb33f..6203eda66 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -64,7 +64,7 @@ from .frdata import FrequencyResponseData from .lti import LTI, _process_frequency_response from .namedio import common_timebase, isdtime, _process_namedio_keywords, \ - _process_dt_keyword + _process_dt_keyword, NamedIOSystem from . import config from copy import deepcopy @@ -794,17 +794,14 @@ def __rmul__(self, other): pass raise TypeError("can't interconnect systems") - # TODO: __div__ and __rdiv__ are not written yet. - def __div__(self, other): - """Divide two LTI systems.""" - - raise NotImplementedError("StateSpace.__div__ is not implemented yet.") - - def __rdiv__(self, other): - """Right divide two LTI systems.""" + # TODO: general __truediv__, and __rtruediv__; requires descriptor system support + def __truediv__(self, other): + """Divide a StateSpace object; only division by scalars is supported""" + if not isinstance(other, (LTI, NamedIOSystem)): + return self * (1/other) + else: + return NotImplemented - raise NotImplementedError( - "StateSpace.__rdiv__ is not implemented yet.") def __call__(self, x, squeeze=None, warn_infinite=True): """Evaluate system's transfer function at complex frequency. diff --git a/control/tests/statesp_test.py b/control/tests/statesp_test.py index 41f0c893a..fa837f30d 100644 --- a/control/tests/statesp_test.py +++ b/control/tests/statesp_test.py @@ -333,6 +333,17 @@ def test_multiply_ss(self, sys222, sys322): np.testing.assert_array_almost_equal(sys.C, C) np.testing.assert_array_almost_equal(sys.D, D) + @pytest.mark.parametrize("k", [2, -3.141, np.float32(2.718), np.array([[4.321], [5.678]])]) + def test_truediv_ss_scalar(self, sys322, k): + """Divide SS by scalar.""" + sys = sys322 / k + syscheck = sys322 * (1/k) + + np.testing.assert_array_almost_equal(sys.A, syscheck.A) + np.testing.assert_array_almost_equal(sys.B, syscheck.B) + np.testing.assert_array_almost_equal(sys.C, syscheck.C) + np.testing.assert_array_almost_equal(sys.D, syscheck.D) + @pytest.mark.parametrize("omega, resp", [(1., np.array([[ 4.37636761e-05-0.01522976j, diff --git a/control/tests/type_conversion_test.py b/control/tests/type_conversion_test.py index 7163f7097..0deb68f88 100644 --- a/control/tests/type_conversion_test.py +++ b/control/tests/type_conversion_test.py @@ -88,11 +88,11 @@ def sys_dict(): ('mul', 'flt', ['ss', 'tf', 'frd', 'lio', 'ios', 'arr', 'flt']), # op left ss tf frd lio ios arr flt - ('truediv', 'ss', ['xs', 'tf', 'frd', 'xio', 'xos', 'xs', 'xs' ]), + ('truediv', 'ss', ['xs', 'tf', 'frd', 'xio', 'xos', 'ss', 'ss' ]), ('truediv', 'tf', ['tf', 'tf', 'xrd', 'tf', 'xos', 'tf', 'tf' ]), ('truediv', 'frd', ['frd', 'frd', 'frd', 'frd', 'E', 'frd', 'frd']), - ('truediv', 'lio', ['xio', 'tf', 'frd', 'xio', 'xio', 'xio', 'xio']), - ('truediv', 'ios', ['xos', 'xos', 'E', 'xos', 'xos' 'xos', 'xos']), + ('truediv', 'lio', ['xio', 'tf', 'frd', 'xio', 'xio', 'lio', 'lio']), + ('truediv', 'ios', ['xos', 'xos', 'E', 'xos', 'xos', 'ios', 'ios']), ('truediv', 'arr', ['xs', 'tf', 'frd', 'xio', 'xos', 'arr', 'arr']), ('truediv', 'flt', ['xs', 'tf', 'frd', 'xio', 'xos', 'arr', 'flt'])] From 0efae636cb831ecba53274e61a33f828d529b5b3 Mon Sep 17 00:00:00 2001 From: Rory Yorke Date: Sat, 10 Dec 2022 12:08:07 +0200 Subject: [PATCH 2/3] Remove __div__ and __rdiv__ methods These aren't used in Python 3. --- control/frdata.py | 8 -------- control/xferfcn.py | 8 -------- 2 files changed, 16 deletions(-) diff --git a/control/frdata.py b/control/frdata.py index a33775afb..c78607a07 100644 --- a/control/frdata.py +++ b/control/frdata.py @@ -408,10 +408,6 @@ def __truediv__(self, other): smooth=(self.ifunc is not None) and (other.ifunc is not None)) - # TODO: Remove when transition to python3 complete - def __div__(self, other): - return self.__truediv__(other) - # TODO: Division of MIMO transfer function objects is not written yet. def __rtruediv__(self, other): """Right divide two LTI objects.""" @@ -429,10 +425,6 @@ def __rtruediv__(self, other): return other / self - # TODO: Remove when transition to python3 complete - def __rdiv__(self, other): - return self.__rtruediv__(other) - def __pow__(self, other): if not type(other) == int: raise ValueError("Exponent must be an integer") diff --git a/control/xferfcn.py b/control/xferfcn.py index 84188a63f..a27b46623 100644 --- a/control/xferfcn.py +++ b/control/xferfcn.py @@ -702,10 +702,6 @@ def __truediv__(self, other): return TransferFunction(num, den, dt) - # TODO: Remove when transition to python3 complete - def __div__(self, other): - return TransferFunction.__truediv__(self, other) - # TODO: Division of MIMO transfer function objects is not written yet. def __rtruediv__(self, other): """Right divide two LTI objects.""" @@ -724,10 +720,6 @@ def __rtruediv__(self, other): return other / self - # TODO: Remove when transition to python3 complete - def __rdiv__(self, other): - return TransferFunction.__rtruediv__(self, other) - def __pow__(self, other): if not type(other) == int: raise ValueError("Exponent must be an integer") From cc3fb2fd903275ade892898b8c5b6779b6b05807 Mon Sep 17 00:00:00 2001 From: Rory Yorke Date: Fri, 16 Dec 2022 06:00:47 +0200 Subject: [PATCH 3/3] Update __truediv__ docstring for InputOutputSystem and StateSpace --- control/iosys.py | 4 +++- control/statesp.py | 6 +++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/control/iosys.py b/control/iosys.py index b6b665030..67cca74de 100644 --- a/control/iosys.py +++ b/control/iosys.py @@ -347,7 +347,9 @@ def __neg__(sys): return newsys def __truediv__(sys2, sys1): - """Multiply two input/output systems (series interconnection)""" + """Division of input/output systems + + Only division by scalars and arrays of scalars is supported""" # Note: order of arguments is flipped so that self = sys2, # corresponding to the ordering convention of sys2 * sys1 diff --git a/control/statesp.py b/control/statesp.py index 6203eda66..249c6f5e0 100644 --- a/control/statesp.py +++ b/control/statesp.py @@ -796,7 +796,11 @@ def __rmul__(self, other): # TODO: general __truediv__, and __rtruediv__; requires descriptor system support def __truediv__(self, other): - """Divide a StateSpace object; only division by scalars is supported""" + """Division of StateSpace systems + + Only division by TFs, FRDs, scalars, and arrays of scalars is + supported. + """ if not isinstance(other, (LTI, NamedIOSystem)): return self * (1/other) else: 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