@@ -162,35 +162,35 @@ def test_nyquist_fbs_examples():
162162
163163 """Run through various examples from FBS2e to compare plots"""
164164 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" )
166166 sys = ct .tf ([1.4 ], [1 , 2 , 1 ]) * ct .tf (* ct .pade (1 , 4 ))
167167 response = ct .nyquist_response (sys )
168168 response .plot ()
169169 assert _Z (sys ) == response .count + _P (sys )
170170
171171 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" )
173173 sys = 1 / (s + 0.6 )** 3
174174 response = ct .nyquist_response (sys )
175175 response .plot ()
176176 assert _Z (sys ) == response .count + _P (sys )
177177
178178 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" )
180180 sys = 1 / (s * (s + 1 )** 2 )
181181 response = ct .nyquist_response (sys )
182182 response .plot ()
183183 assert _Z (sys ) == response .count + _P (sys )
184184
185185 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)" )
187187 sys = 3 * (s + 6 )** 2 / (s * (s + 1 )** 2 )
188188 response = ct .nyquist_response (sys )
189189 response .plot ()
190190 assert _Z (sys ) == response .count + _P (sys )
191191
192192 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]" )
194194 with pytest .warns (UserWarning , match = "encirclements does not match" ):
195195 response = ct .nyquist_response (sys , omega_limits = [1.5 , 1e3 ])
196196 response .plot ()
@@ -208,7 +208,7 @@ def test_nyquist_fbs_examples():
208208def test_nyquist_arrows (arrows ):
209209 sys = ct .tf ([1.4 ], [1 , 2 , 1 ]) * ct .tf (* ct .pade (1 , 4 ))
210210 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 )
212212 response = ct .nyquist_response (sys )
213213 response .plot (arrows = arrows )
214214 assert _Z (sys ) == response .count + _P (sys )
@@ -222,13 +222,13 @@ def test_nyquist_encirclements():
222222 plt .figure ();
223223 response = ct .nyquist_response (sys )
224224 response .plot ()
225- plt . title ("Stable system; encirclements = %d" % response .count )
225+ ct . suptitle ("Stable system; encirclements = %d" % response .count )
226226 assert _Z (sys ) == response .count + _P (sys )
227227
228228 plt .figure ();
229229 response = ct .nyquist_response (sys * 3 )
230230 response .plot ()
231- plt . title ("Unstable system; encirclements = %d" % response .count )
231+ ct . suptitle ("Unstable system; encirclements = %d" % response .count )
232232 assert _Z (sys * 3 ) == response .count + _P (sys * 3 )
233233
234234 # System with pole at the origin
@@ -237,7 +237,7 @@ def test_nyquist_encirclements():
237237 plt .figure ();
238238 response = ct .nyquist_response (sys )
239239 response .plot ()
240- plt . title ("Pole at the origin; encirclements = %d" % response .count )
240+ ct . suptitle ("Pole at the origin; encirclements = %d" % response .count )
241241 assert _Z (sys ) == response .count + _P (sys )
242242
243243 # Non-integer number of encirclements
@@ -251,7 +251,7 @@ def test_nyquist_encirclements():
251251 response = ct .nyquist_response (
252252 sys , omega_limits = [0.5 , 1e3 ], encirclement_threshold = 0.2 )
253253 response .plot ()
254- plt . title ("Non-integer number of encirclements [%g]" % response .count )
254+ ct . suptitle ("Non-integer number of encirclements [%g]" % response .count )
255255
256256
257257@pytest .fixture
@@ -266,7 +266,7 @@ def test_nyquist_indent_default(indentsys):
266266 plt .figure ();
267267 response = ct .nyquist_response (indentsys )
268268 response .plot ()
269- plt . title ("Pole at origin; indent_radius=default" )
269+ ct . suptitle ("Pole at origin; indent_radius=default" )
270270 assert _Z (indentsys ) == response .count + _P (indentsys )
271271
272272
@@ -293,7 +293,7 @@ def test_nyquist_indent_do(indentsys):
293293 indentsys , indent_radius = 0.01 , return_contour = True )
294294 count , contour = response
295295 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 )
297297 assert _Z (indentsys ) == count + _P (indentsys )
298298 # indent radius is smaller than the start of the default omega vector
299299 # check that a quarter circle around the pole at origin has been added.
@@ -314,7 +314,7 @@ def test_nyquist_indent_left(indentsys):
314314 plt .figure ();
315315 response = ct .nyquist_response (indentsys , indent_direction = 'left' )
316316 response .plot ()
317- plt . title (
317+ ct . suptitle (
318318 "Pole at origin; indent_direction='left'; encirclements = %d" %
319319 response .count )
320320 assert _Z (indentsys ) == response .count + _P (indentsys , indent = 'left' )
@@ -328,14 +328,14 @@ def test_nyquist_indent_im():
328328 plt .figure ();
329329 response = ct .nyquist_response (sys )
330330 response .plot ()
331- plt . title ("Imaginary poles; encirclements = %d" % response .count )
331+ ct . suptitle ("Imaginary poles; encirclements = %d" % response .count )
332332 assert _Z (sys ) == response .count + _P (sys )
333333
334334 # Imaginary poles with indentation to the left
335335 plt .figure ();
336336 response = ct .nyquist_response (sys , indent_direction = 'left' )
337337 response .plot (label_freq = 300 )
338- plt . title (
338+ ct . suptitle (
339339 "Imaginary poles; indent_direction='left'; encirclements = %d" %
340340 response .count )
341341 assert _Z (sys ) == response .count + _P (sys , indent = 'left' )
@@ -346,7 +346,7 @@ def test_nyquist_indent_im():
346346 response = ct .nyquist_response (
347347 sys , np .linspace (0 , 1e3 , 1000 ), indent_direction = 'none' )
348348 response .plot ()
349- plt . title (
349+ ct . suptitle (
350350 "Imaginary poles; indent_direction='none'; encirclements = %d" %
351351 response .count )
352352 assert _Z (sys ) == response .count + _P (sys )
@@ -465,6 +465,36 @@ def test_freqresp_omega_limits():
465465 np .array ([resp0 .contour [1 ], resp0 .contour [- 1 ]]))
466466
467467
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+
468498if __name__ == "__main__" :
469499 #
470500 # Interactive mode: generate plots for manual viewing
@@ -508,7 +538,7 @@ def test_freqresp_omega_limits():
508538 print ("Unusual Nyquist plot" )
509539 sys = ct .tf ([1 ], [1 , 3 , 2 ]) * ct .tf ([1 ], [1 , 0 , 1 ])
510540 plt .figure ()
511- plt . title ("Poles: %s" %
541+ ct . suptitle ("Poles: %s" %
512542 np .array2string (sys .poles (), precision = 2 , separator = ',' ))
513543 response = ct .nyquist_response (sys )
514544 response .plot ()
@@ -517,10 +547,17 @@ def test_freqresp_omega_limits():
517547 print ("Discrete time systems" )
518548 sys = ct .c2d (sys , 0.01 )
519549 plt .figure ()
520- plt . title ("Discrete-time; poles: %s" %
550+ ct . suptitle ("Discrete-time; poles: %s" %
521551 np .array2string (sys .poles (), precision = 2 , separator = ',' ))
522552 response = ct .nyquist_response (sys )
523553 response .plot ()
524554
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