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 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.º 3
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.º 4
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.º 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
    def get_tuning_curves(self,
                          decomps=(('spike_rate', -1), ('full_psds', 0),
                                   ('full_psds', 1), ('full_psds', 2))):
        """ Get tuning curves for all sites and acoustic props, by decomposition. """

        all_curves = list()
        all_curves_x = list()
        data = {
            'bird': list(),
            'block': list(),
            'segment': list(),
            'hemi': list(),
            'electrode': list(),
            'cell_index': list(),
            'decomp': list(),
            'band': list(),
            'xindex': list(),
            'r2': list(),
            'aprop': list(),
            'dist_l2a': list(),
            'dist_midline': list(),
            'region': list(),
            'amp_slope': list(),
            'center_freq': list()
        }

        edata = pd.read_csv(
            os.path.join('/auto/tdrive/mschachter/data', 'aggregate',
                         'electrode_data+dist.csv'))
        i = edata.bird != 'BlaBro09xxF'
        edata = edata[i]

        perf_thresh = 0.05
        current_index = 0
        for k, aprop in enumerate(self.acoustic_props[0]):
            for j, (decomp, band_index) in enumerate(decomps):
                i = self.df.decomp == decomp
                assert i.sum() > 0, 'decomp=%s' % decomp

                # aggregate tuning curves across sites
                for (bird, block, segment, hemi), gdf in self.df[i].groupby(
                    ['bird', 'block', 'segment', 'hemi']):
                    wkey = '%s_%s_%s_%s_%s' % (bird, block, segment, hemi,
                                               decomp)
                    eperfs = self.encoder_perfs[wkey]
                    tuning_curves = self.tuning_curves[wkey]
                    tuning_curves_x = self.tuning_curves_x[wkey]
                    acoustic_feature_index = list(
                        self.acoustic_props[0]).index(aprop)
                    index2electrode = self.index2electrode[wkey]
                    cell_index2electrode = self.cell_index2electrode[wkey]

                    if decomp == 'spike_rate':
                        ncells, nprops, nbins = tuning_curves.shape
                        aprop_tc = tuning_curves[:, acoustic_feature_index, :]
                        aprop_tc_x = tuning_curves_x[:,
                                                     acoustic_feature_index, :]

                        for k in range(ncells):
                            e = cell_index2electrode[k]
                            ei = (edata.bird
                                  == bird) & (edata.block == block) & (
                                      edata.hemisphere
                                      == hemi) & (edata.electrode == e)
                            assert ei.sum() == 1
                            reg = clean_region(edata.region[ei].values[0])
                            dist_l2a = edata.dist_l2a[ei].values[0]
                            dist_midline = edata.dist_midline[ei].values[0]
                            if bird == 'GreBlu9508M':
                                dist_l2a *= 4

                            data['bird'].append(bird)
                            data['block'].append(block)
                            data['segment'].append(segment)
                            data['hemi'].append(hemi)
                            data['decomp'].append(decomp)
                            data['band'].append(band_index)
                            data['r2'].append(eperfs[k])
                            data['xindex'].append(current_index)
                            data['aprop'].append(aprop)
                            data['electrode'].append(e)
                            data['cell_index'].append(k)
                            data['dist_l2a'].append(dist_l2a)
                            data['dist_midline'].append(dist_midline)
                            data['region'].append(reg)

                            slope = 0.
                            if aprop in [
                                    'maxAmp', 'meanspect', 'sal', 'skewtime'
                            ]:
                                # compute slope of tuning curve
                                _tc = aprop_tc[k, :]
                                _tc_x = aprop_tc_x[k, :]
                                if ~np.any(np.isnan(_tc)) & ~np.any(
                                        np.isinf(_tc)) & (np.sum(np.abs(_tc))
                                                          != 0):
                                    try:
                                        slope, b = np.polyfit(_tc_x,
                                                              _tc,
                                                              deg=1)
                                    except ValueError:
                                        print('Problem estimating slope for aprop=%s, decomp=spike_rate, cell+index=%d, bird=%s, block=%s, segment=%s, hemi=%s' % \
                                              (aprop, k, bird, block, segment, hemi))
                                        slope = 0.

                            cfreq = 0
                            if aprop == 'meanspect':
                                # compute center frequency
                                _tc = aprop_tc[k, :]
                                _tc_x = aprop_tc_x[k, :]
                                mini, maxi = find_extrema(_tc)
                                if len(maxi) > 0:
                                    cfreq = _tc_x[maxi[0]]

                            data['amp_slope'].append(slope)
                            data['center_freq'].append(cfreq)

                            current_index += 1

                    elif decomp == 'full_psds':

                        nelectrodes, nfreqs, nprops, nbins = tuning_curves.shape
                        aprop_tc = tuning_curves[:, band_index,
                                                 acoustic_feature_index, :]
                        aprop_tc_x = tuning_curves_x[:, band_index,
                                                     acoustic_feature_index, :]

                        for k, e in enumerate(index2electrode):
                            ei = (edata.bird
                                  == bird) & (edata.block == block) & (
                                      edata.hemisphere
                                      == hemi) & (edata.electrode == e)
                            assert ei.sum() == 1
                            reg = clean_region(edata.region[ei].values[0])
                            dist_l2a = edata.dist_l2a[ei].values[0]
                            dist_midline = edata.dist_midline[ei].values[0]
                            if bird == 'GreBlu9508M':
                                dist_l2a *= 4

                            data['bird'].append(bird)
                            data['block'].append(block)
                            data['segment'].append(segment)
                            data['hemi'].append(hemi)
                            data['decomp'].append(decomp)
                            data['band'].append(band_index)
                            data['r2'].append(eperfs[k, band_index])
                            data['xindex'].append(current_index)
                            data['aprop'].append(aprop)
                            data['electrode'].append(e)
                            data['cell_index'].append(-1)
                            data['dist_l2a'].append(dist_l2a)
                            data['dist_midline'].append(dist_midline)
                            data['region'].append(reg)

                            slope = 0.
                            if aprop in [
                                    'maxAmp', 'meanspect', 'sal', 'skewtime'
                            ]:
                                # compute slope of tuning curve
                                _tc = aprop_tc[k, :]
                                _tc_x = aprop_tc_x[k, :]
                                if ~np.any(np.isnan(_tc)) & ~np.any(
                                        np.isinf(_tc)) & (np.sum(np.abs(_tc))
                                                          != 0):
                                    try:
                                        slope, b = np.polyfit(_tc_x,
                                                              _tc,
                                                              deg=1)
                                    except ValueError:
                                        print('Problem estimating slope for aprop=%s, decomp=lfp_psd, band_index=%d, cell+index=%d, bird=%s, block=%s, segment=%s, hemi=%s' % \
                                              (aprop, band_index, k, bird, block, segment, hemi))
                                        print(_tc)
                                        slope = 0.

                            cfreq = 0
                            if aprop == 'meanspect':
                                # compute center frequency
                                _tc = aprop_tc[k, :]
                                _tc_x = aprop_tc_x[k, :]
                                mini, maxi = find_extrema(_tc)
                                if len(maxi) > 0:
                                    cfreq = _tc_x[maxi[0]]

                            data['amp_slope'].append(slope)
                            data['center_freq'].append(cfreq)

                            current_index += 1
                    else:
                        continue

                    all_curves.extend(aprop_tc)
                    all_curves_x.extend(aprop_tc_x)

        all_curves = np.array(all_curves)
        all_curves_x = np.array(all_curves_x)
        df = pd.DataFrame(data)
        """
        # get rid of bad tuning curves
        tc_sum = np.abs(all_curves).sum(axis=1)
        # good_i = (tc_sum > 0) & (all_perfs > perf_thresh)
        tc_diff = np.diff(all_curves, axis=1)
        tc_diff_max = tc_diff.max(axis=1)
        tc_diff_min = tc_diff.min(axis=1)
        tc_max = all_curves.max(axis=1)
        tc_min = all_curves.min(axis=1)
        good_i = (all_perfs > perf_thresh) & (tc_diff_max < 1.5) & (tc_diff_min > -1.5) & (tc_max < 2) & (tc_min > -2) & (tc_max > -0.5) & (tc_sum > 0)
        """

        return all_curves_x, all_curves, df