def testNyquist(self): h1 = TransferFunction([1], [1, 2, 2]) omega = np.logspace(-1, 2, 40) f1 = FRD(h1, omega, smooth=True) freqplot.nyquist(f1, np.logspace(-1, 2, 100)) # plt.savefig('/dev/null', format='svg') plt.figure(2) freqplot.nyquist(f1, f1.omega)
def nyquist(self, ax=None, pairs=None, label="nyquist", title=None, xlabel="Real Axis", ylabel="Imaginary Axis", colors=['b','g','r','c','m','y','k'], **kwargs): """Create a Nyquist plot of the system's response. The Nyquist plots of a MIMO system are overlayed. This is different than MATLAB\ :sup:`®`, which creates an array of subplots. **Arguments:** - *ax*: Axes onto which the Nyquist diagram should be plotted If *ax* is not provided, then axes will be created in a new figure. - *pairs*: List of (input index, output index) tuples of each transfer function to be evaluated If not provided, all of the transfer functions will be plotted. - *label*: Label for the figure (ignored if ax is provided) This will be used as the base filename if the figure is saved. - *title*: Title for the figure If *title* is *None* (default), then the title will be "Nyquist Plot of *fbase*", where *fbase* is the base filename of the data. Use '' for no title. - *xlabel*: x-axis label - *ylabel*: y-axis label - *colors*: Color or list of colors that will be used sequentially Each may be a character, grayscale, or rgb value. .. Seealso:: http://matplotlib.sourceforge.net/api/colors_api.html - *\*\*kwargs*: Additional arguments for :meth:`control.freqplot.nyquist` **Returns:** 1. *ax*: Axes of the Nyquist plot **Example:** .. testsetup:: >>> from modelicares import closeall >>> closeall() .. code-block:: python >>> from modelicares import LinRes, save >>> from numpy import pi, logspace >>> lin = LinRes('examples/PID.mat') >>> lin.nyquist(label='examples/PID-nyquist', ... omega=2*pi*logspace(0, 3, 61), labelFreq=20, ... title="Nyquist Plot of Modelica.Blocks.Continuous.PID") # doctest: +ELLIPSIS <matplotlib.axes._subplots.AxesSubplot object at 0x...> >>> save() Saved examples/PID-nyquist.pdf Saved examples/PID-nyquist.png .. only:: html .. image:: ../examples/PID-nyquist.png :scale: 70 % :alt: example for LinRes.nyquist() .. only:: latex .. figure:: ../examples/PID-nyquist.pdf :scale: 70 % Results of example for :meth:`LinRes.nyquist`. """ # Create axes if necessary. if not ax: fig = base.figure(label) ax = fig.add_subplot(111, aspect='equal') # Create a title if necessary. if title is None: title = r"Nyquist Plot of %s" % self.fbase # Set up the color(s). if not iterable(colors): # Use the single color for all plots. colors = (colors,) n_colors = len(colors) # If input/output pair(s) aren't specified, generate a list of all # pairs. if not pairs: pairs = [(i_u, i_y) for i_u in range(self.sys.inputs) for i_y in range(self.sys.outputs)] # Create the plots. for i, (i_u, i_y) in enumerate(pairs): # Extract the SISO TF. TODO: Is there a better way to do this? sys = ss(self.sys.A, self.sys.B[:, i_u], self.sys.C[i_y, :], self.sys.D[i_y, i_u]) nyquist(sys, mark=False, label=r'$Y_{%i}/U_{%i}$' % (i_y, i_u), color=colors[np.mod(i, n_colors)], ax=ax, **kwargs) # Note: controls.freqplot.nyquist() is currently only implemented # for SISO systems. # Decorate and finish. if len(pairs) > 1: ax.legend() base.add_hlines(ax, color='k', linestyle='--', linewidth=0.5) base.add_vlines(ax, color='k', linestyle='--', linewidth=0.5) ax.set_title(title) if xlabel: # Without this check, xlabel=None will give a label of "None". ax.set_xlabel(xlabel) if ylabel: # Same purpose ax.set_ylabel(ylabel) return ax
def multinyquist(lins, ax=None, pair=(0, 0), label='nyquist', title="Nyquist Plot", xlabel="Real Axis", ylabel="Imaginary Axis", labels='', colors=['b', 'g', 'r', 'c', 'm', 'y', 'k'], leg_kwargs={}, **kwargs): """Plot multiple linearizations onto a single Nyquist diagram. **Arguments:** - *lins*: Linearization result or list of results (instances of :class:`linres.LinRes`) - *ax*: Axes onto which the Nyquist diagrams should be plotted If *ax* is not provided, then axes will be created in a new figure. - *pair*: Tuple of (input index, output index) for the transfer function to be chosen from each system (applied to all) This is ignored if the system is SISO. - *label*: Label for the figure (ignored if axes is provided) This will be used as the base filename if the figure is saved. - *title*: Title for the figure - *xlabel*: x-axis label - *ylabel*: y-axis label - *labels*: Label or list of labels for the legends If *labels* is *None*, then no label will be used. If it is an empty string (''), then the base filenames will be used. - *colors*: Color or list of colors that will be used sequentially Each may be a character, grayscale, or rgb value. .. Seealso:: http://matplotlib.sourceforge.net/api/colors_api.html - *leg_kwargs*: Dictionary of keyword arguments for :meth:`matplotlib.pyplot.legend` If *leg_kwargs* is *None*, then no legend will be shown. - *\*\*kwargs*: Additional arguments for :meth:`control.freqplot.nyquist` If *textFreq* is not specified, then only the frequency points of the first system will have text labels. **Returns:** 1. *ax*: Axes of the Nyquist plot **Example:** .. testsetup:: >>> from modelicares import closeall >>> closeall() .. code-block:: python >>> import os >>> from glob import glob >>> from modelicares import LinRes, multinyquist, save, read_params >>> from numpy import pi, logspace >>> lins = map(LinRes, glob('examples/PID/*/*.mat')) >>> labels = ["Td=%g" % read_params('Td', os.path.join(lin.dir, 'dsin.txt')) ... for lin in lins] >>> multinyquist(lins, ... title="Nyquist Plot of Modelica.Blocks.Continuous.PID", ... label='examples/PIDs-nyquist', textFreq=True, ... omega=2*pi*logspace(-1, 3, 81), labelFreq=20, ... labels=labels) # doctest: +ELLIPSIS <matplotlib.axes._subplots.AxesSubplot object at 0x...> >>> save() Saved examples/PIDs-nyquist.pdf Saved examples/PIDs-nyquist.png .. only:: html .. image:: ../examples/PIDs-nyquist.png :scale: 70 % :alt: Nyquist plot of PID with varying parameters .. only:: latex .. figure:: ../examples/PIDs-nyquist.pdf :scale: 70 % Nyquist plot of PID with varying parameters """ # Create axes if necessary. if not ax: fig = figure(label) ax = fig.add_subplot(111, aspect='equal') # Process the lins input. if not iterable(lins): lins = [lins] # Process the labels input. if labels == '': labels = [lin.fbase for lin in lins] elif labels == None: labels = ['']*len(lins) # Set up the color(s). if not iterable(colors): # Use the single color for all plots. colors = (colors,) n_colors = len(colors) # Create the plots. textFreq = kwargs.pop('textFreq', None) for i, (lin, label) in enumerate(zip(lins, labels)): if lin.sys.inputs > 1 or lin.sys.outputs > 1: # Extract the SISO TF. TODO: Is there a better way to do this? sys = ss(self.sys.A, self.sys.B[:, pair[0]], self.sys.C[pair[1], :], self.sys.D[pair[1], pair[0]]) else: sys = lin.sys nyquist(sys, mark=False, label=label, ax=ax, textFreq=i==0 if textFreq is None else textFreq, color=colors[np.mod(i, n_colors)], **kwargs) # Decorate and finish. add_hlines(ax, color='k', linestyle='--', linewidth=0.5) add_vlines(ax, color='k', linestyle='--', linewidth=0.5) ax.set_title(title) if xlabel: # Without this check, xlabel=None will give a label of "None". ax.set_xlabel(xlabel) if ylabel: # Same purpose ax.set_ylabel(ylabel) if leg_kwargs is not None: loc = leg_kwargs.pop('loc', 'best') ax.legend(loc=loc, **leg_kwargs) return ax