Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
fix issue with multiplying MIMO LTI system by scalar
  • Loading branch information
murrayrm committed Dec 7, 2024
commit 9acbfbbbf3b4e2c9e8453c0cc18d21df88d6230b
15 changes: 13 additions & 2 deletions control/frdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -261,14 +261,20 @@ 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]):
for j in range(self.fresp.shape[1]):
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

Expand Down Expand Up @@ -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:
Expand Down
18 changes: 18 additions & 0 deletions control/tests/lti_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -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))
17 changes: 8 additions & 9 deletions control/xferfcn.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Comment thread
slivingston marked this conversation as resolved.
Outdated
other = _convert_to_transfer_function(np.eye(self.ninputs) * other)
if not isinstance(other, TransferFunction):
return NotImplemented

Expand Down Expand Up @@ -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)
Comment thread
slivingston marked this conversation as resolved.
Outdated
other = _convert_to_transfer_function(np.eye(self.noutputs) * other)
else:
other = _convert_to_transfer_function(other)

Expand Down Expand Up @@ -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)
Comment thread
slivingston marked this conversation as resolved.
Outdated
other = _convert_to_transfer_function(np.eye(self.ninputs) * other)
else:
other = _convert_to_transfer_function(other)

Expand Down