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))
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))
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
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
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)
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)
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