Ejemplo n.º 1
0
 def test_slicing(self):
     # test also the indexing versus direct slicing
     my_sig = np.random.rand(500,)
     wg = WindowGenerator(ns=500, nswin=100, overlap=50)
     # 1) get the window by
     my_rms = np.zeros((wg.nwin,))
     for first, last in wg.slices:
         my_rms[wg.iw] = rms(my_sig[first:last])
     my_rms_ = np.zeros((wg.nwin,))
     for wsig in wg.slice(my_sig):
         my_rms_[wg.iw] = rms(wsig)
     assert(np.all(my_rms_ == my_rms))
Ejemplo n.º 2
0
 def test_firstlast_slices(self):
     # test also the indexing versus direct slicing
     my_sig = np.random.rand(500,)
     wg = WindowGenerator(ns=500, nswin=100, overlap=50)
     # 1) get the window by
     my_rms = np.zeros((wg.nwin,))
     for first, last in wg.firstlast:
         my_rms[wg.iw] = rms(my_sig[first:last])
     # test with slice_array method
     my_rms_ = np.zeros((wg.nwin,))
     for wsig in wg.slice_array(my_sig):
         my_rms_[wg.iw] = rms(wsig)
     self.assertTrue(np.all(my_rms_ == my_rms))
     # test with the slice output
     my_rms_ = np.zeros((wg.nwin,))
     for sl in wg.slice:
         my_rms_[wg.iw] = rms(my_sig[sl])
     self.assertTrue(np.all(my_rms_ == my_rms))
Ejemplo n.º 3
0
def rmsmap(fbin, spectra=True):
    """
    Computes RMS map in time domain and spectra for each channel of Neuropixel probe

    :param fbin: binary file in spike glx format (will look for attached metatdata)
    :type fbin: str or pathlib.Path
    :param spectra: whether to compute the power spectrum (only need for lfp data)
    :type: bool
    :return: a dictionary with amplitudes in channeltime space, channelfrequency space, time
     and frequency scales
    """
    if not isinstance(fbin, spikeglx.Reader):
        sglx = spikeglx.Reader(fbin)
    rms_win_length_samples = 2**np.ceil(np.log2(sglx.fs * RMS_WIN_LENGTH_SECS))
    # the window generator will generates window indices
    wingen = dsp.WindowGenerator(ns=sglx.ns,
                                 nswin=rms_win_length_samples,
                                 overlap=0)
    # pre-allocate output dictionary of numpy arrays
    win = {
        'TRMS': np.zeros((wingen.nwin, sglx.nc)),
        'nsamples': np.zeros((wingen.nwin, )),
        'fscale': dsp.fscale(WELCH_WIN_LENGTH_SAMPLES,
                             1 / sglx.fs,
                             one_sided=True),
        'tscale': wingen.tscale(fs=sglx.fs)
    }
    win['spectral_density'] = np.zeros((len(win['fscale']), sglx.nc))
    # loop through the whole session
    for first, last in wingen.firstlast:
        D = sglx.read_samples(first_sample=first,
                              last_sample=last)[0].transpose()
        # remove low frequency noise below 1 Hz
        D = dsp.hp(D, 1 / sglx.fs, [0, 1])
        iw = wingen.iw
        win['TRMS'][iw, :] = dsp.rms(D)
        win['nsamples'][iw] = D.shape[1]
        if spectra:
            # the last window may be smaller than what is needed for welch
            if last - first < WELCH_WIN_LENGTH_SAMPLES:
                continue
            # compute a smoothed spectrum using welch method
            _, w = signal.welch(D,
                                fs=sglx.fs,
                                window='hanning',
                                nperseg=WELCH_WIN_LENGTH_SAMPLES,
                                detrend='constant',
                                return_onesided=True,
                                scaling='density',
                                axis=-1)
            win['spectral_density'] += w.T
        # print at least every 20 windows
        if (iw % min(20, max(int(np.floor(wingen.nwin / 75)), 1))) == 0:
            print_progress(iw, wingen.nwin)
    return win
Ejemplo n.º 4
0
    def __init__(self,
                 w,
                 fs=1,
                 gain=0.71,
                 color='k',
                 ax=None,
                 linewidth=0.5,
                 t0=0,
                 **kwargs):
        """
        Matplotlib display of traces as a density display

        :param w: 2D array (numpy array dimension nsamples, ntraces)
        :param fs: sampling frequency (Hz)
        :param ax: axis to plot in
        :return: None
        """
        w = w.reshape(w.shape[0], -1)
        nech, ntr = w.shape
        tscale = np.arange(nech) / fs * 1e3
        sf = gain / dsp.rms(w.flatten()) / 2
        if ax is None:
            self.figure, ax = plt.subplots()
        else:
            self.figure = ax.get_figure()
        self.plot = ax.plot(w * sf + np.arange(ntr),
                            tscale + t0,
                            color,
                            linewidth=linewidth,
                            **kwargs)
        ax.set_xlim(-1, ntr + 1)
        ax.set_ylim(tscale[0] + t0, tscale[-1] + t0)
        ax.set_ylabel('Time (ms)')
        ax.set_xlabel('Trace')
        ax.invert_yaxis()
        self.cid_key = self.figure.canvas.mpl_connect('key_press_event',
                                                      self.on_key_press)
        self.ax = ax
Ejemplo n.º 5
0
 def _label_probe_qc(self, folder_probe, df_units, drift):
     """
     Labels the json field of the alyx corresponding probe insertion
     :param folder_probe:
     :param df_units:
     :param drift:
     :return:
     """
     eid = self.one.eid_from_path(self.session_path)
     pdict = self.one.alyx.rest('insertions',
                                'list',
                                session=eid,
                                name=folder_probe.parts[-1])
     if len(pdict) != 1:
         return
     isok = df_units['label'] == 1
     qcdict = {
         'n_units': int(df_units.shape[0]),
         'n_units_qc_pass': int(np.sum(isok)),
         'firing_rate_max': np.max(df_units['firing_rate'][isok]),
         'firing_rate_median': np.median(df_units['firing_rate'][isok]),
         'amplitude_max_uV': np.max(df_units['amp_max'][isok]) * 1e6,
         'amplitude_median_uV': np.max(df_units['amp_median'][isok]) * 1e6,
         'drift_rms_um': rms(drift['drift_um']),
     }
     file_wm = folder_probe.joinpath('_kilosort_whitening.matrix.npy')
     if file_wm.exists():
         wm = np.load(file_wm)
         qcdict['whitening_matrix_conditioning'] = np.linalg.cond(wm)
     # groom qc dict (this function will eventually go directly into the json field update)
     for k in qcdict:
         if isinstance(qcdict[k], np.int64):
             qcdict[k] = int(qcdict[k])
         elif isinstance(qcdict[k], float):
             qcdict[k] = np.round(qcdict[k], 2)
     self.one.alyx.json_field_update("insertions", pdict[0]["id"], "json",
                                     qcdict)
Ejemplo n.º 6
0
 def test_smooth_lp(self):
     np.random.seed(458)
     a = np.random.rand(500,)
     a_ = smooth.lp(a, [0.1, 0.15])
     res = ft.hp(np.pad(a_, 100, mode='edge'), 1, [0.1, 0.15])[100:-100]
     self.assertTrue((rms(a) / rms(res)) > 500)
Ejemplo n.º 7
0
def wiggle(w,
           fs=1,
           gain=0.71,
           color='k',
           ax=None,
           fill=True,
           linewidth=0.5,
           t0=0,
           clip=2,
           **kwargs):
    """
    Matplotlib display of wiggle traces

    :param w: 2D array (numpy array dimension nsamples, ntraces)
    :param fs: sampling frequency
    :param gain: display gain
    :param color: ('k') color of traces
    :param ax: (None) matplotlib axes object
    :param fill: (True) fill variable area above 0
    :param t0: (0) timestamp of the first sample
    :return: None
    """
    nech, ntr = w.shape
    tscale = np.arange(nech) / fs
    sf = gain / np.sqrt(dsp.rms(w.flatten()))

    def insert_zeros(trace):
        # Insert zero locations in data trace and tt vector based on linear fit
        # Find zeros
        zc_idx = np.where(np.diff(np.signbit(trace)))[0]
        x1 = tscale[zc_idx]
        x2 = tscale[zc_idx + 1]
        y1 = trace[zc_idx]
        y2 = trace[zc_idx + 1]
        a = (y2 - y1) / (x2 - x1)
        tt_zero = x1 - y1 / a
        # split tt and trace
        tt_split = np.split(tscale, zc_idx + 1)
        trace_split = np.split(trace, zc_idx + 1)
        tt_zi = tt_split[0]
        trace_zi = trace_split[0]
        # insert zeros in tt and trace
        for i in range(len(tt_zero)):
            tt_zi = np.hstack((tt_zi, np.array([tt_zero[i]]), tt_split[i + 1]))
            trace_zi = np.hstack((trace_zi, np.zeros(1), trace_split[i + 1]))
        return trace_zi, tt_zi

    if not ax:
        ax = plt.gca()
    for ntr in range(ntr):
        if fill:
            trace, t_trace = insert_zeros(w[:, ntr] * sf)
            if clip:
                trace = np.maximum(np.minimum(trace, clip), -clip)
            ax.fill_betweenx(t_trace + t0,
                             ntr,
                             trace + ntr,
                             where=trace >= 0,
                             facecolor=color,
                             linewidth=linewidth)
        wplot = np.minimum(np.maximum(w[:, ntr] * sf, -clip), clip)
        ax.plot(wplot + ntr, tscale + t0, color, linewidth=linewidth, **kwargs)

    ax.set_xlim(-1, ntr + 1)
    ax.set_ylim(tscale[0] + t0, tscale[-1] + t0)
    ax.set_ylabel('Time (s)')
    ax.set_xlabel('Trace')
    ax.invert_yaxis()

    return ax