Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/main' into gh-774
Browse files Browse the repository at this point in the history
  • Loading branch information
bnavigator committed Oct 8, 2022
2 parents c1f1868 + f758725 commit 8aa271d
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 85 deletions.
5 changes: 2 additions & 3 deletions control/iosys.py
Original file line number Diff line number Diff line change
Expand Up @@ -2242,7 +2242,7 @@ def ss(*args, **kwargs):
Convert a linear system into space system form. Always creates a
new system, even if sys is already a state space system.
``ss(updfcn, outfucn)```
``ss(updfcn, outfucn)``
Create a nonlinear input/output system with update function ``updfcn``
and output function ``outfcn``. See :class:`NonlinearIOSystem` for
more information.
Expand All @@ -2269,8 +2269,7 @@ def ss(*args, **kwargs):
Everything that the constructor of :class:`numpy.matrix` accepts is
permissible here too.
``ss(args, inputs=['u1', ..., 'up'], outputs=['y1', ..., 'yq'],
states=['x1', ..., 'xn'])
``ss(args, inputs=['u1', ..., 'up'], outputs=['y1', ..., 'yq'], states=['x1', ..., 'xn'])``
Create a system with named input, output, and state signals.
Parameters
Expand Down
2 changes: 1 addition & 1 deletion control/passivity.py
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ def ispassive(sys, ofp_index=0, ifp_index=0):
guaranteed to have an output of True (the system might not be passive with
both indices at the same time).
For more details, see [1].
For more details, see [1]_.
References
----------
Expand Down
2 changes: 2 additions & 0 deletions control/sisotool.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,8 @@ def rootlocus_pid_designer(plant, gain='P', sign=+1, input_signal='r',
derivative terms are given instead by Kp, Ki*dt/2*(z+1)/(z-1), and
Kd/dt*(z-1)/z, respectively.
::
------> C_ff ------ d
| | |
r | e V V u y
Expand Down
135 changes: 65 additions & 70 deletions control/tests/kwargs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,79 +75,74 @@ def test_kwarg_search(module, prefix):
test_kwarg_search(obj, prefix + obj.__name__ + '.')


@pytest.mark.usefixtures('editsdefaults')
def test_unrecognized_kwargs():
@pytest.mark.parametrize(
"function, nsssys, ntfsys, moreargs, kwargs",
[(control.dlqe, 1, 0, ([[1]], [[1]]), {}),
(control.dlqr, 1, 0, ([[1, 0], [0, 1]], [[1]]), {}),
(control.drss, 0, 0, (2, 1, 1), {}),
(control.input_output_response, 1, 0, ([0, 1, 2], [1, 1, 1]), {}),
(control.lqe, 1, 0, ([[1]], [[1]]), {}),
(control.lqr, 1, 0, ([[1, 0], [0, 1]], [[1]]), {}),
(control.linearize, 1, 0, (0, 0), {}),
(control.pzmap, 1, 0, (), {}),
(control.rlocus, 0, 1, ( ), {}),
(control.root_locus, 0, 1, ( ), {}),
(control.rss, 0, 0, (2, 1, 1), {}),
(control.set_defaults, 0, 0, ('control',), {'default_dt': True}),
(control.ss, 0, 0, (0, 0, 0, 0), {'dt': 1}),
(control.ss2io, 1, 0, (), {}),
(control.ss2tf, 1, 0, (), {}),
(control.summing_junction, 0, 0, (2,), {}),
(control.tf, 0, 0, ([1], [1, 1]), {}),
(control.tf2io, 0, 1, (), {}),
(control.tf2ss, 0, 1, (), {}),
(control.InputOutputSystem, 0, 0, (),
{'inputs': 1, 'outputs': 1, 'states': 1}),
(control.InputOutputSystem.linearize, 1, 0, (0, 0), {}),
(control.StateSpace, 0, 0, ([[-1, 0], [0, -1]], [[1], [1]], [[1, 1]], 0), {}),
(control.TransferFunction, 0, 0, ([1], [1, 1]), {})]
)
def test_unrecognized_kwargs(function, nsssys, ntfsys, moreargs, kwargs,
mplcleanup, editsdefaults):
# Create SISO systems for use in parameterized tests
sssys = control.ss([[-1, 1], [0, -1]], [[0], [1]], [[1, 0]], 0, dt=None)
tfsys = control.tf([1], [1, 1])

args = (sssys, )*nsssys + (tfsys, )*ntfsys + moreargs

# Call the function normally and make sure it works
function(*args, **kwargs)

# Now add an unrecognized keyword and make sure there is an error
with pytest.raises(TypeError, match="unrecognized keyword"):
function(*args, **kwargs, unknown=None)


@pytest.mark.parametrize(
"function, nsysargs, moreargs, kwargs",
[(control.bode, 1, (), {}),
(control.bode_plot, 1, (), {}),
(control.describing_function_plot, 1,
(control.descfcn.saturation_nonlinearity(1), [1, 2, 3, 4]), {}),
(control.gangof4, 2, (), {}),
(control.gangof4_plot, 2, (), {}),
(control.nyquist, 1, (), {}),
(control.nyquist_plot, 1, (), {}),
(control.singular_values_plot, 1, (), {})]
)
def test_matplotlib_kwargs(function, nsysargs, moreargs, kwargs, mplcleanup):
# Create a SISO system for use in parameterized tests
sys = control.ss([[-1, 1], [0, -1]], [[0], [1]], [[1, 0]], 0, dt=None)

table = [
[control.dlqe, (sys, [[1]], [[1]]), {}],
[control.dlqr, (sys, [[1, 0], [0, 1]], [[1]]), {}],
[control.drss, (2, 1, 1), {}],
[control.input_output_response, (sys, [0, 1, 2], [1, 1, 1]), {}],
[control.lqe, (sys, [[1]], [[1]]), {}],
[control.lqr, (sys, [[1, 0], [0, 1]], [[1]]), {}],
[control.linearize, (sys, 0, 0), {}],
[control.pzmap, (sys,), {}],
[control.rlocus, (control.tf([1], [1, 1]), ), {}],
[control.root_locus, (control.tf([1], [1, 1]), ), {}],
[control.rss, (2, 1, 1), {}],
[control.set_defaults, ('control',), {'default_dt': True}],
[control.ss, (0, 0, 0, 0), {'dt': 1}],
[control.ss2io, (sys,), {}],
[control.ss2tf, (sys,), {}],
[control.summing_junction, (2,), {}],
[control.tf, ([1], [1, 1]), {}],
[control.tf2io, (control.tf([1], [1, 1]),), {}],
[control.tf2ss, (control.tf([1], [1, 1]),), {}],
[control.InputOutputSystem, (),
{'inputs': 1, 'outputs': 1, 'states': 1}],
[control.InputOutputSystem.linearize, (sys, 0, 0), {}],
[control.StateSpace, ([[-1, 0], [0, -1]], [[1], [1]], [[1, 1]], 0), {}],
[control.TransferFunction, ([1], [1, 1]), {}],
]

for function, args, kwargs in table:
# Call the function normally and make sure it works
function(*args, **kwargs)

# Now add an unrecognized keyword and make sure there is an error
with pytest.raises(TypeError, match="unrecognized keyword"):
function(*args, **kwargs, unknown=None)

# If we opened any figures, close them to avoid matplotlib warnings
if plt.gca():
plt.close('all')


def test_matplotlib_kwargs():
# Create a SISO system for use in parameterized tests
sys = control.ss([[-1, 1], [0, -1]], [[0], [1]], [[1, 0]], 0, dt=None)
ctl = control.ss([[-1, 1], [0, -1]], [[0], [1]], [[1, 0]], 0, dt=None)

table = [
[control.bode, (sys, ), {}],
[control.bode_plot, (sys, ), {}],
[control.describing_function_plot,
(sys, control.descfcn.saturation_nonlinearity(1), [1, 2, 3, 4]), {}],
[control.gangof4, (sys, ctl), {}],
[control.gangof4_plot, (sys, ctl), {}],
[control.nyquist, (sys, ), {}],
[control.nyquist_plot, (sys, ), {}],
[control.singular_values_plot, (sys, ), {}],
]

for function, args, kwargs in table:
# Call the function normally and make sure it works
function(*args, **kwargs)

# Now add an unrecognized keyword and make sure there is an error
with pytest.raises(AttributeError, match="has no property"):
function(*args, **kwargs, unknown=None)

# If we opened any figures, close them to avoid matplotlib warnings
if plt.gca():
plt.close('all')
# Call the function normally and make sure it works
args = (sys, )*nsysargs + moreargs
function(*args, **kwargs)

# Now add an unrecognized keyword and make sure there is an error
with pytest.raises(AttributeError,
match="(has no property|unexpected keyword)"):
function(*args, **kwargs, unknown=None)



#
Expand Down
17 changes: 7 additions & 10 deletions control/tests/passivity_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
'''
Author: Mark Yeatman
Author: Mark Yeatman
Date: May 30, 2022
'''
import pytest
Expand Down Expand Up @@ -99,20 +99,17 @@ def test_system_dimension():


@pytest.mark.parametrize(
"test_input,expected",
"systemmatrices, expected",
[((A, B, C, D*0.0), True),
((A_d, B, C, D), True),
((A*1e12, B, C, D*0), True),
pytest.param((A*1e12, B, C, D*0), True,
marks=pytest.mark.xfail(reason="gh-761")),
((A, B*0, C*0, D), True),
((A*0, B, C, D), True),
((A*0, B*0, C*0, D*0), True)])
def test_ispassive_edge_cases(test_input, expected):
A = test_input[0]
B = test_input[1]
C = test_input[2]
D = test_input[3]
sys = ss(A, B, C, D)
assert(passivity.ispassive(sys) == expected)
def test_ispassive_edge_cases(systemmatrices, expected):
sys = ss(*systemmatrices)
assert passivity.ispassive(sys) == expected


def test_rho_and_nu_are_none():
Expand Down
2 changes: 1 addition & 1 deletion doc/conventions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ of linear time-invariant (LTI) systems:
where u is the input, y is the output, and x is the state.

To create a state space system, use the :fun:`ss` function:
To create a state space system, use the :func:`ss` function:

sys = ct.ss(A, B, C, D)

Expand Down

0 comments on commit 8aa271d

Please sign in to comment.