Skip to content

Use dict for package/module configuration parameters #327

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 2 commits into from
Jul 21, 2019
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
3 changes: 3 additions & 0 deletions control/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,6 @@
from numpy.testing import Tester
test = Tester().test
bench = Tester().bench

# Initialize default parameter values
reset_defaults()
145 changes: 110 additions & 35 deletions control/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,58 +5,133 @@
# variables that control the behavior of the control package.
# Eventually it will be possible to read and write configuration
# files. For now, you can just choose between MATLAB and FBS default
# values.
# values + tweak a few other things.

import warnings

# Bode plot defaults
bode_dB = False # Bode plot magnitude units
bode_deg = True # Bode Plot phase units
bode_Hz = False # Bode plot frequency units
bode_number_of_samples = None # Bode plot number of samples
bode_feature_periphery_decade = 1.0 # Bode plot feature periphery in decades
__all__ = ['defaults', 'set_defaults', 'reset_defaults',
'use_matlab_defaults', 'use_fbs_defaults',
'use_numpy_matrix']

# Package level default values
_control_defaults = {
# No package level defaults (yet)
}
defaults = dict(_control_defaults)


def set_defaults(module, **keywords):
"""Set default values of parameters for a module.

The set_defaults() function can be used to modify multiple parameter
values for a module at the same time, using keyword arguments:

control.set_defaults('module', param1=val, param2=val)

"""
if not isinstance(module, str):
raise ValueError("module must be a string")
for key, val in keywords.items():
defaults[module + '.' + key] = val

# State space module variables
_use_numpy_matrix = True # Decide whether to use numpy.marix

def reset_defaults():
"""Reset package configuration values to their default values."""
global bode_dB; bode_dB = False
global bode_deg; bode_deg = True
global bode_Hz; bode_Hz = False
global bode_number_of_samples; bode_number_of_samples = None
global bode_feature_periphery_decade; bode_feature_periphery_decade = 1.0
global _use_numpy_matrix; _use_numpy_matrix = True
"""Reset configuration values to their default (initial) values."""
# System level defaults
defaults.update(_control_defaults)

from .freqplot import _bode_defaults, _freqplot_defaults
defaults.update(_bode_defaults)
defaults.update(_freqplot_defaults)

from .nichols import _nichols_defaults
defaults.update(_nichols_defaults)

from .pzmap import _pzmap_defaults
defaults.update(_pzmap_defaults)

from .rlocus import _rlocus_defaults
defaults.update(_rlocus_defaults)

from .statesp import _statesp_defaults
defaults.update(_statesp_defaults)


def _get_param(module, param, argval=None, defval=None, pop=False):
"""Return the default value for a configuration option.

The _get_param() function is a utility function used to get the value of a
parameter for a module based on the default parameter settings and any
arguments passed to the function. The precedence order for parameters is
the value passed to the function (as a keyword), the value from the
config.defaults dictionary, and the default value `defval`.

Parameters
----------
module : str
Name of the module whose parameters are being requested.
param : str
Name of the parameter value to be determeind.
argval : object or dict
Value of the parameter as passed to the function. This can either be
an object or a dictionary (i.e. the keyword list from the function
call). Defaults to None.
defval : object
Default value of the parameter to use, if it is not located in the
`config.defaults` dictionary. If a dictionary is provided, then
`module.param` is used to determine the default value. Defaults to
None.
pop : bool
If True and if argval is a dict, then pop the remove the parameter
entry from the argval dict after retreiving it. This allows the use
of a keyword argument list to be passed through to other functions
internal to the function being called.

"""

# Make sure that we were passed sensible arguments
if not isinstance(module, str) or not isinstance(param, str):
raise ValueError("module and param must be strings")

# Construction the name of the key, for later use
key = module + '.' + param

# If we were passed a dict for the argval, get the param value from there
if isinstance(argval, dict):
argval = argval.pop(param, None) if pop else argval.get(param, None)

# If we were passed a dict for the defval, get the param value from there
if isinstance(defval, dict):
defval = defval.get(key, None)

# Return the parameter value to use (argval > defaults > defval)
return argval if argval is not None else defaults.get(key, defval)


# Set defaults to match MATLAB
def use_matlab_defaults():
"""
Use MATLAB compatible configuration settings
"""Use MATLAB compatible configuration settings.

The following conventions are used:
* Bode plots plot gain in dB, phase in degrees, frequency in Hertz
* Bode plots plot gain in dB, phase in degrees, frequency in
Hertz, with grids
* State space class and functions use Numpy matrix objects

"""
# Bode plot defaults
global bode_dB; bode_dB = True
global bode_deg; bode_deg = True
global bode_Hz; bode_Hz = True
global _use_numpy_matrix; _use_numpy_matrix = True
set_defaults('bode', dB=True, deg=True, Hz=True, grid=True)
set_defaults('statesp', use_numpy_matrix=True)


# Set defaults to match FBS (Astrom and Murray)
def use_fbs_defaults():
"""
Use `Feedback Systems <http://fbsbook.org>`_ (FBS) compatible settings
"""Use `Feedback Systems <http://fbsbook.org>`_ (FBS) compatible settings.

The following conventions are used:
* Bode plots plot gain in powers of ten, phase in degrees,
frequency in Hertz
frequency in Hertz, no grid

"""
# Bode plot defaults
global bode_dB; bode_dB = False
global bode_deg; bode_deg = True
global bode_Hz; bode_Hz = False
set_defaults('bode', dB=False, deg=True, Hz=False, grid=False)


# Decide whether to use numpy.matrix for state space operations
Expand All @@ -68,8 +143,8 @@ def use_numpy_matrix(flag=True, warn=True):
flag : bool
If flag is `True` (default), use the Numpy (soon to be deprecated)
`matrix` class to represent matrices in the `~control.StateSpace`
class and functions. If flat is `False`, then matrices are represnted
by a 2D `ndarray` object.
class and functions. If flat is `False`, then matrices are
represented by a 2D `ndarray` object.

warn : bool
If flag is `True` (default), issue a warning when turning on the use
Expand All @@ -79,5 +154,5 @@ class and functions. If flat is `False`, then matrices are represnted
"""
if flag and warn:
warnings.warn("Return type numpy.matrix is soon to be deprecated.",
stacklevel=2)
global _use_numpy_matrix; _use_numpy_matrix = flag
stacklevel=2)
set_defaults('statesp', use_numpy_matrix=flag)
Loading