Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

TransferFunction array priority plus system type conversion checking#498

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.

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

Already on GitHub?Sign in to your account

Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
12 commits
Select commitHold shift + click to select a range
bb8132e
dev instructions
sawyerbfullerDec 21, 2020
51612df
Merge branch 'master' of https://github.com/sawyerbfuller/python-control
murrayrmJan 6, 2021
4ad565f
Merge branch 'call-method' of https://github.com/sawyerbfuller/python…
murrayrmJan 7, 2021
85c9e7f
Merge branch 'master' of https://github.com/python-control/python-con…
murrayrmJan 8, 2021
8793d78
set array_priority=11 for TransferFunction, to match StateSpace
murrayrmJan 3, 2021
bd77d71
update _convert_to_transfer_function to allow 0D and 1D arrays
murrayrmJan 3, 2021
4b7bf8a
rename _convertToX to _convert_to_x + statesp/ndarray unit tests
murrayrmJan 3, 2021
94b6209
fix converstion exceptions to be TypeError
murrayrmJan 4, 2021
67a0561
add unit tests for checking type converstions
murrayrmJan 4, 2021
4a24c84
update LinearIOSystem.__rmul__ for Python2/Python3 consistency
murrayrmJan 4, 2021
f0593fa
add (skipped) function for desired binary operator conversions
murrayrmJan 5, 2021
e910c22
Update control/tests/type_conversion_test.py
murrayrmJan 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletionscontrol/bdalg.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -242,9 +242,9 @@ def feedback(sys1, sys2=1, sign=-1):
if isinstance(sys2, tf.TransferFunction):
sys1 = tf._convert_to_transfer_function(sys1)
elif isinstance(sys2, ss.StateSpace):
sys1 = ss._convertToStateSpace(sys1)
sys1 = ss._convert_to_statespace(sys1)
elif isinstance(sys2, frd.FRD):
sys1 = frd._convertToFRD(sys1, sys2.omega)
sys1 = frd._convert_to_FRD(sys1, sys2.omega)
else: # sys2 is a scalar.
sys1 = tf._convert_to_transfer_function(sys1)
sys2 = tf._convert_to_transfer_function(sys2)
Expand Down
2 changes: 1 addition & 1 deletioncontrol/dtime.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -47,7 +47,7 @@
"""

from .lti import isctime
from .statesp import StateSpace, _convertToStateSpace
from .statesp import StateSpace

__all__ = ['sample_system', 'c2d']

Expand Down
18 changes: 9 additions & 9 deletionscontrol/frdata.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -197,7 +197,7 @@ def __add__(self, other):

# Convert the second argument to a frequency response function.
# or re-base the frd to the current omega (if needed)
other =_convertToFRD(other, omega=self.omega)
other =_convert_to_FRD(other, omega=self.omega)

# Check that the input-output sizes are consistent.
if self.inputs != other.inputs:
Expand DownExpand Up@@ -232,7 +232,7 @@ def __mul__(self, other):
return FRD(self.fresp * other, self.omega,
smooth=(self.ifunc is not None))
else:
other =_convertToFRD(other, omega=self.omega)
other =_convert_to_FRD(other, omega=self.omega)

# Check that the input-output sizes are consistent.
if self.inputs != other.outputs:
Expand All@@ -259,7 +259,7 @@ def __rmul__(self, other):
return FRD(self.fresp * other, self.omega,
smooth=(self.ifunc is not None))
else:
other =_convertToFRD(other, omega=self.omega)
other =_convert_to_FRD(other, omega=self.omega)

# Check that the input-output sizes are consistent.
if self.outputs != other.inputs:
Expand DownExpand Up@@ -287,7 +287,7 @@ def __truediv__(self, other):
return FRD(self.fresp * (1/other), self.omega,
smooth=(self.ifunc is not None))
else:
other =_convertToFRD(other, omega=self.omega)
other =_convert_to_FRD(other, omega=self.omega)

if (self.inputs > 1 or self.outputs > 1 or
other.inputs > 1 or other.outputs > 1):
Expand All@@ -310,7 +310,7 @@ def __rtruediv__(self, other):
return FRD(other / self.fresp, self.omega,
smooth=(self.ifunc is not None))
else:
other =_convertToFRD(other, omega=self.omega)
other =_convert_to_FRD(other, omega=self.omega)

if (self.inputs > 1 or self.outputs > 1 or
other.inputs > 1 or other.outputs > 1):
Expand DownExpand Up@@ -450,7 +450,7 @@ def freqresp(self, omega):
def feedback(self, other=1, sign=-1):
"""Feedback interconnection between two FRD objects."""

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

if (self.outputs != other.inputs or self.inputs != other.outputs):
raise ValueError(
Expand DownExpand Up@@ -486,7 +486,7 @@ def feedback(self, other=1, sign=-1):
FRD = FrequencyResponseData


def_convertToFRD(sys, omega, inputs=1, outputs=1):
def_convert_to_FRD(sys, omega, inputs=1, outputs=1):
"""Convert a system to frequency response data form (if needed).

If sys is already an frd, and its frequency range matches or
Expand All@@ -496,8 +496,8 @@ def _convertToFRD(sys, omega, inputs=1, outputs=1):
scalar, then the number of inputs and outputs can be specified
manually, as in:

>>> frd =_convertToFRD(3., omega) # Assumes inputs = outputs = 1
>>> frd =_convertToFRD(1., omegs, inputs=3, outputs=2)
>>> frd =_convert_to_FRD(3., omega) # Assumes inputs = outputs = 1
>>> frd =_convert_to_FRD(1., omegs, inputs=3, outputs=2)

In the latter example, sys's matrix transfer function is [[1., 1., 1.]
[1., 1., 1.]].
Expand Down
18 changes: 11 additions & 7 deletionscontrol/iosys.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -220,7 +220,7 @@ def __mul__(sys2, sys1):
raise NotImplemented("Matrix multiplication not yet implemented")

elif not isinstance(sys1, InputOutputSystem):
raiseValueError("Unknown I/O system object ", sys1)
raiseTypeError("Unknown I/O system object ", sys1)

# Make sure systems can be interconnected
if sys1.noutputs != sys2.ninputs:
Expand DownExpand Up@@ -254,20 +254,24 @@ def __mul__(sys2, sys1):

def __rmul__(sys1, sys2):
"""Pre-multiply an input/output systems by a scalar/matrix"""
if isinstance(sys2, (int, float, np.number)):
if isinstance(sys2, InputOutputSystem):
# Both systems are InputOutputSystems => use __mul__
return InputOutputSystem.__mul__(sys2, sys1)

elif isinstance(sys2, (int, float, np.number)):
# TODO: Scale the output
raise NotImplemented("Scalar multiplication not yet implemented")

elif isinstance(sys2, np.ndarray):
# TODO: Post-multiply by a matrix
raise NotImplemented("Matrix multiplication not yet implemented")

elif not isinstance(sys2, InputOutputSystem):
raise ValueError("Unknown I/O system object ", sys1)
elif isinstance(sys2, StateSpace):
# TODO: Should eventuall preserve LinearIOSystem structure
return StateSpace.__mul__(sys2, sys1)

else:
# Both systems are InputOutputSystems => use __mul__
return InputOutputSystem.__mul__(sys2, sys1)
raise TypeError("Unknown I/O system object ", sys1)

def __add__(sys1, sys2):
"""Add two input/output systems (parallel interconnection)"""
Expand All@@ -281,7 +285,7 @@ def __add__(sys1, sys2):
raise NotImplemented("Matrix addition not yet implemented")

elif not isinstance(sys2, InputOutputSystem):
raiseValueError("Unknown I/O system object ", sys2)
raiseTypeError("Unknown I/O system object ", sys2)

# Make sure number of input and outputs match
if sys1.ninputs != sys2.ninputs or sys1.noutputs != sys2.noutputs:
Expand Down
37 changes: 17 additions & 20 deletionscontrol/statesp.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,7 @@

# Python 3 compatibility (needs to go here)
from __future__ import print_function
from __future__ import division # for_convertToStateSpace
from __future__ import division # for_convert_to_statespace

"""Copyright (c) 2010 by California Institute of Technology
All rights reserved.
Expand DownExpand Up@@ -527,7 +527,7 @@ def __add__(self, other):
D = self.D + other
dt = self.dt
else:
other =_convertToStateSpace(other)
other =_convert_to_statespace(other)

# Check to make sure the dimensions are OK
if ((self.inputs != other.inputs) or
Expand DownExpand Up@@ -577,7 +577,7 @@ def __mul__(self, other):
D = self.D * other
dt = self.dt
else:
other =_convertToStateSpace(other)
other =_convert_to_statespace(other)

# Check to make sure the dimensions are OK
if self.inputs != other.outputs:
Expand DownExpand Up@@ -614,7 +614,7 @@ def __rmul__(self, other):

# is lti, and convertible?
if isinstance(other, LTI):
return_convertToStateSpace(other) * self
return_convert_to_statespace(other) * self

# try to treat this as a matrix
try:
Expand DownExpand Up@@ -839,7 +839,7 @@ def zero(self):
def feedback(self, other=1, sign=-1):
"""Feedback interconnection between two LTI systems."""

other =_convertToStateSpace(other)
other =_convert_to_statespace(other)

# Check to make sure the dimensions are OK
if (self.inputs != other.outputs) or (self.outputs != other.inputs):
Expand DownExpand Up@@ -907,7 +907,7 @@ def lft(self, other, nu=-1, ny=-1):
Dimension of (plant) control input.

"""
other =_convertToStateSpace(other)
other =_convert_to_statespace(other)
# maximal values for nu, ny
if ny == -1:
ny = min(other.inputs, self.outputs)
Expand DownExpand Up@@ -1061,7 +1061,7 @@ def append(self, other):
The second model is converted to state-space if necessary, inputs and
outputs are appended and their order is preserved"""
if not isinstance(other, StateSpace):
other =_convertToStateSpace(other)
other =_convert_to_statespace(other)

self.dt = common_timebase(self.dt, other.dt)

Expand DownExpand Up@@ -1186,16 +1186,16 @@ def is_static_gain(self):


# TODO: add discrete time check
def_convertToStateSpace(sys, **kw):
def_convert_to_statespace(sys, **kw):
"""Convert a system to state space form (if needed).

If sys is already a state space, then it is returned. If sys is a
transfer function object, then it is converted to a state space and
returned. If sys is a scalar, then the number of inputs and outputs can
be specified manually, as in:

>>> sys =_convertToStateSpace(3.) # Assumes inputs = outputs = 1
>>> sys =_convertToStateSpace(1., inputs=3, outputs=2)
>>> sys =_convert_to_statespace(3.) # Assumes inputs = outputs = 1
>>> sys =_convert_to_statespace(1., inputs=3, outputs=2)

In the latter example, A = B = C = 0 and D = [[1., 1., 1.]
[1., 1., 1.]].
Expand All@@ -1205,7 +1205,7 @@ def _convertToStateSpace(sys, **kw):

if isinstance(sys, StateSpace):
if len(kw):
raise TypeError("If sys is a StateSpace,_convertToStateSpace "
raise TypeError("If sys is a StateSpace,_convert_to_statespace "
"cannot take keywords.")

# Already a state space system; just return it
Expand All@@ -1221,7 +1221,7 @@ def _convertToStateSpace(sys, **kw):
from slycot import td04ad
if len(kw):
raise TypeError("If sys is a TransferFunction, "
"_convertToStateSpace cannot take keywords.")
"_convert_to_statespace cannot take keywords.")

# Change the numerator and denominator arrays so that the transfer
# function matrix has a common denominator.
Expand DownExpand Up@@ -1281,11 +1281,8 @@ def _convertToStateSpace(sys, **kw):
try:
D = _ssmatrix(sys)
return StateSpace([], [], [], D)
except Exception as e:
print("Failure to assume argument is matrix-like in"
" _convertToStateSpace, result %s" % e)

raise TypeError("Can't convert given type to StateSpace system.")
except:
raise TypeError("Can't convert given type to StateSpace system.")


# TODO: add discrete time option
Expand DownExpand Up@@ -1662,14 +1659,14 @@ def tf2ss(*args):
from .xferfcn import TransferFunction
if len(args) == 2 or len(args) == 3:
# Assume we were given the num, den
return_convertToStateSpace(TransferFunction(*args))
return_convert_to_statespace(TransferFunction(*args))

elif len(args) == 1:
sys = args[0]
if not isinstance(sys, TransferFunction):
raise TypeError("tf2ss(sys): sys must be a TransferFunction "
"object.")
return_convertToStateSpace(sys)
return_convert_to_statespace(sys)
else:
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))

Expand DownExpand Up@@ -1769,5 +1766,5 @@ def ssdata(sys):
(A, B, C, D): list of matrices
State space data for the system
"""
ss =_convertToStateSpace(sys)
ss =_convert_to_statespace(sys)
return ss.A, ss.B, ss.C, ss.D
2 changes: 1 addition & 1 deletioncontrol/tests/bdalg_test.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -255,7 +255,7 @@ def test_feedback_args(self, tsys):
ctrl.feedback(*args)

# If second argument is not LTI or convertable, generate an exception
args = (tsys.sys1,np.array([1]))
args = (tsys.sys1,'hello world')
with pytest.raises(TypeError):
ctrl.feedback(*args)

Expand Down
8 changes: 4 additions & 4 deletionscontrol/tests/frd_test.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -12,7 +12,7 @@
import control as ct
from control.statesp import StateSpace
from control.xferfcn import TransferFunction
from control.frdata import FRD,_convertToFRD, FrequencyResponseData
from control.frdata import FRD,_convert_to_FRD, FrequencyResponseData
from control import bdalg, evalfr, freqplot
from control.tests.conftest import slycotonly

Expand DownExpand Up@@ -174,9 +174,9 @@ def testFeedback2(self):

def testAuto(self):
omega = np.logspace(-1, 2, 10)
f1 =_convertToFRD(1, omega)
f2 =_convertToFRD(np.array([[1, 0], [0.1, -1]]), omega)
f2 =_convertToFRD([[1, 0], [0.1, -1]], omega)
f1 =_convert_to_FRD(1, omega)
f2 =_convert_to_FRD(np.array([[1, 0], [0.1, -1]]), omega)
f2 =_convert_to_FRD([[1, 0], [0.1, -1]], omega)
f1, f2 # reference to avoid pyflakes error

def testNyquist(self):
Expand Down
35 changes: 29 additions & 6 deletionscontrol/tests/statesp_test.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,14 +9,16 @@

import numpy as np
import pytest
import operator
from numpy.linalg import solve
from scipy.linalg import block_diag, eigvals

import control as ct
from control.config import defaults
from control.dtime import sample_system
from control.lti import evalfr
from control.statesp import (StateSpace,_convertToStateSpace, drss, rss, ss,
tf2ss, _statesp_defaults)
from control.statesp import (StateSpace,_convert_to_statespace, drss,
rss, ss,tf2ss, _statesp_defaults)
from control.tests.conftest import ismatarrayout, slycotonly
from control.xferfcn import TransferFunction, ss2tf

Expand DownExpand Up@@ -224,7 +226,7 @@ def test_pole(self, sys322):

def test_zero_empty(self):
"""Test to make sure zero() works with no zeros in system."""
sys =_convertToStateSpace(TransferFunction([1], [1, 2, 1]))
sys =_convert_to_statespace(TransferFunction([1], [1, 2, 1]))
np.testing.assert_array_equal(sys.zero(), np.array([]))

@slycotonly
Expand DownExpand Up@@ -456,7 +458,7 @@ def test_append_tf(self):
s = TransferFunction([1, 0], [1])
h = 1 / (s + 1) / (s + 2)
sys1 = StateSpace(A1, B1, C1, D1)
sys2 =_convertToStateSpace(h)
sys2 =_convert_to_statespace(h)
sys3c = sys1.append(sys2)
np.testing.assert_array_almost_equal(sys1.A, sys3c.A[:3, :3])
np.testing.assert_array_almost_equal(sys1.B, sys3c.B[:3, :2])
Expand DownExpand Up@@ -625,10 +627,10 @@ def test_empty(self):
assert 0 == g1.outputs

def test_matrix_to_state_space(self):
"""_convertToStateSpace(matrix) gives ss([],[],[],D)"""
"""_convert_to_statespace(matrix) gives ss([],[],[],D)"""
with pytest.deprecated_call():
D = np.matrix([[1, 2, 3], [4, 5, 6]])
g =_convertToStateSpace(D)
g =_convert_to_statespace(D)

np.testing.assert_array_equal(np.empty((0, 0)), g.A)
np.testing.assert_array_equal(np.empty((0, D.shape[1])), g.B)
Expand DownExpand Up@@ -927,3 +929,24 @@ def test_latex_repr(gmats, ref, repr_type, num_format, editsdefaults):
g = StateSpace(*gmats)
refkey = "{}_{}".format(refkey_n[num_format], refkey_r[repr_type])
assert g._repr_latex_() == ref[refkey]


@pytest.mark.parametrize(
"op",
[pytest.param(getattr(operator, s), id=s) for s in ('add', 'sub', 'mul')])
@pytest.mark.parametrize(
"tf, arr",
[pytest.param(ct.tf([1], [0.5, 1]), np.array(2.), id="0D scalar"),
pytest.param(ct.tf([1], [0.5, 1]), np.array([2.]), id="1D scalar"),
pytest.param(ct.tf([1], [0.5, 1]), np.array([[2.]]), id="2D scalar")])
def test_xferfcn_ndarray_precedence(op, tf, arr):
# Apply the operator to the transfer function and array
ss = ct.tf2ss(tf)
result = op(ss, arr)
assert isinstance(result, ct.StateSpace)

# Apply the operator to the array and transfer function
ss = ct.tf2ss(tf)
result = op(arr, ss)
assert isinstance(result, ct.StateSpace)

Loading

[8]ページ先頭

©2009-2025 Movatter.jp