def asyncSlot(*args):
    """Make a Qt async slot run on asyncio loop."""
    def outer_decorator(fn):
        @Slot(*args)
        @functools.wraps(fn)
        def wrapper(*args, **kwargs):
            asyncio.ensure_future(fn(*args, **kwargs))
        return wrapper
    return outer_decorator

def asyncSlot ( * args ) : def outer_decorator ( fn ) : @ Slot ( * args ) @ functools . wraps ( fn ) def wrapper ( * args , * * kwargs ) : asyncio . ensure_future ( fn ( * args , * * kwargs ) ) return wrapper return outer_decorator

Make a Qt async slot run on asyncio loop .


def with_logger(cls):
    """Class decorator to add a logger to a class."""
    attr_name = '_logger'
    cls_name = cls.__qualname__
    module = cls.__module__
    if module is not None:
        cls_name = module + '.' + cls_name
    else:
        raise AssertionError
    setattr(cls, attr_name, logging.getLogger(cls_name))
    return cls

def with_logger ( cls ) : attr_name = '_logger' cls_name = cls . __qualname__ module = cls . __module__ if module is not None : cls_name = module + '.' + cls_name else : raise AssertionError setattr ( cls , attr_name , logging . getLogger ( cls_name ) ) return cls

Class decorator to add a logger to a class .


def _process_event(self, key, mask):
        """Selector has delivered us an event."""
        self._logger.debug('Processing event with key {} and mask {}'.format(key, mask))
        fileobj, (reader, writer) = key.fileobj, key.data
        if mask & selectors.EVENT_READ and reader is not None:
            if reader._cancelled:
                self.remove_reader(fileobj)
            else:
                self._logger.debug('Invoking reader callback: {}'.format(reader))
                reader._run()
        if mask & selectors.EVENT_WRITE and writer is not None:
            if writer._cancelled:
                self.remove_writer(fileobj)
            else:
                self._logger.debug('Invoking writer callback: {}'.format(writer))
                writer._run()


def addSources(self, *sources):
        """Add more ASN.1 MIB source repositories.

        MibCompiler.compile will invoke each of configured source objects
        in order of their addition asking each to fetch MIB module specified
        by name.

        Args:
            sources: reader object(s)

        Returns:
            reference to itself (can be used for call chaining)

        """
        self._sources.extend(sources)

        debug.logger & debug.flagCompiler and debug.logger(
            'current MIB source(s): %s' % ', '.join([str(x) for x in self._sources]))

        return self

def
addSources
(
self
,
*
sources
)
:
self
.
_sources
.
extend
(
sources
)
debug
.
logger
&
debug
.
flagCompiler
and
debug
.
logger
(
'current MIB source(s): %s'
%
', '
.
join
(
[
str
(
x
)
for
x
in
self
.
_sources
]
)
)
return
self

Add more ASN . 1 MIB source repositories .


def addSearchers(self, *searchers):
        """Add more transformed MIBs repositories.

        MibCompiler.compile will invoke each of configured searcher objects
        in order of their addition asking each if already transformed MIB
        module already exists and is more recent than specified.

        Args:
            searchers: searcher object(s)

        Returns:
            reference to itself (can be used for call chaining)

        """
        self._searchers.extend(searchers)

        debug.logger & debug.flagCompiler and debug.logger(
            'current compiled MIBs location(s): %s' % ', '.join([str(x) for x in self._searchers]))

        return self

def
addSearchers
(
self
,
*
searchers
)
:
self
.
_searchers
.
extend
(
searchers
)
debug
.
logger
&
debug
.
flagCompiler
and
debug
.
logger
(
'current compiled MIBs location(s): %s'
%
', '
.
join
(
[
str
(
x
)
for
x
in
self
.
_searchers
]
)
)
return
self

Add more transformed MIBs repositories .


def addBorrowers(self, *borrowers):
        """Add more transformed MIBs repositories to borrow MIBs from.

        Whenever MibCompiler.compile encounters MIB module which neither of
        the *searchers* can find or fetched ASN.1 MIB module can not be
        parsed (due to syntax errors), these *borrowers* objects will be
        invoked in order of their addition asking each if already transformed
        MIB can be fetched (borrowed).

        Args:
            borrowers: borrower object(s)

        Returns:
            reference to itself (can be used for call chaining)

        """
        self._borrowers.extend(borrowers)

        debug.logger & debug.flagCompiler and debug.logger(
            'current MIB borrower(s): %s' % ', '.join([str(x) for x in self._borrowers]))

        return self

def
addBorrowers
(
self
,
*
borrowers
)
:
self
.
_borrowers
.
extend
(
borrowers
)
debug
.
logger
&
debug
.
flagCompiler
and
debug
.
logger
(
'current MIB borrower(s): %s'
%
', '
.
join
(
[
str
(
x
)
for
x
in
self
.
_borrowers
]
)
)
return
self

Add more transformed MIBs repositories to borrow MIBs from .


def AIC(N, rho, k):
    r"""Akaike Information Criterion

    :param rho: rho at order k
    :param N: sample size
    :param k: AR order.

    If k is the AR order and N the size of the sample, then Akaike criterion is

    .. math:: AIC(k) = \log(\rho_k) + 2\frac{k+1}{N}

    ::

        AIC(64, [0.5,0.3,0.2], [1,2,3])

    :validation: double checked versus octave.
    """
    from numpy import log, array
    #k+1 #todo check convention. agrees with octave

    res = N * log(array(rho)) + 2.* (array(k)+1)
    return res


def AICc(N, rho, k, norm=True):
    r"""corrected Akaike information criterion

    .. math:: AICc(k) = log(\rho_k) + 2 \frac{k+1}{N-k-2}

    :validation: double checked versus octave.
    """
    from numpy import log, array
    p = k  #todo check convention. agrees with octave
    res = log(rho) + 2. * (p+1) / (N-p-2)
    return res

r corrected Akaike information criterion


def KIC(N, rho, k):
    r"""Kullback information criterion

    .. math:: KIC(k) = log(\rho_k) + 3 \frac{k+1}{N}

    :validation: double checked versus octave.
    """
    from numpy import log, array
    res = log(rho) + 3. * (k+1.) /float(N)
    return res

def KIC ( N , rho , k ) : from numpy import log , array res = log ( rho ) + 3. * ( k + 1. ) / float ( N ) return res


def AKICc(N, rho, k):
    r"""approximate corrected Kullback information

    .. math:: AKICc(k) = log(rho_k) + \frac{p}{N*(N-k)} + (3-\frac{k+2}{N})*\frac{k+1}{N-k-2}

    """
    from numpy import log, array
    p = k
    res = log(rho) + p/N/(N-p) + (3.-(p+2.)/N) * (p+1.) / (N-p-2.)
    return res

def AKICc ( N , rho , k ) : from numpy import log , array p = k res = log ( rho ) + p / N / ( N - p ) + ( 3. - ( p + 2. ) / N ) * ( p + 1. ) / ( N - p - 2. ) return res

r approximate corrected Kullback information


def FPE(N,rho, k=None):
    r"""Final prediction error criterion

    .. math:: FPE(k) = \frac{N + k + 1}{N - k - 1} \rho_k

    :validation: double checked versus octave.

    """
    #k #todo check convention. agrees with octave
    fpe = rho * (N + k + 1.) / (N- k -1)
    return fpe


def MDL(N, rho, k):
    r"""Minimum Description Length

    .. math:: MDL(k) = N log \rho_k + p \log N

    :validation: results
    """
    from numpy import log
    #p = arange(1, len(rho)+1)
    mdl = N* log(rho) + k * log(N)
    return mdl

def
MDL
(
N
,
rho
,
k
)
:
from
numpy
import
log
#p = arange(1, len(rho)+1)
mdl
=
N
*
log
(
rho
)
+
k
*
log
(
N
)
return
mdl


def aic_eigen(s, N):
    r"""AIC order-selection using eigen values

    :param s: a list of `p` sorted eigen values
    :param N: the size of the input data. To be defined precisely.

    :return:
        * an array containing the AIC values

    Given :math:`n` sorted eigen values :math:`\lambda_i` with
    :math:`0 <= i < n`, the proposed criterion from Wax and Kailath (1985)
    is:

    .. math:: AIC(k) = -2(n-k)N \ln \frac{g(k)}{a(k)} + 2k(2n-k)

    where the arithmetic sum :math:`a(k)` is:

    .. math:: a(k) = \sum_{i=k+1}^{n}\lambda_i

    and the geometric sum :math:`g(k)` is:

    .. math:: g(k) = \prod_{i=k+1}^{n} \lambda_i^{-(n-k)}

    The number of relevant sinusoids in the signal subspace is determined by
    selecting the minimum of `AIC`.

    .. seealso:: :func:`~spectrum.eigenfreq.eigen`
    .. todo:: define precisely the input parameter N. Should be the input
       data length but when using correlation matrix (SVD), I suspect it
       should be the length of the correlation matrix rather than the
       original data.

    :References:
        * [Marple]_ Chap 13,
        * [Wax]_
    """
    import numpy as np

    kaic = []
    n = len(s)
    for k in range(0, n-1):
        ak = 1./(n-k) * np.sum(s[k+1:])
        gk = np.prod(s[k+1:]**(1./(n-k)))
        kaic.append( -2.*(n-k)*N * np.log(gk/ak) + 2.*k*(2.*n-k))

    return kaic

def aic_eigen ( s , N ) : import numpy as np kaic = [ ] n = len ( s ) for k in range ( 0 , n - 1 ) : ak = 1. / ( n - k ) * np . sum ( s [ k + 1 : ] ) gk = np . prod ( s [ k + 1 : ] ** ( 1. / ( n - k ) ) ) kaic . append ( - 2. * ( n - k ) * N * np . log ( gk / ak ) + 2. * k * ( 2. * n - k ) ) return kaic

r AIC order - selection using eigen values


def mdl_eigen(s, N):
    r"""MDL order-selection using eigen values

    :param s: a list of `p` sorted eigen values
    :param N: the size of the input data. To be defined precisely.

    :return:
        * an array containing the AIC values

    .. math:: MDL(k) = (n-k)N \ln \frac{g(k)}{a(k)} + 0.5k(2n-k) log(N)

    .. seealso:: :func:`aic_eigen` for details

    :References:
        * [Marple]_ Chap 13,
        * [Wax]_
    """
    import numpy as np
    kmdl = []
    n = len(s)
    for k in range(0, n-1):
        ak = 1./(n-k) * np.sum(s[k+1:])
        gk = np.prod(s[k+1:]**(1./(n-k)))
        kmdl.append( -(n-k)*N * np.log(gk/ak) + 0.5*k*(2.*n-k)*np.log(N))
    return kmdl

def mdl_eigen ( s , N ) : import numpy as np kmdl = [ ] n = len ( s ) for k in range ( 0 , n - 1 ) : ak = 1. / ( n - k ) * np . sum ( s [ k + 1 : ] ) gk = np . prod ( s [ k + 1 : ] ** ( 1. / ( n - k ) ) ) kmdl . append ( - ( n - k ) * N * np . log ( gk / ak ) + 0.5 * k * ( 2. * n - k ) * np . log ( N ) ) return kmdl

r MDL order - selection using eigen values


def generate_gallery_rst(app):
    """Generate the Main examples gallery reStructuredText

    Start the sphinx-gallery configuration and recursively scan the examples
    directories in order to populate the examples gallery
    """
    try:
        plot_gallery = eval(app.builder.config.plot_gallery)
    except TypeError:
        plot_gallery = bool(app.builder.config.plot_gallery)

    gallery_conf.update(app.config.sphinx_gallery_conf)
    gallery_conf.update(plot_gallery=plot_gallery)
    gallery_conf.update(abort_on_example_error=app.builder.config.abort_on_example_error)

    # this assures I can call the config in other places
    app.config.sphinx_gallery_conf = gallery_conf
    app.config.html_static_path.append(glr_path_static())

    clean_gallery_out(app.builder.outdir)

    examples_dirs = gallery_conf['examples_dirs']
    gallery_dirs = gallery_conf['gallery_dirs']

    if not isinstance(examples_dirs, list):
        examples_dirs = [examples_dirs]
    if not isinstance(gallery_dirs, list):
        gallery_dirs = [gallery_dirs]

    mod_examples_dir = os.path.relpath(gallery_conf['mod_example_dir'],
                                       app.builder.srcdir)
    seen_backrefs = set()

    for examples_dir, gallery_dir in zip(examples_dirs, gallery_dirs):
        examples_dir = os.path.relpath(examples_dir,
                                       app.builder.srcdir)
        gallery_dir = os.path.relpath(gallery_dir,
                                      app.builder.srcdir)

        for workdir in [examples_dir, gallery_dir, mod_examples_dir]:
            if not os.path.exists(workdir):
                os.makedirs(workdir)

        # we create an index.rst with all examples
        fhindex = open(os.path.join(gallery_dir, 'index.rst'), 'w')
        # Here we don't use an os.walk, but we recurse only twice: flat is
        # better than nested.
        fhindex.write(generate_dir_rst(examples_dir, gallery_dir, gallery_conf,
                                       seen_backrefs))
        for directory in sorted(os.listdir(examples_dir)):
            if os.path.isdir(os.path.join(examples_dir, directory)):
                src_dir = os.path.join(examples_dir, directory)
                target_dir = os.path.join(gallery_dir, directory)
                fhindex.write(generate_dir_rst(src_dir, target_dir,
                                               gallery_conf,
                                               seen_backrefs))
        fhindex.flush()


def setup(app):
    """Setup sphinx-gallery sphinx extension"""
    app.add_config_value('plot_gallery', True, 'html')
    app.add_config_value('abort_on_example_error', False, 'html')
    app.add_config_value('sphinx_gallery_conf', gallery_conf, 'html')
    app.add_stylesheet('gallery.css')

    app.connect('builder-inited', generate_gallery_rst)

    app.connect('build-finished', embed_code_links)

def setup ( app ) : app . add_config_value ( 'plot_gallery' , True , 'html' ) app . add_config_value ( 'abort_on_example_error' , False , 'html' ) app . add_config_value ( 'sphinx_gallery_conf' , gallery_conf , 'html' ) app . add_stylesheet ( 'gallery.css' ) app . connect ( 'builder-inited' , generate_gallery_rst ) app . connect ( 'build-finished' , embed_code_links )


def CORRELATION(x, y=None, maxlags=None, norm='unbiased'):
    r"""Correlation function

    This function should give the same results as :func:`xcorr` but it
    returns the positive lags only. Moreover the algorithm does not use
    FFT as compared to other algorithms.

    :param array x: first data array of length N
    :param array y: second data array of length N. If not specified, computes the
        autocorrelation.
    :param int maxlags: compute cross correlation between [0:maxlags]
        when maxlags is not specified, the range of lags is [0:maxlags].
    :param str norm: normalisation in ['biased', 'unbiased', None, 'coeff']

        * *biased*   correlation=raw/N,
        * *unbiased* correlation=raw/(N-`|lag|`)
        * *coeff*    correlation=raw/(rms(x).rms(y))/N
        * None       correlation=raw

    :return:
        * a numpy.array correlation sequence,  r[1,N]
        * a float for the zero-lag correlation,  r[0]

    The *unbiased* correlation has the form:

    .. math::

        \hat{r}_{xx} = \frac{1}{N-m}T \sum_{n=0}^{N-m-1} x[n+m]x^*[n] T

    The *biased* correlation differs by the front factor only:

    .. math::

        \check{r}_{xx} = \frac{1}{N}T \sum_{n=0}^{N-m-1} x[n+m]x^*[n] T

    with :math:`0\leq m\leq N-1`.

    .. doctest::

        >>> from spectrum import CORRELATION
        >>> x = [1,2,3,4,5]
        >>> res = CORRELATION(x,x, maxlags=0, norm='biased')
        >>> res[0]
        11.0

    .. note:: this function should be replaced by :func:`xcorr`.

    .. seealso:: :func:`xcorr`
    """
    assert norm in ['unbiased','biased', 'coeff', None]
    #transform lag into list if it is an integer
    x = np.array(x)
    if y is None:
        y = x
    else:
        y = np.array(y)

    # N is the max of x and y
    N = max(len(x), len(y))
    if len(x) < N:
        x = y.copy()
        x.resize(N)
    if len(y) < N:
        y = y.copy()
        y.resize(N)

    #default lag is N-1
    if maxlags is None:
        maxlags = N - 1
    assert maxlags < N, 'lag must be less than len(x)'

    realdata = np.isrealobj(x) and np.isrealobj(y)
    #create an autocorrelation array with same length as lag
    if realdata == True:
        r = np.zeros(maxlags, dtype=float)
    else:
        r = np.zeros(maxlags, dtype=complex)

    if norm == 'coeff':
        rmsx = pylab_rms_flat(x)
        rmsy = pylab_rms_flat(y)

    for k in range(0, maxlags+1):
        nk = N - k - 1

        if realdata == True:
            sum = 0
            for j in range(0, nk+1):
                sum = sum + x[j+k] * y[j]
        else:
            sum = 0. + 0j
            for j in range(0, nk+1):
                sum = sum + x[j+k] * y[j].conjugate()
        if k == 0:
            if norm in ['biased', 'unbiased']:
                r0 = sum/float(N)
            elif norm is None:
                r0 = sum
            else:
                r0 =  1.
        else:
            if norm == 'unbiased':
                r[k-1] = sum / float(N-k)
            elif norm == 'biased':
                r[k-1] = sum / float(N)
            elif norm is None:
                r[k-1] = sum
            elif norm == 'coeff':
                r[k-1] =  sum/(rmsx*rmsy)/float(N)

    r = np.insert(r, 0, r0)
    return r


def xcorr(x, y=None, maxlags=None, norm='biased'):
    """Cross-correlation using numpy.correlate

    Estimates the cross-correlation (and autocorrelation) sequence of a random
    process of length N. By default, there is no normalisation and the output
    sequence of the cross-correlation has a length 2*N+1.

    :param array x: first data array of length N
    :param array y: second data array of length N. If not specified, computes the
        autocorrelation.
    :param int maxlags: compute cross correlation between [-maxlags:maxlags]
        when maxlags is not specified, the range of lags is [-N+1:N-1].
    :param str option: normalisation in ['biased', 'unbiased', None, 'coeff']

    The true cross-correlation sequence is

    .. math:: r_{xy}[m] = E(x[n+m].y^*[n]) = E(x[n].y^*[n-m])

    However, in practice, only a finite segment of one realization of the
    infinite-length random process is available.

    The correlation is estimated using numpy.correlate(x,y,'full').
    Normalisation is handled by this function using the following cases:

        * 'biased': Biased estimate of the cross-correlation function
        * 'unbiased': Unbiased estimate of the cross-correlation function
        * 'coeff': Normalizes the sequence so the autocorrelations at zero
           lag is 1.0.

    :return:
        * a numpy.array containing the cross-correlation sequence (length 2*N-1)
        * lags vector

    .. note:: If x and y are not the same length, the shorter vector is
        zero-padded to the length of the longer vector.

    .. rubric:: Examples

    .. doctest::

        >>> from spectrum import xcorr
        >>> x = [1,2,3,4,5]
        >>> c, l = xcorr(x,x, maxlags=0, norm='biased')
        >>> c
        array([ 11.])

    .. seealso:: :func:`CORRELATION`.
    """
    N = len(x)
    if y is None:
        y = x
    assert len(x) == len(y), 'x and y must have the same length. Add zeros if needed'

    if maxlags is None:
        maxlags = N-1
        lags = np.arange(0, 2*N-1)
    else:
        assert maxlags <= N, 'maxlags must be less than data length'
        lags = np.arange(N-maxlags-1, N+maxlags)

    res = np.correlate(x, y, mode='full')

    if norm == 'biased':
        Nf = float(N)
        res = res[lags] / float(N)    # do not use /= !!
    elif norm == 'unbiased':
        res = res[lags] / (float(N)-abs(np.arange(-N+1, N)))[lags]
    elif norm == 'coeff':
        Nf = float(N)
        rms = pylab_rms_flat(x) * pylab_rms_flat(y)
        res = res[lags] / rms / Nf
    else:
        res = res[lags]

    lags = np.arange(-maxlags, maxlags+1)
    return res, lags

Cross - correlation using numpy . correlate


def MINEIGVAL(T0, T, TOL):
    """Finds the minimum eigenvalue of a Hermitian Toeplitz matrix

    The classical power method is used together with a  fast  Toeplitz
    equation solution routine.  The eigenvector is normalized to unit length.

    :param T0: Scalar corresponding to real matrix element t(0)
    :param T: Array of  M  complex matrix elements t(1),...,t(M) C            from the left column of the Toeplitz matrix
    :param TOL: Real scalar tolerance; routine exits when [ EVAL(k) - EVAL(k-1) ]/EVAL(k-1) < TOL , where the index k denotes the iteration number.

    :return:
        * EVAL - Real scalar denoting the minimum eigenvalue of matrix
        * EVEC - Array of  M  complex eigenvector elements associated

    .. note::
     * External array T must be dimensioned >= M
     * array EVEC must be >= M+1
     *  Internal array E must be dimensioned >= M+1 .

     * **dependencies**
        *  :meth:`spectrum.toeplitz.HERMTOEP`
    """
    M = len(T)
    eigval = 10
    eigvalold = 1
    eigvec  = numpy.zeros(M+1, dtype=complex)
    for k in range(0,M+1):
        eigvec[k] = 1+0j
    it=0
    #print 'initialisation',T0, T, eigval, eigvec
    maxit = 15
    while abs(eigvalold-eigval)>TOL*eigvalold and it<maxit:
        it=it+1
        eigvalold = eigval
        #print 'iteration ',it, 'eigvalold=',eigvalold, 'eigval=', eigval

        eig = toeplitz.HERMTOEP(T0, T, eigvec)
        SUM = 0
        save =0.+0j
        for k in range(0, M+1):
            SUM = SUM + eig[k].real**2+eig[k].imag**2
            save = save +eig[k]*eigvec[k].conjugate()
        SUM=1./SUM
        eigval = save.real*SUM
        for k in range(0,M+1):
            eigvec[k] = SUM * eig[k]
    if it==maxit:
        print('warning reached max number of iteration (%s)' % maxit)
    return eigval, eigvec


def morlet(lb, ub, n):
    r"""Generate the Morlet waveform

    The Morlet waveform is defined as follows:

    .. math:: w[x] = \cos{5x}  \exp^{-x^2/2}

    :param lb: lower bound
    :param ub: upper bound
    :param int n: waveform data samples

    .. plot::
        :include-source:
        :width: 80%

        from spectrum import morlet
        from pylab import plot
        plot(morlet(0,10,100))

    """
    if n <= 0:
        raise ValueError("n must be strictly positive")

    x = numpy.linspace(lb, ub, n)
    psi = numpy.cos(5*x) * numpy.exp(-x**2/2.)
    return psi

def
morlet
(
lb
,
ub
,
n
)
:
if
n
<=
0
:
raise
ValueError
(
"n must be strictly positive"
)
x
=
numpy
.
linspace
(
lb
,
ub
,
n
)
psi
=
numpy
.
cos
(
5
*
x
)
*
numpy
.
exp
(
x
**
2
/
2.
)
return
psi


def chirp(t, f0=0., t1=1., f1=100., form='linear', phase=0):
    r"""Evaluate a chirp signal at time t.

    A chirp signal is a frequency swept cosine wave.

    .. math:: a = \pi  (f_1 - f_0) / t_1
    .. math:: b = 2  \pi  f_0
    .. math:: y = \cos\left( \pi\frac{f_1-f_0}{t_1}  t^2 + 2\pi f_0 t + \rm{phase} \right)

    :param array t: times at which to evaluate the chirp signal
    :param float f0: frequency at time t=0 (Hz)
    :param float t1: time t1
    :param float f1: frequency at time t=t1 (Hz)
    :param str form: shape of frequency sweep in ['linear', 'quadratic', 'logarithmic']
    :param float phase: phase shift at t=0

    The parameter **form** can be:

        * 'linear'      :math:`f(t) = (f_1-f_0)(t/t_1) + f_0`
        * 'quadratic'   :math:`f(t) = (f_1-f_0)(t/t_1)^2 + f_0`
        * 'logarithmic' :math:`f(t) = (f_1-f_0)^{(t/t_1)} + f_0`

    Example:

    .. plot::
        :include-source:
        :width: 80%

        from spectrum import chirp
        from pylab import linspace, plot
        t = linspace(0, 1, 1000)
        y = chirp(t, form='linear')
        plot(y)
        y = chirp(t, form='quadratic')
        plot(y, 'r')

    """
    valid_forms = ['linear', 'quadratic', 'logarithmic']
    if form not in valid_forms:
        raise ValueError("Invalid form. Valid form are %s"
            % valid_forms)
    t = numpy.array(t)
    phase = 2. * pi * phase / 360.
    if form == "linear":
        a = pi * (f1 - f0)/t1
        b = 2. * pi * f0
        y = numpy.cos(a * t**2 + b*t + phase)
    elif form == "quadratic":
        a = (2/3. * pi * (f1-f0)/t1/t1)
        b = 2. * pi * f0
        y = numpy.cos(a*t**3 + b * t + phase)
    elif form == "logarithmic":
        a = 2. * pi * t1/numpy.log(f1-f0)
        b = 2. * pi * f0
        x = (f1-f0)**(1./t1)
        y = numpy.cos(a * x**t + b * t + phase)

    return y

def
chirp
(
t
,
f0
=
0.
,
t1
=
1.
,
f1
=
100.
,
form
=
'linear'
,
phase
=
0
)
:
valid_forms
=
[
'linear'
,
'quadratic'
,
'logarithmic'
]
if
form
not
in
valid_forms
:
raise
ValueError
(
"Invalid form. Valid form are %s"
%
valid_forms
)
t
=
numpy
.
array
(
t
)
phase
=
2.
*
pi
*
phase
/
360.
if
form
==
"linear"
:
a
=
pi
*
(
f1
f0
)
/
t1
b
=
2.
*
pi
*
f0
y
=
numpy
.
cos
(
a
*
t
**
2
+
b
*
t
+
phase
)
elif
form
==
"quadratic"
:
a
=
(
2
/
3.
*
pi
*
(
f1
f0
)
/
t1
/
t1
)
b
=
2.
*
pi
*
f0
y
=
numpy
.
cos
(
a
*
t
**
3
+
b
*
t
+
phase
)
elif
form
==
"logarithmic"
:
a
=
2.
*
pi
*
t1
/
numpy
.
log
(
f1
f0
)
b
=
2.
*
pi
*
f0
x
=
(
f1
f0
)
**
(
1.
/
t1
)
y
=
numpy
.
cos
(
a
*
x
**
t
+
b
*
t
+
phase
)
return
y


def mexican(lb, ub, n):
    r"""Generate the mexican hat wavelet

    The Mexican wavelet is:

    .. math:: w[x] = \cos{5x}  \exp^{-x^2/2}

    :param lb: lower bound
    :param ub: upper bound
    :param int n: waveform data samples
    :return: the waveform

    .. plot::
        :include-source:
        :width: 80%

        from spectrum import mexican
        from pylab import plot
        plot(mexican(0, 10, 100))

    """
    if n <= 0:
        raise ValueError("n must be strictly positive")

    x = numpy.linspace(lb, ub, n)
    psi = (1.-x**2.) * (2./(numpy.sqrt(3.)*pi**0.25)) * numpy.exp(-x**2/2.)
    return psi

def
mexican
(
lb
,
ub
,
n
)
:
if
n
<=
0
:
raise
ValueError
(
"n must be strictly positive"
)
x
=
numpy
.
linspace
(
lb
,
ub
,
n
)
psi
=
(
1.
x
**
2.
)
*
(
2.
/
(
numpy
.
sqrt
(
3.
)
*
pi
**
0.25
)
)
*
numpy
.
exp
(
x
**
2
/
2.
)
return
psi


def ac2poly(data):
    """Convert autocorrelation sequence to prediction polynomial

    :param array data:    input data (list or numpy.array)
    :return:
        * AR parameters
        * noise variance

    This is an alias to::

        a, e, c = LEVINSON(data)

    :Example:

    .. doctest::

        >>> from spectrum import ac2poly
        >>> from numpy import array
        >>> r = [5, -2, 1.01]
        >>> ar, e = ac2poly(r)
        >>> ar
        array([ 1.  ,  0.38, -0.05])
        >>> e
        4.1895000000000007

    """
    a, e, _c = LEVINSON(data)
    a = numpy.insert(a, 0, 1)
    return a, e

def ac2poly ( data ) : a , e , _c = LEVINSON ( data ) a = numpy . insert ( a , 0 , 1 ) return a , e


def rc2poly(kr, r0=None):
    """convert reflection coefficients to prediction filter polynomial

    :param k: reflection coefficients

    """
    # Initialize the recursion
    from .levinson import levup
    p = len(kr)              #% p is the order of the prediction polynomial.
    a = numpy.array([1, kr[0]])           #% a is a true polynomial.
    e = numpy.zeros(len(kr))

    if r0 is None:
        e0 = 0
    else:
        e0 = r0

    e[0] = e0 * (1. - numpy.conj(numpy.conjugate(kr[0])*kr[0]))

    # Continue the recursion for k=2,3,...,p, where p is the order of the
    # prediction polynomial.

    for k in range(1, p):
        [a, e[k]] = levup(a, kr[k], e[k-1])

    efinal = e[-1]
    return a, efinal


def rc2ac(k, R0):
    """Convert reflection coefficients to autocorrelation sequence.

    :param k: reflection coefficients
    :param R0: zero-lag autocorrelation
    :returns: the autocorrelation sequence

    .. seealso:: :func:`ac2rc`, :func:`poly2rc`, :func:`ac2poly`, :func:`poly2rc`, :func:`rc2poly`.

    """
    [a,efinal] = rc2poly(k, R0)
    R, u, kr, e = rlevinson(a, efinal)
    return R

def rc2ac ( k , R0 ) : [ a , efinal ] = rc2poly ( k , R0 ) R , u , kr , e = rlevinson ( a , efinal ) return R

Convert reflection coefficients to autocorrelation sequence .


def rc2is(k):
    """Convert reflection coefficients to inverse sine parameters.

    :param k: reflection coefficients
    :return: inverse sine parameters

    .. seealso:: :func:`is2rc`, :func:`rc2poly`, :func:`rc2acC`, :func:`rc2lar`.

    Reference: J.R. Deller, J.G. Proakis, J.H.L. Hansen, "Discrete-Time
       Processing of Speech Signals", Prentice Hall, Section 7.4.5.

    """
    assert numpy.isrealobj(k), 'Inverse sine parameters not defined for complex reflection coefficients.'
    if max(numpy.abs(k)) >= 1:
        raise ValueError('All reflection coefficients should have magnitude less than unity.')

    return (2/numpy.pi)*numpy.arcsin(k)

Convert reflection coefficients to inverse sine parameters .


def rc2lar(k):
    """Convert reflection coefficients to log area ratios.

    :param k: reflection coefficients
    :return: inverse sine parameters

    The log area ratio is defined by G = log((1+k)/(1-k)) , where the K
    parameter is the reflection coefficient.

    .. seealso:: :func:`lar2rc`, :func:`rc2poly`, :func:`rc2ac`, :func:`rc2ic`.

    :References:
       [1] J. Makhoul, "Linear Prediction: A Tutorial Review," Proc. IEEE, Vol.63, No.4, pp.561-580, Apr 1975.

    """
    assert numpy.isrealobj(k), 'Log area ratios not defined for complex reflection coefficients.'
    if max(numpy.abs(k)) >= 1:
        raise ValueError('All reflection coefficients should have magnitude less than unity.')

    # Use the relation, atanh(x) = (1/2)*log((1+k)/(1-k))
    return -2 * numpy.arctanh(-numpy.array(k))

Convert reflection coefficients to log area ratios .


def lar2rc(g):
    """Convert log area ratios to reflection coefficients.

    :param g:  log area ratios
    :returns: the reflection coefficients

    .. seealso: :func:`rc2lar`, :func:`poly2rc`, :func:`ac2rc`, :func:`is2rc`.

    :References:
       [1] J. Makhoul, "Linear Prediction: A Tutorial Review," Proc. IEEE,  Vol.63, No.4, pp.561-580, Apr 1975.

    """
    assert numpy.isrealobj(g), 'Log area ratios not defined for complex reflection coefficients.'
    # Use the relation, tanh(x) = (1-exp(2x))/(1+exp(2x))
    return -numpy.tanh(-numpy.array(g)/2)

Convert log area ratios to reflection coefficients .


def lsf2poly(lsf):
    """Convert line spectral frequencies to prediction filter coefficients

    returns a vector a containing the prediction filter coefficients from a vector lsf of line spectral frequencies.

    .. doctest::

        >>> from spectrum import lsf2poly
        >>> lsf = [0.7842 ,   1.5605  ,  1.8776 ,   1.8984,    2.3593]
        >>> a = lsf2poly(lsf)

    # array([  1.00000000e+00,   6.14837835e-01,   9.89884967e-01,
    # 9.31594056e-05,   3.13713832e-03,  -8.12002261e-03 ])

    .. seealso:: poly2lsf, rc2poly, ac2poly, rc2is
    """
    #   Reference: A.M. Kondoz, "Digital Speech: Coding for Low Bit Rate Communications
    #   Systems" John Wiley & Sons 1994 ,Chapter 4

    # Line spectral frequencies must be real.

    lsf = numpy.array(lsf)

    if max(lsf) > numpy.pi or min(lsf) < 0:
        raise ValueError('Line spectral frequencies must be between 0 and pi.')

    p = len(lsf) # model order

    # Form zeros using the LSFs and unit amplitudes
    z  = numpy.exp(1.j * lsf)

    # Separate the zeros to those belonging to P and Q
    rQ = z[0::2]
    rP = z[1::2]

    # Include the conjugates as well
    rQ = numpy.concatenate((rQ, rQ.conjugate()))
    rP = numpy.concatenate((rP, rP.conjugate()))

    # Form the polynomials P and Q, note that these should be real
    Q  = numpy.poly(rQ);
    P  = numpy.poly(rP);

    # Form the sum and difference filters by including known roots at z = 1 and
    # z = -1

    if p%2:
        # Odd order: z = +1 and z = -1 are roots of the difference filter, P1(z)
        P1 = numpy.convolve(P, [1, 0, -1])
        Q1 = Q
    else:
        # Even order: z = -1 is a root of the sum filter, Q1(z) and z = 1 is a
        # root of the difference filter, P1(z)
        P1 = numpy.convolve(P, [1, -1])
        Q1 = numpy.convolve(Q, [1,  1])

    # Prediction polynomial is formed by averaging P1 and Q1

    a = .5 * (P1+Q1)
    return a[0:-1:1]


def poly2lsf(a):
    """Prediction polynomial to line spectral frequencies.

    converts the prediction polynomial specified by A,
    into the corresponding line spectral frequencies, LSF.
    normalizes the prediction polynomial by A(1).

    .. doctest::

        >>> from spectrum import poly2lsf
        >>> a = [1.0000,  0.6149, 0.9899, 0.0000 ,0.0031, -0.0082]
        >>> lsf = poly2lsf(a)
        >>> lsf =  array([0.7842, 1.5605, 1.8776, 1.8984, 2.3593])

    .. seealso:: lsf2poly, poly2rc, poly2qc, rc2is
    """

    #Line spectral frequencies are not defined for complex polynomials.

    # Normalize the polynomial

    a = numpy.array(a)
    if a[0] != 1:
        a/=a[0]

    if max(numpy.abs(numpy.roots(a))) >= 1.0:
        error('The polynomial must have all roots inside of the unit circle.');

    # Form the sum and differnce filters

    p  = len(a)-1   # The leading one in the polynomial is not used
    a1 = numpy.concatenate((a, numpy.array([0])))
    a2 = a1[-1::-1]
    P1 = a1 - a2        # Difference filter
    Q1 = a1 + a2        # Sum Filter

    # If order is even, remove the known root at z = 1 for P1 and z = -1 for Q1
    # If odd, remove both the roots from P1

    if p%2: # Odd order
        P, r = deconvolve(P1,[1, 0 ,-1])
        Q = Q1
    else:          # Even order
        P, r = deconvolve(P1, [1, -1])
        Q, r = deconvolve(Q1, [1,  1])

    rP  = numpy.roots(P)
    rQ  = numpy.roots(Q)

    aP  = numpy.angle(rP[1::2])
    aQ  = numpy.angle(rQ[1::2])

    lsf = sorted(numpy.concatenate((-aP,-aQ)))

    return lsf

Prediction polynomial to line spectral frequencies .


def _swapsides(data):
    """todo is it really useful ?

    Swap  sides

    .. doctest::

        >>> from spectrum import swapsides
        >>> x = [-2, -1, 1, 2]
        >>> swapsides(x)
        array([ 2, -2, -1])

    """
    N = len(data)
    return np.concatenate((data[N//2+1:], data[0:N//2]))

def _swapsides ( data ) : N = len ( data ) return np . concatenate ( ( data [ N // 2 + 1 : ] , data [ 0 : N // 2 ] ) )


def twosided_2_onesided(data):
    """Convert a one-sided PSD to a twosided PSD

    In order to keep the power in the onesided PSD the same
    as in the twosided version, the onesided values are twice
    as much as in the input data (except for the zero-lag value).

    ::

        >>> twosided_2_onesided([10, 2,3,3,2,8])
        array([ 10.,   4.,   6.,   8.])

    """
    assert len(data) % 2 == 0
    N = len(data)
    psd = np.array(data[0:N//2+1]) * 2.
    psd[0] /= 2.
    psd[-1] = data[-1]
    return psd

def twosided_2_onesided ( data ) : assert len ( data ) % 2 == 0 N = len ( data ) psd = np . array ( data [ 0 : N // 2 + 1 ] ) * 2. psd [ 0 ] /= 2. psd [ - 1 ] = data [ - 1 ] return psd

Convert a one - sided PSD to a twosided PSD


def onesided_2_twosided(data):
    """Convert a two-sided PSD to a one-sided PSD

    In order to keep the power in the twosided PSD the same
    as in the onesided version, the twosided values are 2 times
    lower than the input data (except for the zero-lag and N-lag
    values).

    ::

        >>> twosided_2_onesided([10, 4, 6, 8])
        array([ 10.,   2.,   3.,   3., 2., 8.])

    """
    psd = np.concatenate((data[0:-1], cshift(data[-1:0:-1], -1)))/2.
    psd[0] *= 2.
    psd[-1] *= 2.
    return psd

def onesided_2_twosided ( data ) : psd = np . concatenate ( ( data [ 0 : - 1 ] , cshift ( data [ - 1 : 0 : - 1 ] , - 1 ) ) ) / 2. psd [ 0 ] *= 2. psd [ - 1 ] *= 2. return psd

Convert a two - sided PSD to a one - sided PSD


def twosided_2_centerdc(data):
    """Convert a two-sided PSD to a center-dc PSD"""
    N = len(data)
    # could us int() or // in python 3
    newpsd = np.concatenate((cshift(data[N//2:], 1), data[0:N//2]))
    newpsd[0] = data[-1]
    return newpsd

def
twosided_2_centerdc
(
data
)
:
N
=
len
(
data
)
# could us int() or // in python 3
newpsd
=
np
.
concatenate
(
(
cshift
(
data
[
N
//
2
:
]
,
1
)
,
data
[
0
:
N
//
2
]
)
)
newpsd
[
0
]
=
data
[
1
]
return
newpsd

Convert a two - sided PSD to a center - dc PSD


def centerdc_2_twosided(data):
    """Convert a center-dc PSD to a twosided PSD"""
    N = len(data)
    newpsd = np.concatenate((data[N//2:], (cshift(data[0:N//2], -1))))
    return newpsd

def centerdc_2_twosided ( data ) : N = len ( data ) newpsd = np . concatenate ( ( data [ N // 2 : ] , ( cshift ( data [ 0 : N // 2 ] , - 1 ) ) ) ) return newpsd

Convert a center - dc PSD to a twosided PSD


def _twosided_zerolag(data, zerolag):
    """Build a symmetric vector out of stricly positive lag vector and zero-lag

    .. doctest::

        >>> data = [3,2,1]
        >>> zerolag = 4
        >>> twosided_zerolag(data, zerolag)
        array([1, 2, 3, 4, 3, 2, 1])

    .. seealso:: Same behaviour as :func:`twosided_zerolag`
    """
    res = twosided(np.insert(data, 0, zerolag))
    return res

def _twosided_zerolag ( data , zerolag ) : res = twosided ( np . insert ( data , 0 , zerolag ) ) return res

Build a symmetric vector out of stricly positive lag vector and zero - lag


def data_cosine(N=1024, A=0.1, sampling=1024., freq=200):
    r"""Return a noisy cosine at a given frequency.

    :param N:           the final data size
    :param A:           the strength of the noise
    :param float sampling: sampling frequency of the input :attr:`data`.
    :param float freq:  the frequency :math:`f_0` of the cosine.

    .. math:: x[t] = cos(2\pi t * f_0) + A w[t]

    where w[t] is a white noise of variance 1.

    .. doctest::

        >>> from spectrum import data_cosine
        >>> a = data_cosine(N=1024, sampling=1024, A=0.5, freq=100)

    """
    t = arange(0, float(N)/sampling, 1./sampling)
    x = cos(2.*pi*t*freq) + A * randn(t.size)
    return x

def data_cosine ( N = 1024 , A = 0.1 , sampling = 1024. , freq = 200 ) : t = arange ( 0 , float ( N ) / sampling , 1. / sampling ) x = cos ( 2. * pi * t * freq ) + A * randn ( t . size ) return x

r Return a noisy cosine at a given frequency .


def data_two_freqs(N=200):
    """A simple test example with two close frequencies

    """
    nn = arange(N)
    xx = cos(0.257*pi*nn) + sin(0.2*pi*nn) + 0.01*randn(nn.size)
    return xx

def data_two_freqs ( N = 200 ) : nn = arange ( N ) xx = cos ( 0.257 * pi * nn ) + sin ( 0.2 * pi * nn ) + 0.01 * randn ( nn . size ) return xx


def spectrum_data(filename):
    """Simple utilities to retrieve data sets from """
    import os
    import pkg_resources
    info = pkg_resources.get_distribution('spectrum')
    location = info.location

    # first try develop mode
    share = os.sep.join([location, "spectrum", 'data'])
    filename2 = os.sep.join([share, filename])
    if os.path.exists(filename2):
        return filename2
    else:
        raise Exception('unknown file %s' % filename2)

def
spectrum_data
(
filename
)
:
import
os
import
pkg_resources
info
=
pkg_resources
.
get_distribution
(
'spectrum'
)
location
=
info
.
location
# first try develop mode
share
=
os
.
sep
.
join
(
[
location
,
"spectrum"
,
'data'
]
)
filename2
=
os
.
sep
.
join
(
[
share
,
filename
]
)
if
os
.
path
.
exists
(
filename2
)
:
return
filename2
else
:
raise
Exception
(
'unknown file %s'
%
filename2
)


def plot(self, **kargs):
        """Plot the data set, using the sampling information to set the x-axis
        correctly."""
        from pylab import plot, linspace, xlabel, ylabel, grid
        time = linspace(1*self.dt, self.N*self.dt, self.N)
        plot(time, self.data, **kargs)
        xlabel('Time')
        ylabel('Amplitude')
        grid(True)

def plot ( self , * * kargs ) : from pylab import plot , linspace , xlabel , ylabel , grid time = linspace ( 1 * self . dt , self . N * self . dt , self . N ) plot ( time , self . data , * * kargs ) xlabel ( 'Time' ) ylabel ( 'Amplitude' ) grid ( True )

Plot the data set using the sampling information to set the x - axis correctly .


def readwav(filename):
    """Read a WAV file and returns the data and sample rate

    ::

        from spectrum.io import readwav
        readwav()

    """
    from scipy.io.wavfile import read as readwav
    samplerate, signal = readwav(filename)
    return signal, samplerate

def readwav ( filename ) : from scipy . io . wavfile import read as readwav samplerate , signal = readwav ( filename ) return signal , samplerate


def _autocov(s, **kwargs):
    """Returns the autocovariance of signal s at all lags.

    Adheres to the definition
    sxx[k] = E{S[n]S[n+k]} = cov{S[n],S[n+k]}
    where E{} is the expectation operator, and S is a zero mean process
    """
    # only remove the mean once, if needed
    debias = kwargs.pop('debias', True)
    axis = kwargs.get('axis', -1)
    if debias:
        s = _remove_bias(s, axis)
    kwargs['debias'] = False
    return _crosscov(s, s, **kwargs)

def
_autocov
(
s
,
*
*
kwargs
)
:
# only remove the mean once, if needed
debias
=
kwargs
.
pop
(
'debias'
,
True
)
axis
=
kwargs
.
get
(
'axis'
,
1
)
if
debias
:
s
=
_remove_bias
(
s
,
axis
)
kwargs
[
'debias'
]
=
False
return
_crosscov
(
s
,
s
,
*
*
kwargs
)

Returns the autocovariance of signal s at all lags .


def _remove_bias(x, axis):
    "Subtracts an estimate of the mean from signal x at axis"
    padded_slice = [slice(d) for d in x.shape]
    padded_slice[axis] = np.newaxis
    mn = np.mean(x, axis=axis)
    return x - mn[tuple(padded_slice)]

def _remove_bias ( x , axis ) : padded_slice = [ slice ( d ) for d in x . shape ] padded_slice [ axis ] = np . newaxis mn = np . mean ( x , axis = axis ) return x - mn [ tuple ( padded_slice ) ]


def get_docstring_and_rest(filename):
    """Separate `filename` content between docstring and the rest

    Strongly inspired from ast.get_docstring.

    Returns
    -------
    docstring: str
        docstring of `filename`
    rest: str
        `filename` content without the docstring
    """
    with open(filename) as f:
        content = f.read()

    node = ast.parse(content)
    if not isinstance(node, ast.Module):
        raise TypeError("This function only supports modules. "
                        "You provided {0}".format(node.__class__.__name__))
    if node.body and isinstance(node.body[0], ast.Expr) and \
       isinstance(node.body[0].value, ast.Str):
        docstring_node = node.body[0]
        docstring = docstring_node.value.s
        # This get the content of the file after the docstring last line
        # Note: 'maxsplit' argument is not a keyword argument in python2
        rest = content.split('\n', docstring_node.lineno)[-1]
        return docstring, rest
    else:
        raise ValueError(('Could not find docstring in file "{0}". '
                          'A docstring is required by sphinx-gallery')
                         .format(filename))

Separate filename content between docstring and the rest


def split_code_and_text_blocks(source_file):
    """Return list with source file separated into code and text blocks.

    Returns
    -------
    blocks : list of (label, content)
        List where each element is a tuple with the label ('text' or 'code'),
        and content string of block.
    """
    docstring, rest_of_content = get_docstring_and_rest(source_file)

    blocks = [('text', docstring)]

    pattern = re.compile(
        r'(?P<header_line>^#{20,}.*)\s(?P<text_content>(?:^#.*\s)*)',
        flags=re.M)

    pos_so_far = 0
    for match in re.finditer(pattern, rest_of_content):
        match_start_pos, match_end_pos = match.span()
        code_block_content = rest_of_content[pos_so_far:match_start_pos]
        text_content = match.group('text_content')
        sub_pat = re.compile('^#', flags=re.M)
        text_block_content = dedent(re.sub(sub_pat, '', text_content))
        if code_block_content.strip():
            blocks.append(('code', code_block_content))
        if text_block_content.strip():
            blocks.append(('text', text_block_content))
        pos_so_far = match_end_pos

    remaining_content = rest_of_content[pos_so_far:]
    if remaining_content.strip():
        blocks.append(('code', remaining_content))

    return blocks

Return list with source file separated into code and text blocks .


def codestr2rst(codestr, lang='python'):
    """Return reStructuredText code block from code string"""
    code_directive = "\n.. code-block:: {0}\n\n".format(lang)
    indented_block = indent(codestr, ' ' * 4)
    return code_directive + indented_block

def
codestr2rst
(
codestr
,
lang
=
'python'
)
:
code_directive
=
"\n.. code-block:: {0}\n\n"
.
format
(
lang
)
indented_block
=
indent
(
codestr
,
' '
*
4
)
return
code_directive
+
indented_block


def get_md5sum(src_file):
    """Returns md5sum of file"""

    with open(src_file, 'r') as src_data:
        src_content = src_data.read()

        # data needs to be encoded in python3 before hashing
        if sys.version_info[0] == 3:
            src_content = src_content.encode('utf-8')

        src_md5 = hashlib.md5(src_content).hexdigest()
    return src_md5


def check_md5sum_change(src_file):
    """Returns True if src_file has a different md5sum"""

    src_md5 = get_md5sum(src_file)

    src_md5_file = src_file + '.md5'
    src_file_changed = True
    if os.path.exists(src_md5_file):
        with open(src_md5_file, 'r') as file_checksum:
            ref_md5 = file_checksum.read()
        if src_md5 == ref_md5:
            src_file_changed = False

    if src_file_changed:
        with open(src_md5_file, 'w') as file_checksum:
            file_checksum.write(src_md5)

    return src_file_changed

def check_md5sum_change ( src_file ) : src_md5 = get_md5sum ( src_file ) src_md5_file = src_file + '.md5' src_file_changed = True if os . path . exists ( src_md5_file ) : with open ( src_md5_file , 'r' ) as file_checksum : ref_md5 = file_checksum . read ( ) if src_md5 == ref_md5 : src_file_changed = False if src_file_changed : with open ( src_md5_file , 'w' ) as file_checksum : file_checksum . write ( src_md5 ) return src_file_changed


def _plots_are_current(src_file, image_file):
    """Test existence of image file and no change in md5sum of
    example"""

    first_image_file = image_file.format(1)
    has_image = os.path.exists(first_image_file)
    src_file_changed = check_md5sum_change(src_file)

    return has_image and not src_file_changed


def save_figures(image_path, fig_count, gallery_conf):
    """Save all open matplotlib figures of the example code-block

    Parameters
    ----------
    image_path : str
        Path where plots are saved (format string which accepts figure number)
    fig_count : int
        Previous figure number count. Figure number add from this number

    Returns
    -------
    list of strings containing the full path to each figure
    """
    figure_list = []

    fig_managers = matplotlib._pylab_helpers.Gcf.get_all_fig_managers()
    for fig_mngr in fig_managers:
        # Set the fig_num figure as the current figure as we can't
        # save a figure that's not the current figure.
        fig = plt.figure(fig_mngr.num)
        kwargs = {}
        to_rgba = matplotlib.colors.colorConverter.to_rgba
        for attr in ['facecolor', 'edgecolor']:
            fig_attr = getattr(fig, 'get_' + attr)()
            default_attr = matplotlib.rcParams['figure.' + attr]
            if to_rgba(fig_attr) != to_rgba(default_attr):
                kwargs[attr] = fig_attr

        current_fig = image_path.format(fig_count + fig_mngr.num)
        fig.savefig(current_fig, **kwargs)
        figure_list.append(current_fig)

    if gallery_conf.get('find_mayavi_figures', False):
        from mayavi import mlab
        e = mlab.get_engine()
        last_matplotlib_fig_num = len(figure_list)
        total_fig_num = last_matplotlib_fig_num + len(e.scenes)
        mayavi_fig_nums = range(last_matplotlib_fig_num, total_fig_num)

        for scene, mayavi_fig_num in zip(e.scenes, mayavi_fig_nums):
            current_fig = image_path.format(mayavi_fig_num)
            mlab.savefig(current_fig, figure=scene)
            # make sure the image is not too large
            scale_image(current_fig, current_fig, 850, 999)
            figure_list.append(current_fig)
        mlab.close(all=True)

    return figure_list

Save all open matplotlib figures of the example code - block


def scale_image(in_fname, out_fname, max_width, max_height):
    """Scales an image with the same aspect ratio centered in an
       image with a given max_width and max_height
       if in_fname == out_fname the image can only be scaled down
    """
    # local import to avoid testing dependency on PIL:
    try:
        from PIL import Image
    except ImportError:
        import Image
    img = Image.open(in_fname)
    width_in, height_in = img.size
    scale_w = max_width / float(width_in)
    scale_h = max_height / float(height_in)

    if height_in * scale_w <= max_height:
        scale = scale_w
    else:
        scale = scale_h

    if scale >= 1.0 and in_fname == out_fname:
        return

    width_sc = int(round(scale * width_in))
    height_sc = int(round(scale * height_in))

    # resize the image
    img.thumbnail((width_sc, height_sc), Image.ANTIALIAS)

    # insert centered
    thumb = Image.new('RGB', (max_width, max_height), (255, 255, 255))
    pos_insert = ((max_width - width_sc) // 2, (max_height - height_sc) // 2)
    thumb.paste(img, pos_insert)

    thumb.save(out_fname)
    # Use optipng to perform lossless compression on the resized image if
    # software is installed
    if os.environ.get('SKLEARN_DOC_OPTIPNG', False):
        try:
            subprocess.call(["optipng", "-quiet", "-o", "9", out_fname])
        except Exception:
            warnings.warn('Install optipng to reduce the size of the \
                          generated images')


def save_thumbnail(image_path, base_image_name, gallery_conf):
    """Save the thumbnail image"""
    first_image_file = image_path.format(1)
    thumb_dir = os.path.join(os.path.dirname(first_image_file), 'thumb')
    if not os.path.exists(thumb_dir):
        os.makedirs(thumb_dir)

    thumb_file = os.path.join(thumb_dir,
                              'sphx_glr_%s_thumb.png' % base_image_name)

    if os.path.exists(first_image_file):
        scale_image(first_image_file, thumb_file, 400, 280)
    elif not os.path.exists(thumb_file):
        # create something to replace the thumbnail
        default_thumb_file = os.path.join(glr_path_static(), 'no_image.png')
        default_thumb_file = gallery_conf.get("default_thumb_file",
                                              default_thumb_file)
        scale_image(default_thumb_file, thumb_file, 200, 140)


def execute_script(code_block, example_globals, image_path, fig_count,
                   src_file, gallery_conf):
    """Executes the code block of the example file"""
    time_elapsed = 0
    stdout = ''

    # We need to execute the code
    print('plotting code blocks in %s' % src_file)

    plt.close('all')
    cwd = os.getcwd()
    # Redirect output to stdout and
    orig_stdout = sys.stdout

    try:
        # First cd in the original example dir, so that any file
        # created by the example get created in this directory
        os.chdir(os.path.dirname(src_file))
        my_buffer = StringIO()
        my_stdout = Tee(sys.stdout, my_buffer)
        sys.stdout = my_stdout

        t_start = time()
        exec(code_block, example_globals)
        time_elapsed = time() - t_start

        sys.stdout = orig_stdout

        my_stdout = my_buffer.getvalue().strip().expandtabs()
        if my_stdout:
            stdout = CODE_OUTPUT.format(indent(my_stdout, ' ' * 4))
        os.chdir(cwd)
        figure_list = save_figures(image_path, fig_count, gallery_conf)

        # Depending on whether we have one or more figures, we're using a
        # horizontal list or a single rst call to 'image'.
        image_list = ""
        if len(figure_list) == 1:
            figure_name = figure_list[0]
            image_list = SINGLE_IMAGE % figure_name.lstrip('/')
        elif len(figure_list) > 1:
            image_list = HLIST_HEADER
            for figure_name in figure_list:
                image_list += HLIST_IMAGE_TEMPLATE % figure_name.lstrip('/')

    except Exception:
        formatted_exception = traceback.format_exc()

        print(80 * '_')
        print('%s is not compiling:' % src_file)
        print(formatted_exception)
        print(80 * '_')

        figure_list = []
        image_list = codestr2rst(formatted_exception, lang='pytb')

        # Overrides the output thumbnail in the gallery for easy identification
        broken_img = os.path.join(glr_path_static(), 'broken_example.png')
        shutil.copyfile(broken_img, os.path.join(cwd, image_path.format(1)))
        fig_count += 1  # raise count to avoid overwriting image

        # Breaks build on first example error

        if gallery_conf['abort_on_example_error']:
            raise

    finally:
        os.chdir(cwd)
        sys.stdout = orig_stdout

    print(" - time elapsed : %.2g sec" % time_elapsed)
    code_output = "\n{0}\n\n{1}\n\n".format(image_list, stdout)

    return code_output, time_elapsed, fig_count + len(figure_list)


def _arburg2(X, order):
    """This version is 10 times faster than arburg, but the output rho is not correct.

    returns [1 a0,a1, an-1]

    """
    x = np.array(X)
    N = len(x)

    if order <= 0.:
        raise ValueError("order must be > 0")

    # Initialisation
    # ------ rho, den
    rho = sum(abs(x)**2.) / N  # Eq 8.21 [Marple]_
    den = rho * 2. * N

    # ------ backward and forward errors
    ef = np.zeros(N, dtype=complex)
    eb = np.zeros(N, dtype=complex)
    for j in range(0, N):  #eq 8.11
        ef[j] = x[j]
        eb[j] = x[j]

    # AR order to be stored
    a = np.zeros(1, dtype=complex)
    a[0] = 1
    # ---- rflection coeff to be stored
    ref = np.zeros(order, dtype=complex)

    temp = 1.
    E = np.zeros(order+1)
    E[0] = rho

    for m in range(0, order):
        #print m
        # Calculate the next order reflection (parcor) coefficient
        efp = ef[1:]
        ebp = eb[0:-1]
        #print efp, ebp
        num = -2.* np.dot(ebp.conj().transpose(),  efp)
        den = np.dot(efp.conj().transpose(),  efp)
        den += np.dot(ebp,  ebp.conj().transpose())
        ref[m] = num / den

        # Update the forward and backward prediction errors
        ef = efp + ref[m] * ebp
        eb = ebp + ref[m].conj().transpose() * efp

        # Update the AR coeff.
        a.resize(len(a)+1)
        a = a + ref[m] * np.flipud(a).conjugate()

        # Update the prediction error
        E[m+1] = (1 - ref[m].conj().transpose()*ref[m]) * E[m]
        #print 'REF', ref, num, den
    return a, E[-1], ref

This version is 10 times faster than arburg but the output rho is not correct .


def _numpy_cholesky(A, B):
    """Solve Ax=B using numpy cholesky solver

    A = LU

    in the case where A is square and Hermitian, A = L.L* where L* is
    transpoed and conjugate matrix

    Ly = b

    where

    Ux=y

    so x = U^{-1} y
    where U = L*
    and y = L^{-1} B
    """
    L = numpy.linalg.cholesky(A)
    # A=L*numpy.transpose(L).conjugate()
    # Ly = b
    y = numpy.linalg.solve(L,B)
    # Ux = y
    x = numpy.linalg.solve(L.transpose().conjugate(),y)
    return x, L

def
_numpy_cholesky
(
A
,
B
)
:
L
=
numpy
.
linalg
.
cholesky
(
A
)
# A=L*numpy.transpose(L).conjugate()
# Ly = b
y
=
numpy
.
linalg
.
solve
(
L
,
B
)
# Ux = y
x
=
numpy
.
linalg
.
solve
(
L
.
transpose
(
)
.
conjugate
(
)
,
y
)
return
x
,
L

Solve Ax = B using numpy cholesky solver


def _numpy_solver(A, B):
    """This function solve Ax=B directly without taking care of the input
    matrix properties.
    """
    x = numpy.linalg.solve(A, B)
    return x

def _numpy_solver ( A , B ) : x = numpy . linalg . solve ( A , B ) return x

This function solve Ax = B directly without taking care of the input matrix properties .


def CHOLESKY(A, B, method='scipy'):
    """Solve linear system `AX=B` using CHOLESKY method.

    :param A: an input Hermitian matrix
    :param B: an array
    :param str method: a choice of method in [numpy, scipy, numpy_solver]

        * `numpy_solver` relies entirely on numpy.solver (no cholesky decomposition)
        * `numpy` relies on the numpy.linalg.cholesky for the decomposition and
          numpy.linalg.solve for the inversion.
        * `scipy` uses scipy.linalg.cholesky for the decomposition and
          scipy.linalg.cho_solve for the inversion.

    .. rubric:: Description

    When a matrix is square and Hermitian (symmetric with lower part being
    the complex conjugate of the upper one), then the usual triangular
    factorization takes on the special form:

    .. math:: A = R R^H

    where :math:`R` is a lower triangular matrix with nonzero real principal
    diagonal element. The input matrix can be made of complex data. Then, the
    inversion to find :math:`x` is made as follows:

    .. math::  Ry = B

    and

    .. math::   Rx = y

    .. doctest::

        >>> import numpy
        >>> from spectrum import CHOLESKY
        >>> A = numpy.array([[ 2.0+0.j ,  0.5-0.5j, -0.2+0.1j],
        ...    [ 0.5+0.5j,  1.0+0.j ,  0.3-0.2j],
        ...    [-0.2-0.1j,  0.3+0.2j,  0.5+0.j ]])
        >>> B = numpy.array([ 1.0+3.j ,  2.0-1.j ,  0.5+0.8j])
        >>> CHOLESKY(A, B)
        array([ 0.95945946+5.25675676j,  4.41891892-7.04054054j,
               -5.13513514+6.35135135j])

    """
    if method == 'numpy_solver':
        X = _numpy_solver(A,B)
        return X
    elif method == 'numpy':
        X, _L = _numpy_cholesky(A, B)
        return X
    elif method == 'scipy':
        import scipy.linalg
        L = scipy.linalg.cholesky(A)
        X = scipy.linalg.cho_solve((L, False), B)
    else:
        raise ValueError('method must be numpy_solver, numpy_cholesky or cholesky_inplace')
    return X

Solve linear system AX = B using CHOLESKY method .


def speriodogram(x, NFFT=None, detrend=True, sampling=1.,
                   scale_by_freq=True, window='hamming', axis=0):
    """Simple periodogram, but matrices accepted.

    :param x: an array or matrix of data samples.
    :param NFFT: length of the data before FFT is computed (zero padding)
    :param bool detrend: detrend the data before co,puteing the FFT
    :param float sampling: sampling frequency of the input :attr:`data`.

    :param scale_by_freq:
    :param str window:

    :return: 2-sided PSD if complex data, 1-sided if real.

    if a matrix is provided (using numpy.matrix), then a periodogram
    is computed for each row. The returned matrix has the same shape as the input
    matrix.

    The mean of the input data is also removed from the data before computing
    the psd.

    .. plot::
        :width: 80%
        :include-source:

        from pylab import grid, semilogy
        from spectrum import data_cosine, speriodogram
        data = data_cosine(N=1024, A=0.1, sampling=1024, freq=200)
        semilogy(speriodogram(data, detrend=False, sampling=1024), marker='o')
        grid(True)

    .. plot::
        :width: 80%
        :include-source:

        import numpy
        from spectrum import speriodogram, data_cosine
        from pylab import figure, semilogy, figure ,imshow
        # create N data sets and make the frequency dependent on the time
        N = 100
        m = numpy.concatenate([data_cosine(N=1024, A=0.1, sampling=1024, freq=x)
            for x in range(1, N)]);
        m.resize(N, 1024)
        res = speriodogram(m)
        figure(1)
        semilogy(res)
        figure(2)
        imshow(res.transpose(), aspect='auto')

    .. todo:: a proper spectrogram class/function that takes care of normalisation
    """
    x = np.array(x)
    # array with 1 dimension case
    if x.ndim == 1:
        axis = 0
        r = x.shape[0]
        w = Window(r, window)   #same size as input data
        w = w.data
    # matrix case
    elif x.ndim == 2:
        logging.debug('2D array. each row is a 1D array')
        [r, c] = x.shape
        w = np.array([Window(r, window).data for this in range(c)]).reshape(r,c)

    if NFFT is None:
        NFFT = len(x)

    isreal = np.isrealobj(x)

    if detrend == True:
        m = np.mean(x, axis=axis)
    else:
        m = 0

    if isreal == True:
        if x.ndim == 2:
            res =  (abs (rfft (x*w - m, NFFT, axis=0))) ** 2. / r
        else:
            res =  (abs (rfft (x*w - m, NFFT, axis=-1))) ** 2. / r
    else:
        if x.ndim == 2:
            res =  (abs (fft (x*w - m, NFFT, axis=0))) ** 2. / r
        else:
            res =  (abs (fft (x*w - m, NFFT, axis=-1))) ** 2. / r

    if scale_by_freq is True:
        df = sampling / float(NFFT)
        res*= 2 * np.pi / df

    if x.ndim == 1:
        return res.transpose()
    else:
        return res

def
speriodogram
(
x
,
NFFT
=
,
detrend
=
True
,
sampling
=
1.
,
scale_by_freq
=
True
,
window
=
'hamming'
,
axis
=
0
)
:
x
=
np
.
array
(
x
)
# array with 1 dimension case
if
x
.
ndim
==
1
:
axis
=
0
r
=
x
.
shape
[
0
]
w
=
Window
(
r
,
window
)
#same size as input data
w
=
w
.
data
# matrix case
elif
x
.
ndim
==
2
:
logging
.
debug
(
'2D array. each row is a 1D array'
)
[
r
,
c
]
=
x
.
shape
w
=
np
.
array
(
[
Window
(
r
,
window
)
.
data
for
this
in
range
(
c
)
]
)
.
reshape
(
r
,
c
)
if
NFFT
is
:
NFFT
=
len
(
x
)
isreal
=
np
.
isrealobj
(
x
)
if
detrend
==
True
:
m
=
np
.
mean
(
x
,
axis
=
axis
)
else
:
m
=
0
if
isreal
==
True
:
if
x
.
ndim
==
2
:
res
=
(
abs
(
rfft
(
x
*
w
m
,
NFFT
,
axis
=
0
)
)
)
**
2.
/
r
else
:
res
=
(
abs
(
rfft
(
x
*
w
m
,
NFFT
,
axis
=
1
)
)
)
**
2.
/
r
else
:
if
x
.
ndim
==
2
:
res
=
(
abs
(
fft
(
x
*
w
m
,
NFFT
,
axis
=
0
)
)
)
**
2.
/
r
else
:
res
=
(
abs
(
fft
(
x
*
w
m
,
NFFT
,
axis
=
1
)
)
)
**
2.
/
r
if
scale_by_freq
is
True
:
df
=
sampling
/
float
(
NFFT
)
res
*=
2
*
np
.
pi
/
df
if
x
.
ndim
==
1
:
return
res
.
transpose
(
)
else
:
return
res

Simple periodogram but matrices accepted .


def WelchPeriodogram(data, NFFT=None,  sampling=1., **kargs):
    r"""Simple periodogram wrapper of numpy.psd function.

    :param A: the input data
    :param int NFFT: total length of the final data sets (padded
        with zero if needed; default is 4096)
    :param str window:

    :Technical documentation:

    When we calculate the periodogram of a set of data we get an estimation
    of the spectral density. In fact as we use a Fourier transform and a
    truncated segments the spectrum is the convolution of the data with a
    rectangular window which Fourier transform is

    .. math::

        W(s)= \frac{1}{N^2} \left[ \frac{\sin(\pi s)}{\sin(\pi s/N)} \right]^2

    Thus oscillations and sidelobes appears around the main frequency. One aim of t he tapering is to reduced this effects. We multiply data by a window whose  sidelobes are much smaller than the main lobe. Classical window is hanning window.  But other windows are available. However we must take into account this energy and divide the spectrum by energy of taper used. Thus periodogram becomes :

    .. math::

        D_k \equiv \sum_{j=0}^{N-1}c_jw_j \; e^{2\pi ijk/N}  \qquad k=0,...,N-1

    .. math::

        P(0)=P(f_0)=\frac{1}{2\pi W_{ss}}\arrowvert{D_0}\arrowvert^2

    .. math::

        P(f_k)=\frac{1}{2\pi W_{ss}} \left[\arrowvert{D_k}\arrowvert^2+\arrowvert{D_{N-k}}\arrowvert^2\right]        \qquad k=0,1,...,     \left( \frac{1}{2}-1 \right)

    .. math::

        P(f_c)=P(f_{N/2})= \frac{1}{2\pi W_{ss}} \arrowvert{D_{N/2}}\arrowvert^2

    with

    .. math::

        {W_{ss}} \equiv N\sum_{j=0}^{N-1}w_j^2

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import WelchPeriodogram, marple_data
        psd = WelchPeriodogram(marple_data, 256)

    """
    from pylab import psd
    spectrum = Spectrum(data, sampling=1.)

    P = psd(data, NFFT, Fs=sampling, **kargs)
    spectrum.psd = P[0]
    #spectrum.__Spectrum_sides = 'twosided'

    return P, spectrum

def
WelchPeriodogram
(
data
,
NFFT
=
,
sampling
=
1.
,
*
*
kargs
)
:
from
pylab
import
psd
spectrum
=
Spectrum
(
data
,
sampling
=
1.
)
P
=
psd
(
data
,
NFFT
,
Fs
=
sampling
,
*
*
kargs
)
spectrum
.
psd
=
P
[
0
]
#spectrum.__Spectrum_sides = 'twosided'
return
P
,
spectrum

r Simple periodogram wrapper of numpy . psd function .


def DaniellPeriodogram(data, P, NFFT=None, detrend='mean', sampling=1.,
                       scale_by_freq=True, window='hamming'):
    r"""Return Daniell's periodogram.

    To reduce fast fluctuations of the spectrum one idea proposed by daniell
    is to average each value with points in its neighboorhood. It's like
    a low filter.

    .. math:: \hat{P}_D[f_i]= \frac{1}{2P+1} \sum_{n=i-P}^{i+P} \tilde{P}_{xx}[f_n]

    where P is the number of points to average.

    Daniell's periodogram is the convolution of the spectrum with a low filter:

    .. math:: \hat{P}_D(f)=   \hat{P}_{xx}(f)*H(f)

    Example::

        >>> DaniellPeriodogram(data, 8)

    if N/P is not integer, the final values of the original PSD are not used.

    using DaniellPeriodogram(data, 0) should give the original PSD.

    """
    psd = speriodogram(data, NFFT=NFFT, detrend=detrend, sampling=sampling,
                   scale_by_freq=scale_by_freq, window=window)

    if len(psd) % 2 == 1:
        datatype = 'real'
    else:
        datatype = 'complex'

    N = len(psd)
    _slice = 2 * P + 1
    if datatype == 'real': #must get odd value
        newN = np.ceil(psd.size/float(_slice))
        if newN % 2 == 0:
            newN = psd.size/_slice
    else:
        newN = np.ceil(psd.size/float(_slice))
        if newN % 2 == 1:
            newN = psd.size/_slice

    newpsd = np.zeros(int(newN)) # keep integer division
    for i in range(0, newpsd.size):
        count = 0 #needed to know the number of valid averaged values
        for n in range(i*_slice-P, i*_slice+P+1): #+1 to have P values on each sides
            if n > 0 and n<N: #needed to start the average
                count += 1
                newpsd[i] += psd[n]
        newpsd[i] /= float(count)

    #todo: check this
    if datatype == 'complex':
        freq = np.linspace(0, sampling, len(newpsd))
    else:
        df = 1. / sampling
        freq = np.linspace(0,sampling/2., len(newpsd))
    #psd.refreq(2*psd.size()/A.freq());
    #psd.retime(-1./psd.freq()+1./A.size());

    return newpsd, freq


def centerdc_gen(self):
        """Return the centered frequency range as a generator.

        ::

            >>> print(list(Range(8).centerdc_gen()))
            [-0.5, -0.375, -0.25, -0.125, 0.0, 0.125, 0.25, 0.375]

        """
        for a in range(0, self.N):
            yield (a-self.N/2) * self.df

def centerdc_gen ( self ) : for a in range ( 0 , self . N ) : yield ( a - self . N / 2 ) * self . df

Return the centered frequency range as a generator .


def onesided_gen(self):
        """Return the one-sided frequency range as a generator.

        If :attr:`N` is even, the length is N/2 + 1.
        If :attr:`N` is odd, the length is (N+1)/2.

        ::

            >>> print(list(Range(8).onesided()))
            [0.0, 0.125, 0.25, 0.375, 0.5]
            >>> print(list(Range(9).onesided()))
            [0.0, 0.1111, 0.2222, 0.3333, 0.4444]

        """
        if self.N % 2 == 0:
            for n in range(0, self.N//2 + 1):
                yield n * self.df
        else:
            for n in range(0, (self.N+1)//2):
                yield n * self.df

def onesided_gen ( self ) : if self . N % 2 == 0 : for n in range ( 0 , self . N // 2 + 1 ) : yield n * self . df else : for n in range ( 0 , ( self . N + 1 ) // 2 ) : yield n * self . df

Return the one - sided frequency range as a generator .


def plot(self, filename=None, norm=False, ylim=None,
              sides=None,  **kargs):
        """a simple plotting routine to plot the PSD versus frequency.

        :param str filename: save the figure into a file
        :param norm: False by default. If True, the PSD is normalised.
        :param ylim: readjust the y range .
        :param sides: if not provided, :attr:`sides` is used. See :attr:`sides`
            for details.
        :param kargs: any optional argument accepted by :func:`pylab.plot`.

        .. plot::
            :width: 80%
            :include-source:

            from spectrum import *
            p = Periodogram(marple_data)
            p.plot(norm=True, marker='o')

        """
        import pylab
        from pylab import ylim as plt_ylim
        #First, check that psd attribute is up-to-date
        # just to get the PSD to be recomputed if needed
        _ = self.psd

        # check that the input sides parameter is correct if provided
        if sides is not None:
            if sides not in self._sides_choices:
                raise errors.SpectrumChoiceError(sides, self._sides_choices)

        # if sides is provided but identical to the current psd, nothing to do.
        # if sides not provided, let us use self.sides
        if sides is None or sides == self.sides:
            frequencies = self.frequencies()
            psd = self.psd
            sides = self.sides
        elif sides is not None:
            # if sides argument is different from the attribute, we need to
            # create a new PSD/Freq ; indeed we do not want to change the
            # attribute itself

            # if data is complex, one-sided is wrong in any case.
            if self.datatype == 'complex':
                if sides == 'onesided':
                    raise ValueError("sides cannot be one-sided with complex data")

            logging.debug("sides is different from the one provided. Converting PSD")
            frequencies = self.frequencies(sides=sides)
            psd = self.get_converted_psd(sides)

        if len(psd) != len(frequencies):
            raise ValueError("PSD length is %s and freq length is %s" % (len(psd), len(frequencies)))

        if 'ax' in list(kargs.keys()):
            save_ax = pylab.gca()
            pylab.sca(kargs['ax'])
            rollback = True
            del kargs['ax']
        else:
            rollback = False

        if norm:
            pylab.plot(frequencies, 10 * stools.log10(psd/max(psd)),  **kargs)
        else:
            pylab.plot(frequencies, 10 * stools.log10(psd),**kargs)

        pylab.xlabel('Frequency')
        pylab.ylabel('Power (dB)')
        pylab.grid(True)

        if ylim:
            plt_ylim(ylim)

        if sides == 'onesided':
            pylab.xlim(0, self.sampling/2.)
        elif sides == 'twosided':
            pylab.xlim(0, self.sampling)
        elif sides == 'centerdc':
            pylab.xlim(-self.sampling/2., self.sampling/2.)

        if filename:
            pylab.savefig(filename)

        if rollback:
            pylab.sca(save_ax)

        del psd, frequencies

a simple plotting routine to plot the PSD versus frequency .


def power(self):
        r"""Return the power contained in the PSD

        if scale_by_freq is False, the power is:

        .. math:: P = N \sum_{k=1}^{N} P_{xx}(k)

        else, it is

        .. math:: P =  \sum_{k=1}^{N} P_{xx}(k) \frac{df}{2\pi}

        .. todo:: check these equations

        """
        if self.scale_by_freq == False:
            return sum(self.psd) * len(self.psd)
        else:
            return sum(self.psd) * self.df/(2.*numpy.pi)

def power ( self ) : if self . scale_by_freq == False : return sum ( self . psd ) * len ( self . psd ) else : return sum ( self . psd ) * self . df / ( 2. * numpy . pi )


def ipy_notebook_skeleton():
    """Returns a dictionary with the elements of a Jupyter notebook"""
    py_version = sys.version_info
    notebook_skeleton = {
        "cells": [],
        "metadata": {
            "kernelspec": {
                "display_name": "Python " + str(py_version[0]),
                "language": "python",
                "name": "python" + str(py_version[0])
            },
            "language_info": {
                "codemirror_mode": {
                    "name": "ipython",
                    "version": py_version[0]
                },
                "file_extension": ".py",
                "mimetype": "text/x-python",
                "name": "python",
                "nbconvert_exporter": "python",
                "pygments_lexer": "ipython" + str(py_version[0]),
                "version": '{0}.{1}.{2}'.format(*sys.version_info[:3])
            }
        },
        "nbformat": 4,
        "nbformat_minor": 0
    }
    return notebook_skeleton

def
ipy_notebook_skeleton
(
)
:
py_version
=
sys
.
version_info
notebook_skeleton
=
{
"cells"
:
[
]
,
"metadata"
:
{
"kernelspec"
:
{
"display_name"
:
"Python "
+
str
(
py_version
[
0
]
)
,
"language"
:
"python"
,
"name"
:
"python"
+
str
(
py_version
[
0
]
)
}
,
"language_info"
:
{
"codemirror_mode"
:
{
"name"
:
"ipython"
,
"version"
:
py_version
[
0
]
}
,
"file_extension"
:
".py"
,
"mimetype"
:
"text/x-python"
,
"name"
:
"python"
,
"nbconvert_exporter"
:
"python"
,
"pygments_lexer"
:
"ipython"
+
str
(
py_version
[
0
]
)
,
"version"
:
'{0}.{1}.{2}'
.
format
(
*
sys
.
version_info
[
:
3
]
)
}
}
,
"nbformat"
:
4
,
"nbformat_minor"
:
0
}
return
notebook_skeleton


def rst2md(text):
    """Converts the RST text from the examples docstrigs and comments
    into markdown text for the IPython notebooks"""

    top_heading = re.compile(r'^=+$\s^([\w\s-]+)^=+$', flags=re.M)
    text = re.sub(top_heading, r'# \1', text)

    math_eq = re.compile(r'^\.\. math::((?:.+)?(?:\n+^  .+)*)', flags=re.M)
    text = re.sub(math_eq,
                  lambda match: r'$${0}$$'.format(match.group(1).strip()),
                  text)
    inline_math = re.compile(r':math:`(.+)`')
    text = re.sub(inline_math, r'$\1$', text)

    return text

def
rst2md
(
text
)
:
top_heading
=
re
.
compile
(
r'^=+$\s^([\w\s-]+)^=+$'
,
flags
=
re
.
M
)
text
=
re
.
sub
(
top_heading
,
r'# \1'
,
text
)
math_eq
=
re
.
compile
(
r'^\.\. math::((?:.+)?(?:\n+^  .+)*)'
,
flags
=
re
.
M
)
text
=
re
.
sub
(
math_eq
,
lambda
match
:
r'$${0}$$'
.
format
(
match
.
group
(
1
)
.
strip
(
)
)
,
text
)
inline_math
=
re
.
compile
(
r':math:`(.+)`'
)
text
=
re
.
sub
(
inline_math
,
r'$\1$'
,
text
)
return
text


def add_markdown_cell(self, text):
        """Add a markdown cell to the notebook

        Parameters
        ----------
        code : str
            Cell content
        """
        markdown_cell = {
            "cell_type": "markdown",
            "metadata": {},
            "source": [rst2md(text)]
        }
        self.work_notebook["cells"].append(markdown_cell)

def add_markdown_cell ( self , text ) : markdown_cell = { "cell_type" : "markdown" , "metadata" : { } , "source" : [ rst2md ( text ) ] } self . work_notebook [ "cells" ] . append ( markdown_cell )


def save_file(self):
        """Saves the notebook to a file"""
        with open(self.write_file, 'w') as out_nb:
            json.dump(self.work_notebook, out_nb, indent=2)

def save_file ( self ) : with open ( self . write_file , 'w' ) as out_nb : json . dump ( self . work_notebook , out_nb , indent = 2 )


def arma2psd(A=None, B=None, rho=1., T=1., NFFT=4096, sides='default',
        norm=False):
    r"""Computes power spectral density given ARMA values.

    This function computes the power spectral density values
    given the ARMA parameters of an ARMA model. It assumes that
    the driving sequence is a white noise process of zero mean and
    variance :math:`\rho_w`. The sampling frequency and noise variance are
    used to scale the PSD output, which length is set by the user with the
    `NFFT` parameter.

    :param array A:   Array of AR parameters (complex or real)
    :param array B:   Array of MA parameters (complex or real)
    :param float rho: White noise variance to scale the returned PSD
    :param float T:   Sample interval in seconds to scale the returned PSD
    :param int NFFT:  Final size of the PSD
    :param str sides: Default PSD is two-sided, but sides can be set to centerdc.

    .. warning:: By convention, the AR or MA arrays does not contain the
        A0=1 value.

    If :attr:`B` is None, the model is a pure AR model. If :attr:`A` is None,
    the model is a pure MA model.

    :return: two-sided PSD

    .. rubric:: Details:

    AR case: the power spectral density is:

    .. math:: P_{ARMA}(f) = T \rho_w \left|\frac{B(f)}{A(f)}\right|^2

    where:

    .. math:: A(f) = 1 + \sum_{k=1}^q b(k) e^{-j2\pi fkT}
    .. math:: B(f) = 1 + \sum_{k=1}^p a(k) e^{-j2\pi fkT}

    .. rubric:: **Example:**

    .. plot::
        :width: 80%
        :include-source:

        import spectrum.arma
        from pylab import plot, log10, legend
        plot(10*log10(spectrum.arma.arma2psd([1,0.5],[0.5,0.5])), label='ARMA(2,2)')
        plot(10*log10(spectrum.arma.arma2psd([1,0.5],None)), label='AR(2)')
        plot(10*log10(spectrum.arma.arma2psd(None,[0.5,0.5])), label='MA(2)')
        legend()

    :References: [Marple]_
    """
    if NFFT is None:
        NFFT = 4096

    if A is None and B is None:
        raise ValueError("Either AR or MA model must be provided")

    psd = np.zeros(NFFT, dtype=complex)

    if A is not None:
        ip = len(A)
        den = np.zeros(NFFT, dtype=complex)
        den[0] = 1.+0j
        for k in range(0, ip):
            den[k+1] = A[k]
        denf = fft(den, NFFT)

    if B is not None:
        iq = len(B)
        num = np.zeros(NFFT, dtype=complex)
        num[0] = 1.+0j
        for k in range(0, iq):
            num[k+1] = B[k]
        numf = fft(num, NFFT)

    # Changed in version 0.6.9 (divided by T instead of multiply)
    if A is not None and B is not None:
        psd = rho / T * abs(numf)**2. / abs(denf)**2.
    elif A is not None:
        psd = rho / T / abs(denf)**2.
    elif B is not None:
        psd = rho / T * abs(numf)**2.

    psd = np.real(psd)
    # The PSD is a twosided PSD.
    # to obtain the centerdc
    if sides != 'default':
        from . import tools
        assert sides in ['centerdc']
        if sides == 'centerdc':
            psd = tools.twosided_2_centerdc(psd)

    if norm == True:
        psd /= max(psd)

    return psd

r Computes power spectral density given ARMA values .


def arma_estimate(X, P, Q, lag):
    """Autoregressive and moving average estimators.

    This function provides an estimate of the autoregressive
    parameters, the moving average parameters, and the driving
    white noise variance of  an ARMA(P,Q) for a complex or real data sequence.

    The parameters are estimated using three steps:

        * Estimate the AR parameters from the original data based on a least
          squares modified Yule-Walker technique,
        * Produce a residual time sequence by filtering the original data
          with a filter based on the AR parameters,
        * Estimate the MA parameters from the residual time sequence.

    :param array X: Array of data samples (length N)
    :param int P: Desired number of AR parameters
    :param int Q: Desired number of MA parameters
    :param int lag: Maximum lag to use for autocorrelation estimates

    :return:
        * A     - Array of complex P AR parameter estimates
        * B     - Array of complex Q MA parameter estimates
        * RHO   - White noise variance estimate

    .. note::
      *  lag must be >= Q (MA order)

    **dependencies**:
        * :meth:`spectrum.correlation.CORRELATION`
        * :meth:`spectrum.covar.arcovar`
        * :meth:`spectrum.arma.ma`

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import arma_estimate, arma2psd, marple_data
        import pylab

        a,b, rho = arma_estimate(marple_data, 15, 15, 30)
        psd = arma2psd(A=a, B=b, rho=rho, sides='centerdc', norm=True)
        pylab.plot(10 * pylab.log10(psd))
        pylab.ylim([-50,0])

    :reference: [Marple]_
    """
    R = CORRELATION(X, maxlags=lag, norm='unbiased')
    R0 = R[0]
    #C   Estimate the AR parameters (no error weighting is used).
    #C   Number of equation errors is M-Q .
    MPQ = lag - Q + P

    N = len(X)
    Y = np.zeros(N-P, dtype=complex)

    for K in range(0, MPQ):
        KPQ = K + Q - P+1
        if KPQ < 0:
            Y[K] = R[-KPQ].conjugate()
        if KPQ == 0:
            Y[K] = R0
        if KPQ > 0:
            Y[K] = R[KPQ]

    # The resize is very important for the normalissation.
    Y.resize(lag)
    if P <= 4:
        res = arcovar_marple(Y.copy(), P)    #! Eq. (10.12)
        ar_params = res[0]
    else:
        res = arcovar(Y.copy(), P)    #! Eq. (10.12)
        ar_params = res[0]

    # the .copy is used to prevent a reference somewhere. this is a bug
    # to be tracked down.
    Y.resize(N-P)

    #C   Filter the original time series
    for k in range(P, N):
        SUM = X[k]
        #SUM += sum([ar_params[j]*X[k-j-1] for j in range(0,P)])
        for j in range(0, P):
            SUM = SUM + ar_params[j] * X[k-j-1]   #! Eq. (10.17)
        Y[k-P] = SUM

    #  Estimate the MA parameters (a "long" AR of order at least 2*IQ
    #C   is suggested)
    #Y.resize(N-P)
    ma_params, rho = ma(Y, Q, 2*Q)     #! Eq. (10.3)

    return ar_params, ma_params, rho

Autoregressive and moving average estimators .


def ma(X, Q, M):
    """Moving average estimator.

    This program provides an estimate of the moving average parameters
    and driving noise variance for a data sequence based on a
    long AR model and a least squares fit.

    :param array X: The input data array
    :param int Q: Desired MA model order (must be >0 and <M)
    :param int M: Order of "long" AR model (suggest at least 2*Q )

    :return:
        * MA    - Array of Q complex MA parameter estimates
        * RHO   - Real scalar of white noise variance estimate

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import arma2psd, ma, marple_data
        import pylab

        # Estimate 15 Ma parameters
        b, rho = ma(marple_data, 15, 30)
        # Create the PSD from those MA parameters
        psd = arma2psd(B=b, rho=rho, sides='centerdc')
        # and finally plot the PSD
        pylab.plot(pylab.linspace(-0.5, 0.5, 4096), 10 * pylab.log10(psd/max(psd)))
        pylab.axis([-0.5, 0.5, -30, 0])

    :reference: [Marple]_
    """
    if Q <= 0 or Q >= M:
        raise ValueError('Q(MA) must be in ]0,lag[')

    #C   Fit a high-order AR to the data
    a, rho, _c = yulewalker.aryule(X, M, 'biased')   #! Eq. (10.5)

    #add an element unity to the AR parameter array
    a = np.insert(a, 0, 1)

    #C   Find MA parameters from autocorrelations by Yule-Walker method
    ma_params, _p, _c = yulewalker.aryule(a, Q, 'biased')    #! Eq. (10.7)

    return ma_params, rho


def CORRELOGRAMPSD(X, Y=None, lag=-1, window='hamming',
                    norm='unbiased', NFFT=4096, window_params={},
                    correlation_method='xcorr'):
    """PSD estimate using correlogram method.

    :param array X: complex or real data samples X(1) to X(N)
    :param array Y: complex data samples Y(1) to Y(N). If provided, computes
        the cross PSD, otherwise the PSD is returned
    :param int lag: highest lag index to compute. Must be less than N
    :param str window_name: see :mod:`window` for list of valid names
    :param str norm: one of the valid normalisation of :func:`xcorr` (biased,
        unbiased, coeff, None)
    :param int NFFT: total length of the final data sets (padded with zero
        if needed; default is 4096)
    :param str correlation_method: either `xcorr` or `CORRELATION`.
        CORRELATION should be removed in the future.

    :return:
        * Array of real (cross) power spectral density estimate values. This is
          a two sided array with negative values following the positive ones
          whatever is the input data (real or complex).

    .. rubric:: Description:

    The exact power spectral density is the Fourier transform of the
    autocorrelation sequence:

    .. math:: P_{xx}(f) = T \sum_{m=-\infty}^{\infty} r_{xx}[m] exp^{-j2\pi fmT}

    The correlogram method of PSD estimation substitutes a finite sequence of
    autocorrelation estimates :math:`\hat{r}_{xx}` in place of :math:`r_{xx}`.
    This estimation can be computed with :func:`xcorr` or :func:`CORRELATION` by
    chosing a proprer lag `L`. The estimated PSD is then

    .. math:: \hat{P}_{xx}(f) = T \sum_{m=-L}^{L} \hat{r}_{xx}[m] exp^{-j2\pi fmT}

    The lag index must be less than the number of data samples `N`. Ideally, it
    should be around `L/10` [Marple]_ so as to avoid greater statistical
    variance associated with higher lags.

    To reduce the leakage of the implicit rectangular window and therefore to
    reduce the bias in the estimate, a tapering window is normally used and lead
    to the so-called Blackman and Tukey correlogram:

    .. math:: \hat{P}_{BT}(f) = T \sum_{m=-L}^{L} w[m] \hat{r}_{xx}[m] exp^{-j2\pi fmT}

    The correlogram for the cross power spectral estimate is

    .. math:: \hat{P}_{xx}(f) = T \sum_{m=-L}^{L} \hat{r}_{xx}[m] exp^{-j2\pi fmT}

    which is computed if :attr:`Y` is not provide. In such case,
    :math:`r_{yx} = r_{xy}` so we compute the correlation only once.

    .. plot::
        :width: 80%
        :include-source:

        from spectrum import CORRELOGRAMPSD, marple_data
        from spectrum.tools import cshift
        from pylab import log10, axis, grid, plot,linspace

        psd = CORRELOGRAMPSD(marple_data, marple_data, lag=15)
        f = linspace(-0.5, 0.5, len(psd))
        psd = cshift(psd, len(psd)/2)
        plot(f, 10*log10(psd/max(psd)))
        axis([-0.5,0.5,-50,0])
        grid(True)

    .. seealso:: :func:`create_window`, :func:`CORRELATION`, :func:`xcorr`,
        :class:`pcorrelogram`.
    """
    N = len(X)
    assert lag<N, 'lag must be < size of input data'
    assert correlation_method in ['CORRELATION', 'xcorr']
    if Y is None:
        Y = numpy.array(X)
        crosscorrelation = False
    else:
        crosscorrelation = True

    if NFFT is None:
        NFFT = N
    psd = numpy.zeros(NFFT, dtype=complex)

    # Window should be centered around zero. Moreover, we want only the
    # positive values. So, we need to use 2*lag + 1 window and keep values on
    # the right side.
    w = Window(2.*lag+1, window, **window_params)
    w = w.data[lag+1:]

    # compute the cross correlation
    if correlation_method == 'CORRELATION':
        rxy = CORRELATION (X, Y, maxlags=lag, norm=norm)
    elif correlation_method == 'xcorr':
        rxy, _l = xcorr (X, Y, maxlags=lag, norm=norm)
        rxy = rxy[lag:]

    # keep track of the first elt.
    psd[0] = rxy[0]

    # create the first part of the PSD
    psd[1:lag+1] = rxy[1:] * w

    # create the second part.
    # First, we need to compute the auto or cross correlation ryx
    if crosscorrelation is True:
        # compute the cross correlation
        if correlation_method == 'CORRELATION':
            ryx = CORRELATION(Y, X, maxlags=lag, norm=norm)
        elif correlation_method == 'xcorr':
            ryx, _l = xcorr(Y, X, maxlags=lag, norm=norm)
            ryx = ryx[lag:]
        #print len(ryx), len(psd[-1:NPSD-lag-1:-1])

        psd[-1:NFFT-lag-1:-1] = ryx[1:].conjugate() * w
    else: #autocorrelation no additional correlation call required
        psd[-1:NFFT-lag-1:-1] = rxy[1:].conjugate() * w

    psd = numpy.real(fft(psd))

    return psd


def _get_data(url):
    """Helper function to get data over http or from a local file"""
    if url.startswith('http://'):
        # Try Python 2, use Python 3 on exception
        try:
            resp = urllib.urlopen(url)
            encoding = resp.headers.dict.get('content-encoding', 'plain')
        except AttributeError:
            resp = urllib.request.urlopen(url)
            encoding = resp.headers.get('content-encoding', 'plain')
        data = resp.read()
        if encoding == 'plain':
            pass
        elif encoding == 'gzip':
            data = StringIO(data)
            data = gzip.GzipFile(fileobj=data).read()
        else:
            raise RuntimeError('unknown encoding')
    else:
        with open(url, 'r') as fid:
            data = fid.read()

    return data


def _select_block(str_in, start_tag, end_tag):
    """Select first block delimited by start_tag and end_tag"""
    start_pos = str_in.find(start_tag)
    if start_pos < 0:
        raise ValueError('start_tag not found')
    depth = 0
    for pos in range(start_pos, len(str_in)):
        if str_in[pos] == start_tag:
            depth += 1
        elif str_in[pos] == end_tag:
            depth -= 1

        if depth == 0:
            break
    sel = str_in[start_pos + 1:pos]
    return sel

def
_select_block
(
str_in
,
start_tag
,
end_tag
)
:
start_pos
=
str_in
.
find
(
start_tag
)
if
start_pos
<
0
:
raise
ValueError
(
'start_tag not found'
)
depth
=
0
for
pos
in
range
(
start_pos
,
len
(
str_in
)
)
:
if
str_in
[
pos
]
==
start_tag
:
depth
+=
1
elif
str_in
[
pos
]
==
end_tag
:
depth
-=
1
if
depth
==
0
:
break
sel
=
str_in
[
start_pos
+
1
:
pos
]
return
sel


def _parse_dict_recursive(dict_str):
    """Parse a dictionary from the search index"""
    dict_out = dict()
    pos_last = 0
    pos = dict_str.find(':')
    while pos >= 0:
        key = dict_str[pos_last:pos]
        if dict_str[pos + 1] == '[':
            # value is a list
            pos_tmp = dict_str.find(']', pos + 1)
            if pos_tmp < 0:
                raise RuntimeError('error when parsing dict')
            value = dict_str[pos + 2: pos_tmp].split(',')
            # try to convert elements to int
            for i in range(len(value)):
                try:
                    value[i] = int(value[i])
                except ValueError:
                    pass
        elif dict_str[pos + 1] == '{':
            # value is another dictionary
            subdict_str = _select_block(dict_str[pos:], '{', '}')
            value = _parse_dict_recursive(subdict_str)
            pos_tmp = pos + len(subdict_str)
        else:
            raise ValueError('error when parsing dict: unknown elem')

        key = key.strip('"')
        if len(key) > 0:
            dict_out[key] = value

        pos_last = dict_str.find(',', pos_tmp)
        if pos_last < 0:
            break
        pos_last += 1
        pos = dict_str.find(':', pos_last)

    return dict_out

def
_parse_dict_recursive
(
dict_str
)
:
dict_out
=
dict
(
)
pos_last
=
0
pos
=
dict_str
.
find
(
':'
)
while
pos
>=
0
:
key
=
dict_str
[
pos_last
:
pos
]
if
dict_str
[
pos
+
1
]
==
'['
:
# value is a list
pos_tmp
=
dict_str
.
find
(
']'
,
pos
+
1
)
if
pos_tmp
<
0
:
raise
RuntimeError
(
'error when parsing dict'
)
value
=
dict_str
[
pos
+
2
:
pos_tmp
]
.
split
(
','
)
# try to convert elements to int
for
i
in
range
(
len
(
value
)
)
:
try
:
value
[
i
]
=
int
(
value
[
i
]
)
except
ValueError
:
pass
elif
dict_str
[
pos
+
1
]
==
'{'
:
# value is another dictionary
subdict_str
=
_select_block
(
dict_str
[
pos
:
]
,
'{'
,
'}'
)
value
=
_parse_dict_recursive
(
subdict_str
)
pos_tmp
=
pos
+
len
(
subdict_str
)
else
:
raise
ValueError
(
'error when parsing dict: unknown elem'
)
key
=
key
.
strip
(
'"'
)
if
len
(
key
)
>
0
:
dict_out
[
key
]
=
value
pos_last
=
dict_str
.
find
(
','
,
pos_tmp
)
if
pos_last
<
0
:
break
pos_last
+=
1
pos
=
dict_str
.
find
(
':'
,
pos_last
)
return
dict_out


def parse_sphinx_searchindex(searchindex):
    """Parse a Sphinx search index

    Parameters
    ----------
    searchindex : str
        The Sphinx search index (contents of searchindex.js)

    Returns
    -------
    filenames : list of str
        The file names parsed from the search index.
    objects : dict
        The objects parsed from the search index.
    """
    # Make sure searchindex uses UTF-8 encoding
    if hasattr(searchindex, 'decode'):
        searchindex = searchindex.decode('UTF-8')

    # parse objects
    query = 'objects:'
    pos = searchindex.find(query)
    if pos < 0:
        raise ValueError('"objects:" not found in search index')

    sel = _select_block(searchindex[pos:], '{', '}')
    objects = _parse_dict_recursive(sel)

    # parse filenames
    query = 'filenames:'
    pos = searchindex.find(query)
    if pos < 0:
        raise ValueError('"filenames:" not found in search index')
    filenames = searchindex[pos + len(query) + 1:]
    filenames = filenames[:filenames.find(']')]
    filenames = [f.strip('"') for f in filenames.split(',')]

    return filenames, objects


def embed_code_links(app, exception):
    """Embed hyperlinks to documentation into example code"""
    if exception is not None:
        return

    # No need to waste time embedding hyperlinks when not running the examples
    # XXX: also at the time of writing this fixes make html-noplot
    # for some reason I don't fully understand
    if not app.builder.config.plot_gallery:
        return

    # XXX: Whitelist of builders for which it makes sense to embed
    # hyperlinks inside the example html. Note that the link embedding
    # require searchindex.js to exist for the links to the local doc
    # and there does not seem to be a good way of knowing which
    # builders creates a searchindex.js.
    if app.builder.name not in ['html', 'readthedocs']:
        return

    print('Embedding documentation hyperlinks in examples..')

    gallery_conf = app.config.sphinx_gallery_conf

    gallery_dirs = gallery_conf['gallery_dirs']
    if not isinstance(gallery_dirs, list):
        gallery_dirs = [gallery_dirs]

    for gallery_dir in gallery_dirs:
        _embed_code_links(app, gallery_conf, gallery_dir)


def _get_link(self, cobj):
        """Get a valid link, False if not found"""

        fname_idx = None
        full_name = cobj['module_short'] + '.' + cobj['name']
        if full_name in self._searchindex['objects']:
            value = self._searchindex['objects'][full_name]
            if isinstance(value, dict):
                value = value[next(iter(value.keys()))]
            fname_idx = value[0]
        elif cobj['module_short'] in self._searchindex['objects']:
            value = self._searchindex['objects'][cobj['module_short']]
            if cobj['name'] in value.keys():
                fname_idx = value[cobj['name']][0]

        if fname_idx is not None:
            fname = self._searchindex['filenames'][fname_idx] + '.html'

            if self._is_windows:
                fname = fname.replace('/', '\\')
                link = os.path.join(self.doc_url, fname)
            else:
                link = posixpath.join(self.doc_url, fname)

            if hasattr(link, 'decode'):
                link = link.decode('utf-8', 'replace')

            if link in self._page_cache:
                html = self._page_cache[link]
            else:
                html = get_data(link, self.gallery_dir)
                self._page_cache[link] = html

            # test if cobj appears in page
            comb_names = [cobj['module_short'] + '.' + cobj['name']]
            if self.extra_modules_test is not None:
                for mod in self.extra_modules_test:
                    comb_names.append(mod + '.' + cobj['name'])
            url = False
            if hasattr(html, 'decode'):
                # Decode bytes under Python 3
                html = html.decode('utf-8', 'replace')

            for comb_name in comb_names:
                if hasattr(comb_name, 'decode'):
                    # Decode bytes under Python 3
                    comb_name = comb_name.decode('utf-8', 'replace')
                if comb_name in html:
                    url = link + u'#' + comb_name
            link = url
        else:
            link = False

        return link

def
_get_link
(
self
,
cobj
)
:
fname_idx
=
full_name
=
cobj
[
'module_short'
]
+
'.'
+
cobj
[
'name'
]
if
full_name
in
self
.
_searchindex
[
'objects'
]
:
value
=
self
.
_searchindex
[
'objects'
]
[
full_name
]
if
isinstance
(
value
,
dict
)
:
value
=
value
[
next
(
iter
(
value
.
keys
(
)
)
)
]
fname_idx
=
value
[
0
]
elif
cobj
[
'module_short'
]
in
self
.
_searchindex
[
'objects'
]
:
value
=
self
.
_searchindex
[
'objects'
]
[
cobj
[
'module_short'
]
]
if
cobj
[
'name'
]
in
value
.
keys
(
)
:
fname_idx
=
value
[
cobj
[
'name'
]
]
[
0
]
if
fname_idx
is
not
:
fname
=
self
.
_searchindex
[
'filenames'
]
[
fname_idx
]
+
'.html'
if
self
.
_is_windows
:
fname
=
fname
.
replace
(
'/'
,
'\\'
)
link
=
os
.
path
.
join
(
self
.
doc_url
,
fname
)
else
:
link
=
posixpath
.
join
(
self
.
doc_url
,
fname
)
if
hasattr
(
link
,
'decode'
)
:
link
=
link
.
decode
(
'utf-8'
,
'replace'
)
if
link
in
self
.
_page_cache
:
html
=
self
.
_page_cache
[
link
]
else
:
html
=
get_data
(
link
,
self
.
gallery_dir
)
self
.
_page_cache
[
link
]
=
html
# test if cobj appears in page
comb_names
=
[
cobj
[
'module_short'
]
+
'.'
+
cobj
[
'name'
]
]
if
self
.
extra_modules_test
is
not
:
for
mod
in
self
.
extra_modules_test
:
comb_names
.
append
(
mod
+
'.'
+
cobj
[
'name'
]
)
url
=
False
if
hasattr
(
html
,
'decode'
)
:
# Decode bytes under Python 3
html
=
html
.
decode
(
'utf-8'
,
'replace'
)
for
comb_name
in
comb_names
:
if
hasattr
(
comb_name
,
'decode'
)
:
# Decode bytes under Python 3
comb_name
=
comb_name
.
decode
(
'utf-8'
,
'replace'
)
if
comb_name
in
html
:
url
=
link
+
u'#'
+
comb_name
link
=
url
else
:
link
=
False
return
link


def tf2zp(b,a):
    """Convert transfer function filter parameters to zero-pole-gain form

    Find the zeros, poles, and gains of this continuous-time system:

    .. warning:: b and a must have the same length.

    ::

        from spectrum import tf2zp
        b = [2,3,0]
        a = [1, 0.4, 1]
        [z,p,k] = tf2zp(b,a)          % Obtain zero-pole-gain form
        z =
            1.5
            0
        p =
           -0.2000 + 0.9798i
            -0.2000 - 0.9798i
        k =
           2

    :param b: numerator
    :param a: denominator
    :param fill: If True, check that the length of a and b are the same. If not, create a copy of the shortest element and append zeros to it.
    :return: z (zeros), p (poles), g (gain)

    Convert transfer function f(x)=sum(b*x^n)/sum(a*x^n) to
    zero-pole-gain form f(x)=g*prod(1-z*x)/prod(1-p*x)

    .. todo:: See if tf2ss followed by ss2zp gives better results.  These
        are available from the control system toolbox.  Note that
        the control systems toolbox doesn't bother, but instead uses

    .. seealso:: scipy.signal.tf2zpk, which gives the same results but uses a different
        algorithm (z^-1 instead of z).
    """
    from numpy import roots
    assert len(b) == len(a), "length of the vectors a and b must be identical. fill with zeros if needed."

    g = b[0] / a[0]
    z = roots(b)
    p = roots(a)

    return z, p, g

Convert transfer function filter parameters to zero - pole - gain form


def eqtflength(b,a):
    """Given two list or arrays, pad with zeros the shortest array

    :param b: list or array
    :param a: list or array

    .. doctest::

        >>> from spectrum.transfer import eqtflength
        >>> a = [1,2]
        >>> b = [1,2,3,4]
        >>> a, b, = eqtflength(a,b)

    """
    d = abs(len(b)-len(a))
    if d != 0:
        if len(a) > len(b):
            try:
                b.extend([0.]*d)
            except:
                b = np.append(b, [0]*d)
        elif len(b)>len(a):
            try:
                a.extend([0.]*d)
            except:
                a = np.append(a, [0]*d)
        return b,a
    else:
        return b,a

def eqtflength ( b , a ) : d = abs ( len ( b ) - len ( a ) ) if d != 0 : if len ( a ) > len ( b ) : try : b . extend ( [ 0. ] * d ) except : b = np . append ( b , [ 0 ] * d ) elif len ( b ) > len ( a ) : try : a . extend ( [ 0. ] * d ) except : a = np . append ( a , [ 0 ] * d ) return b , a else : return b , a

Given two list or arrays pad with zeros the shortest array