|
From: <mur...@us...> - 2012-11-19 05:28:07
|
Revision: 247
http://sourceforge.net/p/python-control/code/247
Author: murrayrm
Date: 2012-11-19 05:28:05 +0000 (Mon, 19 Nov 2012)
Log Message:
-----------
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).
Modified Paths:
--------------
trunk/ChangeLog
trunk/src/__init__.py
trunk/src/freqplot.py
trunk/src/matlab.py
trunk/src/statesp.py
trunk/src/xferfcn.py
Added Paths:
-----------
trunk/src/canonical.py
trunk/src/config.py
Property Changed:
----------------
trunk/
trunk/src/
trunk/tests/
Property changes on: trunk
___________________________________________________________________
Modified: svn:ignore
- MANIFEST*
build
dist
+ MANIFEST*
build
dist
__pycache__
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog 2012-11-11 22:00:29 UTC (rev 246)
+++ trunk/ChangeLog 2012-11-19 05:28:05 UTC (rev 247)
@@ -1,3 +1,31 @@
+2012-11-10 Richard Murray <mu...@al...>
+
+ * src/canonical.py: new module implementing conversions to selected
+ canonical forms: canonical_form(), reachable_form() implemented
+
+ * src/lti.py (issiso): new function to quickly check if a system is
+ single input, single output or not
+
+2012-11-04 Richard Murray <mu...@al...>
+
+ * src/__init__.py: added action item to separate out matlab module
+ functionality (eventually)
+
+ * src/matlab.py: added code for setting up MATLAB defaults if matlab
+ submodule is imported instead of main (control) module. See
+ comments in __init.py__ for what needs to be done to implement.
+
+ * src/freqplot.py (bode_plot): moved default values of plotting
+ options to config module to allow easier use override
+
+ * src/config.py: new module to help set package defaults
+
+ * src/xferfcn.py (_convertToTransferFunction): removed extraneous
+ print statements if slycot is not installed
+
+ * src/statesp.py (StateSpace.__str__): fixed error in printing
+ timebase when dt is None (python 3)
+
---- control-0.6c released -----
2012-11-03 Richard Murray <mu...@al...>
Property changes on: trunk/src
___________________________________________________________________
Modified: svn:ignore
- *.pyc
.*.swp
+ *.pyc
.*.swp
__pycache__
Modified: trunk/src/__init__.py
===================================================================
--- trunk/src/__init__.py 2012-11-11 22:00:29 UTC (rev 246)
+++ trunk/src/__init__.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -63,7 +63,7 @@
from control.dtime import sample_system
from control.freqplot import bode_plot, nyquist_plot, gangof4_plot
from control.freqplot import bode, nyquist, gangof4
-from control.lti import timebase, timebaseEqual, isdtime, isctime
+from control.lti import issiso, timebase, timebaseEqual, isdtime, isctime
from control.margins import stability_margins, phase_crossover_frequencies
from control.mateqn import lyap, dlyap, care, dare
from control.modelsimp import hsvd, modred, balred, era, markov
@@ -77,9 +77,20 @@
from control.xferfcn import TransferFunction
from control.ctrlutil import unwrap, issys
from control.frdata import FRD
+from control.canonical import canonical_form, reachable_form
+# Exceptions
+from exception import *
+
# Import some of the more common (and benign) MATLAB shortcuts
# By default, don't import conflicting commands here
+#! TODO (RMM, 4 Nov 2012): remove MATLAB dependencies from __init__.py
+#!
+#! Eventually, all functionality should be in modules *other* than matlab.
+#! This will allow inclusion of the matlab module to set up a different set
+#! of defaults from the main package. At that point, the matlab module will
+#! allow provide compatibility with MATLAB but no package functionality.
+#!
from control.matlab import ss, tf, ss2tf, tf2ss, drss
from control.matlab import pole, zero, evalfr, freqresp, dcgain
from control.matlab import nichols, rlocus, margin
Added: trunk/src/canonical.py
===================================================================
--- trunk/src/canonical.py (rev 0)
+++ trunk/src/canonical.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -0,0 +1,64 @@
+# canonical.py - functions for converting systems to canonical forms
+# RMM, 10 Nov 2012
+
+import control
+from numpy import zeros, shape, poly
+from numpy.linalg import inv
+
+def canonical_form(sys, form):
+ """Convert a system into canonical form
+
+ Parameters
+ ----------
+ xsys : StateSpace object
+ System to be transformed, with state 'x'
+ form : String
+ Canonical form for transformation. Chosen from:
+ * 'reachable' - reachable canonical form
+ * 'observable' - observable canonical form
+ * 'modal' - modal canonical form [not implemented]
+
+ Outputs
+ -------
+ zsys : StateSpace object
+ System in desired canonical form, with state 'z'
+ T : matrix
+ Coordinate transformation matrix, z = T*x
+ """
+
+ # Call the appropriate tranformation function
+ if form == 'reachable':
+ return reachable_form(xsys)
+ else:
+ raise control.ControlNotImplemented(
+ "Canonical form '%s' not yet implemented" % form)
+
+# Reachable canonical form
+def reachable_form(xsys):
+ # Check to make sure we have a SISO system
+ if not control.issiso(xsys):
+ raise control.ControlNotImplemented(
+ "Canonical forms for MIMO systems not yet supported")
+
+ # Create a new system, starting with a copy of the old one
+ zsys = control.StateSpace(xsys)
+
+ # Generate the system matrices for the desired canonical form
+ zsys.B = zeros(shape(xsys.B)); zsys.B[0, 0] = 1;
+ zsys.A = zeros(shape(xsys.A))
+ Apoly = poly(xsys.A) # characteristic polynomial
+ for i in range(0, xsys.states):
+ zsys.A[0, i] = -Apoly[i+1] / Apoly[0]
+ if (i+1 < xsys.states): zsys.A[i+1, i] = 1
+
+ # Compute the reachability matrices for each set of states
+ Wrx = control.ctrb(xsys.A, xsys.B)
+ Wrz = control.ctrb(zsys.A, zsys.B)
+
+ # Transformation from one form to another
+ Tzx = Wrz * inv(Wrx)
+
+ # Finally, compute the output matrix
+ zsys.C = xsys.C * inv(Tzx)
+
+ return zsys, Tzx
Added: trunk/src/config.py
===================================================================
--- trunk/src/config.py (rev 0)
+++ trunk/src/config.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -0,0 +1,27 @@
+# config.py - package defaults
+# RMM, 4 Nov 2012
+#
+# This file contains default values and utility functions for setting
+# 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.
+
+# Bode plot defaults
+bode_dB = False # Bode plot magnitude units
+bode_deg = True # Bode Plot phase units
+bode_Hz = False # Bode plot frequency units
+
+# Set defaults to match MATLAB
+def use_matlab_defaults():
+ # Bode plot defaults
+ global bode_dB; bode_dB = True
+ global bode_deg; bode_deg = True
+ global bode_Hz; bode_Hz = True
+
+# Set defaults to match FBS (Astrom and Murray)
+def use_fbs_defaults():
+ # Bode plot defaults
+ global bode_dB; bode_dB = False
+ global bode_deg; bode_deg = True
+ global bode_Hz; bode_Hz = True
Modified: trunk/src/freqplot.py
===================================================================
--- trunk/src/freqplot.py 2012-11-11 22:00:29 UTC (rev 246)
+++ trunk/src/freqplot.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -57,7 +57,7 @@
#
# Bode plot
-def bode_plot(syslist, omega=None, dB=False, Hz=False, deg=True,
+def bode_plot(syslist, omega=None, dB=None, Hz=None, deg=None,
Plot=True, *args, **kwargs):
"""Bode plot for a system
@@ -105,6 +105,12 @@
>>> sys = ss("1. -2; 3. -4", "5.; 7", "6. 8", "9.")
>>> mag, phase, omega = bode(sys)
"""
+ # Set default values for options
+ import control.config
+ if (dB is None): dB = control.config.bode_dB
+ if (deg is None): deg = control.config.bode_deg
+ if (Hz is None): Hz = control.config.bode_Hz
+
# If argument was a singleton, turn it into a list
if (not getattr(syslist, '__iter__', False)):
syslist = (syslist,)
Modified: trunk/src/matlab.py
===================================================================
--- trunk/src/matlab.py 2012-11-11 22:00:29 UTC (rev 246)
+++ trunk/src/matlab.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -69,6 +69,18 @@
from scipy.signal import zpk2ss, ss2zpk, tf2zpk, zpk2tf
from numpy import linspace, logspace
+# If configuration is not yet set, import and use MATLAB defaults
+#! NOTE (RMM, 4 Nov 2012): MATLAB default initialization commented out for now
+#!
+#! This code will eventually be used so that import control.matlab will
+#! automatically use MATLAB defaults, while import control will use package
+#! defaults. In order for that to work, we need to make sure that
+#! __init__.py does not include anything in the MATLAB module.
+# import sys
+# if not ('control.config' in sys.modules):
+# import control.config
+# control.config.use_matlab()
+
# Control system library
import control.ctrlutil as ctrlutil
import control.freqplot as freqplot
Modified: trunk/src/statesp.py
===================================================================
--- trunk/src/statesp.py 2012-11-11 22:00:29 UTC (rev 246)
+++ trunk/src/statesp.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -138,6 +138,7 @@
# Here we're going to convert inputs to matrices, if the user gave a
# non-matrix type.
+ #! TODO: [A, B, C, D] = map(matrix, [A, B, C, D])?
matrices = [A, B, C, D]
for i in range(len(matrices)):
# Convert to matrix first, if necessary.
@@ -215,9 +216,10 @@
str += "B = " + self.B.__str__() + "\n\n"
str += "C = " + self.C.__str__() + "\n\n"
str += "D = " + self.D.__str__() + "\n"
+ #! TODO: replace with standard calls to lti functions
if (type(self.dt) == bool and self.dt == True):
str += "\ndt unspecified\n"
- elif (self.dt > 0):
+ elif (not (self.dt is None) and type(self.dt) != bool and self.dt > 0):
str += "\ndt = " + self.dt.__str__() + "\n"
return str
Modified: trunk/src/xferfcn.py
===================================================================
--- trunk/src/xferfcn.py 2012-11-11 22:00:29 UTC (rev 246)
+++ trunk/src/xferfcn.py 2012-11-19 05:28:05 UTC (rev 247)
@@ -266,6 +266,7 @@
mimo = self.inputs > 1 or self.outputs > 1
if (var == None):
+ #! TODO: replace with standard calls to lti functions
var = 's' if self.dt == None or self.dt == 0 else 'z'
outstr = ""
@@ -294,6 +295,7 @@
# See if this is a discrete time system with specific sampling time
if (not (self.dt is None) and type(self.dt) != bool and self.dt > 0):
+ #! TODO: replace with standard calls to lti functions
outstr += "\ndt = " + self.dt.__str__() + "\n"
return outstr
@@ -945,8 +947,8 @@
lti_sys = lti(sys.A, sys.B, sys.C, sys.D)
num = squeeze(lti_sys.num)
den = squeeze(lti_sys.den)
- print(num)
- print(den)
+ # print(num)
+ # print(den)
return TransferFunction(num, den, sys.dt)
Property changes on: trunk/tests
___________________________________________________________________
Added: svn:ignore
+ __pycache__
|