@@ -101,7 +101,7 @@ def bode_plot(syslist, omega=None,
101101 If True, plot phase in degrees (else radians). Default value (True)
102102 config.defaults['bode.deg']
103103 Plot : bool
104- If True, plot magnitude and phase
104+ If True (default) , plot magnitude and phase
105105 omega_limits: tuple, list, ... of two values
106106 Limits of the to generate frequency vector.
107107 If Hz=True the limits are in Hz otherwise in rad/s.
@@ -110,8 +110,10 @@ def bode_plot(syslist, omega=None,
110110 config.defaults['freqplot.number_of_samples'].
111111 margins : bool
112112 If True, plot gain and phase margin.
113- \*args, \**kwargs:
114- Additional options to matplotlib (color, linestyle, etc)
113+ *args
114+ Additional arguments for :func:`matplotlib.plot` (color, linestyle, etc)
115+ **kwargs:
116+ Additional keywords (passed to `matplotlib`)
115117
116118 Returns
117119 -------
@@ -139,7 +141,7 @@ def bode_plot(syslist, omega=None,
139141
140142 2. If a discrete time model is given, the frequency response is plotted
141143 along the upper branch of the unit circle, using the mapping z = exp(j
142- \omega dt) where omega ranges from 0 to pi/dt and dt is the discrete
144+ \\ omega dt) where omega ranges from 0 to pi/dt and dt is the discrete
143145 timebase. If not timebase is specified (dt = True), dt is set to 1.
144146
145147 Examples
@@ -450,8 +452,10 @@ def nyquist_plot(syslist, omega=None, Plot=True, color=None,
450452 Used to specify the color of the plot
451453 labelFreq : int
452454 Label every nth frequency on the plot
453- \*args, \**kwargs:
454- Additional options to matplotlib (color, linestyle, etc)
455+ *args
456+ Additional arguments for :func:`matplotlib.plot` (color, linestyle, etc)
457+ **kwargs:
458+ Additional keywords (passed to `matplotlib`)
455459
456460 Returns
457461 -------
@@ -554,7 +558,7 @@ def nyquist_plot(syslist, omega=None, Plot=True, color=None,
554558#
555559
556560# TODO: think about how (and whether) to handle lists of systems
557- def gangof4_plot (P , C , omega = None ):
561+ def gangof4_plot (P , C , omega = None , ** kwargs ):
558562 """Plot the "Gang of 4" transfer functions for a system
559563
560564 Generates a 2x2 plot showing the "Gang of 4" sensitivity functions
@@ -575,58 +579,79 @@ def gangof4_plot(P, C, omega=None):
575579 # TODO: Add MIMO go4 plots.
576580 raise NotImplementedError (
577581 "Gang of four is currently only implemented for SISO systems." )
578- else :
579582
580- # Select a default range if none is provided
581- # TODO: This needs to be made more intelligent
582- if omega is None :
583- omega = default_frequency_range ((P , C ))
584-
585- # Compute the senstivity functions
586- L = P * C
587- S = feedback (1 , L )
588- T = L * S
589-
590- # Set up the axes with labels so that multiple calls to
591- # gangof4_plot will superimpose the data. See details in bode_plot.
592- plot_axes = {'t' : None , 's' : None , 'ps' : None , 'cs' : None }
593- for ax in plt .gcf ().axes :
594- label = ax .get_label ()
595- if label .startswith ('control-gangof4-' ):
596- key = label [len ('control-gangof4-' ):]
597- if key not in plot_axes :
598- raise RuntimeError (
599- "unknown gangof4 axis type '{}'" .format (label ))
600- plot_axes [key ] = ax
601-
602- # if any of the axes are missing, start from scratch
603- if any ((ax is None for ax in plot_axes .values ())):
604- plt .clf ()
605- plot_axes = {'t' : plt .subplot (221 , label = 'control-gangof4-t' ),
606- 'ps' : plt .subplot (222 , label = 'control-gangof4-ps' ),
607- 'cs' : plt .subplot (223 , label = 'control-gangof4-cs' ),
608- 's' : plt .subplot (224 , label = 'control-gangof4-s' )}
609-
610- #
611- # Plot the four sensitivity functions
612- #
613-
614- # TODO: Need to add in the mag = 1 lines
615- mag_tmp , phase_tmp , omega = T .freqresp (omega )
616- mag = np .squeeze (mag_tmp )
617- plot_axes ['t' ].loglog (omega , mag )
618-
619- mag_tmp , phase_tmp , omega = (P * S ).freqresp (omega )
620- mag = np .squeeze (mag_tmp )
621- plot_axes ['ps' ].loglog (omega , mag )
622-
623- mag_tmp , phase_tmp , omega = (C * S ).freqresp (omega )
624- mag = np .squeeze (mag_tmp )
625- plot_axes ['cs' ].loglog (omega , mag )
626-
627- mag_tmp , phase_tmp , omega = S .freqresp (omega )
628- mag = np .squeeze (mag_tmp )
629- plot_axes ['s' ].loglog (omega , mag )
583+ # Get the default parameter values
584+ dB = config ._get_param ('bode' , 'dB' , kwargs , _bode_defaults , pop = True )
585+ Hz = config ._get_param ('bode' , 'Hz' , kwargs , _bode_defaults , pop = True )
586+ grid = config ._get_param ('bode' , 'grid' , kwargs , _bode_defaults , pop = True )
587+
588+ # Select a default range if none is provided
589+ # TODO: This needs to be made more intelligent
590+ if omega is None :
591+ omega = default_frequency_range ((P , C ))
592+
593+ # Compute the senstivity functions
594+ L = P * C
595+ S = feedback (1 , L )
596+ T = L * S
597+
598+ # Set up the axes with labels so that multiple calls to
599+ # gangof4_plot will superimpose the data. See details in bode_plot.
600+ plot_axes = {'t' : None , 's' : None , 'ps' : None , 'cs' : None }
601+ for ax in plt .gcf ().axes :
602+ label = ax .get_label ()
603+ if label .startswith ('control-gangof4-' ):
604+ key = label [len ('control-gangof4-' ):]
605+ if key not in plot_axes :
606+ raise RuntimeError (
607+ "unknown gangof4 axis type '{}'" .format (label ))
608+ plot_axes [key ] = ax
609+
610+ # if any of the axes are missing, start from scratch
611+ if any ((ax is None for ax in plot_axes .values ())):
612+ plt .clf ()
613+ plot_axes = {'s' : plt .subplot (221 , label = 'control-gangof4-s' ),
614+ 'ps' : plt .subplot (222 , label = 'control-gangof4-ps' ),
615+ 'cs' : plt .subplot (223 , label = 'control-gangof4-cs' ),
616+ 't' : plt .subplot (224 , label = 'control-gangof4-t' )}
617+
618+ #
619+ # Plot the four sensitivity functions
620+ #
621+ omega_plot = omega / (2. * math .pi ) if Hz else omega
622+
623+ # TODO: Need to add in the mag = 1 lines
624+ mag_tmp , phase_tmp , omega = S .freqresp (omega )
625+ mag = np .squeeze (mag_tmp )
626+ plot_axes ['s' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
627+ plot_axes ['s' ].set_ylabel ("$|S|$" )
628+ plot_axes ['s' ].tick_params (labelbottom = False )
629+ plot_axes ['s' ].grid (grid , which = 'both' )
630+
631+ mag_tmp , phase_tmp , omega = (P * S ).freqresp (omega )
632+ mag = np .squeeze (mag_tmp )
633+ plot_axes ['ps' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
634+ plot_axes ['ps' ].tick_params (labelbottom = False )
635+ plot_axes ['ps' ].set_ylabel ("$|PS|$" )
636+ plot_axes ['ps' ].grid (grid , which = 'both' )
637+
638+ mag_tmp , phase_tmp , omega = (C * S ).freqresp (omega )
639+ mag = np .squeeze (mag_tmp )
640+ plot_axes ['cs' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
641+ plot_axes ['cs' ].set_xlabel (
642+ "Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
643+ plot_axes ['cs' ].set_ylabel ("$|CS|$" )
644+ plot_axes ['cs' ].grid (grid , which = 'both' )
645+
646+ mag_tmp , phase_tmp , omega = T .freqresp (omega )
647+ mag = np .squeeze (mag_tmp )
648+ plot_axes ['t' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
649+ plot_axes ['t' ].set_xlabel (
650+ "Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
651+ plot_axes ['t' ].set_ylabel ("$|T|$" )
652+ plot_axes ['t' ].grid (grid , which = 'both' )
653+
654+ plt .tight_layout ()
630655
631656#
632657# Utility functions
0 commit comments