Skip to content

Commit 8fd24c4

Browse files
committed
Set up 'config' module that allows user-defined defaults
* Will eventually allow MATLAB defaults if user imports control.matlab first New module 'canonical' for implementing canconical forms. Needed for trajectory generation module (coming soon).
1 parent 6f0417f commit 8fd24c4

8 files changed

Lines changed: 157 additions & 5 deletions

File tree

ChangeLog

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,31 @@
1+
2012-11-10 Richard Murray <murray@altura.local>
2+
3+
* src/canonical.py: new module implementing conversions to selected
4+
canonical forms: canonical_form(), reachable_form() implemented
5+
6+
* src/lti.py (issiso): new function to quickly check if a system is
7+
single input, single output or not
8+
9+
2012-11-04 Richard Murray <murray@altura.local>
10+
11+
* src/__init__.py: added action item to separate out matlab module
12+
functionality (eventually)
13+
14+
* src/matlab.py: added code for setting up MATLAB defaults if matlab
15+
submodule is imported instead of main (control) module. See
16+
comments in __init.py__ for what needs to be done to implement.
17+
18+
* src/freqplot.py (bode_plot): moved default values of plotting
19+
options to config module to allow easier use override
20+
21+
* src/config.py: new module to help set package defaults
22+
23+
* src/xferfcn.py (_convertToTransferFunction): removed extraneous
24+
print statements if slycot is not installed
25+
26+
* src/statesp.py (StateSpace.__str__): fixed error in printing
27+
timebase when dt is None (python 3)
28+
129
---- control-0.6c released -----
230

331
2012-11-03 Richard Murray <murray@altura.local>

src/__init__.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
from control.dtime import sample_system
6464
from control.freqplot import bode_plot, nyquist_plot, gangof4_plot
6565
from control.freqplot import bode, nyquist, gangof4
66-
from control.lti import timebase, timebaseEqual, isdtime, isctime
66+
from control.lti import issiso, timebase, timebaseEqual, isdtime, isctime
6767
from control.margins import stability_margins, phase_crossover_frequencies
6868
from control.mateqn import lyap, dlyap, care, dare
6969
from control.modelsimp import hsvd, modred, balred, era, markov
@@ -77,9 +77,20 @@
7777
from control.xferfcn import TransferFunction
7878
from control.ctrlutil import unwrap, issys
7979
from control.frdata import FRD
80+
from control.canonical import canonical_form, reachable_form
81+
82+
# Exceptions
83+
from exception import *
8084

8185
# Import some of the more common (and benign) MATLAB shortcuts
8286
# By default, don't import conflicting commands here
87+
#! TODO (RMM, 4 Nov 2012): remove MATLAB dependencies from __init__.py
88+
#!
89+
#! Eventually, all functionality should be in modules *other* than matlab.
90+
#! This will allow inclusion of the matlab module to set up a different set
91+
#! of defaults from the main package. At that point, the matlab module will
92+
#! allow provide compatibility with MATLAB but no package functionality.
93+
#!
8394
from control.matlab import ss, tf, ss2tf, tf2ss, drss
8495
from control.matlab import pole, zero, evalfr, freqresp, dcgain
8596
from control.matlab import nichols, rlocus, margin

src/canonical.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# canonical.py - functions for converting systems to canonical forms
2+
# RMM, 10 Nov 2012
3+
4+
import control
5+
from numpy import zeros, shape, poly
6+
from numpy.linalg import inv
7+
8+
def canonical_form(sys, form):
9+
"""Convert a system into canonical form
10+
11+
Parameters
12+
----------
13+
xsys : StateSpace object
14+
System to be transformed, with state 'x'
15+
form : String
16+
Canonical form for transformation. Chosen from:
17+
* 'reachable' - reachable canonical form
18+
* 'observable' - observable canonical form
19+
* 'modal' - modal canonical form [not implemented]
20+
21+
Outputs
22+
-------
23+
zsys : StateSpace object
24+
System in desired canonical form, with state 'z'
25+
T : matrix
26+
Coordinate transformation matrix, z = T*x
27+
"""
28+
29+
# Call the appropriate tranformation function
30+
if form == 'reachable':
31+
return reachable_form(xsys)
32+
else:
33+
raise control.ControlNotImplemented(
34+
"Canonical form '%s' not yet implemented" % form)
35+
36+
# Reachable canonical form
37+
def reachable_form(xsys):
38+
# Check to make sure we have a SISO system
39+
if not control.issiso(xsys):
40+
raise control.ControlNotImplemented(
41+
"Canonical forms for MIMO systems not yet supported")
42+
43+
# Create a new system, starting with a copy of the old one
44+
zsys = control.StateSpace(xsys)
45+
46+
# Generate the system matrices for the desired canonical form
47+
zsys.B = zeros(shape(xsys.B)); zsys.B[0, 0] = 1;
48+
zsys.A = zeros(shape(xsys.A))
49+
Apoly = poly(xsys.A) # characteristic polynomial
50+
for i in range(0, xsys.states):
51+
zsys.A[0, i] = -Apoly[i+1] / Apoly[0]
52+
if (i+1 < xsys.states): zsys.A[i+1, i] = 1
53+
54+
# Compute the reachability matrices for each set of states
55+
Wrx = control.ctrb(xsys.A, xsys.B)
56+
Wrz = control.ctrb(zsys.A, zsys.B)
57+
58+
# Transformation from one form to another
59+
Tzx = Wrz * inv(Wrx)
60+
61+
# Finally, compute the output matrix
62+
zsys.C = xsys.C * inv(Tzx)
63+
64+
return zsys, Tzx

src/config.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# config.py - package defaults
2+
# RMM, 4 Nov 2012
3+
#
4+
# This file contains default values and utility functions for setting
5+
# variables that control the behavior of the control package.
6+
# Eventually it will be possible to read and write configuration
7+
# files. For now, you can just choose between MATLAB and FBS default
8+
# values.
9+
10+
# Bode plot defaults
11+
bode_dB = False # Bode plot magnitude units
12+
bode_deg = True # Bode Plot phase units
13+
bode_Hz = False # Bode plot frequency units
14+
15+
# Set defaults to match MATLAB
16+
def use_matlab_defaults():
17+
# Bode plot defaults
18+
global bode_dB; bode_dB = True
19+
global bode_deg; bode_deg = True
20+
global bode_Hz; bode_Hz = True
21+
22+
# Set defaults to match FBS (Astrom and Murray)
23+
def use_fbs_defaults():
24+
# Bode plot defaults
25+
global bode_dB; bode_dB = False
26+
global bode_deg; bode_deg = True
27+
global bode_Hz; bode_Hz = True

src/freqplot.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
#
5858

5959
# Bode plot
60-
def bode_plot(syslist, omega=None, dB=False, Hz=False, deg=True,
60+
def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
6161
Plot=True, *args, **kwargs):
6262
"""Bode plot for a system
6363
@@ -105,6 +105,12 @@ def bode_plot(syslist, omega=None, dB=False, Hz=False, deg=True,
105105
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
106106
>>> mag, phase, omega = bode(sys)
107107
"""
108+
# Set default values for options
109+
import control.config
110+
if (dB is None): dB = control.config.bode_dB
111+
if (deg is None): deg = control.config.bode_deg
112+
if (Hz is None): Hz = control.config.bode_Hz
113+
108114
# If argument was a singleton, turn it into a list
109115
if (not getattr(syslist, '__iter__', False)):
110116
syslist = (syslist,)

src/matlab.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,18 @@
6969
from scipy.signal import zpk2ss, ss2zpk, tf2zpk, zpk2tf
7070
from numpy import linspace, logspace
7171

72+
# If configuration is not yet set, import and use MATLAB defaults
73+
#! NOTE (RMM, 4 Nov 2012): MATLAB default initialization commented out for now
74+
#!
75+
#! This code will eventually be used so that import control.matlab will
76+
#! automatically use MATLAB defaults, while import control will use package
77+
#! defaults. In order for that to work, we need to make sure that
78+
#! __init__.py does not include anything in the MATLAB module.
79+
# import sys
80+
# if not ('control.config' in sys.modules):
81+
# import control.config
82+
# control.config.use_matlab()
83+
7284
# Control system library
7385
import control.ctrlutil as ctrlutil
7486
import control.freqplot as freqplot

src/statesp.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ def __init__(self, *args):
138138

139139
# Here we're going to convert inputs to matrices, if the user gave a
140140
# non-matrix type.
141+
#! TODO: [A, B, C, D] = map(matrix, [A, B, C, D])?
141142
matrices = [A, B, C, D]
142143
for i in range(len(matrices)):
143144
# Convert to matrix first, if necessary.
@@ -215,9 +216,10 @@ def __str__(self):
215216
str += "B = " + self.B.__str__() + "\n\n"
216217
str += "C = " + self.C.__str__() + "\n\n"
217218
str += "D = " + self.D.__str__() + "\n"
219+
#! TODO: replace with standard calls to lti functions
218220
if (type(self.dt) == bool and self.dt == True):
219221
str += "\ndt unspecified\n"
220-
elif (self.dt > 0):
222+
elif (not (self.dt is None) and type(self.dt) != bool and self.dt > 0):
221223
str += "\ndt = " + self.dt.__str__() + "\n"
222224
return str
223225

src/xferfcn.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ def __str__(self, var=None):
266266

267267
mimo = self.inputs > 1 or self.outputs > 1
268268
if (var == None):
269+
#! TODO: replace with standard calls to lti functions
269270
var = 's' if self.dt == None or self.dt == 0 else 'z'
270271
outstr = ""
271272

@@ -294,6 +295,7 @@ def __str__(self, var=None):
294295

295296
# See if this is a discrete time system with specific sampling time
296297
if (not (self.dt is None) and type(self.dt) != bool and self.dt > 0):
298+
#! TODO: replace with standard calls to lti functions
297299
outstr += "\ndt = " + self.dt.__str__() + "\n"
298300

299301
return outstr
@@ -945,8 +947,8 @@ def _convertToTransferFunction(sys, **kw):
945947
lti_sys = lti(sys.A, sys.B, sys.C, sys.D)
946948
num = squeeze(lti_sys.num)
947949
den = squeeze(lti_sys.den)
948-
print(num)
949-
print(den)
950+
# print(num)
951+
# print(den)
950952

951953
return TransferFunction(num, den, sys.dt)
952954

0 commit comments

Comments
 (0)