1- #!/usr/bin/env python
2- #
3- # frd_test.py - test FRD class
4- # RvP, 4 Oct 2012
1+ """frd_test.py - test FRD class
52
3+ RvP, 4 Oct 2012
4+ """
65
7- import unittest
86import sys as pysys
7+
98import numpy as np
9+ import matplotlib .pyplot as plt
10+ import pytest
11+
1012import control as ct
1113from control .statesp import StateSpace
1214from control .xferfcn import TransferFunction
1315from control .frdata import FRD , _convertToFRD , FrequencyResponseData
14- from control import bdalg
15- from control import freqplot
16- from control .exception import slycot_check
17- import matplotlib .pyplot as plt
16+ from control import bdalg , evalfr , freqplot
17+ from control .tests .conftest import slycotonly
1818
1919
20- class TestFRD ( unittest . TestCase ) :
20+ class TestFRD :
2121 """These are tests for functionality and correct reporting of the
2222 frequency response data class."""
2323
2424 def testBadInputType (self ):
2525 """Give the constructor invalid input types."""
26- self .assertRaises (ValueError , FRD )
27- self .assertRaises (TypeError , FRD , [1 ])
26+ with pytest .raises (ValueError ):
27+ FRD ()
28+ with pytest .raises (TypeError ):
29+ FRD ([1 ])
2830
2931 def testInconsistentDimension (self ):
30- self .assertRaises (TypeError , FRD , [1 , 1 ], [1 , 2 , 3 ])
32+ with pytest .raises (TypeError ):
33+ FRD ([1 , 1 ], [1 , 2 , 3 ])
3134
3235 def testSISOtf (self ):
3336 # get a SISO transfer function
@@ -169,7 +172,7 @@ def testFeedback2(self):
169172 def testAuto (self ):
170173 omega = np .logspace (- 1 , 2 , 10 )
171174 f1 = _convertToFRD (1 , omega )
172- f2 = _convertToFRD (np .matrix ([[1 , 0 ], [0.1 , - 1 ]]), omega )
175+ f2 = _convertToFRD (np .array ([[1 , 0 ], [0.1 , - 1 ]]), omega )
173176 f2 = _convertToFRD ([[1 , 0 ], [0.1 , - 1 ]], omega )
174177 f1 , f2 # reference to avoid pyflakes error
175178
@@ -183,7 +186,7 @@ def testNyquist(self):
183186 freqplot .nyquist (f1 , f1 .omega )
184187 # plt.savefig('/dev/null', format='svg')
185188
186- @unittest . skipIf ( not slycot_check (), "slycot not installed" )
189+ @slycotonly
187190 def testMIMO (self ):
188191 sys = StateSpace ([[- 0.5 , 0.0 ], [0.0 , - 1.0 ]],
189192 [[1.0 , 0.0 ], [0.0 , 1.0 ]],
@@ -198,7 +201,7 @@ def testMIMO(self):
198201 sys .freqresp ([0.1 , 1.0 , 10 ])[1 ],
199202 f1 .freqresp ([0.1 , 1.0 , 10 ])[1 ])
200203
201- @unittest . skipIf ( not slycot_check (), "slycot not installed" )
204+ @slycotonly
202205 def testMIMOfb (self ):
203206 sys = StateSpace ([[- 0.5 , 0.0 ], [0.0 , - 1.0 ]],
204207 [[1.0 , 0.0 ], [0.0 , 1.0 ]],
@@ -214,13 +217,15 @@ def testMIMOfb(self):
214217 f1 .freqresp ([0.1 , 1.0 , 10 ])[1 ],
215218 f2 .freqresp ([0.1 , 1.0 , 10 ])[1 ])
216219
217- @unittest . skipIf ( not slycot_check (), "slycot not installed" )
220+ @slycotonly
218221 def testMIMOfb2 (self ):
219- sys = StateSpace (np .matrix ('-2.0 0 0; 0 -1 1; 0 0 -3' ),
220- np .matrix ('1.0 0; 0 0; 0 1' ),
222+ sys = StateSpace (np .array ([[- 2.0 , 0 , 0 ],
223+ [0 , - 1 , 1 ],
224+ [0 , 0 , - 3 ]]),
225+ np .array ([[1.0 , 0 ], [0 , 0 ], [0 , 1 ]]),
221226 np .eye (3 ), np .zeros ((3 , 2 )))
222227 omega = np .logspace (- 1 , 2 , 10 )
223- K = np .matrix ( '1 0.3 0; 0.1 0 0' )
228+ K = np .array ([[ 1 , 0.3 , 0 ], [ 0.1 , 0 , 0 ]] )
224229 f1 = FRD (sys , omega ).feedback (K )
225230 f2 = FRD (sys .feedback (K ), omega )
226231 np .testing .assert_array_almost_equal (
@@ -230,7 +235,7 @@ def testMIMOfb2(self):
230235 f1 .freqresp ([0.1 , 1.0 , 10 ])[1 ],
231236 f2 .freqresp ([0.1 , 1.0 , 10 ])[1 ])
232237
233- @unittest . skipIf ( not slycot_check (), "slycot not installed" )
238+ @slycotonly
234239 def testMIMOMult (self ):
235240 sys = StateSpace ([[- 0.5 , 0.0 ], [0.0 , - 1.0 ]],
236241 [[1.0 , 0.0 ], [0.0 , 1.0 ]],
@@ -246,13 +251,13 @@ def testMIMOMult(self):
246251 (f1 * f2 ).freqresp ([0.1 , 1.0 , 10 ])[1 ],
247252 (sys * sys ).freqresp ([0.1 , 1.0 , 10 ])[1 ])
248253
249- @unittest . skipIf ( not slycot_check (), "slycot not installed" )
254+ @slycotonly
250255 def testMIMOSmooth (self ):
251256 sys = StateSpace ([[- 0.5 , 0.0 ], [0.0 , - 1.0 ]],
252257 [[1.0 , 0.0 ], [0.0 , 1.0 ]],
253258 [[1.0 , 0.0 ], [0.0 , 1.0 ], [1.0 , 1.0 ]],
254259 [[0.0 , 0.0 ], [0.0 , 0.0 ], [0.0 , 0.0 ]])
255- sys2 = np .matrix ([[1 , 0 , 0 ], [0 , 1 , 0 ]]) * sys
260+ sys2 = np .array ([[1 , 0 , 0 ], [0 , 1 , 0 ]]) * sys
256261 omega = np .logspace (- 1 , 2 , 10 )
257262 f1 = FRD (sys , omega , smooth = True )
258263 f2 = FRD (sys2 , omega , smooth = True )
@@ -271,47 +276,54 @@ def testAgainstOctave(self):
271276 # sys = ss([-2 0 0; 0 -1 1; 0 0 -3],
272277 # [1 0; 0 0; 0 1], eye(3), zeros(3,2))
273278 # bfr = frd(bsys, [1])
274- sys = StateSpace (np .matrix ( ' -2.0 0 0; 0 -1 1; 0 0 -3' ),
275- np .matrix ( ' 1.0 0; 0 0; 0 1' ),
279+ sys = StateSpace (np .array ([[ - 2.0 , 0 , 0 ], [ 0 , - 1 , 1 ], [ 0 , 0 , - 3 ]] ),
280+ np .array ([[ 1.0 , 0 ], [ 0 , 0 ], [ 0 , 1 ]] ),
276281 np .eye (3 ), np .zeros ((3 , 2 )))
277282 omega = np .logspace (- 1 , 2 , 10 )
278283 f1 = FRD (sys , omega )
279284 np .testing .assert_array_almost_equal (
280285 (f1 .freqresp ([1.0 ])[0 ] *
281- np .exp (1j * f1 .freqresp ([1.0 ])[1 ])).reshape (3 , 2 ),
282- np .matrix (' 0.4- 0.2j 0; 0 0.1- 0.2j; 0 0.3- 0.1j' ))
286+ np .exp (1j * f1 .freqresp ([1.0 ])[1 ])).reshape (3 , 2 ),
287+ np .matrix ([[ 0.4 - 0.2j , 0 ], [ 0 , 0.1 - 0.2j ], [ 0 , 0.3 - 0.1j ]] ))
283288
284- def test_string_representation (self ):
289+ def test_string_representation (self , capsys ):
285290 sys = FRD ([1 , 2 , 3 ], [4 , 5 , 6 ])
286291 print (sys ) # Just print without checking
287292
288- def test_frequency_mismatch (self ):
293+ def test_frequency_mismatch (self , recwarn ):
294+ # recwarn: there may be a warning before the error!
289295 # Overlapping but non-equal frequency ranges
290296 sys1 = FRD ([1 , 2 , 3 ], [4 , 5 , 6 ])
291297 sys2 = FRD ([2 , 3 , 4 ], [5 , 6 , 7 ])
292- self .assertRaises (NotImplementedError , FRD .__add__ , sys1 , sys2 )
298+ with pytest .raises (NotImplementedError ):
299+ FRD .__add__ (sys1 , sys2 )
293300
294301 # One frequency range is a subset of another
295302 sys1 = FRD ([1 , 2 , 3 ], [4 , 5 , 6 ])
296303 sys2 = FRD ([2 , 3 ], [4 , 5 ])
297- self .assertRaises (NotImplementedError , FRD .__add__ , sys1 , sys2 )
304+ with pytest .raises (NotImplementedError ):
305+ FRD .__add__ (sys1 , sys2 )
298306
299307 def test_size_mismatch (self ):
300308 sys1 = FRD (ct .rss (2 , 2 , 2 ), np .logspace (- 1 , 1 , 10 ))
301309
302310 # Different number of inputs
303311 sys2 = FRD (ct .rss (3 , 1 , 2 ), np .logspace (- 1 , 1 , 10 ))
304- self .assertRaises (ValueError , FRD .__add__ , sys1 , sys2 )
312+ with pytest .raises (ValueError ):
313+ FRD .__add__ (sys1 , sys2 )
305314
306315 # Different number of outputs
307316 sys2 = FRD (ct .rss (3 , 2 , 1 ), np .logspace (- 1 , 1 , 10 ))
308- self .assertRaises (ValueError , FRD .__add__ , sys1 , sys2 )
317+ with pytest .raises (ValueError ):
318+ FRD .__add__ (sys1 , sys2 )
309319
310320 # Inputs and outputs don't match
311- self .assertRaises (ValueError , FRD .__mul__ , sys2 , sys1 )
321+ with pytest .raises (ValueError ):
322+ FRD .__mul__ (sys2 , sys1 )
312323
313324 # Feedback mismatch
314- self .assertRaises (ValueError , FRD .feedback , sys2 , sys1 )
325+ with pytest .raises (ValueError ):
326+ FRD .feedback (sys2 , sys1 )
315327
316328 def test_operator_conversion (self ):
317329 sys_tf = ct .tf ([1 ], [1 , 2 , 1 ])
@@ -365,7 +377,8 @@ def test_operator_conversion(self):
365377 np .testing .assert_array_almost_equal (sys_pow .fresp , chk_pow .fresp )
366378
367379 # Assertion error if we try to raise to a non-integer power
368- self .assertRaises (ValueError , FRD .__pow__ , frd_tf , 0.5 )
380+ with pytest .raises (ValueError ):
381+ FRD .__pow__ (frd_tf , 0.5 )
369382
370383 # Selected testing on transfer function conversion
371384 sys_add = frd_2 + sys_tf
@@ -375,44 +388,29 @@ def test_operator_conversion(self):
375388
376389 # Input/output mismatch size mismatch in rmul
377390 sys1 = FRD (ct .rss (2 , 2 , 2 ), np .logspace (- 1 , 1 , 10 ))
378- self .assertRaises (ValueError , FRD .__rmul__ , frd_2 , sys1 )
391+ with pytest .raises (ValueError ):
392+ FRD .__rmul__ (frd_2 , sys1 )
379393
380394 # Make sure conversion of something random generates exception
381- self .assertRaises (TypeError , FRD .__add__ , frd_tf , 'string' )
395+ with pytest .raises (TypeError ):
396+ FRD .__add__ (frd_tf , 'string' )
382397
383398 def test_eval (self ):
384399 sys_tf = ct .tf ([1 ], [1 , 2 , 1 ])
385400 frd_tf = FRD (sys_tf , np .logspace (- 1 , 1 , 3 ))
386- np .testing .assert_almost_equal (sys_tf . evalfr (1 ), frd_tf .eval (1 ))
401+ np .testing .assert_almost_equal (evalfr (sys_tf , 1J ), frd_tf .eval (1 ))
387402
388403 # Should get an error if we evaluate at an unknown frequency
389- self .assertRaises (ValueError , frd_tf .eval , 2 )
404+ with pytest .raises (ValueError ):
405+ frd_tf .eval (2 )
406+
390407
391- # This test only works in Python 3 due to a conflict with the same
392- # warning type in other test modules (frd_test.py). See
393- # https://bugs.python.org/issue4180 for more details
394- @unittest .skipIf (pysys .version_info < (3 , 0 ), "test requires Python 3+" )
395408 def test_evalfr_deprecated (self ):
396409 sys_tf = ct .tf ([1 ], [1 , 2 , 1 ])
397410 frd_tf = FRD (sys_tf , np .logspace (- 1 , 1 , 3 ))
398411
399- # Deprecated version of the call (should generate warning)
400- import warnings
401- with warnings .catch_warnings ():
402- # Make warnings generate an exception
403- warnings .simplefilter ('error' )
404-
405- # Make sure that we get a pending deprecation warning
406- self .assertRaises (PendingDeprecationWarning , frd_tf .evalfr , 1. )
407-
408- # FRD.evalfr() is being deprecated
409- import warnings
410- with warnings .catch_warnings ():
411- # Make warnings generate an exception
412- warnings .simplefilter ('error' )
413-
414- # Make sure that we get a pending deprecation warning
415- self .assertRaises (PendingDeprecationWarning , frd_tf .evalfr , 1. )
412+ with pytest .deprecated_call ():
413+ frd_tf .evalfr (1. )
416414
417415 def test_repr_str (self ):
418416 # repr printing
@@ -427,8 +425,8 @@ def test_repr_str(self):
427425 sysm = FrequencyResponseData (
428426 np .matmul (array ([[1 ],[2 ]]), sys0 .fresp ), sys0 .omega )
429427
430- self . assertEqual ( repr (sys0 ), ref0 )
431- self . assertEqual ( repr (sys1 ), ref1 )
428+ assert repr (sys0 ) == ref0
429+ assert repr (sys1 ) == ref1
432430 sys0r = eval (repr (sys0 ))
433431 np .testing .assert_array_almost_equal (sys0r .fresp , sys0 .fresp )
434432 np .testing .assert_array_almost_equal (sys0r .omega , sys0 .omega )
@@ -444,8 +442,8 @@ def test_repr_str(self):
444442 1.000 0.9 +0.1j
445443 10.000 0.1 +2j
446444 100.000 0.05 +3j"""
447- self . assertEqual ( str (sys0 ), refs )
448- self . assertEqual ( str (sys1 ), refs )
445+ assert str (sys0 ) == refs
446+ assert str (sys1 ) == refs
449447
450448 # print multi-input system
451449 refm = """Frequency response data
@@ -463,7 +461,4 @@ def test_repr_str(self):
463461 1.000 1.8 +0.2j
464462 10.000 0.2 +4j
465463 100.000 0.1 +6j"""
466- self .assertEqual (str (sysm ), refm )
467-
468- if __name__ == "__main__" :
469- unittest .main ()
464+ assert str (sysm ) == refm
0 commit comments