Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
9acbfbb
fix issue with multiplying MIMO LTI system by scalar
murrayrm Dec 7, 2024
fed6c8d
Merge pull request #1 from murrayrm/fix_scalar_tfops-06Dec2024
sdahdah Dec 9, 2024
acc5086
Add append for FRD
sdahdah Dec 9, 2024
686a9b3
Add SISO FRD append test
sdahdah Dec 9, 2024
94481ac
Add MIMO FRD test
sdahdah Dec 9, 2024
053c3c6
Add append for TFs
sdahdah Dec 9, 2024
b6b032f
Move tf_close_coeff to xferfcn
sdahdah Dec 9, 2024
09fca2c
Add append TF tests
sdahdah Dec 9, 2024
aafaa06
Make append() return type of first argument
sdahdah Dec 13, 2024
4cf26b5
Implement transfer function __mul__ dimension promotion
sdahdah Dec 13, 2024
0f59701
Implement TF __rmul__
sdahdah Dec 13, 2024
7aaf355
Add TF __truediv__ and __rtruediv__
sdahdah Dec 13, 2024
3cea5c5
Add __mul__, __rmul__, __truediv__, and __rtruediv__ tests
sdahdah Dec 13, 2024
7dcf256
Rename promoted_self to self
sdahdah Dec 13, 2024
8212a86
Change way bdalg is imported to avoid circular import and add broadca…
sdahdah Dec 13, 2024
525e245
Add failing unit test
sdahdah Dec 13, 2024
cf5a0ab
Implement SS __rmul__ and add __mul__ unit tests
sdahdah Dec 16, 2024
7de9715
Add pow, truediv, and rtruediv
sdahdah Dec 18, 2024
76f9c9f
Fix type conversion error
sdahdah Dec 18, 2024
5636061
Add more truediv and rtruediv tests
sdahdah Dec 18, 2024
a5fe1c1
Add __mul__ and __rmul__ for frdata
sdahdah Dec 19, 2024
cda9afe
Add more __mul__ and __rmul__ frd tests
sdahdah Dec 19, 2024
bbf605d
Add MIMO-SISO truediv and rtruediv
sdahdah Dec 19, 2024
508bc8b
Add MIMO-SISO add for TF
sdahdah Dec 19, 2024
021e34c
Add TF add, sub, radd, rsub tests
sdahdah Dec 19, 2024
4f6fab7
Add SS SISO MIMO add, sub, radd, rsub tests
sdahdah Dec 19, 2024
e0c86a3
Add FRD add promotion
sdahdah Dec 19, 2024
a4afa39
Add FRD add, sub, radd, rsub tests
sdahdah Dec 19, 2024
3e82260
Merge branch 'main' into main
sdahdah Dec 19, 2024
e5358df
Remove randomized state-space matrices
sdahdah Dec 19, 2024
123914b
Add slycotonly to tests
sdahdah Dec 19, 2024
0de8c28
Add split_tf and combine_tf to docs
sdahdah Dec 19, 2024
ff63613
Replace control with ct to fix doctests
sdahdah Dec 19, 2024
bf7f40d
Remove line breaks messing up doctest
sdahdah Dec 19, 2024
612d19b
Fix combine_tf docstring typo
sdahdah Dec 20, 2024
d9a28e5
Merge branch 'main' of github.com:python-control/python-control
sdahdah Jan 17, 2025
e89a727
Use new _ifunc instead of ifunc
sdahdah Jan 17, 2025
2b59fab
Fix typos in docstrings
sdahdah Jan 17, 2025
4a1e034
Adjust indentation style mismatch
sdahdah Jan 17, 2025
9a03dd2
Change some tests to SS comparison instead of TF
sdahdah Jan 17, 2025
ce2f2aa
Get rid of redundant check
sdahdah Jan 17, 2025
ccf9ce1
Update docstring hashes
sdahdah Jan 17, 2025
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
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)
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)
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)
other = _convert_to_transfer_function(np.eye(self.ninputs) * other)
else:
other = _convert_to_transfer_function(other)

Expand Down