Skip to content

add capability to switch to legacy defaults #424

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 11, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 17 additions & 1 deletion control/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

__all__ = ['defaults', 'set_defaults', 'reset_defaults',
'use_matlab_defaults', 'use_fbs_defaults',
'use_numpy_matrix']
'use_legacy_defaults', 'use_numpy_matrix']

# Package level default values
_control_defaults = {
Expand Down Expand Up @@ -53,6 +53,9 @@ def reset_defaults():
from .rlocus import _rlocus_defaults
defaults.update(_rlocus_defaults)

from .xferfcn import _xferfcn_defaults
defaults.update(_xferfcn_defaults)

from .statesp import _statesp_defaults
defaults.update(_statesp_defaults)

Expand Down Expand Up @@ -156,3 +159,16 @@ class and functions. If flat is `False`, then matrices are
warnings.warn("Return type numpy.matrix is soon to be deprecated.",
stacklevel=2)
set_defaults('statesp', use_numpy_matrix=flag)

def use_legacy_defaults(version):
""" Sets the defaults to whatever they were in a given release.

Parameters
----------
version : string
version number of the defaults desired. Currently only supports `0.8.3`.
"""
if version == '0.8.3':
use_numpy_matrix(True) # alternatively: set_defaults('statesp', use_numpy_matrix=True)
else:
raise ValueError('''version number not recognized. Possible values are: ['0.8.3']''')
13 changes: 8 additions & 5 deletions control/statesp.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,9 @@
# Define module default parameter values
_statesp_defaults = {
'statesp.use_numpy_matrix': True,
}
'statesp.default_dt': None,
'statesp.remove_useless_states': True,
}


def _ssmatrix(data, axis=1):
Expand Down Expand Up @@ -147,7 +149,8 @@ class StateSpace(LTI):
Setting dt = 0 specifies a continuous system, while leaving dt = None
means the system timebase is not specified. If 'dt' is set to True, the
system will be treated as a discrete time system with unspecified sampling
time.
time. The default value of 'dt' is None and can be changed by changing the
value of ``control.config.defaults['statesp.default_dt']``.

"""

Expand All @@ -171,7 +174,7 @@ def __init__(self, *args, **kw):
if len(args) == 4:
# The user provided A, B, C, and D matrices.
(A, B, C, D) = args
dt = None
dt = config.defaults['statesp.default_dt']
elif len(args) == 5:
# Discrete time system
(A, B, C, D, dt) = args
Expand All @@ -187,12 +190,12 @@ def __init__(self, *args, **kw):
try:
dt = args[0].dt
except NameError:
dt = None
dt = config.defaults['statesp.default_dt']
else:
raise ValueError("Needs 1 or 4 arguments; received %i." % len(args))

# Process keyword arguments
remove_useless = kw.get('remove_useless', True)
remove_useless = kw.get('remove_useless', config.defaults['statesp.remove_useless_states'])

# Convert all matrices to standard form
A = _ssmatrix(A)
Expand Down
21 changes: 19 additions & 2 deletions control/tests/config_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ def test_get_param(self):


def test_fbs_bode(self):
ct.use_fbs_defaults();
ct.use_fbs_defaults()

# Generate a Bode plot
plt.figure()
Expand Down Expand Up @@ -94,7 +94,7 @@ def test_fbs_bode(self):
ct.reset_defaults()

def test_matlab_bode(self):
ct.use_matlab_defaults();
ct.use_matlab_defaults()

# Generate a Bode plot
plt.figure()
Expand Down Expand Up @@ -211,6 +211,23 @@ def test_reset_defaults(self):
self.assertEqual(
ct.config.defaults['freqplot.feature_periphery_decades'], 1.0)

def test_legacy_defaults(self):
ct.use_legacy_defaults('0.8.3')
assert(isinstance(ct.ss(0,0,0,1).D, np.matrix))
ct.reset_defaults()
assert(isinstance(ct.ss(0,0,0,1).D, np.ndarray))

def test_change_default_dt(self):
ct.set_defaults('statesp', default_dt=0)
self.assertEqual(ct.ss(0,0,0,1).dt, 0)
ct.set_defaults('statesp', default_dt=None)
self.assertEqual(ct.ss(0,0,0,1).dt, None)
ct.set_defaults('xferfcn', default_dt=0)
self.assertEqual(ct.tf(1, 1).dt, 0)
ct.set_defaults('xferfcn', default_dt=None)
self.assertEqual(ct.tf(1, 1).dt, None)


def tearDown(self):
# Get rid of any figures that we created
plt.close('all')
Expand Down
13 changes: 10 additions & 3 deletions control/xferfcn.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,15 @@
from itertools import chain
from re import sub
from .lti import LTI, timebaseEqual, timebase, isdtime
from . import config

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


# Define module default parameter values
_xferfcn_defaults = {
'xferfcn.default_dt': None}

class TransferFunction(LTI):

"""TransferFunction(num, den[, dt])
Expand All @@ -88,7 +93,9 @@ class TransferFunction(LTI):
instance variable and setting it to something other than 'None'. If 'dt'
has a non-zero value, then it must match whenever two transfer functions
are combined. If 'dt' is set to True, the system will be treated as a
discrete time system with unspecified sampling time.
discrete time system with unspecified sampling time. The default value of
'dt' is None and can be changed by changing the value of
``control.config.defaults['xferfcn.default_dt']``.

The TransferFunction class defines two constants ``s`` and ``z`` that
represent the differentiation and delay operators in continuous and
Expand Down Expand Up @@ -117,7 +124,7 @@ def __init__(self, *args):
if len(args) == 2:
# The user provided a numerator and a denominator.
(num, den) = args
dt = None
dt = config.defaults['xferfcn.default_dt']
elif len(args) == 3:
# Discrete time transfer function
(num, den, dt) = args
Expand All @@ -133,7 +140,7 @@ def __init__(self, *args):
try:
dt = args[0].dt
except NameError: # pragma: no coverage
dt = None
dt = config.defaults['xferfcn.default_dt']
else:
raise ValueError("Needs 1, 2 or 3 arguments; received %i."
% len(args))
Expand Down
13 changes: 11 additions & 2 deletions doc/conventions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ the result will be a discrete time system with the sample time of the latter
system. For continuous time systems, the :func:`sample_system` function or
the :meth:`StateSpace.sample` and :meth:`TransferFunction.sample` methods
can be used to create a discrete time system from a continuous time system.
See :ref:`utility-and-conversions`.
See :ref:`utility-and-conversions`. The default value of 'dt' can be changed by
changing the values of ``control.config.defaults['statesp.default_dt']`` and
``control.config.defaults['xferfcn.default_dt']``.

Conversion between representations
----------------------------------
Expand Down Expand Up @@ -220,9 +222,15 @@ Selected variables that can be configured, along with their default values:
* freqplot.feature_periphery_decade (1.0): How many decades to include in the
frequency range on both sides of features (poles, zeros).

* statesp.use_numpy_matrix: set the return type for state space matrices to
* statesp.use_numpy_matrix (True): set the return type for state space matrices to
`numpy.matrix` (verus numpy.ndarray)

* statesp.default_dt and xferfcn.default_dt (None): set the default value of dt when
constructing new LTI systems

* statesp.remove_useless_states (True): remove states that have no effect on the
input-output dynamics of the system

Additional parameter variables are documented in individual functions

Functions that can be used to set standard configurations:
Expand All @@ -234,3 +242,4 @@ Functions that can be used to set standard configurations:
use_fbs_defaults
use_matlab_defaults
use_numpy_matrix
use_legacy_defaults