B
    }d"                 @   sb   d Z ddlmZ ddlZddlmZ ddlmZ ddlm	Z	 dZ
d	gZd
d ZG dd	 d	e	ZdS )zDefinition of a BodePlot
    )piN)MaxNLocator)Quantity   )Plotz(Duncan Macleod <duncan.macleod@ligo.org>BodePlotc             C   s   dt |  S )a  Convert the input array into decibels

    Parameters
    ----------
    a : `float`, `numpy.ndarray`
        value or array of values to convert to decibels

    Returns
    -------
    dB : ``10 * numpy.log10(a)``

    Examples
    --------
    >>> to_db(1000)
    30.0
    
   )numpylog10)a r   [/work/yifan.wang/ringdown/master-ringdown-env/lib/python3.7/site-packages/gwpy/plot/bode.pyto_db$   s    r   c                   sL   e Zd ZdZ fddZedd Zedd ZdddZdddZ	  Z
S )r   ao  A `Plot` class for visualising transfer functions

    Parameters
    ----------
    *filters : `~scipy.signal.lti`, `~gwpy.frequencyseries.FrequencySeries`
        any number of the following:

        - linear time-invariant filters, either
          `~scipy.signal.lti` or `tuple` of the following length and form:
          - 2: (numerator, denominator)
          - 3: (zeros, poles, gain)
          - 4: (A, B, C, D)

        - complex-valued `spectra <gwpy.frequencyseries.FrequencySeries>`
          representing a transfer function

    frequencies : `numpy.ndarray`, optional
        list of frequencies (in Hertz) at which to plot

    dB : `bool`, optional, default: `True`
        if `True`, display magnitude in decibels, otherwise display
        amplitude.

    **kwargs
        other keyword arguments as applicable for `Plot` or
        :meth:`~FrequencySeriesAxes.plot`

    Returns
    -------
    plot : `BodePlot`
        a new BodePlot with two `Axes` - :attr:`~BodePlot.maxes` and
        :attr:`~BodePlot.paxes` - representing the magnitude and
        phase of the input transfer function(s) respectively.
    c                s   ddl m} |dd}|dd}t }|dd}x"dD ]}||kr<||||< q<W t jf | | dd	d	 | jdd	d| jd
 xF|D ]>}	t|	|r| j	|	fd|i| q| j
|	f||d| qW |r$| jd | j }
|
d	 dkr<| jj|
d	 |
d	 |
d  d  d n| jd | jd | jd | jd | jd | jd | jjtdddgd | jjtdddgd |r| j| |dkrt|d	krt|d |r|d jj}t|tdtfs||dk }| j| |  dS )z$Initialise a new `BodePlot`
           )FrequencySeriesdBTfrequenciesNtitle)ZfigsizeZdpiZframeonZsubplotparsZtight_layoutr   )Zsharex)r   r   zMagnitude [dB]r   g?)upperlogZ	AmplitudezFrequency [Hz]zPhase [deg]autog      @	   )ZnbinsZsteps   )Zfrequencyseriesr   popdictsuper__init__Zadd_subplotmaxes
isinstanceadd_frequencyseries
add_filterZ
set_ylabelZget_ylimZ
set_yboundZ
set_yscalepaxesZ
set_xlabelZ
set_xscaleZyaxisZset_major_locatorr   Zset_minor_locator	set_titlelenr   valuetypeintZset_xlimminmax)selffilterskwargsr   r   r   Zfigargsr   keyfilter_Zylim)	__class__r   r   r   [   sR    




"
zBodePlot.__init__c             C   s
   | j d S )z5`FrequencySeriesAxes` for the Bode magnitude
        r   )axes)r)   r   r   r   r      s    zBodePlot.maxesc             C   s
   | j d S )z1`FrequencySeriesAxes` for the Bode phase
        r   )r/   )r)   r   r   r   r!      s    zBodePlot.paxesNTFc             K   s   ddl m}m} ddlm}	 |sl|s,tdt|dj}dt | }
t	|t
dtfslt| }||
9 }|	|dd	\}}|r|| }n||d
|
i}|j|d\}}}|sd|d  }| jj||f|d }| jj||f|d }||fS )a  Add a linear time-invariant filter to this BodePlot

        Parameters
        ----------
        filter_ : `~scipy.signal.lti`, `tuple`
            the filter to plot, either as a `~scipy.signal.lti`, or a
            `tuple` with the following number and meaning of elements

                 - 2: (numerator, denominator)
                 - 3: (zeros, poles, gain)
                 - 4: (A, B, C, D)

        frequencies : `numpy.ndarray`, optional
            list of frequencies (in Hertz) at which to plot

        dB : `bool`, optional
            if `True`, display magnitude in decibels, otherwise display
            amplitude, default: `True`

        **kwargs
            any other keyword arguments accepted by
            :meth:`~matplotlib.axes.Axes.plot`

        Returns
        -------
        mag, phase : `tuple` of `lines <matplotlib.lines.Line2D>`
            the lines drawn for the magnitude and phase of the filter.
        r   )ltidlti)parse_filterzHMust give sample_rate frequency to display digital (analog=False) filterZHzr   NF)analogdt)wr   g      $@)Zscipy.signalr0   r1   Zgwpy.signal.filter_designr2   
ValueErrorr   r$   r   r   r%   r&   r	   Z
atleast_1dcopyZboder   plotr!   )r)   r-   r   r   r3   Zsample_rater+   r0   r1   r2   r4   _ZfcompZ_ltir5   magphasemlinepliner   r   r   r       s(    
zBodePlot.add_filterc       
      K   s~   | d|j t|j}|r2t|}|s2|d9 }tj|jdd}|jj}| jj	||f|d }| j
j	||f|d }	||	fS )a  Plot the magnitude and phase of a complex-valued `FrequencySeries`

        Parameters
        ----------
        spectrum : `~gwpy.frequencyseries.FrequencySeries`
            the (complex-valued) `FrequencySeries` to display

        db : `bool`, optional, default: `True`
            if `True`, display magnitude in decibels, otherwise display
            amplitude.

        power : `bool`, optional, default: `False`
            give `True` to incidate that ``spectrum`` holds power values,
            so ``dB = 10 * log(abs(spectrum))``, otherwise
            ``db = 20 * log(abs(spectrum))``. This argument is ignored if
            ``db=False``.

        **kwargs
            any other keyword arguments accepted by
            :meth:`~matplotlib.axes.Axes.plot`

        Returns
        -------
        mag, phase : `tuple` of `lines <matplotlib.lines.Line2D>`
            the lines drawn for the magnitude and phase of the filter.
        labelg       @T)degr   )
setdefaultnamer	   absoluter$   r   Zangler   r   r8   r!   )
r)   Zspectrumr   powerr+   r:   r;   r5   r<   r=   r   r   r   r      s    zBodePlot.add_frequencyseries)NTFN)TF)__name__
__module____qualname____doc__r   propertyr   r!   r    r   __classcell__r   r   )r.   r   r   8   s   "@ 
=)rG   mathr   r	   Zmatplotlib.tickerr   Zastropy.unitsr    r   
__author____all__r   r   r   r   r   r   <module>   s   