# Path: python/source/peak_detection.py
# def peakdet(v, delta, x=None):
#     """
#     Converted from MATLAB script at http://billauer.co.il/peakdet.html
# 
#     Returns two arrays
# 
#     function [maxtab, mintab]=peakdet(v, delta, x)
#     %PEAKDET Detect peaks in a vector
#     %        [MAXTAB, MINTAB] = PEAKDET(V, DELTA) finds the local
#     %        maxima and minima ("peaks") in the vector V.
#     %        MAXTAB and MINTAB consists of two columns. Column 1
#     %        contains indices in V, and column 2 the found values.
#     %
#     %        With [MAXTAB, MINTAB] = PEAKDET(V, DELTA, X) the indices
#     %        in MAXTAB and MINTAB are replaced with the corresponding
#     %        X-values.
#     %
#     %        A point is considered a maximum peak if it has the maximal
#     %        value, and was preceded (to the left) by a value lower by
#     %        DELTA.
# 
#     % Eli Billauer, 3.4.05 (Explicitly not copyrighted).
#     % This function is released to the public domain; Any use is allowed.
# 
#     """
#     maxtab = []
#     mintab = []
# 
#     if x is None:
#         x = arange(len(v))
# 
#     v = asarray(v)
# 
#     if len(v) != len(x):
#         sys.exit('Input vectors v and x must have same length')
# 
#     if not isscalar(delta):
#         sys.exit('Input argument delta must be a scalar')
# 
#     if delta <= 0:
#         sys.exit('Input argument delta must be positive')
# 
#     mn, mx = Inf, -Inf
#     mnpos, mxpos = NaN, NaN
# 
#     lookformax = True
# 
#     for i in arange(len(v)):
#         this = v[i]
#         if this > mx:
#             mx = this
#             mxpos = x[i]
#         if this < mn:
#             mn = this
#             mnpos = x[i]
# 
#         if lookformax:
#             if this < mx - delta:
#                 maxtab.append((mxpos, mx))
#                 mn = this
#                 mnpos = x[i]
#                 lookformax = False
#         else:
#             if this > mn + delta:
#                 mintab.append((mnpos, mn))
#                 mx = this
#                 mxpos = x[i]
#                 lookformax = True
# 
#     return array(maxtab), array(mintab)
# 
# Path: python/source/observer_pattern.py
# class Observer(object):
#     '''Observer.
# 
#     An observer provides a representation of an observable, called the subject.
#     It may be attached to one or several subjects.
#     Subjects are able to notify the observers that have been attached to them
#     when some change has occured and an update of their representation is
#     necessary.
# 
#     Examples
#     --------
#     >>> ptree = PropertyTree()
#     >>> ptree.put_string('type', 'ConcreteObserver')
#     >>> observer = Observer(ptree)
# 
#     >>> observer.update(subject)
# 
#     >>> subject.attach(observer)
#     >>> subject.notify()
# 
#     See Also
#     --------
#     Observable
#     '''
# 
#     _builders = {}
# 
#     def __new__(cls, ptree, *args, **kwargs):
#         '''Create a new instance of class cls.
# 
#         Parameters
#         ----------
#         cls : class
#         ptree : PropertyTree
# 
#         Raises
#         ------
#         KeyError
#             The observer type is not valid.
#         RuntimeError
#             The property tree is missing the key 'type' or is not able to
#             convert its value to string.
#         '''
#         t = ptree.get_string('type')
#         return Observer._builders[t].__new__(cls, ptree, *args,  **kwargs)
# 
#     def update(self, subject, *args, **kwargs):
#         '''Update the representation of the Observable.
# 
#         Must be overriden in derived classes.
# 
#         Parameters
#         ----------
#         subject : Observable
#         args : list
#             Arbitrary argument list.
#         kwargs : dict
#             Keyword arguments.
#         '''
#         raise RuntimeError('Method Observer.update(...) must be overloaded')
# 
# class Experiment(Observable):
#     '''Experiment
# 
#     Base class for the electrochemical measurement techniques in PyCap.
# 
#     Attributes
#     ----------
#     _data : dict
#         Holds the measurement information.
#     _extra_data : dict
#         Holds other informations such as properties of the device.
#     '''
# 
#     def __init__(self):
#         Observable.__init__(self)
#         self._data = {}
#         self._extra_data = {}
# 
#     def run(self, device):
#         '''Run the experiment on an energy storage device.
# 
#         Parameters
#         ----------
#         device : EnergyStorageDevice
#         '''
#         raise RuntimeError('Method Experiment.run(...) must be overloaded')


from matplotlib import pyplot
from numpy import real, imag, log10, absolute, angle, array, append, power,\
    sin, pi, sum, isclose, fft, mean, argsort
from warnings import warn
from copy import copy
from io import open  # to be able to use parameter ``encoding`` with Python2.7
from .data_helpers import initialize_data, report_data, save_data
from .peak_detection import peakdet
from .observer_pattern import Observer, Experiment
import pycap
        Stores the information computed by the postprocessor and some of the
        input data that need to be saved.

    Examples
    --------
    ptree = PropertyTree()
    ptree.parse_info(eis.info)
    eis = Experiment(ptree)

    observer = NyquistPlot("nyquist_plot.png")
    eis.attach(observer)

    eis.run(device)

    See Also
    --------
    NyquistPlot, BodePlot
    '''
    def __new__(cls, *args, **kwargs):
        return object.__new__(ElectrochemicalImpedanceSpectroscopy)

    def __init__(self, ptree, frequencies=None):
        '''
        Parameters
        ----------
        ptree : PropertyTree
        frequencies : array_like, optional
            Specify the frequencies. If provided will be used to initialize a
            numpy.array of float.
        '''

# Path: python/source/peak_detection.py
# def peakdet(v, delta, x=None):
#     """
#     Converted from MATLAB script at http://billauer.co.il/peakdet.html
# 
#     Returns two arrays
# 
#     function [maxtab, mintab]=peakdet(v, delta, x)
#     %PEAKDET Detect peaks in a vector
#     %        [MAXTAB, MINTAB] = PEAKDET(V, DELTA) finds the local
#     %        maxima and minima ("peaks") in the vector V.
#     %        MAXTAB and MINTAB consists of two columns. Column 1
#     %        contains indices in V, and column 2 the found values.
#     %
#     %        With [MAXTAB, MINTAB] = PEAKDET(V, DELTA, X) the indices
#     %        in MAXTAB and MINTAB are replaced with the corresponding
#     %        X-values.
#     %
#     %        A point is considered a maximum peak if it has the maximal
#     %        value, and was preceded (to the left) by a value lower by
#     %        DELTA.
# 
#     % Eli Billauer, 3.4.05 (Explicitly not copyrighted).
#     % This function is released to the public domain; Any use is allowed.
# 
#     """
#     maxtab = []
#     mintab = []
# 
#     if x is None:
#         x = arange(len(v))
# 
#     v = asarray(v)
# 
#     if len(v) != len(x):
#         sys.exit('Input vectors v and x must have same length')
# 
#     if not isscalar(delta):
#         sys.exit('Input argument delta must be a scalar')
# 
#     if delta <= 0:
#         sys.exit('Input argument delta must be positive')
# 
#     mn, mx = Inf, -Inf
#     mnpos, mxpos = NaN, NaN
# 
#     lookformax = True
# 
#     for i in arange(len(v)):
#         this = v[i]
#         if this > mx:
#             mx = this
#             mxpos = x[i]
#         if this < mn:
#             mn = this
#             mnpos = x[i]
# 
#         if lookformax:
#             if this < mx - delta:
#                 maxtab.append((mxpos, mx))
#                 mn = this
#                 mnpos = x[i]
#                 lookformax = False
#         else:
#             if this > mn + delta:
#                 mintab.append((mnpos, mn))
#                 mx = this
#                 mxpos = x[i]
#                 lookformax = True
# 
#     return array(maxtab), array(mintab)
# 
# Path: python/source/observer_pattern.py
# class Observer(object):
#     '''Observer.
# 
#     An observer provides a representation of an observable, called the subject.
#     It may be attached to one or several subjects.
#     Subjects are able to notify the observers that have been attached to them
#     when some change has occured and an update of their representation is
#     necessary.
# 
#     Examples
#     --------
#     >>> ptree = PropertyTree()
#     >>> ptree.put_string('type', 'ConcreteObserver')
#     >>> observer = Observer(ptree)
# 
#     >>> observer.update(subject)
# 
#     >>> subject.attach(observer)
#     >>> subject.notify()
# 
#     See Also
#     --------
#     Observable
#     '''
# 
#     _builders = {}
# 
#     def __new__(cls, ptree, *args, **kwargs):
#         '''Create a new instance of class cls.
# 
#         Parameters
#         ----------
#         cls : class
#         ptree : PropertyTree
# 
#         Raises
#         ------
#         KeyError
#             The observer type is not valid.
#         RuntimeError
#             The property tree is missing the key 'type' or is not able to
#             convert its value to string.
#         '''
#         t = ptree.get_string('type')
#         return Observer._builders[t].__new__(cls, ptree, *args,  **kwargs)
# 
#     def update(self, subject, *args, **kwargs):
#         '''Update the representation of the Observable.
# 
#         Must be overriden in derived classes.
# 
#         Parameters
#         ----------
#         subject : Observable
#         args : list
#             Arbitrary argument list.
#         kwargs : dict
#             Keyword arguments.
#         '''
#         raise RuntimeError('Method Observer.update(...) must be overloaded')
# 
# class Experiment(Observable):
#     '''Experiment
# 
#     Base class for the electrochemical measurement techniques in PyCap.
# 
#     Attributes
#     ----------
#     _data : dict
#         Holds the measurement information.
#     _extra_data : dict
#         Holds other informations such as properties of the device.
#     '''
# 
#     def __init__(self):
#         Observable.__init__(self)
#         self._data = {}
#         self._extra_data = {}
# 
#     def run(self, device):
#         '''Run the experiment on an energy storage device.
# 
#         Parameters
#         ----------
#         device : EnergyStorageDevice
#         '''
#         raise RuntimeError('Method Experiment.run(...) must be overloaded')


# Path: python/source/impedance_spectroscopy.py
from matplotlib import pyplot
from numpy import real, imag, log10, absolute, angle, array, append, power,\
    sin, pi, sum, isclose, fft, mean, argsort
from warnings import warn
from copy import copy
from io import open  # to be able to use parameter ``encoding`` with Python2.7
from .data_helpers import initialize_data, report_data, save_data
from .peak_detection import peakdet
from .observer_pattern import Observer, Experiment
import pycap

        Stores the information computed by the postprocessor and some of the
        input data that need to be saved.

    Examples
    --------
    ptree = PropertyTree()
    ptree.parse_info(eis.info)
    eis = Experiment(ptree)

    observer = NyquistPlot("nyquist_plot.png")
    eis.attach(observer)

    eis.run(device)

    See Also
    --------
    NyquistPlot, BodePlot
    '''
    def __new__(cls, *args, **kwargs):
        return object.__new__(ElectrochemicalImpedanceSpectroscopy)

    def __init__(self, ptree, frequencies=None):
        '''
        Parameters
        ----------
        ptree : PropertyTree
        frequencies : array_like, optional
            Specify the frequencies. If provided will be used to initialize a
            numpy.array of float.
        '''

        Experiment.__init__(self)