[docs]defa_little_spike(nsw=121,nc=1):# creates a kind of waveform that resembles a spikewav=np.zeros(nsw)wav[0]=1wav[5]=-0.1wav[10]=-0.3wav[15]=-0.1sos=scipy.signal.butter(N=3,Wn=.15,output='sos')spike=scipy.signal.sosfilt(sos,wav)spike=-spike/np.max(spike)ifnc>1:spike=spike[:,np.newaxis]*scipy.signal.hamming(nc)[np.newaxis,:]returnspike
[docs]deftest_impeccable_dataset(self):fpga2bpod=np.array([11*1e-6,-20])# bpod starts 20 secs before with 10 ppm driftfpga_trials={'intervals':np.array([[0,9.5],[10,19.5]]),'stimOn_times':np.array([2,12]),'goCue_times':np.array([2.0001,12.0001]),'stimFreeze_times':np.array([4.,14.]),'feedback_times':np.array([4.0001,14.0001]),'errorCue_times':np.array([4.0001,np.nan]),'valveOpen_times':np.array([np.nan,14.0001]),'stimOff_times':np.array([6.0001,15.0001]),'itiIn_times':np.array([6.0011,15.000]),}alf_trials={'goCueTrigger_times_bpod':np.polyval(fpga2bpod,fpga_trials['goCue_times']-0.00067),'response_times_bpod':np.polyval(fpga2bpod,np.array([4.,14.])),'intervals_bpod':np.polyval(fpga2bpod,fpga_trials['intervals']),# Times from session start'goCueTrigger_times':fpga_trials['goCue_times']-0.00067,'response_times':np.array([4.,14.]),'intervals':fpga_trials['intervals'],'stimOn_times':fpga_trials['stimOn_times'],'goCue_times':fpga_trials['goCue_times'],'feedback_times':fpga_trials['feedback_times'],}qcs,qct=ephysqc.qc_fpga_task(fpga_trials,alf_trials)self.assertTrue(np.all([qcs[k]forkinqcs]))self.assertTrue(np.all([np.all(qct[k])forkinqct]))
[docs]@classmethoddeftearDownClass(cls)->None:# Clear overwritten methods by destroying cached instanceONE.cache_clear()ifcls.tempdir:cls.tempdir.cleanup()
[docs]defsetUp(self)->None:self.eid='b1c968ad-4874-468d-b2e4-5ffa9b9964e9'# make a temp probe insertionself.pname='probe02'# Find any existing insertions with this name and deleteprobe_insertions=self.one.alyx.rest('insertions','list',session=self.eid,name=self.pname,no_cache=True)forpiinprobe_insertions:self.one.alyx.rest('insertions','delete',pi['id'])# Create new insertion with this name and add teardown hook to delete itprobe_insertion=self.one.alyx.rest('insertions','create',data={'session':self.eid,'name':self.pname})self.addCleanup(self.one.alyx.rest,'insertions','delete',id=probe_insertion['id'])self.pid=probe_insertion['id']self.qc=ephysqc.EphysQC(self.pid,one=self.one)
[docs]deftest_ensure_data(self):# Make sure raises an error when no data presentutils.create_fake_raw_ephys_data_folder(self.one.eid2path(self.eid),populate=False)withself.assertRaises(AssertionError):self.qc._ensure_required_data()# Make sure it runs through fine when meta files are presentutils.create_fake_raw_ephys_data_folder(self.one.eid2path(self.eid),populate=True)self.qc._ensure_required_data()
[docs]deftest_spike_detection(self):""" Test that creates a synthetic dataset with spikes and an amplitude decay function with the probe gemetry, and then pastes spikes all around the dataset and detects and de-duplicates The test is feeding the detections in a new round of simulation, and then computing the zero-lag cross-correlation between input and simulated output, and asserting on the similarity """fs=30000nspikes=1200h=neuropixel.trace_header(version=1)ns,nc=(10000,len(h['x']))nss,ncs=(121,21)np.random.seed(973)display=Falsedata=make_synthetic_data(ns,nc,nss,ncs,nspikes)detects=spikes.detection(data,fs=fs,h=h,detect_threshold=-0.8,time_tol=.0006)sample_out=(detects.time*fs+nss/2-4).astype(np.int32)tr_out=detects.trace.astype(np.int32)data_out=make_synthetic_data(ns,nc,nss,ncs,tr=tr_out,sample=sample_out)ifdisplay:fromeasyqc.guiimportviewseiseqc=viewseis(data,si=1/30000*1e3,taxis=0,title='data')eqc.ctrl.add_scatter(detects.time*1e3,detects.trace)eqco=viewseis(data_out,si=1/30000*1e3,taxis=0,title='data_out')# noqaxcor=np.zeros(nc)fortrinnp.arange(nc):ifnp.all(data[:,tr]==0):xcor[tr]=1continuexcor[tr]=np.corrcoef(data[:,tr],data_out[:,tr])[1,0]assertnp.mean(xcor>.8)>.95assertnp.nanmedian(xcor)>.99
[docs]deftest_channel_detections(self):""" This test creates a synthetic dataset with voltage stripes and 3 types of bad channels 1) dead channels or low amplitude 2) noisy 3) out of the brain """data,channels=synthetic_with_bad_channels()labels,xfeats=voltage.detect_bad_channels(data.T,fs=30000)assertnp.all(np.where(labels==1)[0]==np.array(channels['idead']))assertnp.all(np.where(labels==2)[0]==np.array(channels['inoisy']))assertnp.all(np.where(labels==3)[0]==np.array(channels['ioutside']))