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 <murray@altura.local> + + * 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 <murray@altura.local> + + * 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 <murray@altura.local> 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__ |