@@ -554,7 +554,7 @@ def nyquist_plot(syslist, omega=None, Plot=True, color=None,
554554#
555555
556556# TODO: think about how (and whether) to handle lists of systems
557- def gangof4_plot (P , C , omega = None ):
557+ def gangof4_plot (P , C , omega = None , ** kwargs ):
558558 """Plot the "Gang of 4" transfer functions for a system
559559
560560 Generates a 2x2 plot showing the "Gang of 4" sensitivity functions
@@ -575,58 +575,79 @@ def gangof4_plot(P, C, omega=None):
575575 # TODO: Add MIMO go4 plots.
576576 raise NotImplementedError (
577577 "Gang of four is currently only implemented for SISO systems." )
578- else :
579578
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 )
579+ # Get the default parameter values
580+ dB = config ._get_param ('bode' , 'dB' , kwargs , _bode_defaults , pop = True )
581+ Hz = config ._get_param ('bode' , 'Hz' , kwargs , _bode_defaults , pop = True )
582+ grid = config ._get_param ('bode' , 'grid' , kwargs , _bode_defaults , pop = True )
583+
584+ # Select a default range if none is provided
585+ # TODO: This needs to be made more intelligent
586+ if omega is None :
587+ omega = default_frequency_range ((P , C ))
588+
589+ # Compute the senstivity functions
590+ L = P * C
591+ S = feedback (1 , L )
592+ T = L * S
593+
594+ # Set up the axes with labels so that multiple calls to
595+ # gangof4_plot will superimpose the data. See details in bode_plot.
596+ plot_axes = {'t' : None , 's' : None , 'ps' : None , 'cs' : None }
597+ for ax in plt .gcf ().axes :
598+ label = ax .get_label ()
599+ if label .startswith ('control-gangof4-' ):
600+ key = label [len ('control-gangof4-' ):]
601+ if key not in plot_axes :
602+ raise RuntimeError (
603+ "unknown gangof4 axis type '{}'" .format (label ))
604+ plot_axes [key ] = ax
605+
606+ # if any of the axes are missing, start from scratch
607+ if any ((ax is None for ax in plot_axes .values ())):
608+ plt .clf ()
609+ plot_axes = {'s' : plt .subplot (221 , label = 'control-gangof4-s' ),
610+ 'ps' : plt .subplot (222 , label = 'control-gangof4-ps' ),
611+ 'cs' : plt .subplot (223 , label = 'control-gangof4-cs' ),
612+ 't' : plt .subplot (224 , label = 'control-gangof4-t' )}
613+
614+ #
615+ # Plot the four sensitivity functions
616+ #
617+ omega_plot = omega / (2. * math .pi ) if Hz else omega
618+
619+ # TODO: Need to add in the mag = 1 lines
620+ mag_tmp , phase_tmp , omega = S .freqresp (omega )
621+ mag = np .squeeze (mag_tmp )
622+ plot_axes ['s' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
623+ plot_axes ['s' ].set_ylabel ("$|S|$" )
624+ plot_axes ['s' ].tick_params (labelbottom = False )
625+ plot_axes ['s' ].grid (grid , which = 'both' )
626+
627+ mag_tmp , phase_tmp , omega = (P * S ).freqresp (omega )
628+ mag = np .squeeze (mag_tmp )
629+ plot_axes ['ps' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
630+ plot_axes ['ps' ].tick_params (labelbottom = False )
631+ plot_axes ['ps' ].set_ylabel ("$|PS|$" )
632+ plot_axes ['ps' ].grid (grid , which = 'both' )
633+
634+ mag_tmp , phase_tmp , omega = (C * S ).freqresp (omega )
635+ mag = np .squeeze (mag_tmp )
636+ plot_axes ['cs' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
637+ plot_axes ['cs' ].set_xlabel (
638+ "Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
639+ plot_axes ['cs' ].set_ylabel ("$|CS|$" )
640+ plot_axes ['cs' ].grid (grid , which = 'both' )
641+
642+ mag_tmp , phase_tmp , omega = T .freqresp (omega )
643+ mag = np .squeeze (mag_tmp )
644+ plot_axes ['t' ].loglog (omega_plot , 20 * np .log10 (mag ) if dB else mag )
645+ plot_axes ['t' ].set_xlabel (
646+ "Frequency (Hz)" if Hz else "Frequency (rad/sec)" )
647+ plot_axes ['t' ].set_ylabel ("$|T|$" )
648+ plot_axes ['t' ].grid (grid , which = 'both' )
649+
650+ plt .tight_layout ()
630651
631652#
632653# Utility functions
0 commit comments