5353
5454"""
5555
56+ from functools import reduce
5657import numpy as np
58+ from warnings import warn
5759from . import xferfcn as tf
5860from . import statesp as ss
5961from . import frdata as frd
62+ from .iosys import InputOutputSystem
6063
6164__all__ = ['series' , 'parallel' , 'negate' , 'feedback' , 'append' , 'connect' ]
6265
@@ -68,12 +71,13 @@ def series(sys1, *sysn):
6871
6972 Parameters
7073 ----------
71- sys1 : scalar, StateSpace, TransferFunction, or FRD
72- *sysn : other scalars, StateSpaces, TransferFunctions, or FRDs
74+ sys1, sys2, ..., sysn : scalar, array, or :class:`InputOutputSystem`
75+ I/O systems to combine.
7376
7477 Returns
7578 -------
76- out : scalar, StateSpace, or TransferFunction
79+ out : scalar, array, or :class:`InputOutputSystem`
80+ Series interconnection of the systems.
7781
7882 Raises
7983 ------
@@ -83,14 +87,15 @@ def series(sys1, *sysn):
8387
8488 See Also
8589 --------
86- parallel
87- feedback
90+ append, feedback, interconnect, negate, parallel
8891
8992 Notes
9093 -----
91- This function is a wrapper for the __mul__ function in the StateSpace and
92- TransferFunction classes. The output type is usually the type of `sys2`.
93- If `sys2` is a scalar, then the output type is the type of `sys1`.
94+ This function is a wrapper for the __mul__ function in the appropriate
95+ :class:`NonlinearIOSystem`, :class:`StateSpace`,
96+ :class:`TransferFunction`, or other I/O system class. The output type
97+ is the type of `sys1` unless a more general type is required based on
98+ type type of `sys2`.
9499
95100 If both systems have a defined timebase (dt = 0 for continuous time,
96101 dt > 0 for discrete time), then the timebase for both systems must
@@ -112,8 +117,7 @@ def series(sys1, *sysn):
112117 (2, 1, 5)
113118
114119 """
115- from functools import reduce
116- return reduce (lambda x , y :y * x , sysn , sys1 )
120+ return reduce (lambda x , y : y * x , sysn , sys1 )
117121
118122
119123def parallel (sys1 , * sysn ):
@@ -123,12 +127,13 @@ def parallel(sys1, *sysn):
123127
124128 Parameters
125129 ----------
126- sys1 : scalar, StateSpace, TransferFunction, or FRD
127- *sysn : other scalars, StateSpaces, TransferFunctions, or FRDs
130+ sys1, sys2, ..., sysn : scalar, array, or :class:`InputOutputSystem`
131+ I/O systems to combine.
128132
129133 Returns
130134 -------
131- out : scalar, StateSpace, or TransferFunction
135+ out : scalar, array, or :class:`InputOutputSystem`
136+ Parallel interconnection of the systems.
132137
133138 Raises
134139 ------
@@ -137,8 +142,7 @@ def parallel(sys1, *sysn):
137142
138143 See Also
139144 --------
140- series
141- feedback
145+ append, feedback, interconnect, negate, series
142146
143147 Notes
144148 -----
@@ -167,8 +171,7 @@ def parallel(sys1, *sysn):
167171 (3, 4, 7)
168172
169173 """
170- from functools import reduce
171- return reduce (lambda x , y :x + y , sysn , sys1 )
174+ return reduce (lambda x , y : x + y , sysn , sys1 )
172175
173176
174177def negate (sys ):
@@ -177,17 +180,23 @@ def negate(sys):
177180
178181 Parameters
179182 ----------
180- sys : StateSpace, TransferFunction or FRD
183+ sys: scalar, array, or :class:`InputOutputSystem`
184+ I/O systems to negate.
181185
182186 Returns
183187 -------
184- out : StateSpace or TransferFunction
188+ out : scalar, array, or :class:`InputOutputSystem`
189+ Negated system.
185190
186191 Notes
187192 -----
188193 This function is a wrapper for the __neg__ function in the StateSpace and
189194 TransferFunction classes. The output type is the same as the input type.
190195
196+ See Also
197+ --------
198+ append, feedback, interconnect, parallel, series
199+
191200 Examples
192201 --------
193202 >>> G = ct.tf([2], [1, 1])
@@ -202,24 +211,23 @@ def negate(sys):
202211 return - sys
203212
204213#! TODO: expand to allow sys2 default to work in MIMO case?
214+ #! TODO: allow renaming of signals (for all bdalg operations)
205215def feedback (sys1 , sys2 = 1 , sign = - 1 ):
206- """
207- Feedback interconnection between two I/O systems.
216+ """Feedback interconnection between two I/O systems.
208217
209218 Parameters
210219 ----------
211- sys1 : scalar, StateSpace, TransferFunction, FRD
212- The primary process.
213- sys2 : scalar, StateSpace, TransferFunction, FRD
214- The feedback process (often a feedback controller).
220+ sys1, sys2: scalar, array, or :class:`InputOutputSystem`
221+ I/O systems to combine.
215222 sign: scalar
216223 The sign of feedback. `sign` = -1 indicates negative feedback, and
217224 `sign` = 1 indicates positive feedback. `sign` is an optional
218225 argument; it assumes a value of -1 if not specified.
219226
220227 Returns
221228 -------
222- out : StateSpace or TransferFunction
229+ out : scalar, array, or :class:`InputOutputSystem`
230+ Feedback interconnection of the systems.
223231
224232 Raises
225233 ------
@@ -232,17 +240,14 @@ def feedback(sys1, sys2=1, sign=-1):
232240
233241 See Also
234242 --------
235- series
236- parallel
243+ append, interconnect, negate, parallel, series
237244
238245 Notes
239246 -----
240- This function is a wrapper for the feedback function in the StateSpace and
241- TransferFunction classes. It calls TransferFunction.feedback if `sys1` is a
242- TransferFunction object, and StateSpace.feedback if `sys1` is a StateSpace
243- object. If `sys1` is a scalar, then it is converted to `sys2`'s type, and
244- the corresponding feedback function is used. If `sys1` and `sys2` are both
245- scalars, then TransferFunction.feedback is used.
247+ This function is a wrapper for the `feedback` function in the I/O
248+ system classes. It calls sys1.feedback if `sys1` is an I/O system
249+ object. If `sys1` is a scalar, then it is converted to `sys2`'s type,
250+ and the corresponding feedback function is used.
246251
247252 Examples
248253 --------
@@ -254,57 +259,55 @@ def feedback(sys1, sys2=1, sign=-1):
254259
255260 """
256261 # Allow anything with a feedback function to call that function
262+ # TODO: rewrite to allow __rfeedback__
257263 try :
258264 return sys1 .feedback (sys2 , sign )
259- except AttributeError :
265+ except ( AttributeError , TypeError ) :
260266 pass
261267
262- # Check for correct input types.
263- if not isinstance (sys1 , (int , float , complex , np .number ,
264- tf .TransferFunction , ss .StateSpace , frd .FRD )):
265- raise TypeError ("sys1 must be a TransferFunction, StateSpace " +
266- "or FRD object, or a scalar." )
267- if not isinstance (sys2 , (int , float , complex , np .number ,
268- tf .TransferFunction , ss .StateSpace , frd .FRD )):
269- raise TypeError ("sys2 must be a TransferFunction, StateSpace " +
270- "or FRD object, or a scalar." )
271-
272- # If sys1 is a scalar, convert it to the appropriate LTI type so that we can
273- # its feedback member function.
274- if isinstance (sys1 , (int , float , complex , np .number )):
275- if isinstance (sys2 , tf .TransferFunction ):
268+ # Check for correct input types
269+ if not isinstance (sys1 , (int , float , complex , np .number , np .ndarray ,
270+ InputOutputSystem )):
271+ raise TypeError ("sys1 must be an I/O system, scalar, or array" )
272+ elif not isinstance (sys2 , (int , float , complex , np .number , np .ndarray ,
273+ InputOutputSystem )):
274+ raise TypeError ("sys2 must be an I/O system, scalar, or array" )
275+
276+ # If sys1 is a scalar or ndarray, use the type of sys2 to figure
277+ # out how to convert sys1, using transfer functions whenever possible.
278+ if isinstance (sys1 , (int , float , complex , np .number , np .ndarray )):
279+ if isinstance (sys2 , (int , float , complex , np .number , np .ndarray ,
280+ tf .TransferFunction )):
276281 sys1 = tf ._convert_to_transfer_function (sys1 )
277- elif isinstance (sys2 , ss .StateSpace ):
278- sys1 = ss ._convert_to_statespace (sys1 )
279282 elif isinstance (sys2 , frd .FRD ):
280283 sys1 = frd ._convert_to_FRD (sys1 , sys2 .omega )
281- else : # sys2 is a scalar.
282- sys1 = tf ._convert_to_transfer_function (sys1 )
283- sys2 = tf ._convert_to_transfer_function (sys2 )
284+ else :
285+ sys1 = ss ._convert_to_statespace (sys1 )
284286
285287 return sys1 .feedback (sys2 , sign )
286288
287289def append (* sys ):
288290 """append(sys1, sys2, [..., sysn])
289291
290- Group models by appending their inputs and outputs.
292+ Group LTI state space models by appending their inputs and outputs.
291293
292294 Forms an augmented system model, and appends the inputs and
293- outputs together. The system type will be the type of the first
294- system given; if you mix state-space systems and gain matrices,
295- make sure the gain matrices are not first.
295+ outputs together.
296296
297297 Parameters
298298 ----------
299- sys1, sys2, ..., sysn: StateSpace or TransferFunction
300- LTI systems to combine
301-
299+ sys1, sys2, ..., sysn: scalar, array, or :class:`StateSpace`
300+ I/O systems to combine.
302301
303302 Returns
304303 -------
305- sys: LTI system
306- Combined LTI system, with input/output vectors consisting of all
307- input/output vectors appended
304+ out: :class:`StateSpace`
305+ Combined system, with input/output vectors consisting of all
306+ input/output vectors appended.
307+
308+ See Also
309+ --------
310+ interconnect, feedback, negate, parallel, series
308311
309312 Examples
310313 --------
@@ -329,6 +332,10 @@ def append(*sys):
329332def connect (sys , Q , inputv , outputv ):
330333 """Index-based interconnection of an LTI system.
331334
335+ .. deprecated:: 0.10.0
336+ `connect` will be removed in a future version of python-control in
337+ favor of `interconnect`, which works with named signals.
338+
332339 The system `sys` is a system typically constructed with `append`, with
333340 multiple inputs and outputs. The inputs and outputs are connected
334341 according to the interconnection matrix `Q`, and then the final inputs and
@@ -340,8 +347,8 @@ def connect(sys, Q, inputv, outputv):
340347
341348 Parameters
342349 ----------
343- sys : StateSpace or TransferFunction
344- System to be connected
350+ sys : :class:`InputOutputSystem`
351+ System to be connected.
345352 Q : 2D array
346353 Interconnection matrix. First column gives the input to be connected.
347354 The second column gives the index of an output that is to be fed into
@@ -356,8 +363,12 @@ def connect(sys, Q, inputv, outputv):
356363
357364 Returns
358365 -------
359- sys: LTI system
360- Connected and trimmed LTI system
366+ out : :class:`InputOutputSystem`
367+ Connected and trimmed I/O system.
368+
369+ See Also
370+ --------
371+ append, feedback, interconnect, negate, parallel, series
361372
362373 Examples
363374 --------
@@ -369,12 +380,14 @@ def connect(sys, Q, inputv, outputv):
369380
370381 Notes
371382 -----
372- The :func:`~control.interconnect` function in the
373- :ref:`input/output systems <iosys-module>` module allows the use
374- of named signals and provides an alternative method for
375- interconnecting multiple systems.
383+ The :func:`~control.interconnect` function in the :ref:`input/output
384+ systems <iosys-module>` module allows the use of named signals and
385+ provides an alternative method for interconnecting multiple systems.
376386
377387 """
388+ # TODO: maintain `connect` for use in MATLAB submodule (?)
389+ warn ("`connect` is deprecated; use `interconnect`" , DeprecationWarning )
390+
378391 inputv , outputv , Q = \
379392 np .atleast_1d (inputv ), np .atleast_1d (outputv ), np .atleast_1d (Q )
380393 # check indices
0 commit comments