Ejemplo n.º 1
0
 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)
Ejemplo n.º 2
0
 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)
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
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