Skip to content

Commit ed4a963

Browse files
authored
Reorder Gang of Four plots to match FBS (#354)
* reorder gangof4 plots to be consistent with FBS * add configuration parameter processing to gangof4 * add gangof4 labels and tight_layout
1 parent fe6d774 commit ed4a963

1 file changed

Lines changed: 73 additions & 52 deletions

File tree

control/freqplot.py

Lines changed: 73 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)