From: <mur...@us...> - 2014-03-22 18:09:56
|
Revision: 294 http://sourceforge.net/p/python-control/code/294 Author: murrayrm Date: 2014-03-22 18:09:48 +0000 (Sat, 22 Mar 2014) Log Message: ----------- Fixed bug #5 ('dt' instead of 'Ts' in dtime.py) and added some unit tests for dtime and FRD bdalg. Modified Paths: -------------- trunk/ChangeLog trunk/src/bdalg.py trunk/src/dtime.py trunk/src/frdata.py trunk/tests/discrete_test.py trunk/tests/frd_test.py Modified: trunk/ChangeLog =================================================================== --- trunk/ChangeLog 2013-07-16 14:59:20 UTC (rev 293) +++ trunk/ChangeLog 2014-03-22 18:09:48 UTC (rev 294) @@ -1,3 +1,17 @@ +2014-03-22 Richard Murray <murray@sidamo.local> + + * tests/discrete_test.py (TestDiscrete.test_sample_system): added + conversions using tustin and zoh to catch 'dt' bug #5 + + * src/dtime.py (sample_system): Changed 'dt' to 'Ts' to fix bug #4 + + * tests/frd_test.py (TestFRD.testbdalg): added unit tests for bdalg + functions operating on FRD data + + * src/bdalg.py (series, parallel, negate, feedback): updated + documentation to note that FRD ovjects work. + (feedback): updated conversions to allow for FRD + 2013-07-15 Richard Murray <murray@altura-2.local> * src/frdata.py, src/xferfcn.py: updated to use __truediv__ and Modified: trunk/src/bdalg.py =================================================================== --- trunk/src/bdalg.py 2013-07-16 14:59:20 UTC (rev 293) +++ trunk/src/bdalg.py 2014-03-22 18:09:48 UTC (rev 294) @@ -56,14 +56,15 @@ import scipy as sp import control.xferfcn as tf import control.statesp as ss +import control.frdata as frd def series(sys1, sys2): """Return the series connection sys2 * sys1 for --> sys1 --> sys2 -->. Parameters ---------- - sys1: scalar, StateSpace, or TransferFunction - sys2: scalar, StateSpace, or TransferFunction + sys1: scalar, StateSpace, TransferFunction, or FRD + sys2: scalar, StateSpace, TransferFunction, or FRD Returns ------- @@ -105,8 +106,8 @@ Parameters ---------- - sys1: scalar, StateSpace, or TransferFunction - sys2: scalar, StateSpace, or TransferFunction + sys1: scalar, StateSpace, TransferFunction, or FRD + sys2: scalar, StateSpace, TransferFunction, or FRD Returns ------- @@ -148,7 +149,7 @@ Parameters ---------- - sys: StateSpace or TransferFunction + sys: StateSpace, TransferFunction or FRD Returns ------- @@ -179,9 +180,9 @@ Parameters ---------- - sys1: scalar, StateSpace, or TransferFunction + sys1: scalar, StateSpace, TransferFunction, FRD The primary plant. - sys2: scalar, StateSpace, or TransferFunction + sys2: scalar, StateSpace, TransferFunction, FRD The feedback plant (often a feedback controller). sign: scalar The sign of feedback. `sign` = -1 indicates negative feedback, and @@ -219,13 +220,13 @@ # Check for correct input types. if not isinstance(sys1, (int, float, complex, tf.TransferFunction, - ss.StateSpace)): - raise TypeError("sys1 must be a TransferFunction or StateSpace object, \ -or a scalar.") + ss.StateSpace)): + raise TypeError("sys1 must be a TransferFunction or StateSpace " + + "object, or a scalar.") if not isinstance(sys2, (int, float, complex, tf.TransferFunction, - ss.StateSpace)): - raise TypeError("sys2 must be a TransferFunction or StateSpace object, \ -or a scalar.") + ss.StateSpace)): + raise TypeError("sys2 must be a TransferFunction or StateSpace " + + "object, or a scalar.") # If sys1 is a scalar, convert it to the appropriate LTI type so that we can # its feedback member function. @@ -234,6 +235,8 @@ sys1 = tf._convertToTransferFunction(sys1) elif isinstance(sys2, ss.StateSpace): sys1 = ss._convertToStateSpace(sys1) + elif isinstance(sys2, frd.FRD): + sys1 = ss._convertToFRD(sys1) else: # sys2 is a scalar. sys1 = tf._convertToTransferFunction(sys1) sys2 = tf._convertToTransferFunction(sys2) Modified: trunk/src/dtime.py =================================================================== --- trunk/src/dtime.py 2013-07-16 14:59:20 UTC (rev 293) +++ trunk/src/dtime.py 2014-03-22 18:09:48 UTC (rev 294) @@ -112,7 +112,7 @@ from scipy.signal import cont2discrete sys = [sysc.num[0][0], sysc.den[0][0]] scipySysD = cont2discrete(sys, Ts, method='bilinear') - sysd = TransferFunction(scipySysD[0][0], scipySysD[1], dt) + sysd = TransferFunction(scipySysD[0][0], scipySysD[1], Ts) except ImportError: raise TypeError("cont2discrete not found in scipy.signal; upgrade to v0.10.0+") @@ -121,7 +121,7 @@ from scipy.signal import cont2discrete sys = [sysc.num[0][0], sysc.den[0][0]] scipySysD = cont2discrete(sys, Ts, method='zoh') - sysd = TransferFunction(scipySysD[0][0],scipySysD[1], dt) + sysd = TransferFunction(scipySysD[0][0],scipySysD[1], Ts) except ImportError: raise TypeError("cont2discrete not found in scipy.signal; upgrade to v0.10.0+") Modified: trunk/src/frdata.py =================================================================== --- trunk/src/frdata.py 2013-07-16 14:59:20 UTC (rev 293) +++ trunk/src/frdata.py 2014-03-22 18:09:48 UTC (rev 294) @@ -451,7 +451,6 @@ """ if isinstance(sys, FRD): - omega.sort() if (abs(omega - sys.omega) < FRD.epsw).all(): # frequencies match, and system was already frd; simply use Modified: trunk/tests/discrete_test.py =================================================================== --- trunk/tests/discrete_test.py 2013-07-16 14:59:20 UTC (rev 293) +++ trunk/tests/discrete_test.py 2014-03-22 18:09:48 UTC (rev 294) @@ -264,6 +264,12 @@ for sysc in (self.siso_ss1, self.siso_ss1c, self.siso_tf1c): sysd = sample_system(sysc, 1, method='matched') self.assertEqual(sysd.dt, 1) + + sysd = sample_system(sysc, 1, method='tustin') + self.assertEqual(sysd.dt, 1) + + sysd = sample_system(sysc, 1, method='zoh') + self.assertEqual(sysd.dt, 1) # TODO: put in other generic checks # TODO: check results of converstion Modified: trunk/tests/frd_test.py =================================================================== --- trunk/tests/frd_test.py 2013-07-16 14:59:20 UTC (rev 293) +++ trunk/tests/frd_test.py 2014-03-22 18:09:48 UTC (rev 294) @@ -10,6 +10,7 @@ from control.xferfcn import TransferFunction from control.frdata import FRD, _convertToFRD from control.matlab import bode +import control.bdalg as bdalg import control.freqplot import matplotlib.pyplot as plt @@ -106,7 +107,43 @@ (f1 / h2).freqresp([0.1, 1.0, 10])[1], (h1 / h2).freqresp([0.1, 1.0, 10])[1]) # the reverse does not work - + + def testbdalg(self): + # get two SISO transfer functions + h1 = TransferFunction([1], [1, 2, 2]) + h2 = TransferFunction([1], [0.1, 1]) + omega = np.logspace(-1, 2, 10) + f1 = FRD(h1, omega) + f2 = FRD(h2, omega) + + np.testing.assert_array_almost_equal( + (bdalg.series(f1, f2)).freqresp([0.1, 1.0, 10])[0], + (bdalg.series(h1, h2)).freqresp([0.1, 1.0, 10])[0]) + + np.testing.assert_array_almost_equal( + (bdalg.parallel(f1, f2)).freqresp([0.1, 1.0, 10])[0], + (bdalg.parallel(h1, h2)).freqresp([0.1, 1.0, 10])[0]) + + np.testing.assert_array_almost_equal( + (bdalg.feedback(f1, f2)).freqresp([0.1, 1.0, 10])[0], + (bdalg.feedback(h1, h2)).freqresp([0.1, 1.0, 10])[0]) + + np.testing.assert_array_almost_equal( + (bdalg.negate(f1)).freqresp([0.1, 1.0, 10])[0], + (bdalg.negate(h1)).freqresp([0.1, 1.0, 10])[0]) + +# append() and connect() not implemented for FRD objects +# np.testing.assert_array_almost_equal( +# (bdalg.append(f1, f2)).freqresp([0.1, 1.0, 10])[0], +# (bdalg.append(h1, h2)).freqresp([0.1, 1.0, 10])[0]) +# +# f3 = bdalg.append(f1, f2, f2) +# h3 = bdalg.append(h1, h2, h2) +# Q = np.mat([ [1, 2], [2, -1] ]) +# np.testing.assert_array_almost_equal( +# (bdalg.connect(f3, Q, [2], [1])).freqresp([0.1, 1.0, 10])[0], +# (bdalg.connect(h3, Q, [2], [1])).freqresp([0.1, 1.0, 10])[0]) + def testFeedback(self): h1 = TransferFunction([1], [1, 2, 2]) omega = np.logspace(-1, 2, 10) |