66import unittest
77import numpy as np
88from control .xferfcn import TransferFunction
9+ from control .frdata import FRD
910from control .statesp import StateSpace
1011from control .margins import *
1112
@@ -28,7 +29,7 @@ def test_stability_margins(self):
2829 gm , pm , sm , wg , wp , ws = stability_margins (self .sys4 );
2930 np .testing .assert_array_almost_equal (
3031 [gm , pm , sm , wg , wp , ws ],
31- [2.2716 , 97.5941 , 1.0454 , 10.0053 , 0.0850 , 0.4973 ], 3 )
32+ [2.2716 , 97.5941 , 0.9565 , 10.0053 , 0.0850 , 0.4973 ], 3 )
3233
3334 def test_phase_crossover_frequencies (self ):
3435 omega , gain = phase_crossover_frequencies (self .sys2 )
@@ -59,7 +60,65 @@ def test_mag_phase_omega(self):
5960 marg2 = np .array (out2 )[ind ]
6061 np .testing .assert_array_almost_equal (marg1 , marg2 , 4 )
6162
63+ def test_frd (self ):
64+ f = np .array ([0.005 , 0.010 , 0.020 , 0.030 , 0.040 ,
65+ 0.050 , 0.060 , 0.070 , 0.080 , 0.090 ,
66+ 0.100 , 0.200 , 0.300 , 0.400 , 0.500 ,
67+ 0.750 , 1.000 , 1.250 , 1.500 , 1.750 ,
68+ 2.000 , 2.250 , 2.500 , 2.750 , 3.000 ,
69+ 3.250 , 3.500 , 3.750 , 4.000 , 4.250 ,
70+ 4.500 , 4.750 , 5.000 , 6.000 , 7.000 ,
71+ 8.000 , 9.000 , 10.000 ])
72+ gain = np .array ([ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ,
73+ 0.0 , 0.0 , 0.0 , 0.0 , 0.0 ,
74+ 0.0 , 0.1 , 0.2 , 0.3 , 0.5 ,
75+ 0.5 , - 0.4 , - 2.3 , - 4.8 , - 7.3 ,
76+ - 9.6 , - 11.7 , - 13.6 , - 15.3 , - 16.9 ,
77+ - 18.3 , - 19.6 , - 20.8 , - 22.0 , - 23.1 ,
78+ - 24.1 , - 25.0 , - 25.9 , - 29.1 , - 31.9 ,
79+ - 34.2 , - 36.2 , - 38.1 ])
80+ phase = np .array ([ 0 , - 1 , - 2 , - 3 , - 4 ,
81+ - 5 , - 6 , - 7 , - 8 , - 9 ,
82+ - 10 , - 19 , - 29 , - 40 , - 51 ,
83+ - 81 , - 114 , - 144 , - 168 , - 187 ,
84+ - 202 , - 214 , - 224 , - 233 , - 240 ,
85+ - 247 , - 253 , - 259 , - 264 , - 269 ,
86+ - 273 , - 277 , - 280 , - 292 , - 301 ,
87+ - 307 , - 313 , - 317 ])
88+ # calculate response as complex number
89+ resp = 10 ** (gain / 20 ) * np .exp (1j * phase / (180. / np .pi ))
90+ # frequency response data
91+ fresp = FRD (resp , f * 2 * np .pi , smooth = True )
92+ s = TransferFunction ([1 ,0 ],[1 ])
93+ G = 1. / (s ** 2 )
94+ K = 1.
95+ C = K * (1 + 1.9 * s )
96+ TFopen = fresp * C * G
97+ gm , pm , sm , wg , wp , ws = stability_margins (TFopen )
98+ print gm
99+ np .testing .assert_array_almost_equal (
100+ [pm ], [44.55 ], 2 )
101+
102+ def test_nocross (self ):
103+ # what happens when no gain/phase crossover?
104+ s = TransferFunction ([1 , 0 ], [1 ])
105+ h1 = 1 / (1 + s )
106+ h2 = 3 * (10 + s )/ (2 + s )
107+ h3 = 0.01 * (10 - s )/ (2 + s )/ (1 + s )
108+ gm , pm , sm , wg , wp , ws = stability_margins (h1 )
109+ self .assertEqual (gm , None )
110+ self .assertEqual (wg , None )
111+ gm , pm , wm , wg , wp , ws = stability_margins (h2 )
112+ self .assertEqual (pm , None )
113+ gm , pm , wm , wg , wp , ws = stability_margins (h3 )
114+ self .assertEqual (pm , None )
115+ omega = np .logspace (- 2 ,2 , 100 )
116+ out1b = stability_margins (FRD (h1 , omega ))
117+ out2b = stability_margins (FRD (h2 , omega ))
118+ out3b = stability_margins (FRD (h3 , omega ))
119+
62120
121+
63122def test_suite ():
64123 return unittest .TestLoader ().loadTestsFromTestCase (TestMargin )
65124
0 commit comments