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

add zpk() function#816

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
murrayrm merged 2 commits intopython-control:mainfrommurrayrm:zpk-13Dec2022
Dec 17, 2022
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
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
2 changes: 1 addition & 1 deletioncontrol/matlab/__init__.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -115,7 +115,7 @@

== ========================== ============================================
\* :func:`tf` create transfer function (TF) models
\zpk create zero/pole/gain (ZPK) models.
\* :func:`zpk` create zero/pole/gain (ZPK) models.
\* :func:`ss` create state-space (SS) models
\ dss create descriptor state-space models
\ delayss create state-space models with delayed terms
Expand Down
1 change: 0 additions & 1 deletioncontrol/statesp.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1521,7 +1521,6 @@ def output(self, t, x, u=None, params=None):


# TODO: add discrete time check
# TODO: copy signal names
def _convert_to_statespace(sys):
"""Convert a system to state space form (if needed).

Expand Down
2 changes: 2 additions & 0 deletionscontrol/tests/kwargs_test.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -96,6 +96,7 @@ def test_kwarg_search(module, prefix):
(control.tf, 0, 0, ([1], [1, 1]), {}),
(control.tf2io, 0, 1, (), {}),
(control.tf2ss, 0, 1, (), {}),
(control.zpk, 0, 0, ([1], [2, 3], 4), {}),
(control.InputOutputSystem, 0, 0, (),
{'inputs': 1, 'outputs': 1, 'states': 1}),
(control.InputOutputSystem.linearize, 1, 0, (0, 0), {}),
Expand DownExpand Up@@ -184,6 +185,7 @@ def test_matplotlib_kwargs(function, nsysargs, moreargs, kwargs, mplcleanup):
'tf2io' : test_unrecognized_kwargs,
'tf2ss' : test_unrecognized_kwargs,
'sample_system' : test_unrecognized_kwargs,
'zpk': test_unrecognized_kwargs,
'flatsys.point_to_point':
flatsys_test.TestFlatSys.test_point_to_point_errors,
'flatsys.solve_flat_ocp':
Expand Down
74 changes: 72 additions & 2 deletionscontrol/tests/xferfcn_test.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -8,7 +8,8 @@
import operator

import control as ct
from control import StateSpace, TransferFunction, rss, ss2tf, evalfr
from control import StateSpace, TransferFunction, rss, evalfr
from control import ss, ss2tf, tf, tf2ss
from control import isctime, isdtime, sample_system, defaults
from control.statesp import _convert_to_statespace
from control.xferfcn import _convert_to_transfer_function
Expand DownExpand Up@@ -986,7 +987,7 @@ def test_repr(self, Hargs, ref):
np.testing.assert_array_almost_equal(H.num[p][m], H2.num[p][m])
np.testing.assert_array_almost_equal(H.den[p][m], H2.den[p][m])
assert H.dt == H2.dt

def test_sample_named_signals(self):
sysc = ct.TransferFunction(1.1, (1, 2), inputs='u', outputs='y')

Expand DownExpand Up@@ -1073,3 +1074,72 @@ def test_xferfcn_ndarray_precedence(op, tf, arr):
# Apply the operator to the array and transfer function
result = op(arr, tf)
assert isinstance(result, ct.TransferFunction)


@pytest.mark.parametrize(
"zeros, poles, gain, args, kwargs", [
([], [-1], 1, [], {}),
([1, 2], [-1, -2, -3], 5, [], {}),
([1, 2], [-1, -2, -3], 5, [], {'name': "sys"}),
([1, 2], [-1, -2, -3], 5, [], {'inputs': ["in"], 'outputs': ["out"]}),
([1, 2], [-1, -2, -3], 5, [0.1], {}),
(np.array([1, 2]), np.array([-1, -2, -3]), 5, [], {}),
])
def test_zpk(zeros, poles, gain, args, kwargs):
# Create the transfer function
sys = ct.zpk(zeros, poles, gain, *args, **kwargs)

# Make sure the poles and zeros match
np.testing.assert_equal(sys.zeros().sort(), zeros.sort())
np.testing.assert_equal(sys.poles().sort(), poles.sort())

# Check to make sure the gain is OK
np.testing.assert_almost_equal(
gain, sys(0) * np.prod(-sys.poles()) / np.prod(-sys.zeros()))

# Check time base
if args:
assert sys.dt == args[0]

# Check inputs, outputs, name
input_labels = kwargs.get('inputs', [])
for i, label in enumerate(input_labels):
assert sys.input_labels[i] == label

output_labels = kwargs.get('outputs', [])
for i, label in enumerate(output_labels):
assert sys.output_labels[i] == label

if kwargs.get('name'):
assert sys.name == kwargs.get('name')

@pytest.mark.parametrize("create, args, kwargs, convert", [
(StateSpace, ([-1], [1], [1], [0]), {}, ss2tf),
(StateSpace, ([-1], [1], [1], [0]), {}, ss),
(StateSpace, ([-1], [1], [1], [0]), {}, tf),
(StateSpace, ([-1], [1], [1], [0]), dict(inputs='i', outputs='o'), ss2tf),
(StateSpace, ([-1], [1], [1], [0]), dict(inputs=1, outputs=1), ss2tf),
(StateSpace, ([-1], [1], [1], [0]), dict(inputs='i', outputs='o'), ss),
(StateSpace, ([-1], [1], [1], [0]), dict(inputs='i', outputs='o'), tf),
(TransferFunction, ([1], [1, 1]), {}, tf2ss),
(TransferFunction, ([1], [1, 1]), {}, tf),
(TransferFunction, ([1], [1, 1]), {}, ss),
(TransferFunction, ([1], [1, 1]), dict(inputs='i', outputs='o'), tf2ss),
(TransferFunction, ([1], [1, 1]), dict(inputs=1, outputs=1), tf2ss),
(TransferFunction, ([1], [1, 1]), dict(inputs='i', outputs='o'), tf),
(TransferFunction, ([1], [1, 1]), dict(inputs='i', outputs='o'), ss),
])
def test_copy_names(create, args, kwargs, convert):
# Convert a system with no renaming
sys = create(*args, **kwargs)
cpy = convert(sys)

assert cpy.input_labels == sys.input_labels
assert cpy.input_labels == sys.input_labels
if cpy.nstates is not None and sys.nstates is not None:
assert cpy.state_labels == sys.state_labels

# Relabel inputs and outputs
cpy = convert(sys, inputs='myin', outputs='myout')
assert cpy.input_labels == ['myin']
assert cpy.output_labels == ['myout']
64 changes: 56 additions & 8 deletionscontrol/xferfcn.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -65,7 +65,7 @@
from .frdata import FrequencyResponseData
from . import config

__all__ = ['TransferFunction', 'tf', 'ss2tf', 'tfdata']
__all__ = ['TransferFunction', 'tf', 'zpk', 'ss2tf', 'tfdata']


# Define module default parameter values
Expand DownExpand Up@@ -796,7 +796,7 @@ def zeros(self):
"""Compute the zeros of a transfer function."""
if self.ninputs > 1 or self.noutputs > 1:
raise NotImplementedError(
"TransferFunction.zero is currently only implemented "
"TransferFunction.zeros is currently only implemented "
"for SISO systems.")
else:
# for now, just give zeros of a SISO tf
Expand DownExpand Up@@ -1424,16 +1424,13 @@ def _convert_to_transfer_function(sys, inputs=1, outputs=1):
num = squeeze(num) # Convert to 1D array
den = squeeze(den) # Probably not needed

return TransferFunction(
num, den, sys.dt, inputs=sys.input_labels,
outputs=sys.output_labels)
return TransferFunction(num, den, sys.dt)

elif isinstance(sys, (int, float, complex, np.number)):
num = [[[sys] for j in range(inputs)] for i in range(outputs)]
den = [[[1] for j in range(inputs)] for i in range(outputs)]

return TransferFunction(
num, den, inputs=inputs, outputs=outputs)
return TransferFunction(num, den)

elif isinstance(sys, FrequencyResponseData):
raise TypeError("Can't convert given FRD to TransferFunction system.")
Expand DownExpand Up@@ -1577,8 +1574,54 @@ def tf(*args, **kwargs):
else:
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))

# TODO: copy signal names

def zpk(zeros, poles, gain, *args, **kwargs):
"""zpk(zeros, poles, gain[, dt])

Create a transfer function from zeros, poles, gain.

Given a list of zeros z_i, poles p_j, and gain k, return the transfer
function:

.. math::
H(s) = k \\frac{(s - z_1) (s - z_2) \\cdots (s - z_m)}
{(s - p_1) (s - p_2) \\cdots (s - p_n)}

Parameters
----------
zeros : array_like
Array containing the location of zeros.
poles : array_like
Array containing the location of zeros.
gain : float
System gain
dt : None, True or float, optional
System timebase. 0 (default) indicates continuous
time, True indicates discrete time with unspecified sampling
time, positive number is discrete time with specified
sampling time, None indicates unspecified timebase (either
continuous or discrete time).
inputs, outputs, states : str, or list of str, optional
List of strings that name the individual signals. If this parameter
is not given or given as `None`, the signal names will be of the
form `s[i]` (where `s` is one of `u`, `y`, or `x`). See
:class:`InputOutputSystem` for more information.
name : string, optional
System name (used for specifying signals). If unspecified, a generic
name <sys[id]> is generated with a unique integer id.

Returns
-------
out: :class:`TransferFunction`
Transfer function with given zeros, poles, and gain.

"""
num, den = zpk2tf(zeros, poles, gain)
return TransferFunction(num, den, *args, **kwargs)


def ss2tf(*args, **kwargs):

"""ss2tf(sys)

Transform a state space system to a transfer function.
Expand DownExpand Up@@ -1658,6 +1701,11 @@ def ss2tf(*args, **kwargs):
if len(args) == 1:
sys = args[0]
if isinstance(sys, StateSpace):
kwargs = kwargs.copy()
if not kwargs.get('inputs'):
kwargs['inputs'] = sys.input_labels
if not kwargs.get('outputs'):
kwargs['outputs'] = sys.output_labels
return TransferFunction(
_convert_to_transfer_function(sys), **kwargs)
else:
Expand Down
1 change: 1 addition & 0 deletionsdoc/control.rst
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -18,6 +18,7 @@ System creation
ss
tf
frd
zpk
rss
drss
NonlinearIOSystem
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp