1111from control .statesp import StateSpace
1212from control .margins import *
1313
14+ def assert_array_almost_equal (x , y , ndigit = 4 ):
15+
16+ x = np .array (x )
17+ y = np .array (y )
18+ try :
19+ if np .isfinite (x ).any () and (np .isfinite (x ) == np .isfinite (y )).all () and \
20+ (x [np .logical_not (np .isfinite (x ))] ==
21+ y [np .logical_not (np .isfinite (y ))]).all ():
22+ np .testing .assert_array_almost_equal (
23+ x [np .isfinite (x )], y [np .isfinite (y )], ndigit )
24+ return
25+ except TypeError as e :
26+ print ("Error" , e , "with" , x , "and" , y )
27+ #raise e
28+ np .testing .assert_array_almost_equal (x , y , ndigit )
29+
1430class TestMargin (unittest .TestCase ):
1531 """These are tests for the margin commands in margin.py."""
1632
@@ -27,10 +43,19 @@ def setUp(self):
2743 [], [], [147.0743 ], [2.5483 ]),
2844 ((8.75 * (4 * s ** 2 + 0.4 * s + 1 ))/ ((100 * s + 1 )* (s ** 2 + 0.22 * s + 1 )) *
2945 1. / (s ** 2 / (10. ** 2 )+ 2 * 0.04 * s / 10. + 1 ),
30- [2.2716 ], [10.0053 ], [97.5941 , 360 - 157.7904 , 134.7359 ],
46+ [2.2716 ], [10.0053 ], [97.5941 , - 157.7904 , 134.7359 ],
3147 [0.0850 , 0.9373 , 1.0919 ]))
3248
33-
49+
50+ """
51+ sys1 = tf([1, 2], [1, 2, 3]);
52+ sys2 = tf([1], [1, 2, 3, 4]);
53+ sys3 = ss([1, 4; 3, 2], [1; -4], ...
54+ [1, 0], [0])
55+ s = tf('s')
56+ sys4 = (8.75*(4*s^2+0.4*s+1))/((100*s+1)*(s^2+0.22*s+1)) * ...
57+ 1.0/(s^2/(10.0^2)+2*0.04*s/10.0+1);
58+ """
3459 self .sys1 = TransferFunction ([1 , 2 ], [1 , 2 , 3 ])
3560 # alternative
3661 # sys1 = tf([1, 2], [1, 2, 3])
@@ -43,13 +68,44 @@ def setUp(self):
4368 self .stability_margins4 = \
4469 [2.2716 , 97.5941 , 0.5591 , 10.0053 , 0.0850 , 9.9918 ]
4570
71+ """
72+ h1 = (s + 0.1)/s/(s+1);
73+ h2 = (s + 0.1)/s^2/(s+1);
74+ h3 = (s + 0.1)*(s+0.1)/s^3/(s+1);
75+ """
76+ self .types = {
77+ 'type1' : (s + 0.1 )/ s / (s + 1 ),
78+ 'type2' : (s + 0.1 )/ s ** 2 / (s + 1 ),
79+ 'type3' : (s + 0.1 )* (s + 0.1 )/ s ** 3 / (s + 1 ) }
80+ self .tmargin = ( self .types ,
81+ dict (sys = 'type1' , K = 1.0 , digits = 4 , result = (
82+ float ('Inf' ), 144.9032 , float ('NaN' ), 0.3162 )),
83+ dict (sys = 'type2' , K = 1.0 , digits = 4 , result = (
84+ float ('Inf' ), 44.4594 , float ('NaN' ), 0.7907 )),
85+ dict (sys = 'type3' , K = 1.0 , digits = 3 , result = (
86+ 0.0626 , 37.1748 , 0.1119 , 0.7951 )),
87+ )
88+
4689 # from "A note on the Gain and Phase Margin Concepts
4790 # Journal of Control and Systems Engineering, Yazdan Bavafi-Toosi,
4891 # Dec 205, vol 3 iss 1, pp 51-59
4992 #
5093 # A cornucopia of tricky systems for phase / gain margin
5194 # Still have to convert this to tests + fix margin to handle
5295 # also these torture cases
96+ """
97+ % matlab compatible
98+ s = tf('s');
99+ h21 = 0.002*(s+0.02)*(s+0.05)*(s+5)*(s+10)/( ...
100+ (s-0.0005)*(s+0.0001)*(s+0.01)*(s+0.2)*(s+1)*(s+100)^2 );
101+ h23 = ((s+0.1)^2 + 1)*(s-0.1)/( ...
102+ ((s+0.1)^2+4)*(s+1) );
103+ h25a = s/(s^2+2*s+2)^4; h25b = h25a*100;
104+ h26a = ((s-0.1)^2 + 1)/( ...
105+ (s + 0.1)*((s-0.2)^2 + 4) ) ;
106+ h26b = ((s-0.1)^2 + 1)/( ...
107+ (s - 0.3)*((s-0.2)^2 + 4) );
108+ """
53109 self .yazdan = {
54110 'example21' :
55111 0.002 * (s + 0.02 )* (s + 0.05 )* (s + 5 )* (s + 10 )/ (
@@ -93,22 +149,22 @@ def test_stability_margins(self):
93149 gm , pm , sm , wg , wp , ws = out
94150 outf = np .array (stability_margins (FRD (sys , omega )))
95151 print (out ,'\n ' , outf )
96- print (out != np .array (None ))
97- np .testing .assert_array_almost_equal (
98- out [out != np .array (None )],
99- outf [outf != np .array (None )], 2 )
152+ #print(out != np.array(None))
153+ assert_array_almost_equal (
154+ out , outf , 2 )
100155
101156 # final one with fixed values
102- np . testing . assert_array_almost_equal (
157+ assert_array_almost_equal (
103158 [gm , pm , sm , wg , wp , ws ],
104159 self .stability_margins4 , 3 )
105160
106161 def test_margin (self ):
107162 gm , pm , wg , wp = margin (self .sys4 )
108- np . testing . assert_array_almost_equal (
163+ assert_array_almost_equal (
109164 [gm , pm , wg , wp ],
110165 self .stability_margins4 [:2 ] + self .stability_margins4 [3 :5 ], 3 )
111166
167+
112168 def test_stability_margins_all (self ):
113169 for sys ,rgm ,rwgm ,rpm ,rwpm in self .tsys :
114170 out = stability_margins (sys , returnall = True )
@@ -117,25 +173,25 @@ def test_stability_margins_all(self):
117173 for res ,comp in zip (out , (rgm ,rpm ,[],rwgm ,rwpm ,[])):
118174 if comp :
119175 print (res , '\n ' , comp )
120- np . testing . assert_array_almost_equal (
176+ assert_array_almost_equal (
121177 res , comp , 2 )
122178
123179 def test_phase_crossover_frequencies (self ):
124180 omega , gain = phase_crossover_frequencies (self .sys2 )
125- np . testing . assert_array_almost_equal (omega , [1.73205 , 0. ])
126- np . testing . assert_array_almost_equal (gain , [- 0.5 , 0.25 ])
181+ assert_array_almost_equal (omega , [1.73205 , 0. ])
182+ assert_array_almost_equal (gain , [- 0.5 , 0.25 ])
127183
128184 tf = TransferFunction ([1 ],[1 ,1 ])
129185 omega , gain = phase_crossover_frequencies (tf )
130- np . testing . assert_array_almost_equal (omega , [0. ])
131- np . testing . assert_array_almost_equal (gain , [1. ])
186+ assert_array_almost_equal (omega , [0. ])
187+ assert_array_almost_equal (gain , [1. ])
132188
133189 # testing MIMO, only (0,0) element is considered
134190 tf = TransferFunction ([[[1 ],[2 ]],[[3 ],[4 ]]],
135191 [[[1 , 2 , 3 , 4 ],[1 ,1 ]],[[1 ,1 ],[1 ,1 ]]])
136192 omega , gain = phase_crossover_frequencies (tf )
137- np . testing . assert_array_almost_equal (omega , [1.73205081 , 0. ])
138- np . testing . assert_array_almost_equal (gain , [- 0.5 , 0.25 ])
193+ assert_array_almost_equal (omega , [1.73205081 , 0. ])
194+ assert_array_almost_equal (gain , [- 0.5 , 0.25 ])
139195
140196 def test_mag_phase_omega (self ):
141197 # test for bug reported in gh-58
@@ -148,7 +204,7 @@ def test_mag_phase_omega(self):
148204 ind = [0 ,1 ,3 ,4 ] # indices of gm, pm, wg, wp -- ignore sm
149205 marg1 = np .array (out )[ind ]
150206 marg2 = np .array (out2 )[ind ]
151- np . testing . assert_array_almost_equal (marg1 , marg2 , 4 )
207+ assert_array_almost_equal (marg1 , marg2 , 4 )
152208
153209 def test_frd (self ):
154210 f = np .array ([0.005 , 0.010 , 0.020 , 0.030 , 0.040 ,
@@ -185,7 +241,7 @@ def test_frd(self):
185241 C = K * (1 + 1.9 * s )
186242 TFopen = fresp * C * G
187243 gm , pm , sm , wg , wp , ws = stability_margins (TFopen )
188- np . testing . assert_array_almost_equal (
244+ assert_array_almost_equal (
189245 [pm ], [44.55 ], 2 )
190246
191247 def test_nocross (self ):
@@ -195,16 +251,27 @@ def test_nocross(self):
195251 h2 = 3 * (10 + s )/ (2 + s )
196252 h3 = 0.01 * (10 - s )/ (2 + s )/ (1 + s )
197253 gm , pm , wm , wg , wp , ws = stability_margins (h1 )
198- self .assertEqual (gm , None )
199- self .assertEqual (wg , None )
254+ assert_array_almost_equal (
255+ [gm , pm , wg , wp ],
256+ [float ('Inf' ), float ('Inf' ), float ('NaN' ), float ('NaN' )])
200257 gm , pm , wm , wg , wp , ws = stability_margins (h2 )
201- self .assertEqual (pm , None )
258+ self .assertEqual (pm , float ( 'Inf' ) )
202259 gm , pm , wm , wg , wp , ws = stability_margins (h3 )
203- self .assertEqual ( pm , None )
260+ self .assertTrue ( np . isnan ( wp ) )
204261 omega = np .logspace (- 2 ,2 , 100 )
205262 out1b = stability_margins (FRD (h1 , omega ))
206263 out2b = stability_margins (FRD (h2 , omega ))
207264 out3b = stability_margins (FRD (h3 , omega ))
265+
266+ def test_zmore_margin (self ):
267+ sdict = self .tmargin [0 ]
268+ for test in self .tmargin [1 :]:
269+ res = margin (sdict [test ['sys' ]]* test ['K' ])
270+ print ("more margin {}\n " .format (sdict [test ['sys' ]]),
271+ res , '\n ' , test ['result' ])
272+ assert_array_almost_equal (
273+ res , test ['result' ], test ['digits' ])
274+
208275
209276
210277def test_suite ():
0 commit comments