From: <mur...@us...> - 2011-03-30 19:42:06
|
Revision: 141 http://python-control.svn.sourceforge.net/python-control/?rev=141&view=rev Author: murrayrm Date: 2011-03-30 19:41:58 +0000 (Wed, 30 Mar 2011) Log Message: ----------- moved unit tests into a separate directory; use 'python tests/test_all.py' to run all tests Modified Paths: -------------- branches/control-0.4b/ChangeLog branches/control-0.4b/Pending branches/control-0.4b/setup.py Added Paths: ----------- branches/control-0.4b/tests/ branches/control-0.4b/tests/bdalg_test.py branches/control-0.4b/tests/convert_test.py branches/control-0.4b/tests/freqresp.py branches/control-0.4b/tests/matlab_test.py branches/control-0.4b/tests/modelsimp_test.py branches/control-0.4b/tests/slycot_convert_test.py branches/control-0.4b/tests/statefbk_test.py branches/control-0.4b/tests/statesp_test.py branches/control-0.4b/tests/test_all.py branches/control-0.4b/tests/xferfcn_test.py Removed Paths: ------------- branches/control-0.4b/src/TestBDAlg.py branches/control-0.4b/src/TestConvert.py branches/control-0.4b/src/TestFreqRsp.py branches/control-0.4b/src/TestMatlab.py branches/control-0.4b/src/TestModelsimp.py branches/control-0.4b/src/TestSlycot.py branches/control-0.4b/src/TestStateSp.py branches/control-0.4b/src/TestStatefbk.py branches/control-0.4b/src/TestXferFcn.py Modified: branches/control-0.4b/ChangeLog =================================================================== --- branches/control-0.4b/ChangeLog 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/ChangeLog 2011-03-30 19:41:58 UTC (rev 141) @@ -1,3 +1,15 @@ +2011-03-30 Richard Murray <murray@malabar.local> + + * tests/: added top level subdirectory, to be used for unit tests. + The idea in putting the code here is that you can do 'setup.py test' + during installation to make sure everything is working correctly. + The test code would normally *not* be callable from the installed + module. + + * tests/*_test.py: moved from src/Test*.py + + * setup.py: updated version number. + 2011-02-13 Richard Murray <murray@sumatra.local> * src/*.py: added svn:keywords Id properly Modified: branches/control-0.4b/Pending =================================================================== --- branches/control-0.4b/Pending 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/Pending 2011-03-30 19:41:58 UTC (rev 141) @@ -9,7 +9,10 @@ to be implemented. OPEN BUGS - * step() doesn't handle systems with a pole at the origin (use lsim2) + * matlab.step() doesn't handle systems with a pole at the origin (use lsim2) + * tests/convert_test.py not working yet + * tests/test_all.py should report on failed tests + * tests/freqresp.py needs to be converted to unit test Transfer code from Roberto Bucher's yottalab to python-control acker - pole placement using Ackermann method Modified: branches/control-0.4b/setup.py =================================================================== --- branches/control-0.4b/setup.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/setup.py 2011-03-30 19:41:58 UTC (rev 141) @@ -3,12 +3,12 @@ from distutils.core import setup setup(name='control', - version='0.4a', + version='0.4b', description='Python Control Systems Library', author='Richard Murray', author_email='mu...@cd...', url='http://python-control.sourceforge.net', requires='scipy', + packages=['control'], package_dir = {'control':'src'}, - packages=['control'], ) Deleted: branches/control-0.4b/src/TestBDAlg.py =================================================================== --- branches/control-0.4b/src/TestBDAlg.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestBDAlg.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,166 +0,0 @@ -#!/usr/bin/env python - -import numpy as np -from xferfcn import TransferFunction -from statesp import StateSpace -from bdalg import feedback -import unittest - -class TestFeedback(unittest.TestCase): - """These are tests for the feedback function in bdalg.py. Currently, some - of the tests are not implemented, or are not working properly. TODO: these - need to be fixed.""" - - def setUp(self): - """This contains some random LTI systems and scalars for testing.""" - - # Two random SISO systems. - self.sys1 = TransferFunction([1, 2], [1, 2, 3]) - self.sys2 = StateSpace([[1., 4.], [3., 2.]], [[1.], [-4.]], - [[1., 0.]], [[0.]]) - # Two random scalars. - self.x1 = 2.5 - self.x2 = -3. - - def testScalarScalar(self): - """Scalar system with scalar feedback block.""" - - ans1 = feedback(self.x1, self.x2) - ans2 = feedback(self.x1, self.x2, 1.) - - self.assertAlmostEqual(ans1.num[0][0][0] / ans1.den[0][0][0], - -2.5 / 6.5) - self.assertAlmostEqual(ans2.num[0][0][0] / ans2.den[0][0][0], 2.5 / 8.5) - - def testScalarSS(self): - """Scalar system with state space feedback block.""" - - ans1 = feedback(self.x1, self.sys2) - ans2 = feedback(self.x1, self.sys2, 1.) - - np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) - np.testing.assert_array_almost_equal(ans1.B, [[2.5], [-10.]]) - np.testing.assert_array_almost_equal(ans1.C, [[-2.5, 0.]]) - np.testing.assert_array_almost_equal(ans1.D, [[2.5]]) - np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) - np.testing.assert_array_almost_equal(ans2.B, [[2.5], [-10.]]) - np.testing.assert_array_almost_equal(ans2.C, [[2.5, 0.]]) - np.testing.assert_array_almost_equal(ans2.D, [[2.5]]) - - def testScalarTF(self): - """Scalar system with transfer function feedback block.""" - - ans1 = feedback(self.x1, self.sys1) - ans2 = feedback(self.x1, self.sys1, 1.) - - np.testing.assert_array_almost_equal(ans1.num, [[[2.5, 5., 7.5]]]) - np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) - np.testing.assert_array_almost_equal(ans2.num, [[[2.5, 5., 7.5]]]) - np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]]) - - def testSSScalar(self): - """State space system with scalar feedback block.""" - - ans1 = feedback(self.sys2, self.x1) - ans2 = feedback(self.sys2, self.x1, 1.) - - np.testing.assert_array_almost_equal(ans1.A, [[-1.5, 4.], [13., 2.]]) - np.testing.assert_array_almost_equal(ans1.B, [[1.], [-4.]]) - np.testing.assert_array_almost_equal(ans1.C, [[1., 0.]]) - np.testing.assert_array_almost_equal(ans1.D, [[0.]]) - np.testing.assert_array_almost_equal(ans2.A, [[3.5, 4.], [-7., 2.]]) - np.testing.assert_array_almost_equal(ans2.B, [[1.], [-4.]]) - np.testing.assert_array_almost_equal(ans2.C, [[1., 0.]]) - np.testing.assert_array_almost_equal(ans2.D, [[0.]]) - - def testSSSS1(self): - """State space system with state space feedback block.""" - - ans1 = feedback(self.sys2, self.sys2) - ans2 = feedback(self.sys2, self.sys2, 1.) - - np.testing.assert_array_almost_equal(ans1.A, [[1., 4., -1., 0.], - [3., 2., 4., 0.], [1., 0., 1., 4.], [-4., 0., 3., 2]]) - np.testing.assert_array_almost_equal(ans1.B, [[1.], [-4.], [0.], [0.]]) - np.testing.assert_array_almost_equal(ans1.C, [[1., 0., 0., 0.]]) - np.testing.assert_array_almost_equal(ans1.D, [[0.]]) - np.testing.assert_array_almost_equal(ans2.A, [[1., 4., 1., 0.], - [3., 2., -4., 0.], [1., 0., 1., 4.], [-4., 0., 3., 2.]]) - np.testing.assert_array_almost_equal(ans2.B, [[1.], [-4.], [0.], [0.]]) - np.testing.assert_array_almost_equal(ans2.C, [[1., 0., 0., 0.]]) - np.testing.assert_array_almost_equal(ans2.D, [[0.]]) - - def testSSSS2(self): - """State space system with state space feedback block, including a - direct feedthrough term.""" - - sys3 = StateSpace([[-1., 4.], [2., -3]], [[2.], [3.]], [[-3., 1.]], - [[-2.]]) - sys4 = StateSpace([[-3., -2.], [1., 4.]], [[-2.], [-6.]], [[2., -3.]], - [[3.]]) - - ans1 = feedback(sys3, sys4) - ans2 = feedback(sys3, sys4, 1.) - - np.testing.assert_array_almost_equal(ans1.A, - [[-4.6, 5.2, 0.8, -1.2], [-3.4, -1.2, 1.2, -1.8], - [-1.2, 0.4, -1.4, -4.4], [-3.6, 1.2, 5.8, -3.2]]) - np.testing.assert_array_almost_equal(ans1.B, - [[-0.4], [-0.6], [-0.8], [-2.4]]) - np.testing.assert_array_almost_equal(ans1.C, [[0.6, -0.2, -0.8, 1.2]]) - np.testing.assert_array_almost_equal(ans1.D, [[0.4]]) - np.testing.assert_array_almost_equal(ans2.A, - [[-3.57142857142857, 4.85714285714286, 0.571428571428571, - -0.857142857142857], - [-1.85714285714286, -1.71428571428571, 0.857142857142857, - -1.28571428571429], - [0.857142857142857, -0.285714285714286, -1.85714285714286, - -3.71428571428571], - [2.57142857142857, -0.857142857142857, 4.42857142857143, - -1.14285714285714]]) - np.testing.assert_array_almost_equal(ans2.B, [[0.285714285714286], - [0.428571428571429], [0.571428571428571], [1.71428571428571]]) - np.testing.assert_array_almost_equal(ans2.C, [[-0.428571428571429, - 0.142857142857143, -0.571428571428571, 0.857142857142857]]) - np.testing.assert_array_almost_equal(ans2.D, [[-0.285714285714286]]) - - - def testSSTF(self): - """State space system with transfer function feedback block.""" - - # This functionality is not implemented yet. - pass - - def testTFScalar(self): - """Transfer function system with scalar feedback block.""" - - ans1 = feedback(self.sys1, self.x1) - ans2 = feedback(self.sys1, self.x1, 1.) - - np.testing.assert_array_almost_equal(ans1.num, [[[1., 2.]]]) - np.testing.assert_array_almost_equal(ans1.den, [[[1., 4.5, 8.]]]) - np.testing.assert_array_almost_equal(ans2.num, [[[1., 2.]]]) - np.testing.assert_array_almost_equal(ans2.den, [[[1., -0.5, -2.]]]) - - def testTFSS(self): - """Transfer function system with state space feedback block.""" - - # This functionality is not implemented yet. - pass - - def testTFTF(self): - """Transfer function system with transfer function feedback block.""" - - ans1 = feedback(self.sys1, self.sys1) - ans2 = feedback(self.sys1, self.sys1, 1.) - - np.testing.assert_array_almost_equal(ans1.num, [[[1., 4., 7., 6.]]]) - np.testing.assert_array_almost_equal(ans1.den, - [[[1., 4., 11., 16., 13.]]]) - np.testing.assert_array_almost_equal(ans2.num, [[[1., 4., 7., 6.]]]) - np.testing.assert_array_almost_equal(ans2.den, [[[1., 4., 9., 8., 5.]]]) -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestFeedback) - -if __name__ == "__main__": - unittest.main() Deleted: branches/control-0.4b/src/TestConvert.py =================================================================== --- branches/control-0.4b/src/TestConvert.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestConvert.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,91 +0,0 @@ -#!/usr/bin/env python - -"""TestConvert.py - -Test state space and transfer function conversion. - -Currently, this unit test script is not complete. It converts several random -state spaces back and forth between state space and transfer function -representations. Ideally, it should be able to assert that the conversion -outputs are correct. This is not yet implemented. - -Also, the conversion seems to enter an infinite loop once in a while. The cause -of this is unknown. - -""" - -import numpy as np -import matlab -import unittest - -class TestConvert(unittest.TestCase): - """Test state space and transfer function conversions.""" - - def setUp(self): - """Set up testing parameters.""" - - # Number of times to run each of the randomized tests. - self.numTests = 1 #almost guarantees failure - # Maximum number of states to test + 1 - self.maxStates = 20 - # Maximum number of inputs and outputs to test + 1 - self.maxIO = 20 - # Set to True to print systems to the output. - self.debug = True - - def printSys(self, sys, ind): - """Print system to the standard output.""" - - if self.debug: - print "sys%i:\n" % ind - print sys - - def testConvert(self): - """Test state space to transfer function conversion.""" - #Currently it only tests that a TF->SS->TF generates an unchanged TF - - #print __doc__ - - for states in range(1, self.maxStates): - for inputs in range(1, self.maxIO): - for outputs in range(1, self.maxIO): - #start with a random SS system and transform to TF - #then back to SS, check that the matrices are the same. - ssOriginal = matlab.rss(states, inputs, outputs) - self.printSys(ssOriginal, 1) - - tfOriginal = matlab.tf(ssOriginal) - self.printSys(tfOriginal, 2) - - ssTransformed = matlab.ss(tfOriginal) - self.printSys(ssTransformed, 3) - - tfTransformed = matlab.tf(ssTransformed) - self.printSys(tfTransformed, 4) - - for inputNum in range(inputs): - for outputNum in range(outputs): - np.testing.assert_array_almost_equal(\ - tfOriginal.num[outputNum][inputNum],\ - tfTransformed.num[outputNum][inputNum]) - - np.testing.assert_array_almost_equal(\ - tfOriginal.den[outputNum][inputNum],\ - tfTransformed.den[outputNum][inputNum]) - - #To test the ss systems is harder because they aren't the same - #realization. This could be done with checking that they have the - #same freq response with bode, but apparently it doesn't work - #the way it should right now: - ## Bode should work like this: - #[mag,phase,freq]=bode(sys) - #it doesn't seem to...... - #This should be added. - - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestConvert) - -if __name__ == "__main__": - unittest.main() Deleted: branches/control-0.4b/src/TestFreqRsp.py =================================================================== --- branches/control-0.4b/src/TestFreqRsp.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestFreqRsp.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,63 +0,0 @@ -#!/usr/bin/env python - -### MUST BE CONVERTED TO A UNIT TEST!!! - - -# Script to test frequency response and frequency response plots like bode, nyquist and gang of 4. -# Especially need to ensure that nothing SISO is broken and that MIMO at least handles exceptions and has some default to SISO in place. - - -import unittest -from statesp import StateSpace -from matlab import ss, tf, bode -import numpy as np -import matplotlib.pyplot as plt - -# SISO -plt.close('all') - -A = np.matrix('1,1;0,1') -B = np.matrix('0;1') -C = np.matrix('1,0') -D = 0 -sys = StateSpace(A,B,C,D) -#or try -#sys = ss(A,B,C,D) - -# test frequency response -omega = np.linspace(10e-2,10e2,1000) -frq=sys.freqresp(omega) - -# MIMO -B = np.matrix('1,0;0,1') -D = np.matrix('0,0') -sysMIMO = ss(A,B,C,D) -frqMIMO = sysMIMO.freqresp(omega) - -plt.figure(1) -bode(sys) - -systf = tf(sys) -tfMIMO = tf(sysMIMO) - -print systf.pole() -#print tfMIMO.pole() # - should throw not implemented exception -#print tfMIMO.zero() # - should throw not implemented exception - -plt.figure(2) -bode(systf) - -#bode(sysMIMO) # - should throw not implemented exception -#bode(tfMIMO) # - should throw not implemented exception - -#plt.figure(3) -#plt.semilogx(omega,20*np.log10(np.squeeze(frq[0]))) - -#plt.figure(4) -#bode(sysMIMO,omega) - - -def suite(): - pass - #Uncomment this once it is a real unittest - #return unittest.TestLoader().loadTestsFromTestCase(TestFreqRsp) Deleted: branches/control-0.4b/src/TestMatlab.py =================================================================== --- branches/control-0.4b/src/TestMatlab.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestMatlab.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -from matlab import * -import numpy as np -import unittest - -class TestMatlab(unittest.TestCase): - def testStep(self): - A = np.matrix("1. -2.; 3. -4.") - B = np.matrix("5.; 7.") - C = np.matrix("6. 8.") - D = np.matrix("9.") - sys = ss(A,B,C,D) - t = np.linspace(0, 1, 10) - t, yout = step(sys, T=t) - youttrue = np.matrix("9. 17.6457 24.7072 30.4855 35.2234 39.1165 42.3227 44.9694 47.1599 48.9776") - np.testing.assert_array_almost_equal(yout, youttrue,decimal=4) - - def testImpulse(self): - A = np.matrix("1. -2.; 3. -4.") - B = np.matrix("5.; 7.") - C = np.matrix("6. 8.") - D = np.matrix("9.") - sys = ss(A,B,C,D) - t = np.linspace(0, 1, 10) - t, yout = impulse(sys, T=t) - youttrue = np.matrix("86. 70.1808 57.3753 46.9975 38.5766 31.7344 26.1668 21.6292 17.9245 14.8945") - np.testing.assert_array_almost_equal(yout, youttrue,decimal=4) - -# def testInitial(self): -# A = np.matrix("1. -2.; 3. -4.") -# B = np.matrix("5.; 7.") -# C = np.matrix("6. 8.") -# D = np.matrix("9.") -# sys = ss(A,B,C,D) -# t = np.linspace(0, 1, 10) -# x0 = np.matrix(".5; 1.") -# t, yout = initial(sys, T=t, X0=x0) -# youttrue = np.matrix("11. 8.1494 5.9361 4.2258 2.9118 1.9092 1.1508 0.5833 0.1645 -0.1391") -# np.testing.assert_array_almost_equal(yout, youttrue,decimal=4) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestMatlab) - -if __name__ == '__main__': - unittest.main() Deleted: branches/control-0.4b/src/TestModelsimp.py =================================================================== --- branches/control-0.4b/src/TestModelsimp.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestModelsimp.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,96 +0,0 @@ -#!/usr/bin/env python - -from modelsimp import * -from matlab import * -import numpy as np -import unittest - -class TestModelsimp(unittest.TestCase): - def testHSVD(self): - A = np.matrix("1. -2.; 3. -4.") - B = np.matrix("5.; 7.") - C = np.matrix("6. 8.") - D = np.matrix("9.") - sys = ss(A,B,C,D) - hsv = hsvd(sys) - hsvtrue = np.matrix("24.42686 0.5731395") - np.testing.assert_array_almost_equal(hsv, hsvtrue) - - def testMarkov(self): - U = np.matrix("1.; 1.; 1.; 1.; 1.") - Y = U - M = 3 - H = markov(Y,U,M) - Htrue = np.matrix("1.; 0.; 0.") - np.testing.assert_array_almost_equal( H, Htrue ) - - def testModredMatchDC(self): - #balanced realization computed in matlab for the transfer function: - # num = [1 11 45 32], den = [1 15 60 200 60] - A = np.matrix('-1.958, -1.194, 1.824, -1.464; \ - -1.194, -0.8344, 2.563, -1.351; \ - -1.824, -2.563, -1.124, 2.704; \ - -1.464, -1.351, -2.704, -11.08') - B = np.matrix('-0.9057; -0.4068; -0.3263; -0.3474') - C = np.matrix('-0.9057, -0.4068, 0.3263, -0.3474') - D = np.matrix('0.') - sys = ss(A,B,C,D) - rsys = modred(sys,[2, 3],'matchdc') - Artrue = np.matrix('-4.431, -4.552; -4.552, -5.361') - Brtrue = np.matrix('-1.362; -1.031') - Crtrue = np.matrix('-1.362, -1.031') - Drtrue = np.matrix('-0.08384') - np.testing.assert_array_almost_equal(rsys.A, Artrue,decimal=3) - np.testing.assert_array_almost_equal(rsys.B, Brtrue,decimal=3) - np.testing.assert_array_almost_equal(rsys.C, Crtrue,decimal=3) - np.testing.assert_array_almost_equal(rsys.D, Drtrue,decimal=2) - - def testModredTruncate(self): - #balanced realization computed in matlab for the transfer function: - # num = [1 11 45 32], den = [1 15 60 200 60] - A = np.matrix('-1.958, -1.194, 1.824, -1.464; \ - -1.194, -0.8344, 2.563, -1.351; \ - -1.824, -2.563, -1.124, 2.704; \ - -1.464, -1.351, -2.704, -11.08') - B = np.matrix('-0.9057; -0.4068; -0.3263; -0.3474') - C = np.matrix('-0.9057, -0.4068, 0.3263, -0.3474') - D = np.matrix('0.') - sys = ss(A,B,C,D) - rsys = modred(sys,[2, 3],'truncate') - Artrue = np.matrix('-1.958, -1.194; -1.194, -0.8344') - Brtrue = np.matrix('-0.9057; -0.4068') - Crtrue = np.matrix('-0.9057, -0.4068') - Drtrue = np.matrix('0.') - np.testing.assert_array_almost_equal(rsys.A, Artrue) - np.testing.assert_array_almost_equal(rsys.B, Brtrue) - np.testing.assert_array_almost_equal(rsys.C, Crtrue) - np.testing.assert_array_almost_equal(rsys.D, Drtrue) - - def testBalredTruncate(self): - #controlable canonical realization computed in matlab for the transfer function: - # num = [1 11 45 32], den = [1 15 60 200 60] - A = np.matrix('-15., -7.5, -6.25, -1.875; \ - 8., 0., 0., 0.; \ - 0., 4., 0., 0.; \ - 0., 0., 1., 0.') - B = np.matrix('2.; 0.; 0.; 0.') - C = np.matrix('0.5, 0.6875, 0.7031, 0.5') - D = np.matrix('0.') - sys = ss(A,B,C,D) - orders = 2 - rsys = balred(sys,orders,method='truncate') - Artrue = np.matrix('-1.958, -1.194; -1.194, -0.8344') - Brtrue = np.matrix('0.9057; 0.4068') - Crtrue = np.matrix('0.9057, 0.4068') - Drtrue = np.matrix('0.') - np.testing.assert_array_almost_equal(rsys.A, Artrue,decimal=2) - np.testing.assert_array_almost_equal(rsys.B, Brtrue,decimal=4) - np.testing.assert_array_almost_equal(rsys.C, Crtrue,decimal=4) - np.testing.assert_array_almost_equal(rsys.D, Drtrue,decimal=4) - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestModelsimp) - - -if __name__ == '__main__': - unittest.main() Deleted: branches/control-0.4b/src/TestSlycot.py =================================================================== --- branches/control-0.4b/src/TestSlycot.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestSlycot.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,124 +0,0 @@ -#!/usr/bin/env python - - -import numpy as np -from slycot import tb04ad, td04ad -import matlab -import unittest - - -class TestSlycot(unittest.TestCase): - """TestSlycot compares transfer function and state space conversions for - various numbers of inputs,outputs and states. - 1. Usually passes for SISO systems of any state dim, occasonally, there will be a dimension mismatch if the original randomly generated ss system is not minimal because td04ad returns a minimal system. - - 2. For small systems with many inputs, n<<m, the tests fail because td04ad returns a minimal ss system which has fewer states than the original system. It is typical for systems with many more inputs than states to have extraneous states. - - 3. For systems with larger dimensions, n~>5 and with 2 or more outputs the conversion to statespace (td04ad) intermittently results in an equivalent realization of higher order than the original tf order. We think this has to do with minimum realization tolerances in the Fortran. The algorithm doesn't recognize that two denominators are identical and so it creates a system with nearly duplicate eigenvalues and double the state dimension. This should not be a problem in the python-control usage because the common_den() method finds repeated roots within a tolerance that we specify. - - Matlab: Matlab seems to force its statespace system output to have order less than or equal to the order of denominators provided, avoiding the problem of very large state dimension we describe in 3. It does however, still have similar problems with pole/zero cancellation such as we encounter in 2, where a statespace system may have fewer states than the original order of transfer function. - """ - def setUp(self): - """Define some test parameters.""" - self.numTests = 5 - self.maxStates = 10 - self.maxI = 1 - self.maxO = 1 - - def testTF(self): - """ Directly tests the functions tb04ad and td04ad through direct comparison of transfer function coefficients. - Similar to TestConvert, but tests at a lower level. - """ - for states in range(1, self.maxStates): - for inputs in range(1, self.maxI+1): - for outputs in range(1, self.maxO+1): - for testNum in range(self.numTests): - - ssOriginal = matlab.rss(states, inputs, outputs) - - print '====== Original SS ==========' - print ssOriginal - print 'states=',states - print 'inputs=',inputs - print 'outputs=',outputs - - - tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb, tfOrigingal_nctrb, tfOriginal_index,\ - tfOriginal_dcoeff, tfOriginal_ucoeff = tb04ad(states,inputs,outputs,\ - ssOriginal.A,ssOriginal.B,ssOriginal.C,ssOriginal.D,tol1=0.0) - - ssTransformed_nr, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D\ - = td04ad('R',inputs,outputs,tfOriginal_index,tfOriginal_dcoeff,tfOriginal_ucoeff,tol=0.0) - - tfTransformed_Actrb, tfTransformed_Bctrb, tfTransformed_Cctrb, tfTransformed_nctrb,\ - tfTransformed_index, tfTransformed_dcoeff, tfTransformed_ucoeff = tb04ad(ssTransformed_nr,\ - inputs,outputs,ssTransformed_A, ssTransformed_B, ssTransformed_C,ssTransformed_D,tol1=0.0) - #print 'size(Trans_A)=',ssTransformed_A.shape - print '===== Transformed SS ==========' - print matlab.ss(ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D) - #print 'Trans_nr=',ssTransformed_nr - #print 'tfOrig_index=',tfOriginal_index - #print 'tfOrig_ucoeff=',tfOriginal_ucoeff - #print 'tfOrig_dcoeff=',tfOriginal_dcoeff - #print 'tfTrans_index=',tfTransformed_index - #print 'tfTrans_ucoeff=',tfTransformed_ucoeff - #print 'tfTrans_dcoeff=',tfTransformed_dcoeff - #Compare the TF directly, must match - #numerators - np.testing.assert_array_almost_equal(tfOriginal_ucoeff,tfTransformed_ucoeff,decimal=3) - #denominators - np.testing.assert_array_almost_equal(tfOriginal_dcoeff,tfTransformed_dcoeff,decimal=3) - - def testFreqResp(self): - """Compare the bode reponses of the SS systems and TF systems to the original SS - They generally are different realizations but have same freq resp. - Currently this test may only be applied to SISO systems. - """ - for states in range(1,self.maxStates): - for testNum in range(self.numTests): - for inputs in range(1,1): - for outputs in range(1,1): - ssOriginal = matlab.rss(states, inputs, outputs) - - tfOriginal_Actrb, tfOriginal_Bctrb, tfOriginal_Cctrb, tfOrigingal_nctrb, tfOriginal_index,\ - tfOriginal_dcoeff, tfOriginal_ucoeff = tb04ad(states,inputs,outputs,\ - ssOriginal.A,ssOriginal.B,ssOriginal.C,ssOriginal.D,tol1=0.0) - - ssTransformed_nr, ssTransformed_A, ssTransformed_B, ssTransformed_C, ssTransformed_D\ - = td04ad('R',inputs,outputs,tfOriginal_index,tfOriginal_dcoeff,tfOriginal_ucoeff,tol=0.0) - - tfTransformed_Actrb, tfTransformed_Bctrb, tfTransformed_Cctrb, tfTransformed_nctrb,\ - tfTransformed_index, tfTransformed_dcoeff, tfTransformed_ucoeff = tb04ad(\ - ssTransformed_nr,inputs,outputs,ssTransformed_A, ssTransformed_B, ssTransformed_C,\ - ssTransformed_D,tol1=0.0) - - numTransformed = np.array(tfTransformed_ucoeff) - denTransformed = np.array(tfTransformed_dcoeff) - numOriginal = np.array(tfOriginal_ucoeff) - denOriginal = np.array(tfOriginal_dcoeff) - - ssTransformed = matlab.ss(ssTransformed_A,ssTransformed_B,ssTransformed_C,ssTransformed_D) - for inputNum in range(inputs): - for outputNum in range(outputs): - [ssOriginalMag,ssOriginalPhase,freq] = matlab.bode(ssOriginal,Plot=False) - [tfOriginalMag,tfOriginalPhase,freq] = matlab.bode(matlab.tf(numOriginal[outputNum][inputNum],denOriginal[outputNum]),Plot=False) - [ssTransformedMag,ssTransformedPhase,freq] = matlab.bode(ssTransformed,freq,Plot=False) - [tfTransformedMag,tfTransformedPhase,freq] = matlab.bode(matlab.tf(numTransformed[outputNum][inputNum],denTransformed[outputNum]),freq,Plot=False) - #print 'numOrig=',numOriginal[outputNum][inputNum] - #print 'denOrig=',denOriginal[outputNum] - #print 'numTrans=',numTransformed[outputNum][inputNum] - #print 'denTrans=',denTransformed[outputNum] - np.testing.assert_array_almost_equal(ssOriginalMag,tfOriginalMag,decimal=3) - np.testing.assert_array_almost_equal(ssOriginalPhase,tfOriginalPhase,decimal=3) - np.testing.assert_array_almost_equal(ssOriginalMag,ssTransformedMag,decimal=3) - np.testing.assert_array_almost_equal(ssOriginalPhase,ssTransformedPhase,decimal=3) - np.testing.assert_array_almost_equal(tfOriginalMag,tfTransformedMag,decimal=3) - np.testing.assert_array_almost_equal(tfOriginalPhase,tfTransformedPhase,decimal=2) - -#These are here for once the above is made into a unittest. -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestSlycot) - -if __name__=='__main__': - unittest.main() - Deleted: branches/control-0.4b/src/TestStateSp.py =================================================================== --- branches/control-0.4b/src/TestStateSp.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestStateSp.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,209 +0,0 @@ -#!/usr/bin/env python - -import numpy as np -import unittest -import matlab -from statesp import StateSpace - -class TestStateSpace(unittest.TestCase): - """Tests for the StateSpace class.""" - - def setUp(self): - """Set up a MIMO system to test operations on.""" - - A = [[-3., 4., 2.], [-1., -3., 0.], [2., 5., 3.]] - B = [[1., 4.], [-3., -3.], [-2., 1.]] - C = [[4., 2., -3.], [1., 4., 3.]] - D = [[-2., 4.], [0., 1.]] - - a = [[4., 1.], [2., -3]] - b = [[5., 2.], [-3., -3.]] - c = [[2., -4], [0., 1.]] - d = [[3., 2.], [1., -1.]] - - self.sys1 = StateSpace(A, B, C, D) - self.sys2 = StateSpace(a, b, c, d) - - def testPole(self): - """Evaluate the poles of a MIMO system.""" - - p = self.sys1.pole() - - np.testing.assert_array_almost_equal(p, [3.34747678408874, - -3.17373839204437 + 1.47492908003839j, - -3.17373839204437 - 1.47492908003839j]) - - def testZero(self): - """Evaluate the zeros of a SISO system.""" - - sys = StateSpace(self.sys1.A, [[3.], [-2.], [4.]], [[-1., 3., 2.]], [[-4.]]) - z = sys.zero() - - np.testing.assert_array_almost_equal(z, [4.26864638637134, - -3.75932319318567 + 1.10087776649554j, - -3.75932319318567 - 1.10087776649554j]) - - def testAdd(self): - """Add two MIMO systems.""" - - A = [[-3., 4., 2., 0., 0.], [-1., -3., 0., 0., 0.], - [2., 5., 3., 0., 0.], [0., 0., 0., 4., 1.], [0., 0., 0., 2., -3.]] - B = [[1., 4.], [-3., -3.], [-2., 1.], [5., 2.], [-3., -3.]] - C = [[4., 2., -3., 2., -4.], [1., 4., 3., 0., 1.]] - D = [[1., 6.], [1., 0.]] - - sys = self.sys1 + self.sys2 - - np.testing.assert_array_almost_equal(sys.A, A) - np.testing.assert_array_almost_equal(sys.B, B) - np.testing.assert_array_almost_equal(sys.C, C) - np.testing.assert_array_almost_equal(sys.D, D) - - def testSub(self): - """Subtract two MIMO systems.""" - - A = [[-3., 4., 2., 0., 0.], [-1., -3., 0., 0., 0.], - [2., 5., 3., 0., 0.], [0., 0., 0., 4., 1.], [0., 0., 0., 2., -3.]] - B = [[1., 4.], [-3., -3.], [-2., 1.], [5., 2.], [-3., -3.]] - C = [[4., 2., -3., -2., 4.], [1., 4., 3., 0., -1.]] - D = [[-5., 2.], [-1., 2.]] - - sys = self.sys1 - self.sys2 - - np.testing.assert_array_almost_equal(sys.A, A) - np.testing.assert_array_almost_equal(sys.B, B) - np.testing.assert_array_almost_equal(sys.C, C) - np.testing.assert_array_almost_equal(sys.D, D) - - def testMul(self): - """Multiply two MIMO systems.""" - - A = [[4., 1., 0., 0., 0.], [2., -3., 0., 0., 0.], [2., 0., -3., 4., 2.], - [-6., 9., -1., -3., 0.], [-4., 9., 2., 5., 3.]] - B = [[5., 2.], [-3., -3.], [7., -2.], [-12., -3.], [-5., -5.]] - C = [[-4., 12., 4., 2., -3.], [0., 1., 1., 4., 3.]] - D = [[-2., -8.], [1., -1.]] - - sys = self.sys1 * self.sys2 - - np.testing.assert_array_almost_equal(sys.A, A) - np.testing.assert_array_almost_equal(sys.B, B) - np.testing.assert_array_almost_equal(sys.C, C) - np.testing.assert_array_almost_equal(sys.D, D) - - def testEvalFr(self): - """Evaluate the frequency response at one frequency.""" - - A = [[-2, 0.5], [0.5, -0.3]] - B = [[0.3, -1.3], [0.1, 0.]] - C = [[0., 0.1], [-0.3, -0.2]] - D = [[0., -0.8], [-0.3, 0.]] - sys = StateSpace(A, B, C, D) - - resp = [[4.37636761487965e-05 - 0.0152297592997812j, - -0.792603938730853 + 0.0261706783369803j], - [-0.331544857768052 + 0.0576105032822757j, - 0.128919037199125 - 0.143824945295405j]] - - np.testing.assert_almost_equal(sys.evalfr(1.), resp) - - def testFreqResp(self): - """Evaluate the frequency response at multiple frequencies.""" - - A = [[-2, 0.5], [0.5, -0.3]] - B = [[0.3, -1.3], [0.1, 0.]] - C = [[0., 0.1], [-0.3, -0.2]] - D = [[0., -0.8], [-0.3, 0.]] - sys = StateSpace(A, B, C, D) - - truemag = [[[0.0852992637230322, 0.00103596611395218], - [0.935374692849736, 0.799380720864549]], - [[0.55656854563842, 0.301542699860857], - [0.609178071542849, 0.0382108097985257]]] - truephase = [[[-0.566195599644593, -1.68063565332582], - [3.0465958317514, 3.14141384339534]], - [[2.90457947657161, 3.10601268291914], - [-0.438157380501337, -1.40720969147217]]] - trueomega = [0.1, 10.] - - mag, phase, omega = sys.freqresp(trueomega) - - np.testing.assert_almost_equal(mag, truemag) - np.testing.assert_almost_equal(phase, truephase) - np.testing.assert_equal(omega, trueomega) - -class TestRss(unittest.TestCase): - """These are tests for the proper functionality of statesp.rss.""" - - def setUp(self): - # Number of times to run each of the randomized tests. - self.numTests = 100 - # Maxmimum number of states to test + 1 - self.maxStates = 10 - # Maximum number of inputs and outputs to test + 1 - self.maxIO = 5 - - def testShape(self): - """Test that rss outputs have the right state, input, and output - size.""" - - for states in range(1, self.maxStates): - for inputs in range(1, self.maxIO): - for outputs in range(1, self.maxIO): - sys = matlab.rss(states, inputs, outputs) - self.assertEqual(sys.states, states) - self.assertEqual(sys.inputs, inputs) - self.assertEqual(sys.outputs, outputs) - - def testPole(self): - """Test that the poles of rss outputs have a negative real part.""" - - for states in range(1, self.maxStates): - for inputs in range(1, self.maxIO): - for outputs in range(1, self.maxIO): - sys = matlab.rss(states, inputs, outputs) - p = sys.pole() - for z in p: - self.assertTrue(z.real < 0) - -class TestDrss(unittest.TestCase): - """These are tests for the proper functionality of statesp.drss.""" - - def setUp(self): - # Number of times to run each of the randomized tests. - self.numTests = 100 - # Maxmimum number of states to test + 1 - self.maxStates = 10 - # Maximum number of inputs and outputs to test + 1 - self.maxIO = 5 - - def testShape(self): - """Test that drss outputs have the right state, input, and output - size.""" - - for states in range(1, self.maxStates): - for inputs in range(1, self.maxIO): - for outputs in range(1, self.maxIO): - sys = matlab.drss(states, inputs, outputs) - self.assertEqual(sys.states, states) - self.assertEqual(sys.inputs, inputs) - self.assertEqual(sys.outputs, outputs) - - def testPole(self): - """Test that the poles of drss outputs have less than unit magnitude.""" - - for states in range(1, self.maxStates): - for inputs in range(1, self.maxIO): - for outputs in range(1, self.maxIO): - sys = matlab.drss(states, inputs, outputs) - p = sys.pole() - for z in p: - self.assertTrue(abs(z) < 1) - - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestStateSpace) - - -if __name__ == "__main__": - unittest.main() Deleted: branches/control-0.4b/src/TestStatefbk.py =================================================================== --- branches/control-0.4b/src/TestStatefbk.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestStatefbk.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,88 +0,0 @@ -#!/usr/bin/env python - -from statefbk import ctrb, obsv, place, lqr, gram -from matlab import * -import numpy as np -import unittest - -class TestStatefbk(unittest.TestCase): - def testCtrbSISO(self): - A = np.matrix("1. 2.; 3. 4.") - B = np.matrix("5.; 7.") - Wctrue = np.matrix("5. 19.; 7. 43.") - Wc = ctrb(A,B) - np.testing.assert_array_almost_equal(Wc, Wctrue) - - def testCtrbMIMO(self): - A = np.matrix("1. 2.; 3. 4.") - B = np.matrix("5. 6.; 7. 8.") - Wctrue = np.matrix("5. 6. 19. 22.; 7. 8. 43. 50.") - Wc = ctrb(A,B) - np.testing.assert_array_almost_equal(Wc, Wctrue) - - def testObsvSISO(self): - A = np.matrix("1. 2.; 3. 4.") - C = np.matrix("5. 7.") - Wotrue = np.matrix("5. 7.; 26. 38.") - Wo = obsv(A,C) - np.testing.assert_array_almost_equal(Wo, Wotrue) - - def testObsvMIMO(self): - A = np.matrix("1. 2.; 3. 4.") - C = np.matrix("5. 6.; 7. 8.") - Wotrue = np.matrix("5. 6.; 7. 8.; 23. 34.; 31. 46.") - Wo = obsv(A,C) - np.testing.assert_array_almost_equal(Wo, Wotrue) - - def testCtrbObsvDuality(self): - A = np.matrix("1.2 -2.3; 3.4 -4.5") - B = np.matrix("5.8 6.9; 8. 9.1") - Wc = ctrb(A,B); - A = np.transpose(A) - C = np.transpose(B) - Wo = np.transpose(obsv(A,C)); - np.testing.assert_array_almost_equal(Wc,Wo) - - def testGramWc(self): - A = np.matrix("1. -2.; 3. -4.") - B = np.matrix("5. 6.; 7. 8.") - C = np.matrix("4. 5.; 6. 7.") - D = np.matrix("13. 14.; 15. 16.") - sys = ss(A, B, C, D) - Wctrue = np.matrix("18.5 24.5; 24.5 32.5") - Wc = gram(sys,'c') - np.testing.assert_array_almost_equal(Wc, Wctrue) - - def testGramWo(self): - A = np.matrix("1. -2.; 3. -4.") - B = np.matrix("5. 6.; 7. 8.") - C = np.matrix("4. 5.; 6. 7.") - D = np.matrix("13. 14.; 15. 16.") - sys = ss(A, B, C, D) - Wotrue = np.matrix("257.5 -94.5; -94.5 56.5") - Wo = gram(sys,'o') - np.testing.assert_array_almost_equal(Wo, Wotrue) - - def testGramWo2(self): - A = np.matrix("1. -2.; 3. -4.") - B = np.matrix("5.; 7.") - C = np.matrix("6. 8.") - D = np.matrix("9.") - sys = ss(A,B,C,D) - Wotrue = np.matrix("198. -72.; -72. 44.") - Wo = gram(sys,'o') - np.testing.assert_array_almost_equal(Wo, Wotrue) - - def testGramsys(self): - num =[1.] - den = [1., 1., 1.] - sys = tf(num,den) - self.assertRaises(ValueError, gram, sys, 'o') - self.assertRaises(ValueError, gram, sys, 'c') - -def suite(): - return unittest.TestLoader().loadTestsFromTestCase(TestStatefbk) - - -if __name__ == '__main__': - unittest.main() Deleted: branches/control-0.4b/src/TestXferFcn.py =================================================================== --- branches/control-0.4b/src/TestXferFcn.py 2011-03-30 16:27:27 UTC (rev 140) +++ branches/control-0.4b/src/TestXferFcn.py 2011-03-30 19:41:58 UTC (rev 141) @@ -1,437 +0,0 @@ -#!/usr/bin/env python - -import numpy as np -from statesp import StateSpace -from xferfcn import TransferFunction, _convertToTransferFunction -import unittest - -class TestXferFcn(unittest.TestCase): - """These are tests for functionality and correct reporting of the transfer - function class. Throughout these tests, we will give different input - formats to the xTranferFunction constructor, to try to break it. These - tests have been verified in MATLAB.""" - - # Tests for raising exceptions. - - def testBadInputType(self): - """Give the constructor invalid input types.""" - - self.assertRaises(TypeError, TransferFunction, [[0., 1.], [2., 3.]], - [[5., 2.], [3., 0.]]) - - def testInconsistentDimension(self): - """Give the constructor a numerator and denominator of different - sizes.""" - - self.assertRaises(ValueError, TransferFunction, [[[1.]]], - [[[1.], [2., 3.]]]) - self.assertRaises(ValueError, TransferFunction, [[[1.]]], - [[[1.]], [[2., 3.]]]) - self.assertRaises(ValueError, TransferFunction, [[[1.]]], - [[[1.], [1., 2.]], [[5., 2.], [2., 3.]]]) - - def testInconsistentColumns(self): - """Give the constructor inputs that do not have the same number of - columns in each row.""" - - self.assertRaises(ValueError, TransferFunction, 1., - [[[1.]], [[2.], [3.]]]) - self.assertRaises(ValueError, TransferFunction, [[[1.]], [[2.], [3.]]], - 1.) - - def testZeroDenominator(self): - """Give the constructor a transfer function with a zero denominator.""" - - self.assertRaises(ValueError, TransferFunction, 1., 0.) - self.assertRaises(ValueError, TransferFunction, - [[[1.], [2., 3.]], [[-1., 4.], [3., 2.]]], - [[[1., 0.], [0.]], [[0., 0.], [2.]]]) - - def testAddInconsistentDimension(self): - """Add two transfer function matrices of different sizes.""" - - sys1 = TransferFunction([[[1., 2.]]], [[[4., 5.]]]) - sys2 = TransferFunction([[[4., 3.]], [[1., 2.]]], - [[[1., 6.]], [[2., 4.]]]) - self.assertRaises(ValueError, sys1.__add__, sys2) - self.assertRaises(ValueError, sys1.__sub__, sys2) - self.assertRaises(ValueError, sys1.__radd__, sys2) - self.assertRaises(ValueError, sys1.__rsub__, sys2) - - def testMulInconsistentDimension(self): - """Multiply two transfer function matrices of incompatible sizes.""" - - sys1 = TransferFunction([[[1., 2.], [4., 5.]], [[2., 5.], [4., 3.]]], - [[[6., 2.], [4., 1.]], [[6., 7.], [2., 4.]]]) - sys2 = TransferFunction([[[1.]], [[2.]], [[3.]]], - [[[4.]], [[5.]], [[6.]]]) - self.assertRaises(ValueError, sys1.__mul__, sys2) - self.assertRaises(ValueError, sys2.__mul__, sys1) - self.assertRaises(ValueError, sys1.__rmul__, sys2) - self.assertRaises(ValueError, sys2.__rmul__, sys1) - - # Tests for TransferFunction._truncatecoeff - - def testTruncateCoeff1(self): - """Remove extraneous zeros in polynomial representations.""" - - sys1 = TransferFunction([0., 0., 1., 2.], [[[0., 0., 0., 3., 2., 1.]]]) - - np.testing.assert_array_equal(sys1.num, [[[1., 2.]]]) - np.testing.assert_array_equal(sys1.den, [[[3., 2., 1.]]]) - - def testTruncateCoeff2(self): - """Remove extraneous zeros in polynomial representations.""" - - sys1 = TransferFunction([0., 0., 0.], 1.) - - np.testing.assert_array_equal(sys1.num, [[[0.]]]) - np.testing.assert_array_equal(sys1.den, [[[1.]]]) - - # Tests for TransferFunction.__neg__ - - def testNegScalar(self): - """Negate a direct feedthrough system.""" - - sys1 = TransferFunction(2., np.array([-3])) - sys2 = - sys1 - - np.testing.assert_array_equal(sys2.num, [[[-2.]]]) - np.testing.assert_array_equal(sys2.den, [[[-3.]]]) - - def testNegSISO(self): - """Negate a SISO system.""" - - sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1.]) - sys2 = - sys1 - - np.testing.assert_array_equal(sys2.num, [[[-1., -3., -5.]]]) - np.testing.assert_array_equal(sys2.den, [[[1., 6., 2., -1.]]]) - - def testNegMIMO(self): - """Negate a MIMO system.""" - - num1 = [[[1., 2.], [0., 3.], [2., -1.]], - [[1.], [4., 0.], [1., -4., 3.]]] - num3 = [[[-1., -2.], [0., -3.], [-2., 1.]], - [[-1.], [-4., 0.], [-1., 4., -3.]]] - den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], - [[3., 0., .0], [2., -1., -1.], [1.]]] - - sys1 = TransferFunction(num1, den1) - sys2 = - sys1 - sys3 = TransferFunction(num3, den1) - - for i in range(sys3.outputs): - for j in range(sys3.inputs): - np.testing.assert_array_equal(sys2.num[i][j], sys3.num[i][j]) - np.testing.assert_array_equal(sys2.den[i][j], sys3.den[i][j]) - - # Tests for TransferFunction.__add__ - - def testAddScalar(self): - """Add two direct feedthrough systems.""" - - sys1 = TransferFunction(1., [[[1.]]]) - sys2 = TransferFunction(np.array([2.]), [1.]) - sys3 = sys1 + sys2 - - np.testing.assert_array_equal(sys3.num, 3.) - np.testing.assert_array_equal(sys3.den, 1.) - - def testAddSISO(self): - """Add two SISO systems.""" - - sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = TransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) - sys3 = sys1 + sys2 - - # If sys3.num is [[[0., 20., 4., -8.]]], then this is wrong! - np.testing.assert_array_equal(sys3.num, [[[20., 4., -8]]]) - np.testing.assert_array_equal(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) - - def testAddMIMO(self): - """Add two MIMO systems.""" - - num1 = [[[1., 2.], [0., 3.], [2., -1.]], - [[1.], [4., 0.], [1., -4., 3.]]] - den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], - [[3., 0., .0], [2., -1., -1.], [1.]]] - num2 = [[[0., 0., -1], [2.], [-1., -1.]], - [[1., 2.], [-1., -2.], [4.]]] - den2 = [[[-1.], [1., 2., 3.], [-1., -1.]], - [[-4., -3., 2.], [0., 1.], [1., 0.]]] - num3 = [[[3., -3., -6], [5., 6., 9.], [-4., -2., 2]], - [[3., 2., -3., 2], [-2., -3., 7., 2.], [1., -4., 3., 4]]] - den3 = [[[3., -2., -4.], [1., 2., 3., 0., 0.], [-2., -1., 1.]], - [[-12., -9., 6., 0., 0.], [2., -1., -1.], [1., 0.]]] - - sys1 = TransferFunction(num1, den1) - sys2 = TransferFunction(num2, den2) - sys3 = sys1 + sys2 - - for i in range(sys3.outputs): - for j in range(sys3.inputs): - np.testing.assert_array_equal(sys3.num[i][j], num3[i][j]) - np.testing.assert_array_equal(sys3.den[i][j], den3[i][j]) - - # Tests for TransferFunction.__sub__ - - def testSubScalar(self): - """Add two direct feedthrough systems.""" - - sys1 = TransferFunction(1., [[[1.]]]) - sys2 = TransferFunction(np.array([2.]), [1.]) - sys3 = sys1 - sys2 - - np.testing.assert_array_equal(sys3.num, -1.) - np.testing.assert_array_equal(sys3.den, 1.) - - def testSubSISO(self): - """Add two SISO systems.""" - - sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = TransferFunction([[np.array([-1., 3.])]], [[[1., 0., -1.]]]) - sys3 = sys1 - sys2 - sys4 = sys2 - sys1 - - np.testing.assert_array_equal(sys3.num, [[[2., 6., -12., -10., -2.]]]) - np.testing.assert_array_equal(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) - np.testing.assert_array_equal(sys4.num, [[[-2., -6., 12., 10., 2.]]]) - np.testing.assert_array_equal(sys4.den, [[[1., 6., 1., -7., -2., 1.]]]) - - def testSubMIMO(self): - """Add two MIMO systems.""" - - num1 = [[[1., 2.], [0., 3.], [2., -1.]], - [[1.], [4., 0.], [1., -4., 3.]]] - den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], - [[3., 0., .0], [2., -1., -1.], [1.]]] - num2 = [[[0., 0., -1], [2.], [-1., -1.]], - [[1., 2.], [-1., -2.], [4.]]] - den2 = [[[-1.], [1., 2., 3.], [-1., -1.]], - [[-4., -3., 2.], [0., 1.], [1., 0.]]] - num3 = [[[-3., 1., 2.], [1., 6., 9.], [0.]], - [[-3., -10., -3., 2], [2., 3., 1., -2], [1., -4., 3., -4]]] - den3 = [[[3., -2., -4], [1., 2., 3., 0., 0.], [1]], - [[-12., -9., 6., 0., 0.], [2., -1., -1], [1., 0.]]] - - sys1 = TransferFunction(num1, den1) - sys2 = TransferFunction(num2, den2) - sys3 = sys1 - sys2 - - for i in range(sys3.outputs): - for j in range(sys3.inputs): - np.testing.assert_array_equal(sys3.num[i][j], num3[i][j]) - np.testing.assert_array_equal(sys3.den[i][j], den3[i][j]) - - # Tests for TransferFunction.__mul__ - - def testMulScalar(self): - """Multiply two direct feedthrough systems.""" - - sys1 = TransferFunction(2., [1.]) - sys2 = TransferFunction(1., 4.) - sys3 = sys1 * sys2 - sys4 = sys1 * sys2 - - np.testing.assert_array_equal(sys3.num, [[[2.]]]) - np.testing.assert_array_equal(sys3.den, [[[4.]]]) - np.testing.assert_array_equal(sys3.num, sys4.num) - np.testing.assert_array_equal(sys3.den, sys4.den) - - def testMulSISO(self): - """Multiply two SISO systems.""" - - sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) - sys3 = sys1 * sys2 - sys4 = sys2 * sys1 - - np.testing.assert_array_equal(sys3.num, [[[-1., 0., 4., 15.]]]) - np.testing.assert_array_equal(sys3.den, [[[1., 6., 1., -7., -2., 1.]]]) - np.testing.assert_array_equal(sys3.num, sys4.num) - np.testing.assert_array_equal(sys3.den, sys4.den) - - def testMulMIMO(self): - """Multiply two MIMO systems.""" - - num1 = [[[1., 2.], [0., 3.], [2., -1.]], - [[1.], [4., 0.], [1., -4., 3.]]] - den1 = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], - [[3., 0., .0], [2., -1., -1.], [1.]]] - num2 = [[[0., 1., 2.]], - [[1., -5.]], - [[-2., 1., 4.]]] - den2 = [[[1., 0., 0., 0.]], - [[-2., 1., 3.]], - [[4., -1., -1., 0.]]] - num3 = [[[-24., 52., -14., 245., -490., -115., 467., -95., -56., 12., - 0., 0., 0.]], - [[24., -132., 138., 345., -768., -106., 510., 41., -79., -69., - -23., 17., 6., 0.]]] - den3 = [[[48., -92., -84., 183., 44., -97., -2., 12., 0., 0., 0., 0., - 0., 0.]], - [[-48., 60., 84., -81., -45., 21., 9., 0., 0., 0., 0., 0., 0.]]] - - sys1 = TransferFunction(num1, den1) - sys2 = TransferFunction(num2, den2) - sys3 = sys1 * sys2 - - for i in range(sys3.outputs): - for j in range(sys3.inputs): - np.testing.assert_array_equal(sys3.num[i][j], num3[i][j]) - np.testing.assert_array_equal(sys3.den[i][j], den3[i][j]) - - # Tests for TransferFunction.__div__ - - def testDivScalar(self): - """Divide two direct feedthrough systems.""" - - sys1 = TransferFunction(np.array([3.]), -4.) - sys2 = TransferFunction(5., 2.) - sys3 = sys1 / sys2 - - np.testing.assert_array_equal(sys3.num, [[[6.]]]) - np.testing.assert_array_equal(sys3.den, [[[-20.]]]) - - def testDivSISO(self): - """Divide two SISO systems.""" - - sys1 = TransferFunction([1., 3., 5], [1., 6., 2., -1]) - sys2 = TransferFunction([[[-1., 3.]]], [[[1., 0., -1.]]]) - sys3 = sys1 / sys2 - sys4 = sys2 / sys1 - - np.testing.assert_array_equal(sys3.num, [[[1., 3., 4., -3., -5.]]]) - np.testing.assert_array_equal(sys3.den, [[[-1., -3., 16., 7., -3.]]]) - np.testing.assert_array_equal(sys4.num, sys3.den) - np.testing.assert_array_equal(sys4.den, sys3.num) - - # Tests for TransferFunction.evalfr. - - def testEvalFrSISO(self): - """Evaluate the frequency response of a SISO system at one frequency.""" - - sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) - - np.testing.assert_array_almost_equal(sys.evalfr(1.), - np.array([[-0.5 - 0.5j]])) - np.testing.assert_array_almost_equal(sys.evalfr(32.), - np.array([[0.00281959302585077 - 0.030628473607392j]])) - - def testEvalFrMIMO(self): - """Evaluate the frequency response of a MIMO system at one frequency.""" - - num = [[[1., 2.], [0., 3.], [2., -1.]], - [[1.], [4., 0.], [1., -4., 3.]]] - den = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], - [[3., 0., .0], [2., -1., -1.], [1.]]] - sys = TransferFunction(num, den) - resp = [[0.147058823529412 + 0.0882352941176471j, -0.75, 1.], - [-0.083333333333333, -0.188235294117647 - 0.847058823529412j, - -1. - 8.j]] - - np.testing.assert_array_almost_equal(sys.evalfr(2.), resp) - - # Tests for TransferFunction.freqresp. - - def testFreqRespSISO(self): - """Evaluate the magnitude and phase of a SISO system at multiple - frequencies.""" - - sys = TransferFunction([1., 3., 5], [1., 6., 2., -1]) - - truemag = [[[4.63507337473906, 0.707106781186548, 0.0866592803995351]]] - truephase = [[[-2.89596891081488, -2.35619449019234, - -1.32655885133871]]] - trueomega = [0.1, 1., 10.] - - mag, phase, omega = sys.freqresp(trueomega) - - np.testing.assert_array_almost_equal(mag, truemag) - np.testing.assert_array_almost_equal(phase, truephase) - np.testing.assert_array_almost_equal(omega, trueomega) - - def testFreqRespMIMO(self): - """Evaluate the magnitude and phase of a MIMO system at multiple - frequencies.""" - - num = [[[1., 2.], [0., 3.], [2., -1.]], - [[1.], [4., 0.], [1., -4., 3.]]] - den = [[[-3., 2., 4.], [1., 0., 0.], [2., -1.]], - [[3., 0., .0], [2., -1., -1.], [1.]]] - sys = TransferFunction(num, den) - - trueomega = [0.1, 1., 10.] - truemag = [[[0.496287094505259, 0.307147558416976, 0.0334738176210382], - [300., 3., 0.03], [1., 1., 1.]], - [[33.3333333333333, 0.333333333333333, 0.00333333333333333], - [0.390285696125482, 1.26491106406735, 0.198759144198533], - [3.01663720059274, 4.47213595499958, 104.92378186093]]] - truephase = [[[3.7128711165168e-4, 0.185347949995695, 1.30770596539255], - [-np.pi, -np.pi, -np.pi], [0., 0., 0.]], - [[-np.pi, -np.pi, -np.pi], - [-1.66852323415362, -1.89254688119154, -1.62050658356412], - [-0.132989648369409, -1.1071487177940, -2.7504672066207]]] - - mag, phase, omega = sys.freqresp(trueomega) - - np.testing.assert_array_almost_equal(mag, truemag) - np.testing.assert_array_almost_equal(phase, truephase) - np.testing.assert_array_equal(omega, trueomega) - - # Tests for TransferFunction.pole and TransferFunction.zero. - - def testPoleMIMO(self): - """Test for correct MIMO poles.""" - - sys = TransferFunction([[[1.], [1.]], [[1.], [1.]]], - [[[1., 2.], [1., 3.]], [[1., 4., 4.], [1., 9., 14.]]]) - p = sys.pole() - - np.testing.assert_array_almost_equal(p, [-7., -3., -2., -2.]) - - # Tests for TransferFunction.feedback. - - def testFeedbackSISO(self): - """Test for correct SISO transfer function feedback.""" - - sys1 = TransferFunction([-1., 4.], [1., 3., 5.]) - sys2 = TransferFunction([2., 3., 0.], [1., -3., 4., 0]) - - sys3 = sys1.feedback(sys2) - sys4 = sys1.feedback(sys2, 1) - - np.testing.assert_array_equal(sys3.num, [[[-1., 7., -16., 16., 0.]]]) - np.testing.assert_array_equal(sys3.den, [[[1., 0., -2., 2., 32., 0.]]]) - np.testing.assert_array_equal(sys4.num, [[[-1., 7., -16., 16., 0.]]]) - np.testing.assert_array_equal(sys4.den, [[[1., 0., 2., -8., 8., 0.]]]) - - def testConvertToTransferFunctio... [truncated message content] |