Ejemplo n.º 1
0
    def test_mirror_spline(self):

        freqs = [2.0, 25.0, 40.0]
        sr = 1e3
        dt = 1.0 / sr
        t = np.arange(0.0, 1.0 + dt, dt)
        s = np.zeros([len(t)])
        # add a few sine waves up
        for f in freqs:
            s += np.sin(2 * np.pi * f * t)

        # identity maxima and minima
        mini, maxi = find_extrema(s)
        mini_orig = copy.copy(mini)
        maxi_orig = copy.copy(maxi)

        # extrapolate and build splines using mirroring
        low_spline, high_spline = create_mirrored_spline(mini, maxi, s)

        # evaluate splines
        ti = np.arange(len(t))
        low_env = splev(ti, low_spline)
        high_env = splev(ti, high_spline)
        env = (high_env + low_env) / 2.0

        """
Ejemplo n.º 2
0
    def test_mirror_spline(self):

        freqs = [2.0, 25.0, 40.0]
        sr = 1e3
        dt = 1.0 / sr
        t = np.arange(0.0, 1.0 + dt, dt)
        s = np.zeros([len(t)])
        #add a few sine waves up
        for f in freqs:
            s += np.sin(2 * np.pi * f * t)

        #identity maxima and minima
        mini, maxi = find_extrema(s)
        mini_orig = copy.copy(mini)
        maxi_orig = copy.copy(maxi)

        #extrapolate and build splines using mirroring
        low_spline, high_spline = create_mirrored_spline(mini, maxi, s)

        #evaluate splines
        ti = np.arange(len(t))
        low_env = splev(ti, low_spline)
        high_env = splev(ti, high_spline)
        env = (high_env + low_env) / 2.0
        """
Ejemplo n.º 3
0
    def compute_emd(self, s):
        """
            Perform the empirical mode decomposition on a signal s.
        """

        self.imfs = list()
        #make a copy of the signal that will hold the residual
        r = copy.copy(s)
        stop = False
        while not stop:
            #compute the IMF from the signal
            if self.ensemble_num_samples == 1:
                imf_mean = self.compute_imf(r)
                if imf_mean is None:
                    stop = True
                    break
                imf_std = np.zeros_like(imf_mean)
            else:
                imf_mean, imf_std = self.compute_imf_ensemble(r)

            #compute the normalized hilbert transform
            #am,fm,phase,ifreq = self.normalized_hilbert(imf_mean)
            amplitude, phase = self.hilbert(imf_mean)

            #construct an IMF object
            imf = IMF()
            imf.imf = imf_mean
            imf.std = imf_std
            imf.amplitude = amplitude
            imf.phase = phase

            self.imfs.append(imf)

            #subtract the IMF off to produce a new residual
            r -= imf_mean

            #compute extrema for detecting a trend IMF
            maxi, mini = find_extrema(r)

            #compute convergence criteria
            if np.abs(r).sum() < self.emd_resid_tol or len(
                    self.imfs) == self.emd_max_modes or (len(maxi) == 0
                                                         and len(mini) == 0):
                stop = True

        #append the residual as the last mode
        self.emd_residual = r
Ejemplo n.º 4
0
    def compute_emd(self, s):
        """
            Perform the empirical mode decomposition on a signal s.
        """

        self.imfs = list()
        #make a copy of the signal that will hold the residual
        r = copy.copy(s)
        stop = False
        while not stop:
            #compute the IMF from the signal
            if self.ensemble_num_samples == 1:
                imf_mean = self.compute_imf(r)
                if imf_mean is None:
                    stop = True
                    break
                imf_std = np.zeros_like(imf_mean)
            else:
                imf_mean,imf_std = self.compute_imf_ensemble(r)

            #compute the normalized hilbert transform
            #am,fm,phase,ifreq = self.normalized_hilbert(imf_mean)
            amplitude,phase = self.hilbert(imf_mean)

            #construct an IMF object
            imf = IMF()
            imf.imf = imf_mean
            imf.std = imf_std
            imf.amplitude = amplitude
            imf.phase = phase

            self.imfs.append(imf)

            #subtract the IMF off to produce a new residual
            r -= imf_mean

            #compute extrema for detecting a trend IMF
            maxi,mini = find_extrema(r)

            #compute convergence criteria
            if np.abs(r).sum() < self.emd_resid_tol or len(self.imfs) == self.emd_max_modes or (len(maxi) == 0 and len(mini) == 0):
                stop = True

        #append the residual as the last mode
        self.emd_residual = r
Ejemplo n.º 5
0
def compute_mean_envelope(s, nsamps=1000):
    """ Use random sampling to compute the mean envelope of a multi-dimensional signal.

    Args:
        s (np.ndarray): an NxT matrix describing a multi-variate signal. N is the number of channels, T is the number of time points.
        nsamps (int): the number of N dimensional projections to use in computing the multi-variate envelope.

    Returns:
        env (np.ndarray): an NxT matrix giving the multi-dimensional envelope of s.
    """

    N,T = s.shape

    #pre-allocate the mean envelope matrix
    mean_env = np.zeros([N, T])

    #generate quasi-random points on an N-dimensional sphere
    #stime = time.time()
    R = quasirand(N, nsamps, spherical=True)
    #etime = time.time() - stime
    #print 'Elapsed time for quasirand: %d seconds' % int(etime)

    stime = time.time()
    for k in range(nsamps):
        #istime = time.time()
        r = R[:, k].squeeze()

        #print 'k=%d, s.shape=%s, r.shape=%s' % (k, str(s.shape), str(r.shape))

        #project s onto a scalar time series using random vector
        #dtime = time.time()
        p = np.dot(s.T, r)
        #detime = time.time() - dtime
        #print '\t[%d] Time to do dot %0.6f s' % (k, detime)

        #print 'p.shape=',p.shape

        #identify minima and maxima of projection
        #eetime = time.time()
        mini_p,maxi_p = find_extrema(p)
        #eeetime = time.time() - eetime
        #print '\t[%d] time to find extrema: %0.6fs' % (k, eeetime)

        #for each signal dimension, fit maxima with cubic spline to produce envelope

        t = np.arange(T)
        for n in range(N):
            #sptime = time.time()
            mini = copy.copy(mini_p)
            maxi = copy.copy(maxi_p)
            if len(mini) < 4 or len(maxi) < 4:
                return None

            #extrapolate edges using mirroring
            lower_env_spline, upper_env_spline = create_mirrored_spline(mini, maxi, s[n, :].squeeze())
            if lower_env_spline is None or upper_env_spline is None:
                return None

            #evaluate upper and lower envelopes
            upper_env = splev(t, upper_env_spline)
            lower_env = splev(t, lower_env_spline)

            #compute the envelope for this projected dimension
            env = (upper_env + lower_env) / 2.0

            #update the mean envelope for this dimension in an online way
            delta = env - mean_env[n, :]
            mean_env[n, :] += delta / (k+1)
            #esptime = time.time() - sptime
            #print '\t[%d] time for spline iteration on dimension %d: %0.6fs' % (k, n, esptime)
        #ietime = time.time() - istime
        #print '\t[%d] took %0.6f seconds' % (k, ietime)

    etime = time.time() - stime
    #print '%d samples took %0.6f seconds' % (nsamps, etime)

    return mean_env
Ejemplo n.º 6
0
    def normalized_hilbert(self, s):
        """
            Perform the "Normalized" Hilbert transform (Huang 2008 sec. 3.1) on the IMF s, decomposing the
            signal s into AM and FM components. Returns am,fm,phase,ifreq - am is the AM component, fm is the FM
            component, phase is the the arccos of fm, and ifreq is the instantaneous frequency.
        """

        x = copy.copy(s)
        iter = 0
        converged = False

        while not converged:
            #take the absolute value of the IMF and find the extrema
            absx = np.abs(x)
            mini,maxi = find_extrema(absx)
            if len(mini) == 0 or len(maxi) == 0:
                converged = True
                break
            spline_order = 3

            #reflect first and last maxima to remove edge effects for interpolation
            left_padding = maxi[0]
            right_padding = len(x) - maxi[-1]
            x_padded = np.zeros([len(x)+left_padding+right_padding])
            x_padded[left_padding:-right_padding] = absx
            x_padded[0] = absx[maxi[0]]
            x_padded[-1] = absx[maxi[-1]]

            #create new array of extremas
            new_maxi = [i+left_padding for i in maxi]
            new_maxi.insert(0, 0)
            new_maxi.append(len(x_padded)-1)

            #fit a cubic spline to the extrema of the absolute value of the signal
            if len(maxi) <= 3:
                spline_order = 1
            max_spline = splrep(new_maxi, x_padded[new_maxi], k=spline_order)

            #use the spline to interpolate over the course of the signal
            t = np.arange(0, len(x_padded))
            fit_index = range(left_padding, len(x_padded)-right_padding)
            env = splev(t[fit_index], max_spline)

            """
            plt.figure()
            plt.plot(t, x_padded, 'k-')
            plt.plot(new_maxi, x_padded[new_maxi], 'ro-', markersize=8)
            plt.axis('tight')
            plt.suptitle('Iter %d' % iter)
            """

            #divide by envelope
            x /= env

            #check for convergence
            iter += 1
            if iter >= self.hilbert_max_iter:
                converged = True
            if (x.max() - 1.0) <= 1e-6:
                converged = True
            if len(mini) == 0 or len(maxi) == 0:
                converged = True

        #compute the FM and AM components
        fm = x
        am = s / fm

        #compute the phase
        phase = np.arccos(fm)

        #compute the instantaneous frequency
        ifreq = np.zeros([len(phase)])
        ifreq[1:] = np.diff(phase) * self.sample_rate

        return am,fm,phase,ifreq
Ejemplo n.º 7
0
    def compute_imf(self, s, plot=False):
        """
            Compute an intrinsic mode function from a signal s using sifting.
        """

        stop = False
        #make a copy of the signal
        imf = copy.copy(s)
        #find extrema for first iteration
        mini,maxi = find_extrema(s)

        if len(mini) == 0 or len(maxi) == 0:
            return None

        #keep track of extrema difference
        num_extrema = np.zeros([self.sift_stoppage_S, 2])  # first column are maxima, second column are minima
        num_extrema[-1, :] = [len(maxi), len(mini)]
        iter = 0
        while not stop:

            #set some things up for the iteration
            s_used = s
            left_padding = 0
            right_padding = 0

            #add an extra oscillation at the beginning and end of the signal to reduce edge effects; from Rato et. al (2008) section 3.2.2
            if self.sift_remove_edge_effects:
                Tl = maxi[0]  # index of left-hand (first) maximum
                tl = mini[0]  # index of left-hand (first) minimum

                Tr = maxi[-1]  # index of right hand (last) maximum
                tr = mini[-1]  # index of right hand (last) minimum

                #to reduce end effects, we need to extend the signal on both sides and reflect the first and last extrema
                #so that interpolation works better at the edges
                left_padding = max(Tl, tl)
                right_padding = len(s) - min(Tr, tr)

                #pad the original signal with zeros and reflected extrema
                s_used = np.zeros([len(s) + left_padding + right_padding])
                s_used[left_padding:-right_padding] = s

                #reflect the maximum on the left side
                imax_left = left_padding-tl
                s_used[imax_left] = s[Tl]
                #reflect the minimum on the left side
                imin_left = left_padding-Tl
                s_used[imin_left] = s[tl]

                #correct the indices on the right hand side so they're useful
                trr = len(s) - tr
                Trr = len(s) - Tr

                #reflect the maximum on the right side
                roffset = left_padding + len(s)
                imax_right = roffset+trr-1
                s_used[imax_right] = s[Tr]
                #reflect the minimum on the right side
                imin_right = roffset+Trr-1
                s_used[imin_right] = s[tr]

                #extend the array of maxima
                new_maxi = [i + left_padding for i in maxi]
                new_maxi.insert(0, imax_left)
                new_maxi.append(imax_right)
                maxi = new_maxi

                #extend the array of minima
                new_mini = [i + left_padding for i in mini]
                new_mini.insert(0, imin_left)
                new_mini.append(imin_right)
                mini = new_mini

            t = np.arange(0, len(s_used))
            fit_index = range(left_padding, len(s_used)-right_padding)

            #fit minimums with cubic splines
            spline_order = 3
            if len(mini) <= 3:
                spline_order = 1
            min_spline = splrep(mini, s_used[mini], k=spline_order)
            min_fit = splev(t[fit_index], min_spline)

            #fit maximums with cubic splines
            spline_order = 3
            if len(maxi) <= 3:
                spline_order = 1
            max_spline = splrep(maxi, s_used[maxi], k=spline_order)
            max_fit = splev(t[fit_index], max_spline)

            if plot:
                plt.figure()
                plt.plot(t[fit_index], max_fit, 'r-')
                plt.plot(maxi, s_used[maxi], 'ro')
                plt.plot(left_padding, 0.0, 'kx', markersize=10.0)
                plt.plot(left_padding+len(s), 0.0, 'kx', markersize=10.0)
                plt.plot(t, s_used, 'k-')
                plt.plot(t[fit_index], min_fit, 'b-')
                plt.plot(mini, s_used[mini], 'bo')
                plt.suptitle('Iteration %d' % iter)

            #take average of max and min splines
            z = (max_fit + min_fit) / 2.0

            #compute a factor used to dampen the subtraction of the mean spline; Rato et. al 2008, sec 3.2.3
            alpha,palpha = pearsonr(imf, z)
            alpha = min(alpha, 1e-2)

            #subtract off average of the two splines
            d = imf - alpha*z

            #set the IMF to the residual for next iteration
            imf = d

            #check for IMF S-stoppage criteria
            mini,maxi = find_extrema(imf)
            num_extrema = np.roll(num_extrema, -1, axis=0)
            num_extrema[-1, :] = [len(mini), len(maxi)]
            if iter >= self.sift_stoppage_S:
                num_extrema_change = np.diff(num_extrema, axis=0)
                de = np.abs(num_extrema[-1, 0] - num_extrema[-1, 1])
                if np.abs(num_extrema_change).sum() == 0 and de < 2 and np.abs(imf.mean()) < self.sift_mean_tol:
                    stop = True
            if iter > self.sift_max_iter:
                stop = True
            print 'Iter %d: len(mini)=%d, len(maxi=%d), imf.mean()=%0.6f, alpha=%0.2f' % (iter, len(mini), len(maxi), imf.mean(), alpha)
            #print 'num_extrema=',num_extrema
            iter += 1
        return imf
Ejemplo n.º 8
0
def compute_mean_envelope(s, nsamps=1000):
    """ Use random sampling to compute the mean envelope of a multi-dimensional signal.

    Args:
        s (np.ndarray): an NxT matrix describing a multi-variate signal. N is the number of channels, T is the number of time points.
        nsamps (int): the number of N dimensional projections to use in computing the multi-variate envelope.

    Returns:
        env (np.ndarray): an NxT matrix giving the multi-dimensional envelope of s.
    """

    N, T = s.shape

    #pre-allocate the mean envelope matrix
    mean_env = np.zeros([N, T])

    #generate quasi-random points on an N-dimensional sphere
    #stime = time.time()
    R = quasirand(N, nsamps, spherical=True)
    #etime = time.time() - stime
    #print 'Elapsed time for quasirand: %d seconds' % int(etime)

    stime = time.time()
    for k in range(nsamps):
        #istime = time.time()
        r = R[:, k].squeeze()

        #print 'k=%d, s.shape=%s, r.shape=%s' % (k, str(s.shape), str(r.shape))

        #project s onto a scalar time series using random vector
        #dtime = time.time()
        p = np.dot(s.T, r)
        #detime = time.time() - dtime
        #print '\t[%d] Time to do dot %0.6f s' % (k, detime)

        #print 'p.shape=',p.shape

        #identify minima and maxima of projection
        #eetime = time.time()
        mini_p, maxi_p = find_extrema(p)
        #eeetime = time.time() - eetime
        #print '\t[%d] time to find extrema: %0.6fs' % (k, eeetime)

        #for each signal dimension, fit maxima with cubic spline to produce envelope

        t = np.arange(T)
        for n in range(N):
            #sptime = time.time()
            mini = copy.copy(mini_p)
            maxi = copy.copy(maxi_p)
            if len(mini) < 4 or len(maxi) < 4:
                return None

            #extrapolate edges using mirroring
            lower_env_spline, upper_env_spline = create_mirrored_spline(
                mini, maxi, s[n, :].squeeze())
            if lower_env_spline is None or upper_env_spline is None:
                return None

            #evaluate upper and lower envelopes
            upper_env = splev(t, upper_env_spline)
            lower_env = splev(t, lower_env_spline)

            #compute the envelope for this projected dimension
            env = (upper_env + lower_env) / 2.0

            #update the mean envelope for this dimension in an online way
            delta = env - mean_env[n, :]
            mean_env[n, :] += delta / (k + 1)
            #esptime = time.time() - sptime
            #print '\t[%d] time for spline iteration on dimension %d: %0.6fs' % (k, n, esptime)
        #ietime = time.time() - istime
        #print '\t[%d] took %0.6f seconds' % (k, ietime)

    etime = time.time() - stime
    #print '%d samples took %0.6f seconds' % (nsamps, etime)

    return mean_env
Ejemplo n.º 9
0
    def normalized_hilbert(self, s):
        """
            Perform the "Normalized" Hilbert transform (Huang 2008 sec. 3.1) on the IMF s, decomposing the
            signal s into AM and FM components. Returns am,fm,phase,ifreq - am is the AM component, fm is the FM
            component, phase is the the arccos of fm, and ifreq is the instantaneous frequency.
        """

        x = copy.copy(s)
        iter = 0
        converged = False

        while not converged:
            #take the absolute value of the IMF and find the extrema
            absx = np.abs(x)
            mini, maxi = find_extrema(absx)
            if len(mini) == 0 or len(maxi) == 0:
                converged = True
                break
            spline_order = 3

            #reflect first and last maxima to remove edge effects for interpolation
            left_padding = maxi[0]
            right_padding = len(x) - maxi[-1]
            x_padded = np.zeros([len(x) + left_padding + right_padding])
            x_padded[left_padding:-right_padding] = absx
            x_padded[0] = absx[maxi[0]]
            x_padded[-1] = absx[maxi[-1]]

            #create new array of extremas
            new_maxi = [i + left_padding for i in maxi]
            new_maxi.insert(0, 0)
            new_maxi.append(len(x_padded) - 1)

            #fit a cubic spline to the extrema of the absolute value of the signal
            if len(maxi) <= 3:
                spline_order = 1
            max_spline = splrep(new_maxi, x_padded[new_maxi], k=spline_order)

            #use the spline to interpolate over the course of the signal
            t = np.arange(0, len(x_padded))
            fit_index = range(left_padding, len(x_padded) - right_padding)
            env = splev(t[fit_index], max_spline)
            """
            plt.figure()
            plt.plot(t, x_padded, 'k-')
            plt.plot(new_maxi, x_padded[new_maxi], 'ro-', markersize=8)
            plt.axis('tight')
            plt.suptitle('Iter %d' % iter)
            """

            #divide by envelope
            x /= env

            #check for convergence
            iter += 1
            if iter >= self.hilbert_max_iter:
                converged = True
            if (x.max() - 1.0) <= 1e-6:
                converged = True
            if len(mini) == 0 or len(maxi) == 0:
                converged = True

        #compute the FM and AM components
        fm = x
        am = s / fm

        #compute the phase
        phase = np.arccos(fm)

        #compute the instantaneous frequency
        ifreq = np.zeros([len(phase)])
        ifreq[1:] = np.diff(phase) * self.sample_rate

        return am, fm, phase, ifreq
Ejemplo n.º 10
0
    def compute_imf(self, s, plot=False):
        """
            Compute an intrinsic mode function from a signal s using sifting.
        """

        stop = False
        #make a copy of the signal
        imf = copy.copy(s)
        #find extrema for first iteration
        mini, maxi = find_extrema(s)

        if len(mini) == 0 or len(maxi) == 0:
            return None

        #keep track of extrema difference
        num_extrema = np.zeros(
            [self.sift_stoppage_S,
             2])  # first column are maxima, second column are minima
        num_extrema[-1, :] = [len(maxi), len(mini)]
        iter = 0
        while not stop:

            #set some things up for the iteration
            s_used = s
            left_padding = 0
            right_padding = 0

            #add an extra oscillation at the beginning and end of the signal to reduce edge effects; from Rato et. al (2008) section 3.2.2
            if self.sift_remove_edge_effects:
                Tl = maxi[0]  # index of left-hand (first) maximum
                tl = mini[0]  # index of left-hand (first) minimum

                Tr = maxi[-1]  # index of right hand (last) maximum
                tr = mini[-1]  # index of right hand (last) minimum

                #to reduce end effects, we need to extend the signal on both sides and reflect the first and last extrema
                #so that interpolation works better at the edges
                left_padding = max(Tl, tl)
                right_padding = len(s) - min(Tr, tr)

                #pad the original signal with zeros and reflected extrema
                s_used = np.zeros([len(s) + left_padding + right_padding])
                s_used[left_padding:-right_padding] = s

                #reflect the maximum on the left side
                imax_left = left_padding - tl
                s_used[imax_left] = s[Tl]
                #reflect the minimum on the left side
                imin_left = left_padding - Tl
                s_used[imin_left] = s[tl]

                #correct the indices on the right hand side so they're useful
                trr = len(s) - tr
                Trr = len(s) - Tr

                #reflect the maximum on the right side
                roffset = left_padding + len(s)
                imax_right = roffset + trr - 1
                s_used[imax_right] = s[Tr]
                #reflect the minimum on the right side
                imin_right = roffset + Trr - 1
                s_used[imin_right] = s[tr]

                #extend the array of maxima
                new_maxi = [i + left_padding for i in maxi]
                new_maxi.insert(0, imax_left)
                new_maxi.append(imax_right)
                maxi = new_maxi

                #extend the array of minima
                new_mini = [i + left_padding for i in mini]
                new_mini.insert(0, imin_left)
                new_mini.append(imin_right)
                mini = new_mini

            t = np.arange(0, len(s_used))
            fit_index = range(left_padding, len(s_used) - right_padding)

            #fit minimums with cubic splines
            spline_order = 3
            if len(mini) <= 3:
                spline_order = 1
            min_spline = splrep(mini, s_used[mini], k=spline_order)
            min_fit = splev(t[fit_index], min_spline)

            #fit maximums with cubic splines
            spline_order = 3
            if len(maxi) <= 3:
                spline_order = 1
            max_spline = splrep(maxi, s_used[maxi], k=spline_order)
            max_fit = splev(t[fit_index], max_spline)

            if plot:
                plt.figure()
                plt.plot(t[fit_index], max_fit, 'r-')
                plt.plot(maxi, s_used[maxi], 'ro')
                plt.plot(left_padding, 0.0, 'kx', markersize=10.0)
                plt.plot(left_padding + len(s), 0.0, 'kx', markersize=10.0)
                plt.plot(t, s_used, 'k-')
                plt.plot(t[fit_index], min_fit, 'b-')
                plt.plot(mini, s_used[mini], 'bo')
                plt.suptitle('Iteration %d' % iter)

            #take average of max and min splines
            z = (max_fit + min_fit) / 2.0

            #compute a factor used to dampen the subtraction of the mean spline; Rato et. al 2008, sec 3.2.3
            alpha, palpha = pearsonr(imf, z)
            alpha = min(alpha, 1e-2)

            #subtract off average of the two splines
            d = imf - alpha * z

            #set the IMF to the residual for next iteration
            imf = d

            #check for IMF S-stoppage criteria
            mini, maxi = find_extrema(imf)
            num_extrema = np.roll(num_extrema, -1, axis=0)
            num_extrema[-1, :] = [len(mini), len(maxi)]
            if iter >= self.sift_stoppage_S:
                num_extrema_change = np.diff(num_extrema, axis=0)
                de = np.abs(num_extrema[-1, 0] - num_extrema[-1, 1])
                if np.abs(num_extrema_change).sum() == 0 and de < 2 and np.abs(
                        imf.mean()) < self.sift_mean_tol:
                    stop = True
            if iter > self.sift_max_iter:
                stop = True
            print 'Iter %d: len(mini)=%d, len(maxi=%d), imf.mean()=%0.6f, alpha=%0.2f' % (
                iter, len(mini), len(maxi), imf.mean(), alpha)
            #print 'num_extrema=',num_extrema
            iter += 1
        return imf