Skip to content

Commit 2fd3802

Browse files
committed
document and fix {input,output,state}_prefix parameters
1 parent 237e5ef commit 2fd3802

File tree

7 files changed

+105
-23
lines changed

7 files changed

+105
-23
lines changed

control/flatsys/flatsys.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,12 @@ def flatsys(*args, updfcn=None, outfcn=None, **kwargs):
236236
sys: :class:`FlatSystem`
237237
Flat system.
238238
239+
Other Parameters
240+
----------------
241+
input_prefix, output_prefix, state_prefix : string, optional
242+
Set the prefix for input, output, and state signals. Defaults =
243+
'u', 'y', 'x'.
244+
239245
"""
240246
from .linflat import LinearFlatSystem
241247
from ..statesp import StateSpace

control/frdata.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -298,9 +298,9 @@ def __init__(self, *args, **kwargs):
298298

299299
# Process signal names
300300
name, inputs, outputs, states, dt = _process_iosys_keywords(
301-
kwargs, defaults, end=True)
301+
kwargs, defaults)
302302
InputOutputSystem.__init__(
303-
self, name=name, inputs=inputs, outputs=outputs, dt=dt)
303+
self, name=name, inputs=inputs, outputs=outputs, dt=dt, **kwargs)
304304

305305
# create interpolation functions
306306
if smooth:
@@ -1008,6 +1008,8 @@ def frd(*args, **kwargs):
10081008
List of strings that name the individual signals of the transformed
10091009
system. If not given, the inputs and outputs are the same as the
10101010
original system.
1011+
input_prefix, output_prefix : string, optional
1012+
Set the prefix for input and output signals. Defaults = 'u', 'y'.
10111013
name : string, optional
10121014
System name. If unspecified, a generic name <sys[id]> is generated
10131015
with a unique integer id.

control/nlsys.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1285,6 +1285,12 @@ def nlsys(updfcn, outfcn=None, **kwargs):
12851285
sys : :class:`NonlinearIOSystem`
12861286
Nonlinear input/output system.
12871287
1288+
Other Parameters
1289+
----------------
1290+
input_prefix, output_prefix, state_prefix : string, optional
1291+
Set the prefix for input, output, and state signals. Defaults =
1292+
'u', 'y', 'x'.
1293+
12881294
See Also
12891295
--------
12901296
ss, tf

control/statesp.py

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1591,14 +1591,6 @@ def ss(*args, **kwargs):
15911591
time, positive number is discrete time with specified
15921592
sampling time, None indicates unspecified timebase (either
15931593
continuous or discrete time).
1594-
inputs, outputs, states : str, or list of str, optional
1595-
List of strings that name the individual signals. If this parameter
1596-
is not given or given as `None`, the signal names will be of the
1597-
form `s[i]` (where `s` is one of `u`, `y`, or `x`). See
1598-
:class:`InputOutputSystem` for more information.
1599-
name : string, optional
1600-
System name (used for specifying signals). If unspecified, a generic
1601-
name <sys[id]> is generated with a unique integer id.
16021594
remove_useless_states : bool, optional
16031595
If `True`, remove states that have no effect on the input/output
16041596
dynamics. If not specified, the value is read from
@@ -1613,6 +1605,20 @@ def ss(*args, **kwargs):
16131605
out: StateSpace
16141606
Linear input/output system.
16151607
1608+
Other Parameters
1609+
----------------
1610+
inputs, outputs, states : str, or list of str, optional
1611+
List of strings that name the individual signals. If this parameter
1612+
is not given or given as `None`, the signal names will be of the
1613+
form `s[i]` (where `s` is one of `u`, `y`, or `x`). See
1614+
:class:`InputOutputSystem` for more information.
1615+
input_prefix, output_prefix, state_prefix : string, optional
1616+
Set the prefix for input, output, and state signals. Defaults =
1617+
'u', 'y', 'x'.
1618+
name : string, optional
1619+
System name (used for specifying signals). If unspecified, a generic
1620+
name <sys[id]> is generated with a unique integer id.
1621+
16161622
Raises
16171623
------
16181624
ValueError

control/tests/docstrings_test.py

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,13 @@ def test_deprecated_functions(module, prefix):
281281
ct.TransferFunction: ct.tf,
282282
}
283283

284+
#
284285
# List of arguments described in class docstrings
286+
#
287+
# These are the minimal arguments needed to initialized the class. Optional
288+
# arguments should be documented in the factory functions and do not need
289+
# to be duplicated in the class documentation.
290+
#
285291
class_args = {
286292
fs.FlatSystem: ['forward', 'reverse'],
287293
ct.FrequencyResponseData: ['response', 'omega', 'dt'],
@@ -291,15 +297,27 @@ def test_deprecated_functions(module, prefix):
291297
ct.TransferFunction: ['num', 'den', 'dt'],
292298
}
293299

294-
# List of attributes defined for all I/O systems
300+
#
301+
# List of attributes described in class docstrings
302+
#
303+
# This is the list of attributes for the class that are not already listed
304+
# as parameters used to inialize the class. These should all be defined
305+
# in the class docstring.
306+
#
307+
# Attributes that are part of all I/O system classes should be listed in
308+
# `std_class_attributes`. Attributes that are not commonly needed are
309+
# defined as part of a parent class can just be documented there, and
310+
# should be listed in `iosys_parent_attributes` (these will be searched
311+
# using the MRO).
312+
295313
std_class_attributes = [
296314
'ninputs', 'noutputs', 'input_labels', 'output_labels', 'name', 'shape']
297315

298316
# List of attributes defined for specific I/O systems
299317
class_attributes = {
300318
fs.FlatSystem: [],
301319
ct.FrequencyResponseData: [],
302-
ct.NonlinearIOSystem: [],
320+
ct.NonlinearIOSystem: ['nstates', 'state_labels'],
303321
ct.StateSpace: ['nstates', 'state_labels'],
304322
ct.TransferFunction: [],
305323
}
@@ -312,13 +330,22 @@ def test_deprecated_functions(module, prefix):
312330
'params', 'outfcn', 'updfcn' # NL I/O, SS overlap
313331
]
314332

333+
#
315334
# List of arguments described (only) in factory function docstrings
316-
std_factory_args = ['inputs', 'outputs', 'name']
335+
#
336+
# These lists consist of the arguments that should be documented in the
337+
# factory functions and should not be duplicated in the class
338+
# documentation, even though in some cases they are actually processed in
339+
# the class __init__ function.
340+
#
341+
std_factory_args = [
342+
'inputs', 'outputs', 'name', 'input_prefix', 'output_prefix']
343+
317344
factory_args = {
318-
fs.flatsys: [],
345+
fs.flatsys: ['states', 'state_prefix'],
319346
ct.frd: ['sys'],
320-
ct.nlsys: [],
321-
ct.ss: ['sys', 'states'],
347+
ct.nlsys: ['state_prefix'],
348+
ct.ss: ['sys', 'states', 'state_prefix'],
322349
ct.tf: ['sys'],
323350
}
324351

@@ -343,7 +370,7 @@ def test_iosys_primary_classes(cls, fcn, args):
343370
f"{cls.__name__} does not reference factory function "
344371
f"{fcn.__name__}")
345372

346-
# Make sure we don't reference parameters in the factory function
373+
# Make sure we don't reference parameters from the factory function
347374
for argname in factory_args[fcn]:
348375
if re.search(f"[\\s]+{argname}(, .*)*[\\s]*:", docstring) is not None:
349376
pytest.fail(
@@ -448,7 +475,7 @@ def test_iosys_factory_functions(fcn):
448475
list(class_factory_function.values()).index(fcn)]
449476

450477
# Make sure we reference parameters in class and factory function docstring
451-
for argname in class_args[cls] + factory_args[fcn]:
478+
for argname in class_args[cls] + std_factory_args + factory_args[fcn]:
452479
_check_parameter_docs(fcn.__name__, argname, docstring)
453480

454481
# Make sure we don't reference any class attributes
@@ -516,4 +543,3 @@ def _check_parameter_docs(
516543
pytest.fail(f"{funcname} '{argname}' documented twice")
517544

518545
return True
519-

control/tests/iosys_test.py

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2341,7 +2341,7 @@ def test_loadable_system_repr(fcn, spec, expected, missing, format):
23412341
assert out == iosys_expected
23422342
else:
23432343
assert re.search(expected, out) != None
2344-
2344+
23452345
# Now set the format to the given type and make sure things look right
23462346
sys.repr_format = format
23472347
out = repr(sys)
@@ -2377,3 +2377,37 @@ def test_relabeling(fcn):
23772377
if sys.nstates:
23782378
assert sys.state_labels == ['x']
23792379
assert sys.name == 'new'
2380+
2381+
2382+
@pytest.mark.parametrize("fcn", [ct.ss, ct.tf, ct.frd, ct.nlsys, fs.flatsys])
2383+
def test_signal_prefixing(fcn):
2384+
sys = ct.rss(2, 1, 1)
2385+
2386+
# Recreate the system in different forms, with non-standard prefixes
2387+
match fcn:
2388+
case ct.ss:
2389+
sys = ct.ss(
2390+
sys.A, sys.B, sys.C, sys.D, state_prefix='xx',
2391+
input_prefix='uu', output_prefix='yy')
2392+
case ct.tf:
2393+
sys = ct.tf(sys)
2394+
sys = fcn(sys.num, sys.den, input_prefix='uu', output_prefix='yy')
2395+
case ct.frd:
2396+
freq = [0.1, 1, 10]
2397+
data = [sys(w * 1j) for w in freq]
2398+
sys = fcn(data, freq, input_prefix='uu', output_prefix='yy')
2399+
case ct.nlsys:
2400+
sys = ct.nlsys(sys)
2401+
sys = fcn(
2402+
sys.updfcn, sys.outfcn, inputs=1, outputs=1, states=2,
2403+
state_prefix='xx', input_prefix='uu', output_prefix='yy')
2404+
case fs.flatsys:
2405+
sys = fs.flatsys(sys)
2406+
sys = fcn(
2407+
sys.forward, sys.reverse, inputs=1, outputs=1, states=2,
2408+
state_prefix='xx', input_prefix='uu', output_prefix='yy')
2409+
2410+
assert sys.input_labels == ['uu[0]']
2411+
assert sys.output_labels == ['yy[0]']
2412+
if sys.nstates:
2413+
assert sys.state_labels == ['xx[0]', 'xx[1]']

control/xferfcn.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121

2222
import numpy as np
2323
import scipy as sp
24-
from numpy import angle, array, delete, empty, exp, finfo, ndarray, nonzero, \
25-
ones, pi, poly, polyadd, polymul, polyval, real, roots, sqrt, squeeze, \
26-
where, zeros
24+
from numpy import angle, array, delete, empty, exp, finfo, float64, ndarray, \
25+
nonzero, ones, pi, poly, polyadd, polymul, polyval, real, roots, sqrt, \
26+
squeeze, where, zeros
2727
from scipy.signal import TransferFunction as signalTransferFunction
2828
from scipy.signal import cont2discrete, tf2zpk, zpk2tf
2929

@@ -1638,6 +1638,8 @@ def tf(*args, **kwargs):
16381638
List of strings that name the individual signals of the transformed
16391639
system. If not given, the inputs and outputs are the same as the
16401640
original system.
1641+
input_prefix, output_prefix : string, optional
1642+
Set the prefix for input and output signals. Defaults = 'u', 'y'.
16411643
name : string, optional
16421644
System name. If unspecified, a generic name <sys[id]> is generated
16431645
with a unique integer id.

0 commit comments

Comments
 (0)