Skip to content

Commit

Permalink
convert inputs, outputs, ... to ninputs... w/ getter/setter warning
Browse files Browse the repository at this point in the history
  • Loading branch information
murrayrm committed Jan 20, 2021
1 parent 0a08ff2 commit 374c82f
Show file tree
Hide file tree
Showing 20 changed files with 428 additions and 368 deletions.
18 changes: 9 additions & 9 deletions control/bdalg.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ def series(sys1, *sysn):
Raises
------
ValueError
if `sys2.inputs` does not equal `sys1.outputs`
if `sys2.ninputs` does not equal `sys1.noutputs`
if `sys1.dt` is not compatible with `sys2.dt`
See Also
Expand Down Expand Up @@ -199,7 +199,7 @@ def feedback(sys1, sys2=1, sign=-1):
Raises
------
ValueError
if `sys1` does not have as many inputs as `sys2` has outputs, or if
if `sys1` does not have as many inputsg as `sys2` has outputs, or if
`sys2` does not have as many inputs as `sys1` has outputs
NotImplementedError
if an attempt is made to perform a feedback on a MIMO TransferFunction
Expand Down Expand Up @@ -336,25 +336,25 @@ def connect(sys, Q, inputv, outputv):
"""
inputv, outputv, Q = np.asarray(inputv), np.asarray(outputv), np.asarray(Q)
# check indices
index_errors = (inputv - 1 > sys.inputs) | (inputv < 1)
index_errors = (inputv - 1 > sys.ninputs) | (inputv < 1)
if np.any(index_errors):
raise IndexError(
"inputv index %s out of bounds" % inputv[np.where(index_errors)])
index_errors = (outputv - 1 > sys.outputs) | (outputv < 1)
index_errors = (outputv - 1 > sys.noutputs) | (outputv < 1)
if np.any(index_errors):
raise IndexError(
"outputv index %s out of bounds" % outputv[np.where(index_errors)])
index_errors = (Q[:,0:1] - 1 > sys.inputs) | (Q[:,0:1] < 1)
index_errors = (Q[:,0:1] - 1 > sys.ninputs) | (Q[:,0:1] < 1)
if np.any(index_errors):
raise IndexError(
"Q input index %s out of bounds" % Q[np.where(index_errors)])
index_errors = (np.abs(Q[:,1:]) - 1 > sys.outputs)
index_errors = (np.abs(Q[:,1:]) - 1 > sys.noutputs)
if np.any(index_errors):
raise IndexError(
"Q output index %s out of bounds" % Q[np.where(index_errors)])

# first connect
K = np.zeros((sys.inputs, sys.outputs))
K = np.zeros((sys.ninputs, sys.noutputs))
for r in np.array(Q).astype(int):
inp = r[0]-1
for outp in r[1:]:
Expand All @@ -365,8 +365,8 @@ def connect(sys, Q, inputv, outputv):
sys = sys.feedback(np.array(K), sign=1)

# now trim
Ytrim = np.zeros((len(outputv), sys.outputs))
Utrim = np.zeros((sys.inputs, len(inputv)))
Ytrim = np.zeros((len(outputv), sys.noutputs))
Utrim = np.zeros((sys.ninputs, len(inputv)))
for i,u in enumerate(inputv):
Utrim[u-1,i] = 1.
for i,y in enumerate(outputv):
Expand Down
14 changes: 7 additions & 7 deletions control/canonical.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,24 +79,24 @@ def reachable_form(xsys):
zsys.B[0, 0] = 1.0
zsys.A = zeros_like(xsys.A)
Apoly = poly(xsys.A) # characteristic polynomial
for i in range(0, xsys.states):
for i in range(0, xsys.nstates):
zsys.A[0, i] = -Apoly[i+1] / Apoly[0]
if (i+1 < xsys.states):
if (i+1 < xsys.nstates):
zsys.A[i+1, i] = 1.0

# Compute the reachability matrices for each set of states
Wrx = ctrb(xsys.A, xsys.B)
Wrz = ctrb(zsys.A, zsys.B)

if matrix_rank(Wrx) != xsys.states:
if matrix_rank(Wrx) != xsys.nstates:
raise ValueError("System not controllable to working precision.")

# Transformation from one form to another
Tzx = solve(Wrx.T, Wrz.T).T # matrix right division, Tzx = Wrz * inv(Wrx)

# Check to make sure inversion was OK. Note that since we are inverting
# Wrx and we already checked its rank, this exception should never occur
if matrix_rank(Tzx) != xsys.states: # pragma: no cover
if matrix_rank(Tzx) != xsys.nstates: # pragma: no cover
raise ValueError("Transformation matrix singular to working precision.")

# Finally, compute the output matrix
Expand Down Expand Up @@ -133,9 +133,9 @@ def observable_form(xsys):
zsys.C[0, 0] = 1
zsys.A = zeros_like(xsys.A)
Apoly = poly(xsys.A) # characteristic polynomial
for i in range(0, xsys.states):
for i in range(0, xsys.nstates):
zsys.A[i, 0] = -Apoly[i+1] / Apoly[0]
if (i+1 < xsys.states):
if (i+1 < xsys.nstates):
zsys.A[i, i+1] = 1

# Compute the observability matrices for each set of states
Expand All @@ -145,7 +145,7 @@ def observable_form(xsys):
# Transformation from one form to another
Tzx = solve(Wrz, Wrx) # matrix left division, Tzx = inv(Wrz) * Wrx

if matrix_rank(Tzx) != xsys.states:
if matrix_rank(Tzx) != xsys.nstates:
raise ValueError("Transformation matrix singular to working precision.")

# Finally, compute the output matrix
Expand Down
54 changes: 27 additions & 27 deletions control/frdata.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,11 +155,11 @@ def __init__(self, *args, **kwargs):
def __str__(self):
"""String representation of the transfer function."""

mimo = self.inputs > 1 or self.outputs > 1
mimo = self.ninputs > 1 or self.noutputs > 1
outstr = ['Frequency response data']

for i in range(self.inputs):
for j in range(self.outputs):
for i in range(self.ninputs):
for j in range(self.noutputs):
if mimo:
outstr.append("Input %i to output %i:" % (i + 1, j + 1))
outstr.append('Freq [rad/s] Response')
Expand Down Expand Up @@ -201,12 +201,12 @@ def __add__(self, other):
other = _convert_to_FRD(other, omega=self.omega)

# Check that the input-output sizes are consistent.
if self.inputs != other.inputs:
if self.ninputs != other.ninputs:
raise ValueError("The first summand has %i input(s), but the \
second has %i." % (self.inputs, other.inputs))
if self.outputs != other.outputs:
second has %i." % (self.ninputs, other.ninputs))
if self.noutputs != other.noutputs:
raise ValueError("The first summand has %i output(s), but the \
second has %i." % (self.outputs, other.outputs))
second has %i." % (self.noutputs, other.noutputs))

return FRD(self.fresp + other.fresp, other.omega)

Expand Down Expand Up @@ -236,14 +236,14 @@ def __mul__(self, other):
other = _convert_to_FRD(other, omega=self.omega)

# Check that the input-output sizes are consistent.
if self.inputs != other.outputs:
if self.ninputs != other.noutputs:
raise ValueError(
"H = G1*G2: input-output size mismatch: "
"G1 has %i input(s), G2 has %i output(s)." %
(self.inputs, other.outputs))
(self.ninputs, other.noutputs))

inputs = other.inputs
outputs = self.outputs
inputs = other.ninputs
outputs = self.noutputs
fresp = empty((outputs, inputs, len(self.omega)),
dtype=self.fresp.dtype)
for i in range(len(self.omega)):
Expand All @@ -263,14 +263,14 @@ def __rmul__(self, other):
other = _convert_to_FRD(other, omega=self.omega)

# Check that the input-output sizes are consistent.
if self.outputs != other.inputs:
if self.noutputs != other.ninputs:
raise ValueError(
"H = G1*G2: input-output size mismatch: "
"G1 has %i input(s), G2 has %i output(s)." %
(other.inputs, self.outputs))
(other.ninputs, self.noutputs))

inputs = self.inputs
outputs = other.outputs
inputs = self.ninputs
outputs = other.noutputs

fresp = empty((outputs, inputs, len(self.omega)),
dtype=self.fresp.dtype)
Expand All @@ -290,8 +290,8 @@ def __truediv__(self, other):
else:
other = _convert_to_FRD(other, omega=self.omega)

if (self.inputs > 1 or self.outputs > 1 or
other.inputs > 1 or other.outputs > 1):
if (self.ninputs > 1 or self.noutputs > 1 or
other.ninputs > 1 or other.noutputs > 1):
raise NotImplementedError(
"FRD.__truediv__ is currently only implemented for SISO "
"systems.")
Expand All @@ -313,8 +313,8 @@ def __rtruediv__(self, other):
else:
other = _convert_to_FRD(other, omega=self.omega)

if (self.inputs > 1 or self.outputs > 1 or
other.inputs > 1 or other.outputs > 1):
if (self.ninputs > 1 or self.noutputs > 1 or
other.ninputs > 1 or other.noutputs > 1):
raise NotImplementedError(
"FRD.__rtruediv__ is currently only implemented for "
"SISO systems.")
Expand Down Expand Up @@ -392,10 +392,10 @@ def eval(self, omega, squeeze=None):
else:
out = self.fresp[:, :, elements]
else:
out = empty((self.outputs, self.inputs, len(omega_array)),
out = empty((self.noutputs, self.ninputs, len(omega_array)),
dtype=complex)
for i in range(self.outputs):
for j in range(self.inputs):
for i in range(self.noutputs):
for j in range(self.ninputs):
for k, w in enumerate(omega_array):
frraw = splev(w, self.ifunc[i, j], der=0)
out[i, j, k] = frraw[0] + 1.0j * frraw[1]
Expand All @@ -406,7 +406,7 @@ def __call__(self, s, squeeze=None):
"""Evaluate system's transfer function at complex frequencies.
Returns the complex frequency response `sys(s)` of system `sys` with
`m = sys.inputs` number of inputs and `p = sys.outputs` number of
`m = sys.ninputs` number of inputs and `p = sys.noutputs` number of
outputs.
To evaluate at a frequency omega in radians per second, enter
Expand Down Expand Up @@ -474,10 +474,10 @@ def feedback(self, other=1, sign=-1):

other = _convert_to_FRD(other, omega=self.omega)

if (self.outputs != other.inputs or self.inputs != other.outputs):
if (self.noutputs != other.ninputs or self.ninputs != other.noutputs):
raise ValueError(
"FRD.feedback, inputs/outputs mismatch")
fresp = empty((self.outputs, self.inputs, len(other.omega)),
fresp = empty((self.noutputs, self.ninputs, len(other.omega)),
dtype=complex)
# TODO: vectorize this
# TODO: handle omega re-mapping
Expand All @@ -487,9 +487,9 @@ def feedback(self, other=1, sign=-1):
fresp[:, :, k] = np.dot(
self.fresp[:, :, k],
linalg.solve(
eye(self.inputs)
eye(self.ninputs)
+ np.dot(other.fresp[:, :, k], self.fresp[:, :, k]),
eye(self.inputs))
eye(self.ninputs))
)

return FRD(fresp, other.omega, smooth=(self.ifunc is not None))
Expand Down
6 changes: 3 additions & 3 deletions control/freqplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ def bode_plot(syslist, omega=None,

mags, phases, omegas, nyquistfrqs = [], [], [], []
for sys in syslist:
if sys.inputs > 1 or sys.outputs > 1:
if sys.ninputs > 1 or sys.noutputs > 1:
# TODO: Add MIMO bode plots.
raise NotImplementedError(
"Bode is currently only implemented for SISO systems.")
Expand Down Expand Up @@ -582,7 +582,7 @@ def nyquist_plot(syslist, omega=None, plot=True, label_freq=0,
num=50, endpoint=True, base=10.0)

for sys in syslist:
if sys.inputs > 1 or sys.outputs > 1:
if sys.ninputs > 1 or sys.noutputs > 1:
# TODO: Add MIMO nyquist plots.
raise NotImplementedError(
"Nyquist is currently only implemented for SISO systems.")
Expand Down Expand Up @@ -672,7 +672,7 @@ def gangof4_plot(P, C, omega=None, **kwargs):
-------
None
"""
if P.inputs > 1 or P.outputs > 1 or C.inputs > 1 or C.outputs > 1:
if P.ninputs > 1 or P.noutputs > 1 or C.ninputs > 1 or C.noutputs > 1:
# TODO: Add MIMO go4 plots.
raise NotImplementedError(
"Gang of four is currently only implemented for SISO systems.")
Expand Down
22 changes: 11 additions & 11 deletions control/iosys.py
Original file line number Diff line number Diff line change
Expand Up @@ -659,25 +659,25 @@ def __init__(self, linsys, inputs=None, outputs=None, states=None,

# Create the I/O system object
super(LinearIOSystem, self).__init__(
inputs=linsys.inputs, outputs=linsys.outputs,
states=linsys.states, params={}, dt=linsys.dt, name=name)
inputs=linsys.ninputs, outputs=linsys.noutputs,
states=linsys.nstates, params={}, dt=linsys.dt, name=name)

# Initalize additional state space variables
StateSpace.__init__(self, linsys, remove_useless=False)

# Process input, output, state lists, if given
# Make sure they match the size of the linear system
ninputs, self.input_index = self._process_signal_list(
inputs if inputs is not None else linsys.inputs, prefix='u')
if ninputs is not None and linsys.inputs != ninputs:
inputs if inputs is not None else linsys.ninputs, prefix='u')
if ninputs is not None and linsys.ninputs != ninputs:
raise ValueError("Wrong number/type of inputs given.")
noutputs, self.output_index = self._process_signal_list(
outputs if outputs is not None else linsys.outputs, prefix='y')
if noutputs is not None and linsys.outputs != noutputs:
outputs if outputs is not None else linsys.noutputs, prefix='y')
if noutputs is not None and linsys.noutputs != noutputs:
raise ValueError("Wrong number/type of outputs given.")
nstates, self.state_index = self._process_signal_list(
states if states is not None else linsys.states, prefix='x')
if nstates is not None and linsys.states != nstates:
states if states is not None else linsys.nstates, prefix='x')
if nstates is not None and linsys.nstates != nstates:
raise ValueError("Wrong number/type of states given.")

def _update_params(self, params={}, warning=True):
Expand Down Expand Up @@ -1345,9 +1345,9 @@ def __init__(self, io_sys, ss_sys=None):
# Initialize the state space attributes
if isinstance(ss_sys, StateSpace):
# Make sure the dimension match
if io_sys.ninputs != ss_sys.inputs or \
io_sys.noutputs != ss_sys.outputs or \
io_sys.nstates != ss_sys.states:
if io_sys.ninputs != ss_sys.ninputs or \
io_sys.noutputs != ss_sys.noutputs or \
io_sys.nstates != ss_sys.nstates:
raise ValueError("System dimensions for first and second "
"arguments must match.")
StateSpace.__init__(self, ss_sys, remove_useless=False)
Expand Down

0 comments on commit 374c82f

Please sign in to comment.