@@ -367,7 +367,7 @@ def test_phase_wrap(TF, wrap_phase, min_phase, max_phase):
367
367
368
368
369
369
def test_freqresp_warn_infinite ():
370
- """Test evaluation of transfer functions at the origin"""
370
+ """Test evaluation warnings for transfer functions w/ pole at the origin"""
371
371
sys_finite = ctrl .tf ([1 ], [1 , 0.01 ])
372
372
sys_infinite = ctrl .tf ([1 ], [1 , 0.01 , 0 ])
373
373
@@ -378,11 +378,13 @@ def test_freqresp_warn_infinite():
378
378
379
379
# Transfer function with infinite zero frequency gain
380
380
with pytest .warns (RuntimeWarning , match = "divide by zero" ):
381
- np .testing .assert_almost_equal (sys_infinite (0 ), np .inf )
381
+ np .testing .assert_almost_equal (
382
+ sys_infinite (0 ), complex (np .inf , np .nan ))
382
383
with pytest .warns (RuntimeWarning , match = "divide by zero" ):
383
384
np .testing .assert_almost_equal (
384
- sys_infinite (0 , warn_infinite = True ), np .inf )
385
- np .testing .assert_almost_equal (sys_infinite (0 , warn_infinite = False ), np .inf )
385
+ sys_infinite (0 , warn_infinite = True ), complex (np .inf , np .nan ))
386
+ np .testing .assert_almost_equal (
387
+ sys_infinite (0 , warn_infinite = False ), complex (np .inf , np .nan ))
386
388
387
389
# Switch to state space
388
390
sys_finite = ctrl .tf2ss (sys_finite )
@@ -394,13 +396,15 @@ def test_freqresp_warn_infinite():
394
396
np .testing .assert_almost_equal (sys_finite (0 , warn_infinite = True ), 100 )
395
397
396
398
# State space system with infinite zero frequency gain
397
- with pytest .warns (RuntimeWarning , match = "not finite" ):
398
- np .testing .assert_almost_equal (sys_infinite (0 ), np .inf )
399
- with pytest .warns (RuntimeWarning , match = "not finite" ):
400
- np .testing .assert_almost_equal (sys_infinite (0 ), np .inf )
401
- np .testing .assert_almost_equal (sys_infinite (0 , warn_infinite = True ), np .inf )
402
- np .testing .assert_almost_equal (sys_infinite (0 , warn_infinite = False ), np .inf )
403
-
399
+ with pytest .warns (RuntimeWarning , match = "singular matrix" ):
400
+ np .testing .assert_almost_equal (
401
+ sys_infinite (0 ), complex (np .inf , np .nan ))
402
+ with pytest .warns (RuntimeWarning , match = "singular matrix" ):
403
+ np .testing .assert_almost_equal (
404
+ sys_infinite (0 , warn_infinite = True ), complex (np .inf , np .nan ))
405
+ np .testing .assert_almost_equal (sys_infinite (
406
+ 0 , warn_infinite = False ), complex (np .inf , np .nan ))
407
+
404
408
405
409
def test_dcgain_consistency ():
406
410
"""Test to make sure that DC gain is consistently evaluated"""
@@ -412,25 +416,74 @@ def test_dcgain_consistency():
412
416
sys_ss = ctrl .tf2ss (sys_tf )
413
417
assert 0 in sys_ss .pole ()
414
418
415
- # Evaluation
416
- np .testing .assert_equal (sys_tf (0 ), np .inf + 0j )
417
- np .testing .assert_equal (sys_ss (0 ), np .inf + 0j )
418
- np .testing .assert_equal (sys_tf .dcgain (), np .inf + 0j )
419
- np .testing .assert_equal (sys_ss .dcgain (), np .inf + 0j )
419
+ # Finite (real) numerator over 0 denominator => inf + nanj
420
+ np .testing .assert_equal (
421
+ sys_tf (0 , warn_infinite = False ), complex (np .inf , np .nan ))
422
+ np .testing .assert_equal (
423
+ sys_ss (0 , warn_infinite = False ), complex (np .inf , np .nan ))
424
+ np .testing .assert_equal (
425
+ sys_tf (0j , warn_infinite = False ), complex (np .inf , np .nan ))
426
+ np .testing .assert_equal (
427
+ sys_ss (0j , warn_infinite = False ), complex (np .inf , np .nan ))
428
+ np .testing .assert_equal (
429
+ sys_tf .dcgain (warn_infinite = False ), complex (np .inf , np .nan ))
430
+ np .testing .assert_equal (
431
+ sys_ss .dcgain (warn_infinite = False ), complex (np .inf , np .nan ))
420
432
421
433
# Set up transfer function with pole, zero at the origin
422
434
sys_tf = ctrl .tf ([1 , 0 ], [1 , 0 ])
423
435
assert 0 in sys_tf .pole ()
424
436
assert 0 in sys_tf .zero ()
425
-
437
+
426
438
sys_ss = ctrl .tf2ss (ctrl .tf ([1 , 0 ], [1 , 1 ])) * \
427
439
ctrl .tf2ss (ctrl .tf ([1 ], [1 , 0 ]))
428
440
assert 0 in sys_ss .pole ()
429
441
assert 0 in sys_ss .zero ()
430
442
431
- # Pole and zero at the origin should give nan for the response
432
- np .testing .assert_equal (sys_tf (0 ), np .nan )
433
- np .testing .assert_equal (sys_tf .dcgain (), np .nan )
434
- # TODO: state space cases not yet working
435
- # np.testing.assert_equal(sys_ss(0), np.nan)
436
- # np.testing.assert_equal(sys_ss.dcgain(), np.nan)
443
+ # Pole and zero at the origin should give nan + nanj for the response
444
+ np .testing .assert_equal (
445
+ sys_tf (0 , warn_infinite = False ), complex (np .nan , np .nan ))
446
+ np .testing .assert_equal (
447
+ sys_tf (0j , warn_infinite = False ), complex (np .nan , np .nan ))
448
+ np .testing .assert_equal (
449
+ sys_tf .dcgain (warn_infinite = False ), complex (np .nan , np .nan ))
450
+ np .testing .assert_equal (
451
+ sys_ss (0 , warn_infinite = False ), complex (np .nan , np .nan ))
452
+ np .testing .assert_equal (
453
+ sys_ss (0j , warn_infinite = False ), complex (np .nan , np .nan ))
454
+ np .testing .assert_equal (
455
+ sys_ss .dcgain (warn_infinite = False ), complex (np .nan , np .nan ))
456
+
457
+ # Pole with non-zero, complex numerator => inf + infj
458
+ s = ctrl .tf ('s' )
459
+ sys_tf = (s + 1 ) / (s ** 2 + 1 )
460
+ assert 1j in sys_tf .pole ()
461
+
462
+ # Set up state space system with pole on imaginary axis
463
+ sys_ss = ctrl .tf2ss (sys_tf )
464
+ assert 1j in sys_tf .pole ()
465
+
466
+ # Make sure we get correct response if evaluated at the pole
467
+ np .testing .assert_equal (
468
+ sys_tf (1j , warn_infinite = False ), complex (np .inf , np .inf ))
469
+
470
+ # For state space, numerical errors come into play
471
+ resp_ss = sys_ss (1j , warn_infinite = False )
472
+ if np .isfinite (resp_ss ):
473
+ assert abs (resp_ss ) > 1e15
474
+ else :
475
+ if resp_ss != complex (np .inf , np .inf ):
476
+ pytest .xfail ("statesp evaluation at poles not fully implemented" )
477
+ else :
478
+ np .testing .assert_equal (resp_ss , complex (np .inf , np .inf ))
479
+
480
+ # DC gain is finite
481
+ np .testing .assert_almost_equal (sys_tf .dcgain (), 1. )
482
+ np .testing .assert_almost_equal (sys_ss .dcgain (), 1. )
483
+
484
+ # Make sure that we get the *signed* DC gain
485
+ sys_tf = - 1 / (s + 1 )
486
+ np .testing .assert_almost_equal (sys_tf .dcgain (), - 1 )
487
+
488
+ sys_ss = ctrl .tf2ss (sys_tf )
489
+ np .testing .assert_almost_equal (sys_ss .dcgain (), - 1 )
0 commit comments