@@ -162,35 +162,35 @@ def test_nyquist_fbs_examples():
162
162
163
163
"""Run through various examples from FBS2e to compare plots"""
164
164
plt .figure ()
165
- plt . title ("Figure 10.4: L(s) = 1.4 e^{-s}/(s+1)^2" )
165
+ ct . suptitle ("Figure 10.4: L(s) = 1.4 e^{-s}/(s+1)^2" )
166
166
sys = ct .tf ([1.4 ], [1 , 2 , 1 ]) * ct .tf (* ct .pade (1 , 4 ))
167
167
response = ct .nyquist_response (sys )
168
168
response .plot ()
169
169
assert _Z (sys ) == response .count + _P (sys )
170
170
171
171
plt .figure ()
172
- plt . title ("Figure 10.4: L(s) = 1/(s + a)^2 with a = 0.6" )
172
+ ct . suptitle ("Figure 10.4: L(s) = 1/(s + a)^2 with a = 0.6" )
173
173
sys = 1 / (s + 0.6 )** 3
174
174
response = ct .nyquist_response (sys )
175
175
response .plot ()
176
176
assert _Z (sys ) == response .count + _P (sys )
177
177
178
178
plt .figure ()
179
- plt . title ("Figure 10.6: L(s) = 1/(s (s+1)^2) - pole at the origin" )
179
+ ct . suptitle ("Figure 10.6: L(s) = 1/(s (s+1)^2) - pole at the origin" )
180
180
sys = 1 / (s * (s + 1 )** 2 )
181
181
response = ct .nyquist_response (sys )
182
182
response .plot ()
183
183
assert _Z (sys ) == response .count + _P (sys )
184
184
185
185
plt .figure ()
186
- plt . title ("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2)" )
186
+ ct . suptitle ("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2)" )
187
187
sys = 3 * (s + 6 )** 2 / (s * (s + 1 )** 2 )
188
188
response = ct .nyquist_response (sys )
189
189
response .plot ()
190
190
assert _Z (sys ) == response .count + _P (sys )
191
191
192
192
plt .figure ()
193
- plt . title ("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2) [zoom]" )
193
+ ct . suptitle ("Figure 10.10: L(s) = 3 (s+6)^2 / (s (s+1)^2) [zoom]" )
194
194
with pytest .warns (UserWarning , match = "encirclements does not match" ):
195
195
response = ct .nyquist_response (sys , omega_limits = [1.5 , 1e3 ])
196
196
response .plot ()
@@ -208,7 +208,7 @@ def test_nyquist_fbs_examples():
208
208
def test_nyquist_arrows (arrows ):
209
209
sys = ct .tf ([1.4 ], [1 , 2 , 1 ]) * ct .tf (* ct .pade (1 , 4 ))
210
210
plt .figure ();
211
- plt . title ("L(s) = 1.4 e^{-s}/(s+1)^2 / arrows = %s" % arrows )
211
+ ct . suptitle ("L(s) = 1.4 e^{-s}/(s+1)^2 / arrows = %s" % arrows )
212
212
response = ct .nyquist_response (sys )
213
213
response .plot (arrows = arrows )
214
214
assert _Z (sys ) == response .count + _P (sys )
@@ -222,13 +222,13 @@ def test_nyquist_encirclements():
222
222
plt .figure ();
223
223
response = ct .nyquist_response (sys )
224
224
response .plot ()
225
- plt . title ("Stable system; encirclements = %d" % response .count )
225
+ ct . suptitle ("Stable system; encirclements = %d" % response .count )
226
226
assert _Z (sys ) == response .count + _P (sys )
227
227
228
228
plt .figure ();
229
229
response = ct .nyquist_response (sys * 3 )
230
230
response .plot ()
231
- plt . title ("Unstable system; encirclements = %d" % response .count )
231
+ ct . suptitle ("Unstable system; encirclements = %d" % response .count )
232
232
assert _Z (sys * 3 ) == response .count + _P (sys * 3 )
233
233
234
234
# System with pole at the origin
@@ -237,7 +237,7 @@ def test_nyquist_encirclements():
237
237
plt .figure ();
238
238
response = ct .nyquist_response (sys )
239
239
response .plot ()
240
- plt . title ("Pole at the origin; encirclements = %d" % response .count )
240
+ ct . suptitle ("Pole at the origin; encirclements = %d" % response .count )
241
241
assert _Z (sys ) == response .count + _P (sys )
242
242
243
243
# Non-integer number of encirclements
@@ -251,7 +251,7 @@ def test_nyquist_encirclements():
251
251
response = ct .nyquist_response (
252
252
sys , omega_limits = [0.5 , 1e3 ], encirclement_threshold = 0.2 )
253
253
response .plot ()
254
- plt . title ("Non-integer number of encirclements [%g]" % response .count )
254
+ ct . suptitle ("Non-integer number of encirclements [%g]" % response .count )
255
255
256
256
257
257
@pytest .fixture
@@ -266,7 +266,7 @@ def test_nyquist_indent_default(indentsys):
266
266
plt .figure ();
267
267
response = ct .nyquist_response (indentsys )
268
268
response .plot ()
269
- plt . title ("Pole at origin; indent_radius=default" )
269
+ ct . suptitle ("Pole at origin; indent_radius=default" )
270
270
assert _Z (indentsys ) == response .count + _P (indentsys )
271
271
272
272
@@ -293,7 +293,7 @@ def test_nyquist_indent_do(indentsys):
293
293
indentsys , indent_radius = 0.01 , return_contour = True )
294
294
count , contour = response
295
295
response .plot ()
296
- plt . title ("Pole at origin; indent_radius=0.01; encirclements = %d" % count )
296
+ ct . suptitle ("Pole at origin; indent_radius=0.01; encirclements = %d" % count )
297
297
assert _Z (indentsys ) == count + _P (indentsys )
298
298
# indent radius is smaller than the start of the default omega vector
299
299
# check that a quarter circle around the pole at origin has been added.
@@ -314,7 +314,7 @@ def test_nyquist_indent_left(indentsys):
314
314
plt .figure ();
315
315
response = ct .nyquist_response (indentsys , indent_direction = 'left' )
316
316
response .plot ()
317
- plt . title (
317
+ ct . suptitle (
318
318
"Pole at origin; indent_direction='left'; encirclements = %d" %
319
319
response .count )
320
320
assert _Z (indentsys ) == response .count + _P (indentsys , indent = 'left' )
@@ -328,14 +328,14 @@ def test_nyquist_indent_im():
328
328
plt .figure ();
329
329
response = ct .nyquist_response (sys )
330
330
response .plot ()
331
- plt . title ("Imaginary poles; encirclements = %d" % response .count )
331
+ ct . suptitle ("Imaginary poles; encirclements = %d" % response .count )
332
332
assert _Z (sys ) == response .count + _P (sys )
333
333
334
334
# Imaginary poles with indentation to the left
335
335
plt .figure ();
336
336
response = ct .nyquist_response (sys , indent_direction = 'left' )
337
337
response .plot (label_freq = 300 )
338
- plt . title (
338
+ ct . suptitle (
339
339
"Imaginary poles; indent_direction='left'; encirclements = %d" %
340
340
response .count )
341
341
assert _Z (sys ) == response .count + _P (sys , indent = 'left' )
@@ -346,7 +346,7 @@ def test_nyquist_indent_im():
346
346
response = ct .nyquist_response (
347
347
sys , np .linspace (0 , 1e3 , 1000 ), indent_direction = 'none' )
348
348
response .plot ()
349
- plt . title (
349
+ ct . suptitle (
350
350
"Imaginary poles; indent_direction='none'; encirclements = %d" %
351
351
response .count )
352
352
assert _Z (sys ) == response .count + _P (sys )
@@ -465,6 +465,36 @@ def test_freqresp_omega_limits():
465
465
np .array ([resp0 .contour [1 ], resp0 .contour [- 1 ]]))
466
466
467
467
468
+ def test_nyquist_frd ():
469
+ sys = ct .rss (4 , 1 , 1 )
470
+ sys1 = ct .frd (sys , np .logspace (- 1 , 1 , 10 ), name = 'sys1' )
471
+ sys2 = ct .frd (sys , np .logspace (- 2 , 2 , 10 ), name = 'sys2' )
472
+ sys3 = ct .frd (sys , np .logspace (- 2 , 2 , 10 ), smooth = True , name = 'sys3' )
473
+
474
+ # Turn off warnings about number of encirclements
475
+ warnings .filterwarnings (
476
+ 'ignore' , message = "number of encirclements was a non-integer value" ,
477
+ category = UserWarning )
478
+
479
+ # OK to specify frequency with FRD sys if frequencies match
480
+ nyqresp = ct .nyquist_response (sys1 , np .logspace (- 1 , 1 , 10 ))
481
+ np .testing .assert_allclose (nyqresp .contour , np .logspace (- 1 , 1 , 10 ) * 1j )
482
+
483
+ # If a fixed FRD omega is used, generate an error on mismatch
484
+ with pytest .raises (ValueError , match = "not all frequencies .* in .* list" ):
485
+ nyqresp = ct .nyquist_response (sys2 , np .logspace (- 1 , 1 , 10 ))
486
+
487
+ # OK to specify frequency with FRD sys if interpolating FRD is used
488
+ nyqresp = ct .nyquist_response (sys3 , np .logspace (- 1 , 1 , 12 ))
489
+ np .testing .assert_allclose (nyqresp .contour , np .logspace (- 1 , 1 , 12 ) * 1j )
490
+
491
+ # Computing Nyquist response w/ different frequencies OK if given as a list
492
+ nyqresp = ct .nyquist_response ([sys1 , sys2 ])
493
+ out = nyqresp .plot ()
494
+
495
+ warnings .resetwarnings ()
496
+
497
+
468
498
if __name__ == "__main__" :
469
499
#
470
500
# Interactive mode: generate plots for manual viewing
@@ -508,7 +538,7 @@ def test_freqresp_omega_limits():
508
538
print ("Unusual Nyquist plot" )
509
539
sys = ct .tf ([1 ], [1 , 3 , 2 ]) * ct .tf ([1 ], [1 , 0 , 1 ])
510
540
plt .figure ()
511
- plt . title ("Poles: %s" %
541
+ ct . suptitle ("Poles: %s" %
512
542
np .array2string (sys .poles (), precision = 2 , separator = ',' ))
513
543
response = ct .nyquist_response (sys )
514
544
response .plot ()
@@ -517,10 +547,17 @@ def test_freqresp_omega_limits():
517
547
print ("Discrete time systems" )
518
548
sys = ct .c2d (sys , 0.01 )
519
549
plt .figure ()
520
- plt . title ("Discrete-time; poles: %s" %
550
+ ct . suptitle ("Discrete-time; poles: %s" %
521
551
np .array2string (sys .poles (), precision = 2 , separator = ',' ))
522
552
response = ct .nyquist_response (sys )
523
553
response .plot ()
524
554
525
-
526
-
555
+ print ("Frequency response data (FRD) systems" )
556
+ sys = ct .tf (
557
+ (0.02 * s ** 3 - 0.1 * s ) / (s ** 4 + s ** 3 + s ** 2 + 0.25 * s + 0.04 ),
558
+ name = 'tf' )
559
+ sys1 = ct .frd (sys , np .logspace (- 1 , 1 , 15 ), name = 'frd1' )
560
+ sys2 = ct .frd (sys , np .logspace (- 2 , 2 , 20 ), name = 'frd2' )
561
+ plt .figure ()
562
+ ct .nyquist_plot ([sys , sys1 , sys2 ])
563
+ ct .suptitle ("Mixed FRD, tf data" )
0 commit comments