Skip to content

Commit 4d718af

Browse files
authored
Use dict for package/module configuration parameters (#327)
* update config module to use dictionary + 'module.variable' format to store configuration defaults * create helper functions to allow processing of configuration parameters to functions * update modules/functions that use configuration parameters to use the new config module functionality
1 parent 7c96fcc commit 4d718af

11 files changed

Lines changed: 498 additions & 229 deletions

File tree

control/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,6 @@
8484
from numpy.testing import Tester
8585
test = Tester().test
8686
bench = Tester().bench
87+
88+
# Initialize default parameter values
89+
reset_defaults()

control/config.py

Lines changed: 110 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,133 @@
55
# variables that control the behavior of the control package.
66
# Eventually it will be possible to read and write configuration
77
# files. For now, you can just choose between MATLAB and FBS default
8-
# values.
8+
# values + tweak a few other things.
99

1010
import warnings
1111

12-
# Bode plot defaults
13-
bode_dB = False # Bode plot magnitude units
14-
bode_deg = True # Bode Plot phase units
15-
bode_Hz = False # Bode plot frequency units
16-
bode_number_of_samples = None # Bode plot number of samples
17-
bode_feature_periphery_decade = 1.0 # Bode plot feature periphery in decades
12+
__all__ = ['defaults', 'set_defaults', 'reset_defaults',
13+
'use_matlab_defaults', 'use_fbs_defaults',
14+
'use_numpy_matrix']
15+
16+
# Package level default values
17+
_control_defaults = {
18+
# No package level defaults (yet)
19+
}
20+
defaults = dict(_control_defaults)
21+
22+
23+
def set_defaults(module, **keywords):
24+
"""Set default values of parameters for a module.
25+
26+
The set_defaults() function can be used to modify multiple parameter
27+
values for a module at the same time, using keyword arguments:
28+
29+
control.set_defaults('module', param1=val, param2=val)
30+
31+
"""
32+
if not isinstance(module, str):
33+
raise ValueError("module must be a string")
34+
for key, val in keywords.items():
35+
defaults[module + '.' + key] = val
1836

19-
# State space module variables
20-
_use_numpy_matrix = True # Decide whether to use numpy.marix
2137

2238
def reset_defaults():
23-
"""Reset package configuration values to their default values."""
24-
global bode_dB; bode_dB = False
25-
global bode_deg; bode_deg = True
26-
global bode_Hz; bode_Hz = False
27-
global bode_number_of_samples; bode_number_of_samples = None
28-
global bode_feature_periphery_decade; bode_feature_periphery_decade = 1.0
29-
global _use_numpy_matrix; _use_numpy_matrix = True
39+
"""Reset configuration values to their default (initial) values."""
40+
# System level defaults
41+
defaults.update(_control_defaults)
42+
43+
from .freqplot import _bode_defaults, _freqplot_defaults
44+
defaults.update(_bode_defaults)
45+
defaults.update(_freqplot_defaults)
46+
47+
from .nichols import _nichols_defaults
48+
defaults.update(_nichols_defaults)
49+
50+
from .pzmap import _pzmap_defaults
51+
defaults.update(_pzmap_defaults)
52+
53+
from .rlocus import _rlocus_defaults
54+
defaults.update(_rlocus_defaults)
55+
56+
from .statesp import _statesp_defaults
57+
defaults.update(_statesp_defaults)
58+
59+
60+
def _get_param(module, param, argval=None, defval=None, pop=False):
61+
"""Return the default value for a configuration option.
62+
63+
The _get_param() function is a utility function used to get the value of a
64+
parameter for a module based on the default parameter settings and any
65+
arguments passed to the function. The precedence order for parameters is
66+
the value passed to the function (as a keyword), the value from the
67+
config.defaults dictionary, and the default value `defval`.
68+
69+
Parameters
70+
----------
71+
module : str
72+
Name of the module whose parameters are being requested.
73+
param : str
74+
Name of the parameter value to be determeind.
75+
argval : object or dict
76+
Value of the parameter as passed to the function. This can either be
77+
an object or a dictionary (i.e. the keyword list from the function
78+
call). Defaults to None.
79+
defval : object
80+
Default value of the parameter to use, if it is not located in the
81+
`config.defaults` dictionary. If a dictionary is provided, then
82+
`module.param` is used to determine the default value. Defaults to
83+
None.
84+
pop : bool
85+
If True and if argval is a dict, then pop the remove the parameter
86+
entry from the argval dict after retreiving it. This allows the use
87+
of a keyword argument list to be passed through to other functions
88+
internal to the function being called.
89+
90+
"""
91+
92+
# Make sure that we were passed sensible arguments
93+
if not isinstance(module, str) or not isinstance(param, str):
94+
raise ValueError("module and param must be strings")
95+
96+
# Construction the name of the key, for later use
97+
key = module + '.' + param
98+
99+
# If we were passed a dict for the argval, get the param value from there
100+
if isinstance(argval, dict):
101+
argval = argval.pop(param, None) if pop else argval.get(param, None)
102+
103+
# If we were passed a dict for the defval, get the param value from there
104+
if isinstance(defval, dict):
105+
defval = defval.get(key, None)
106+
107+
# Return the parameter value to use (argval > defaults > defval)
108+
return argval if argval is not None else defaults.get(key, defval)
30109

31110

32111
# Set defaults to match MATLAB
33112
def use_matlab_defaults():
34-
"""
35-
Use MATLAB compatible configuration settings
113+
"""Use MATLAB compatible configuration settings.
36114
37115
The following conventions are used:
38-
* Bode plots plot gain in dB, phase in degrees, frequency in Hertz
116+
* Bode plots plot gain in dB, phase in degrees, frequency in
117+
Hertz, with grids
118+
* State space class and functions use Numpy matrix objects
119+
39120
"""
40-
# Bode plot defaults
41-
global bode_dB; bode_dB = True
42-
global bode_deg; bode_deg = True
43-
global bode_Hz; bode_Hz = True
44-
global _use_numpy_matrix; _use_numpy_matrix = True
121+
set_defaults('bode', dB=True, deg=True, Hz=True, grid=True)
122+
set_defaults('statesp', use_numpy_matrix=True)
45123

46124

47125
# Set defaults to match FBS (Astrom and Murray)
48126
def use_fbs_defaults():
49-
"""
50-
Use `Feedback Systems <http://fbsbook.org>`_ (FBS) compatible settings
127+
"""Use `Feedback Systems <http://fbsbook.org>`_ (FBS) compatible settings.
51128
52129
The following conventions are used:
53130
* Bode plots plot gain in powers of ten, phase in degrees,
54-
frequency in Hertz
131+
frequency in Hertz, no grid
132+
55133
"""
56-
# Bode plot defaults
57-
global bode_dB; bode_dB = False
58-
global bode_deg; bode_deg = True
59-
global bode_Hz; bode_Hz = False
134+
set_defaults('bode', dB=False, deg=True, Hz=False, grid=False)
60135

61136

62137
# Decide whether to use numpy.matrix for state space operations
@@ -68,8 +143,8 @@ def use_numpy_matrix(flag=True, warn=True):
68143
flag : bool
69144
If flag is `True` (default), use the Numpy (soon to be deprecated)
70145
`matrix` class to represent matrices in the `~control.StateSpace`
71-
class and functions. If flat is `False`, then matrices are represnted
72-
by a 2D `ndarray` object.
146+
class and functions. If flat is `False`, then matrices are
147+
represented by a 2D `ndarray` object.
73148
74149
warn : bool
75150
If flag is `True` (default), issue a warning when turning on the use
@@ -79,5 +154,5 @@ class and functions. If flat is `False`, then matrices are represnted
79154
"""
80155
if flag and warn:
81156
warnings.warn("Return type numpy.matrix is soon to be deprecated.",
82-
stacklevel=2)
83-
global _use_numpy_matrix; _use_numpy_matrix = flag
157+
stacklevel=2)
158+
set_defaults('statesp', use_numpy_matrix=flag)

0 commit comments

Comments
 (0)