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..5304ea636 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 identity 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 identity 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 identity matrix (transfer function) + other = _convert_to_transfer_function(np.eye(self.ninputs) * other) else: other = _convert_to_transfer_function(other)
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: