80
80
81
81
82
82
def bode_plot (syslist , omega = None ,
83
- Plot = True , omega_limits = None , omega_num = None ,
83
+ plot = True , omega_limits = None , omega_num = None ,
84
84
margins = None , * args , ** kwargs ):
85
85
"""Bode plot for a system
86
86
@@ -100,7 +100,7 @@ def bode_plot(syslist, omega=None,
100
100
deg : bool
101
101
If True, plot phase in degrees (else radians). Default value (True)
102
102
config.defaults['bode.deg']
103
- Plot : bool
103
+ plot : bool
104
104
If True (default), plot magnitude and phase
105
105
omega_limits: tuple, list, ... of two values
106
106
Limits of the to generate frequency vector.
@@ -110,9 +110,9 @@ def bode_plot(syslist, omega=None,
110
110
config.defaults['freqplot.number_of_samples'].
111
111
margins : bool
112
112
If True, plot gain and phase margin.
113
- *args
114
- Additional arguments for :func: `matplotlib.plot` (color, linestyle, etc)
115
- **kwargs:
113
+ *args : `matplotlib` plot positional properties, optional
114
+ Additional arguments for `matplotlib` plots (color, linestyle, etc)
115
+ **kwargs : `matplotlib` plot keyword properties, optional
116
116
Additional keywords (passed to `matplotlib`)
117
117
118
118
Returns
@@ -153,12 +153,20 @@ def bode_plot(syslist, omega=None,
153
153
# Make a copy of the kwargs dictonary since we will modify it
154
154
kwargs = dict (kwargs )
155
155
156
+ # Check to see if legacy 'Plot' keyword was used
157
+ if 'Plot' in kwargs :
158
+ import warnings
159
+ warnings .warn ("'Plot' keyword is deprecated in bode_plot; use 'plot'" ,
160
+ FutureWarning )
161
+ # Map 'Plot' keyword to 'plot' keyword
162
+ plot = kwargs .pop ('Plot' )
163
+
156
164
# Get values for params (and pop from list to allow keyword use in plot)
157
165
dB = config ._get_param ('bode' , 'dB' , kwargs , _bode_defaults , pop = True )
158
166
deg = config ._get_param ('bode' , 'deg' , kwargs , _bode_defaults , pop = True )
159
167
Hz = config ._get_param ('bode' , 'Hz' , kwargs , _bode_defaults , pop = True )
160
168
grid = config ._get_param ('bode' , 'grid' , kwargs , _bode_defaults , pop = True )
161
- Plot = config ._get_param ('bode' , 'grid' , Plot , True )
169
+ plot = config ._get_param ('bode' , 'grid' , plot , True )
162
170
margins = config ._get_param ('bode' , 'margins' , margins , False )
163
171
164
172
# If argument was a singleton, turn it into a list
@@ -211,7 +219,7 @@ def bode_plot(syslist, omega=None,
211
219
# Get the dimensions of the current axis, which we will divide up
212
220
# TODO: Not current implemented; just use subplot for now
213
221
214
- if Plot :
222
+ if plot :
215
223
nyquistfrq_plot = None
216
224
if Hz :
217
225
omega_plot = omega_sys / (2. * math .pi )
@@ -429,12 +437,13 @@ def gen_zero_centered_series(val_min, val_max, period):
429
437
else :
430
438
return mags , phases , omegas
431
439
440
+
432
441
#
433
442
# Nyquist plot
434
443
#
435
444
436
- def nyquist_plot (syslist , omega = None , Plot = True ,
437
- labelFreq = 0 , arrowhead_length = 0.1 , arrowhead_width = 0.1 ,
445
+ def nyquist_plot (syslist , omega = None , plot = True , label_freq = 0 ,
446
+ arrowhead_length = 0.1 , arrowhead_width = 0.1 ,
438
447
color = None , * args , ** kwargs ):
439
448
"""
440
449
Nyquist plot for a system
@@ -451,13 +460,13 @@ def nyquist_plot(syslist, omega=None, Plot=True,
451
460
If True, plot magnitude
452
461
color : string
453
462
Used to specify the color of the plot
454
- labelFreq : int
463
+ label_freq : int
455
464
Label every nth frequency on the plot
456
465
arrowhead_width : arrow head width
457
466
arrowhead_length : arrow head length
458
- *args
459
- Additional arguments for :func: `matplotlib.plot` (color, linestyle, etc)
460
- **kwargs:
467
+ *args : `matplotlib` plot positional properties, optional
468
+ Additional arguments for `matplotlib` plots (color, linestyle, etc)
469
+ **kwargs : `matplotlib` plot keyword properties, optional
461
470
Additional keywords (passed to `matplotlib`)
462
471
463
472
Returns
@@ -475,6 +484,22 @@ def nyquist_plot(syslist, omega=None, Plot=True,
475
484
>>> real, imag, freq = nyquist_plot(sys)
476
485
477
486
"""
487
+ # Check to see if legacy 'Plot' keyword was used
488
+ if 'Plot' in kwargs :
489
+ import warnings
490
+ warnings .warn ("'Plot' keyword is deprecated in nyquist_plot; "
491
+ "use 'plot'" , FutureWarning )
492
+ # Map 'Plot' keyword to 'plot' keyword
493
+ plot = kwargs .pop ('Plot' )
494
+
495
+ # Check to see if legacy 'labelFreq' keyword was used
496
+ if 'labelFreq' in kwargs :
497
+ import warnings
498
+ warnings .warn ("'labelFreq' keyword is deprecated in nyquist_plot; "
499
+ "use 'label_freq'" , FutureWarning )
500
+ # Map 'labelFreq' keyword to 'label_freq' keyword
501
+ label_freq = kwargs .pop ('labelFreq' )
502
+
478
503
# If argument was a singleton, turn it into a list
479
504
if not getattr (syslist , '__iter__' , False ):
480
505
syslist = (syslist ,)
@@ -507,7 +532,7 @@ def nyquist_plot(syslist, omega=None, Plot=True,
507
532
x = sp .multiply (mag , sp .cos (phase ))
508
533
y = sp .multiply (mag , sp .sin (phase ))
509
534
510
- if Plot :
535
+ if plot :
511
536
# Plot the primary curve and mirror image
512
537
p = plt .plot (x , y , '-' , color = color , * args , ** kwargs )
513
538
c = p [0 ].get_color ()
@@ -527,8 +552,8 @@ def nyquist_plot(syslist, omega=None, Plot=True,
527
552
plt .plot ([- 1 ], [0 ], 'r+' )
528
553
529
554
# Label the frequencies of the points
530
- if labelFreq :
531
- ind = slice (None , None , labelFreq )
555
+ if label_freq :
556
+ ind = slice (None , None , label_freq )
532
557
for xpt , ypt , omegapt in zip (x [ind ], y [ind ], omega [ind ]):
533
558
# Convert to Hz
534
559
f = omegapt / (2 * sp .pi )
@@ -550,14 +575,15 @@ def nyquist_plot(syslist, omega=None, Plot=True,
550
575
str (int (np .round (f / 1000 ** pow1000 , 0 ))) + ' ' +
551
576
prefix + 'Hz' )
552
577
553
- if Plot :
578
+ if plot :
554
579
ax = plt .gca ()
555
580
ax .set_xlabel ("Real axis" )
556
581
ax .set_ylabel ("Imaginary axis" )
557
582
ax .grid (color = "lightgray" )
558
583
559
584
return x , y , omega
560
585
586
+
561
587
#
562
588
# Gang of Four plot
563
589
#
@@ -575,6 +601,8 @@ def gangof4_plot(P, C, omega=None, **kwargs):
575
601
Linear input/output systems (process and control)
576
602
omega : array
577
603
Range of frequencies (list or bounds) in rad/sec
604
+ **kwargs : `matplotlib` plot keyword properties, optional
605
+ Additional keywords (passed to `matplotlib`)
578
606
579
607
Returns
580
608
-------
@@ -590,16 +618,16 @@ def gangof4_plot(P, C, omega=None, **kwargs):
590
618
Hz = config ._get_param ('bode' , 'Hz' , kwargs , _bode_defaults , pop = True )
591
619
grid = config ._get_param ('bode' , 'grid' , kwargs , _bode_defaults , pop = True )
592
620
593
- # Select a default range if none is provided
594
- # TODO: This needs to be made more intelligent
595
- if omega is None :
596
- omega = default_frequency_range ((P , C ))
597
-
598
621
# Compute the senstivity functions
599
622
L = P * C
600
623
S = feedback (1 , L )
601
624
T = L * S
602
625
626
+ # Select a default range if none is provided
627
+ # TODO: This needs to be made more intelligent
628
+ if omega is None :
629
+ omega = default_frequency_range ((P , C , S ))
630
+
603
631
# Set up the axes with labels so that multiple calls to
604
632
# gangof4_plot will superimpose the data. See details in bode_plot.
605
633
plot_axes = {'t' : None , 's' : None , 'ps' : None , 'cs' : None }
@@ -628,36 +656,49 @@ def gangof4_plot(P, C, omega=None, **kwargs):
628
656
# TODO: Need to add in the mag = 1 lines
629
657
mag_tmp , phase_tmp , omega = S .freqresp (omega )
630
658
mag = np .squeeze (mag_tmp )
631
- plot_axes ['s' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
632
- plot_axes ['s' ].set_ylabel ("$|S|$" )
659
+ if dB :
660
+ plot_axes ['s' ].semilogx (omega_plot , 20 * np .log10 (mag ), ** kwargs )
661
+ else :
662
+ plot_axes ['s' ].loglog (omega_plot , mag , ** kwargs )
663
+ plot_axes ['s' ].set_ylabel ("$|S|$" + " (dB)" if dB else "" )
633
664
plot_axes ['s' ].tick_params (labelbottom = False )
634
665
plot_axes ['s' ].grid (grid , which = 'both' )
635
666
636
667
mag_tmp , phase_tmp , omega = (P * S ).freqresp (omega )
637
668
mag = np .squeeze (mag_tmp )
638
- plot_axes ['ps' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
669
+ if dB :
670
+ plot_axes ['ps' ].semilogx (omega_plot , 20 * np .log10 (mag ), ** kwargs )
671
+ else :
672
+ plot_axes ['ps' ].loglog (omega_plot , mag , ** kwargs )
639
673
plot_axes ['ps' ].tick_params (labelbottom = False )
640
- plot_axes ['ps' ].set_ylabel ("$|PS|$" )
674
+ plot_axes ['ps' ].set_ylabel ("$|PS|$" + " (dB)" if dB else "" )
641
675
plot_axes ['ps' ].grid (grid , which = 'both' )
642
676
643
677
mag_tmp , phase_tmp , omega = (C * S ).freqresp (omega )
644
678
mag = np .squeeze (mag_tmp )
645
- plot_axes ['cs' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
679
+ if dB :
680
+ plot_axes ['cs' ].semilogx (omega_plot , 20 * np .log10 (mag ), ** kwargs )
681
+ else :
682
+ plot_axes ['cs' ].loglog (omega_plot , mag , ** kwargs )
646
683
plot_axes ['cs' ].set_xlabel (
647
684
"Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
648
- plot_axes ['cs' ].set_ylabel ("$|CS|$" )
685
+ plot_axes ['cs' ].set_ylabel ("$|CS|$" + " (dB)" if dB else "" )
649
686
plot_axes ['cs' ].grid (grid , which = 'both' )
650
687
651
688
mag_tmp , phase_tmp , omega = T .freqresp (omega )
652
689
mag = np .squeeze (mag_tmp )
653
- plot_axes ['t' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
690
+ if dB :
691
+ plot_axes ['t' ].semilogx (omega_plot , 20 * np .log10 (mag ), ** kwargs )
692
+ else :
693
+ plot_axes ['t' ].loglog (omega_plot , mag , ** kwargs )
654
694
plot_axes ['t' ].set_xlabel (
655
695
"Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
656
- plot_axes ['t' ].set_ylabel ("$|T|$" )
696
+ plot_axes ['t' ].set_ylabel ("$|T|$" + " (dB)" if dB else "" )
657
697
plot_axes ['t' ].grid (grid , which = 'both' )
658
698
659
699
plt .tight_layout ()
660
700
701
+
661
702
#
662
703
# Utility functions
663
704
#
@@ -754,7 +795,7 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None,
754
795
# TODO
755
796
raise NotImplementedError (
756
797
"type of system in not implemented now" )
757
- except :
798
+ except NotImplementedError :
758
799
pass
759
800
760
801
# Make sure there is at least one point in the range
@@ -787,15 +828,17 @@ def default_frequency_range(syslist, Hz=None, number_of_samples=None,
787
828
omega = sp .logspace (lsp_min , lsp_max , endpoint = True )
788
829
return omega
789
830
831
+
790
832
#
791
- # KLD 5/23/11: Two functions to create nice looking labels
833
+ # Utility functions to create nice looking labels (KLD 5/23/11)
792
834
#
793
835
794
836
def get_pow1000 (num ):
795
837
"""Determine exponent for which significand of a number is within the
796
838
range [1, 1000).
797
839
"""
798
- # Based on algorithm from http://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg14433.html, accessed 2010/11/7
840
+ # Based on algorithm from http://www.mail-archive.com/
841
+ # matplotlib-users@lists.sourceforge.net/msg14433.html, accessed 2010/11/7
799
842
# by Jason Heeris 2009/11/18
800
843
from decimal import Decimal
801
844
from math import floor
0 commit comments