Example #1
0
 def computeTimeFreq(self):
     """ Compute the scalogram and returns a :class:`TimeFreq` object as
     self.timeFreq. """
     self.timeFreq = TimeFreq(
         self.anaSig,
         method=self.scalogram_method,
         f_start=self.f_start,
         f_stop=self.f_stop,
         deltafreq=self.deltafreq,
         sampling_rate=self.sampling_rate,
         t_start=self.t_start,
         t_stop=self.t_stop,
         f0=self.f0,
         normalisation=self.normalisation,
     )
Example #2
0
 def computeTimeFreq(self):
     """ Compute the scalogram and returns a :class:`TimeFreq` object as
     self.timeFreq. """
     self.timeFreq  = TimeFreq(   self.anaSig,
                                                 method = self.scalogram_method,
                                                 f_start=self.f_start,
                                                 f_stop=self.f_stop,
                                                 deltafreq = self.deltafreq,
                                                 sampling_rate = self.sampling_rate,
                                                 t_start = self.t_start,
                                                 t_stop = self.t_stop,
                                                 f0=self.f0,
                                                 normalisation = self.normalisation,
                                             )    
Example #3
0
class LineDetector():
    """ 
    LineDetector(anaSig, 
                 scalogram_method = 'convolution_freq',
                 f_start=5.,
                 f_stop=100.,
                 deltafreq = 1.,
                 sampling_rate = 200.,
                 t_start = -inf, 
                 t_stop = inf,
                 f0=2.5, 
                 normalisation = 0.,
                 linedetection_method = 'detect_line_from_max',
                 detection_zone = [ 0, inf, 5, 100.],
                 manual_threshold = False,
                 abs_threshold = nan,
                 std_relative_threshold = 6.,
                 reference_zone = [ -inf, 0,5., 100.],
                 minimum_cycle_number= 0.,
                 eliminate_simultaneous = True,
                 regroup_full_overlap = True , 
                 eliminate_partial_overlap = True)    
    
    Class for line detection in the scalogram. 
    """
    def __init__(self,
                        anaSig,
                        
                        scalogram_method = 'convolution_freq',
                        #scalogram
                        f_start=5.,
                        f_stop=100.,
                        deltafreq = 1.,
                        sampling_rate = 200.,
                        t_start = -inf, 
                        t_stop = inf,
                        f0=2.5, 
                        normalisation = 0.,
                        
                        #~ linedetection_method = 'detect_all_lines',
                        linedetection_method = 'detect_line_from_max',
                        
                        
                        # detection_zone
                        detection_zone = [ 0, inf, 5, 100.],
                        
                        # threshold
                        manual_threshold = False,
                        abs_threshold = nan,
                        std_relative_threshold = 6.,
                        reference_zone = [ -inf, 0,5., 100.],
                        
                        # clean 
                        minimum_cycle_number= 0.,
                        eliminate_simultaneous = True,
                        regroup_full_overlap = True , 
                        eliminate_partial_overlap = True,                        
                        
                        ):
        """ 
    Construct a :class:`.LineDetector` object.
        
    Parameters
    ----------
    anaSig : AnalogSignal
        The AnalogSignal in which oscillations will be detected.    
    
    Scalogram parameters:
    
    f_start : float, optional
        Lower frequency bound (Hz) of scalogram
    f_stop : float, optional
        Upper frequency bound (Hz) of scalogram
    deltafreq : float, optional
        Frequency resolution of scalogram
    sampling_rate : float, optional
        Sampling rate of scalogram (Hz)
    t_start : float, optional
        Starting point of scalogram (s)
    t_stop : float, optional
        End point of scalogram (s)
    f0 : float, optional
        Number of cycles within one standard deviation of the Morlet wavelet.
    normalisation : float, optional
        Normalisation exponent along the frequency dimension. Negative 
        (positive) values stress lower (higher) frequencies.
        
    
    Detection parameters
    
    detection_zone : array-like
        Time-frequency zone for oscillations detection of shape
        [t_start, t_stop, f_start, f_stop]        
    manual_threshold : bool, optional
        Boolean switch for manual thresholding 
    abs_threshold : float, optional
        Absolute power threshold for maxima detection
    std_relative_threshold : float, optional
        Threshold in units of of standard deviations from mean value in 
        reference_zone 
    reference_zone : array-like, optional
        Time-frequency reference zone for relative thresholding of shape
        [t_start, t_stop, f_start, f_stop]        
     
    Cleaning parameters
    
    minimum_cycle_number : float, optional
        Minimum number of cycles for cleaning of spurious oscillations
    eliminate_simultaneous : bool, optional
        Eliminate the less powerful oscillation of two oscillations overlapping
        in time but not in frequency, e.g. for the elimination of harmonics        
    regroup_full_overlap : bool, optional
        Merge oscillations completely overlapping in time and frequency, e.g.
        when one oscillations has several maximas in its envelope
    eliminate_partial_overlap : bool, optional
        Keep the more powerful oscillation of two partially overlapping
        oscillations, e.g. for the case of two forking ones
        
    Examples
    --------
    >>> ana = AnalogSignal.load(id)    
    >>> lid = LineDetector(ana)
    >>> lid.computeAllStep()        
        
        
        """
        self.anaSig = anaSig
        
        self.scalogram_method = scalogram_method
        #scalogram
        self.f_start=f_start
        self.f_stop=f_stop
        self.deltafreq = deltafreq
        self.sampling_rate = sampling_rate
        self.t_start = t_start
        self.t_stop = t_stop
        self.f0= f0
        self.normalisation = normalisation

        #~ self.t_start = max(self.t_start , self.anaSig.t_start)
        #~ self.t_stop = min(self.t_stop , self.anaSig.t()[-1] )
        
        self.linedetection_method = linedetection_method

        # detection_zone
        self.detection_zone = detection_zone
        #~ self.detection_zone[1] = min(self.detection_zone[1], self.anaSig.t()[-1] )
        
        # threshold
        self.manual_threshold = manual_threshold
        self.abs_threshold = abs_threshold
        self.std_relative_threshold = std_relative_threshold
        self.reference_zone = reference_zone
        #~ self.reference_zone[0] = max(self.reference_zone[0], self.anaSig.t()[0] )

        # clean 
        self.minimum_cycle_number= minimum_cycle_number
        self.eliminate_simultaneous =eliminate_simultaneous
        self.regroup_full_overlap = regroup_full_overlap
        self.eliminate_partial_overlap = eliminate_partial_overlap
        
        self.checkParam()

        self.timeFreq = None
        self.threshold = inf
        self.list_max = None
    
    def update(self, **params):
        self.__dict__.update(params)
    
    def checkParam(self):
        """ Perform checks and corrections to parameters t_start, t_stop, 
        sampling_rate, detection_zone[0] and detection_zone[1]. """
        self.t_start = max(self.t_start , self.anaSig.t_start)
        self.t_stop = min(self.t_stop , self.anaSig.t()[-1]+1./self.anaSig.sampling_rate )
        self.sampling_rate = max(self.f_stop*2, self.sampling_rate)
        
        self.detection_zone[1] = min(self.detection_zone[1], self.anaSig.t()[-1]+1./self.anaSig.sampling_rate )
        
        self.reference_zone[0] = max(self.reference_zone[0], self.anaSig.t()[0] )
        
    
    def computeAllStep(self):
        """ Compute the scalogram (:func:`computeTimeFreq`), detects maxima 
        (:func:`detectMax`) and lines (:func:`detectLine`), and cleans the 
        detected oscillations (:func:`cleanLine`. """
        #~ self.checkParam()
        self.computeTimeFreq()
        self.detectMax()
        self.detectLine()
        self.cleanLine()        
    
    def computeTimeFreq(self):
        """ Compute the scalogram and returns a :class:`TimeFreq` object as
        self.timeFreq. """
        self.timeFreq  = TimeFreq(   self.anaSig,
                                                    method = self.scalogram_method,
                                                    f_start=self.f_start,
                                                    f_stop=self.f_stop,
                                                    deltafreq = self.deltafreq,
                                                    sampling_rate = self.sampling_rate,
                                                    t_start = self.t_start,
                                                    t_stop = self.t_stop,
                                                    f0=self.f0,
                                                    normalisation = self.normalisation,
                                                )    
    
    def computeThreshold(self):
        """ Either set self.threshold to the specified self.abs_threshold or 
        (re)compute the relative threshold and sets it. In both cases the 
        the threshold is returned. """
        if self.manual_threshold:
            self.threshold = self.abs_threshold
        else:
            map = self.timeFreq.map
            t = self.timeFreq.t()
            f = self.timeFreq.f()
            t1,t2,f1,f2 = self.reference_zone
            subMap =  map[ (t>=t1) & (t<t2), :][: ,  (f>=f1) & (f<f2)]
            subMap = abs(subMap)
            self.threshold = numpy.mean(subMap) + self.std_relative_threshold*numpy.std(subMap)
        return self.threshold
        
        
    
    def detectMax(self):
        """ Detect the maxima in the scalogram using :func:`max_detection`."""
        map = self.timeFreq.map
        t = self.timeFreq.t()
        f = self.timeFreq.f()
        t1,t2,f1,f2 = self.detection_zone
        subMap =  map[ (t>=t1) & (t<t2), :][: ,  (f>=f1) & (f<f2)]
        
        new_t =  t[ (t>=t1) & (t<t2) ]
        new_f = f[ (f>=f1) & (f<f2)]
        
        self.computeThreshold()
        
        ind_t,ind_f = numpy.array(max_detection(abs(subMap),threshold= self.threshold))
        self.list_max = numpy.recarray(ind_t.size , formats = ['f8', 'f8'], names=['time', 'freq'] , )
        self.list_max.time  = new_t[ind_t]
        self.list_max.freq  = new_f[ind_f]
        
        
    def detectLine(self):
        """ Detect lines in the scalogram using self.linedetection_method. """
        map = self.timeFreq.map
        t = self.timeFreq.t()
        f = self.timeFreq.f()
        t1,t2,f1,f2 = self.detection_zone
        subMap =  map[ (t>=t1) & (t<t2), :][: ,  (f>=f1) & (f<f2)]
        new_t =  t[ (t>=t1) & (t<t2) ]
        new_f = f[ (f>=f1) & (f<f2)]
        
        self.computeThreshold()
        
        if self.linedetection_method == 'detect_all_lines':
            self.list_oscillation = detectalllines.detect_oscillations(subMap,
                new_t[0],   #self.detection_zone[0],
                self.sampling_rate,
                new_f[0],   #self.detection_zone[3],
                self.deltafreq,
                self.threshold,
                list_max = self.list_max,
                )
                                                        
        elif self.linedetection_method == 'detect_line_from_max':
            self.list_oscillation = detectlinefrommax.detect_oscillations(subMap,
                new_t[0],   #self.detection_zone[0],
                self.sampling_rate,
                new_f[0],   #self.detection_zone[3],
                self.deltafreq,
                self.threshold,
                list_max =self.list_max,
                )

    def recomputeSelection(self , ind):
        pass


    def cleanLine(self):
        """ Clean all oscillations with selected parameters and sort them in time. """
        self.list_oscillation = clean_oscillations_list(self.list_oscillation,
            minimum_cycle_number=self.minimum_cycle_number,
            eliminate_simultaneous = self.eliminate_simultaneous,
            regroup_full_overlap = self.regroup_full_overlap,
            eliminate_partial_overlap = self.eliminate_partial_overlap,
                    )
        self.sortOscillations()
    
    
    def cleanSelection(self, ind):
        """ Clean only selected oscillations and sort them in time. """
        not_selected = [ ]
        selected = []
        for i in range(len(self.list_oscillation)):
            if i  in ind:
                selected.append( self.list_oscillation[i] )
            else:
                not_selected.append( self.list_oscillation[i] )
        
        list_cleaned = clean_oscillations_list(selected,
               minimum_cycle_number=self.minimum_cycle_number,
               eliminate_simultaneous = self.eliminate_simultaneous,
               regroup_full_overlap = self.regroup_full_overlap,
               eliminate_partial_overlap = self.eliminate_partial_overlap,
               )
        self.list_oscillation = list_cleaned + not_selected
        self.sortOscillations()
        
    
    def sortOscillations(self):
        """ Sort the detected oscillations by time. """
        t = [ ]
        for osci in self.list_oscillation:
            t.append( osci.time_max )
        ind = numpy.argsort(t)
        sorted = [ self.list_oscillation[i] for i in ind ]
        self.list_oscillation = sorted
Example #4
0
class LineDetector():
    """ 
    LineDetector(anaSig, 
                 scalogram_method = 'convolution_freq',
                 f_start=5.,
                 f_stop=100.,
                 deltafreq = 1.,
                 sampling_rate = 200.,
                 t_start = -inf, 
                 t_stop = inf,
                 f0=2.5, 
                 normalisation = 0.,
                 linedetection_method = 'detect_line_from_max',
                 detection_zone = [ 0, inf, 5, 100.],
                 manual_threshold = False,
                 abs_threshold = nan,
                 std_relative_threshold = 6.,
                 reference_zone = [ -inf, 0,5., 100.],
                 minimum_cycle_number= 0.,
                 eliminate_simultaneous = True,
                 regroup_full_overlap = True , 
                 eliminate_partial_overlap = True)    
    
    Class for line detection in the scalogram. 
    """
    def __init__(
        self,
        anaSig,
        scalogram_method='convolution_freq',
        #scalogram
        f_start=5.,
        f_stop=100.,
        deltafreq=1.,
        sampling_rate=200.,
        t_start=-inf,
        t_stop=inf,
        f0=2.5,
        normalisation=0.,

        #~ linedetection_method = 'detect_all_lines',
        linedetection_method='detect_line_from_max',

        # detection_zone
        detection_zone=[0, inf, 5, 100.],

        # threshold
        manual_threshold=False,
        abs_threshold=nan,
        std_relative_threshold=6.,
        reference_zone=[-inf, 0, 5., 100.],

        # clean
        minimum_cycle_number=0.,
        eliminate_simultaneous=True,
        regroup_full_overlap=True,
        eliminate_partial_overlap=True,
    ):
        """ 
    Construct a :class:`.LineDetector` object.
        
    Parameters
    ----------
    anaSig : AnalogSignal
        The AnalogSignal in which oscillations will be detected.    
    
    Scalogram parameters:
    
    f_start : float, optional
        Lower frequency bound (Hz) of scalogram
    f_stop : float, optional
        Upper frequency bound (Hz) of scalogram
    deltafreq : float, optional
        Frequency resolution of scalogram
    sampling_rate : float, optional
        Sampling rate of scalogram (Hz)
    t_start : float, optional
        Starting point of scalogram (s)
    t_stop : float, optional
        End point of scalogram (s)
    f0 : float, optional
        Number of cycles within one standard deviation of the Morlet wavelet.
    normalisation : float, optional
        Normalisation exponent along the frequency dimension. Negative 
        (positive) values stress lower (higher) frequencies.
        
    
    Detection parameters
    
    detection_zone : array-like
        Time-frequency zone for oscillations detection of shape
        [t_start, t_stop, f_start, f_stop]        
    manual_threshold : bool, optional
        Boolean switch for manual thresholding 
    abs_threshold : float, optional
        Absolute power threshold for maxima detection
    std_relative_threshold : float, optional
        Threshold in units of of standard deviations from mean value in 
        reference_zone 
    reference_zone : array-like, optional
        Time-frequency reference zone for relative thresholding of shape
        [t_start, t_stop, f_start, f_stop]        
     
    Cleaning parameters
    
    minimum_cycle_number : float, optional
        Minimum number of cycles for cleaning of spurious oscillations
    eliminate_simultaneous : bool, optional
        Eliminate the less powerful oscillation of two oscillations overlapping
        in time but not in frequency, e.g. for the elimination of harmonics        
    regroup_full_overlap : bool, optional
        Merge oscillations completely overlapping in time and frequency, e.g.
        when one oscillations has several maximas in its envelope
    eliminate_partial_overlap : bool, optional
        Keep the more powerful oscillation of two partially overlapping
        oscillations, e.g. for the case of two forking ones
        
    Examples
    --------
    >>> ana = AnalogSignal.load(id)    
    >>> lid = LineDetector(ana)
    >>> lid.computeAllStep()        
        
        
        """
        self.anaSig = anaSig

        self.scalogram_method = scalogram_method
        #scalogram
        self.f_start = f_start
        self.f_stop = f_stop
        self.deltafreq = deltafreq
        self.sampling_rate = sampling_rate
        self.t_start = t_start
        self.t_stop = t_stop
        self.f0 = f0
        self.normalisation = normalisation

        #~ self.t_start = max(self.t_start , self.anaSig.t_start)
        #~ self.t_stop = min(self.t_stop , self.anaSig.t()[-1] )

        self.linedetection_method = linedetection_method

        # detection_zone
        self.detection_zone = detection_zone
        #~ self.detection_zone[1] = min(self.detection_zone[1], self.anaSig.t()[-1] )

        # threshold
        self.manual_threshold = manual_threshold
        self.abs_threshold = abs_threshold
        self.std_relative_threshold = std_relative_threshold
        self.reference_zone = reference_zone
        #~ self.reference_zone[0] = max(self.reference_zone[0], self.anaSig.t()[0] )

        # clean
        self.minimum_cycle_number = minimum_cycle_number
        self.eliminate_simultaneous = eliminate_simultaneous
        self.regroup_full_overlap = regroup_full_overlap
        self.eliminate_partial_overlap = eliminate_partial_overlap

        self.checkParam()

        self.timeFreq = None
        self.threshold = inf
        self.list_max = None

    def update(self, **params):
        self.__dict__.update(params)

    def checkParam(self):
        """ Perform checks and corrections to parameters t_start, t_stop, 
        sampling_rate, detection_zone[0] and detection_zone[1]. """
        self.t_start = max(self.t_start, self.anaSig.t_start)
        self.t_stop = min(self.t_stop,
                          self.anaSig.t()[-1] + 1. / self.anaSig.sampling_rate)
        self.sampling_rate = max(self.f_stop * 2, self.sampling_rate)

        self.detection_zone[1] = min(
            self.detection_zone[1],
            self.anaSig.t()[-1] + 1. / self.anaSig.sampling_rate)

        self.reference_zone[0] = max(self.reference_zone[0],
                                     self.anaSig.t()[0])

    def computeAllStep(self):
        """ Compute the scalogram (:func:`computeTimeFreq`), detects maxima 
        (:func:`detectMax`) and lines (:func:`detectLine`), and cleans the 
        detected oscillations (:func:`cleanLine`. """
        #~ self.checkParam()
        self.computeTimeFreq()
        self.detectMax()
        self.detectLine()
        self.cleanLine()

    def computeTimeFreq(self):
        """ Compute the scalogram and returns a :class:`TimeFreq` object as
        self.timeFreq. """
        self.timeFreq = TimeFreq(
            self.anaSig,
            method=self.scalogram_method,
            f_start=self.f_start,
            f_stop=self.f_stop,
            deltafreq=self.deltafreq,
            sampling_rate=self.sampling_rate,
            t_start=self.t_start,
            t_stop=self.t_stop,
            f0=self.f0,
            normalisation=self.normalisation,
        )

    def computeThreshold(self):
        """ Either set self.threshold to the specified self.abs_threshold or 
        (re)compute the relative threshold and sets it. In both cases the 
        the threshold is returned. """
        if self.manual_threshold:
            self.threshold = self.abs_threshold
        else:
            map = self.timeFreq.map
            t = self.timeFreq.t()
            f = self.timeFreq.f()
            t1, t2, f1, f2 = self.reference_zone
            subMap = map[(t >= t1) & (t < t2), :][:, (f >= f1) & (f < f2)]
            subMap = abs(subMap)
            self.threshold = numpy.mean(
                subMap) + self.std_relative_threshold * numpy.std(subMap)
        return self.threshold

    def detectMax(self):
        """ Detect the maxima in the scalogram using :func:`max_detection`."""
        map = self.timeFreq.map
        t = self.timeFreq.t()
        f = self.timeFreq.f()
        t1, t2, f1, f2 = self.detection_zone
        subMap = map[(t >= t1) & (t < t2), :][:, (f >= f1) & (f < f2)]

        new_t = t[(t >= t1) & (t < t2)]
        new_f = f[(f >= f1) & (f < f2)]

        self.computeThreshold()

        ind_t, ind_f = numpy.array(
            max_detection(abs(subMap), threshold=self.threshold))
        self.list_max = numpy.recarray(
            ind_t.size,
            formats=['f8', 'f8'],
            names=['time', 'freq'],
        )
        self.list_max.time = new_t[ind_t]
        self.list_max.freq = new_f[ind_f]

    def detectLine(self):
        """ Detect lines in the scalogram using self.linedetection_method. """
        map = self.timeFreq.map
        t = self.timeFreq.t()
        f = self.timeFreq.f()
        t1, t2, f1, f2 = self.detection_zone
        subMap = map[(t >= t1) & (t < t2), :][:, (f >= f1) & (f < f2)]
        new_t = t[(t >= t1) & (t < t2)]
        new_f = f[(f >= f1) & (f < f2)]

        self.computeThreshold()

        if self.linedetection_method == 'detect_all_lines':
            self.list_oscillation = detectalllines.detect_oscillations(
                subMap,
                new_t[0],  #self.detection_zone[0],
                self.sampling_rate,
                new_f[0],  #self.detection_zone[3],
                self.deltafreq,
                self.threshold,
                list_max=self.list_max,
            )

        elif self.linedetection_method == 'detect_line_from_max':
            self.list_oscillation = detectlinefrommax.detect_oscillations(
                subMap,
                new_t[0],  #self.detection_zone[0],
                self.sampling_rate,
                new_f[0],  #self.detection_zone[3],
                self.deltafreq,
                self.threshold,
                list_max=self.list_max,
            )

    def recomputeSelection(self, ind):
        pass

    def cleanLine(self):
        """ Clean all oscillations with selected parameters and sort them in time. """
        self.list_oscillation = clean_oscillations_list(
            self.list_oscillation,
            minimum_cycle_number=self.minimum_cycle_number,
            eliminate_simultaneous=self.eliminate_simultaneous,
            regroup_full_overlap=self.regroup_full_overlap,
            eliminate_partial_overlap=self.eliminate_partial_overlap,
        )
        self.sortOscillations()

    def cleanSelection(self, ind):
        """ Clean only selected oscillations and sort them in time. """
        not_selected = []
        selected = []
        for i in range(len(self.list_oscillation)):
            if i in ind:
                selected.append(self.list_oscillation[i])
            else:
                not_selected.append(self.list_oscillation[i])

        list_cleaned = clean_oscillations_list(
            selected,
            minimum_cycle_number=self.minimum_cycle_number,
            eliminate_simultaneous=self.eliminate_simultaneous,
            regroup_full_overlap=self.regroup_full_overlap,
            eliminate_partial_overlap=self.eliminate_partial_overlap,
        )
        self.list_oscillation = list_cleaned + not_selected
        self.sortOscillations()

    def sortOscillations(self):
        """ Sort the detected oscillations by time. """
        t = []
        for osci in self.list_oscillation:
            t.append(osci.time_max)
        ind = numpy.argsort(t)
        sorted = [self.list_oscillation[i] for i in ind]
        self.list_oscillation = sorted