GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Switch LTI class and subclasses to use ninputs, noutputs, nstates by murrayrm · Pull Request #515 · python-control/python-control

Switch LTI class and subclasses to use ninputs, noutputs, nstates #515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Sign up for GitHub

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
bnavigator merged 4 commits into python-control:master from murrayrm:input_output_to_ninput_noutput
Jan 24, 2021

Uh oh!

There was an error while loading. Please reload this page.

Merged

Switch LTI class and subclasses to use ninputs, noutputs, nstates #515

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
4 commits
Select commit Hold shift + click to select a range
5a4c3ab
convert inputs, outputs, ... to ninputs... w/ getter/setter warning
murrayrm Jan 20, 2021
9d469f1
update getter/setter comments to match code
murrayrm Jan 21, 2021
f633874
add unit test for input/output/state deprecation warning
murrayrm Jan 22, 2021
eb401a9
fix up deprecation warnings in response to @bnavigator review
murrayrm Jan 24, 2021
File filter
Filter by extension

Clear filters
Conversations
Failed to load comments.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Jump to
Jump to file
Failed to load files.
Loading

Uh oh!

There was an error while loading. Please reload this page.

Diff view
Diff view

There are no files selected for viewing

16 changes: 8 additions & 8 deletions 16 control/bdalg.py
Show comments
View file
Open in desktop
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 @@ -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 14 control/canonical.py
Show comments
View file
Open in desktop
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 54 control/frdata.py
Show comments
View file
Open in desktop
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 6 control/freqplot.py
Show comments
View file
Open in desktop
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 22 control/iosys.py
Show comments
View file
Open in desktop
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
48 changes: 42 additions & 6 deletions 48 control/lti.py
Show comments
View file
Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,46 @@ def __init__(self, inputs=1, outputs=1, dt=None):
"""Assign the LTI object's numbers of inputs and ouputs."""

# Data members common to StateSpace and TransferFunction.
self.inputs = inputs
self.outputs = outputs
self.ninputs = inputs
self.noutputs = outputs
self.dt = dt

#
# Getter and setter functions for legacy state attributes
#
# For this iteration, generate a deprecation warning whenever the
# getter/setter is called. For a future iteration, turn it into a
# future warning, so that users will see it.
#

@property
def inputs(self):
warn("The LTI `inputs` attribute will be deprecated in a future "
"release. Use `ninputs` instead.",
DeprecationWarning, stacklevel=2)
return self.ninputs

@inputs.setter
def inputs(self, value):
warn("The LTI `inputs` attribute will be deprecated in a future "
"release. Use `ninputs` instead.",
DeprecationWarning, stacklevel=2)
self.ninputs = value

@property
def outputs(self):
warn("The LTI `outputs` attribute will be deprecated in a future "
"release. Use `noutputs` instead.",
DeprecationWarning, stacklevel=2)
return self.noutputs

@outputs.setter
def outputs(self, value):
warn("The LTI `outputs` attribute will be deprecated in a future "
"release. Use `noutputs` instead.",
DeprecationWarning, stacklevel=2)
self.noutputs = value

def isdtime(self, strict=False):
"""
Check to see if a system is a discrete-time system
Expand Down Expand Up @@ -88,7 +124,7 @@ def isctime(self, strict=False):

def issiso(self):
'''Check to see if a system is single input, single output'''
return self.inputs == 1 and self.outputs == 1
return self.ninputs == 1 and self.noutputs == 1

def damp(self):
'''Natural frequency, damping ratio of system poles
Expand Down Expand Up @@ -126,7 +162,7 @@ def frequency_response(self, omega, squeeze=None):
G(exp(j*omega*dt)) = mag*exp(j*phase).

In general the system may be multiple input, multiple output (MIMO),
where `m = self.inputs` number of inputs and `p = self.outputs` number
where `m = self.ninputs` number of inputs and `p = self.noutputs` number
of outputs.

Parameters
Expand Down Expand Up @@ -475,7 +511,7 @@ def evalfr(sys, x, squeeze=None):

Returns the complex frequency response `sys(x)` where `x` is `s` for
continuous-time systems and `z` for discrete-time systems, 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 @@ -532,7 +568,7 @@ def freqresp(sys, omega, squeeze=None):
"""Frequency response of an LTI system at multiple angular frequencies.

In general the system may be multiple input, multiple output (MIMO), where
`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.

Parameters
Expand Down
Loading
Oops, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Add this suggestion to a batch that can be applied as a single commit. This suggestion is invalid because no changes were made to the code. Suggestions cannot be applied while the pull request is closed. Suggestions cannot be applied while viewing a subset of changes. Only one suggestion per line can be applied in a batch. Add this suggestion to a batch that can be applied as a single commit. Applying suggestions on deleted lines is not supported. You must change the existing code in this line in order to create a valid suggestion. Outdated suggestions cannot be applied. This suggestion has been applied or marked resolved. Suggestions cannot be applied from pending reviews. Suggestions cannot be applied on multi-line comments. Suggestions cannot be applied while the pull request is queued to merge. Suggestion cannot be applied right now. Please check back later.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.