/* $Id: samutils.hoc,v 1.59 2009/12/11 03:56:04 samn Exp $ */ use_samn_utils=0 if(name_declared("INSTALLED_sn")){ use_samn_utils=1 install_sn() } else { printf("Warning: couldn't install samnutils.mod\n") } //whether to print debug info mydbg=0 ////////////////////////////////////////////////////////////////////////////////////// //color consts black=1 red=2 blue=3 green=4 ////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// //time functions ////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// //drawing functions //plot and mark $o1 in color $2 using optional xinc = $3 proc plotit () { local xi localobj vv vv=$o1 clr=$2 if(numarg()>2)xi=$3 else xi=1 vv.plot(g,xi,clr,4) vv.mark(g,xi,"O",12,clr,1) } //plot $o1 with error bars in $o2, using xvec $o3, and color $4 proc plotite () { local clr localobj vv,ve,vx vv=$o1 ve=$o2 vx=$o3 clr=$4 vv.ploterr(g,vx,ve,15,clr,4) vv.plot(g,vx,clr,4) vv.mark(g,vx,"O",15,clr,1) } ////////////////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////// //string functions func strlen(){ localobj strobj strobj = new StringFunctions() if(argtype(1)==1){ return strobj.len($o1.s) } else if(argtype(1)==2){ return strobj.len($s1) } printf("strlen ERRA: invalid argtype\n") return 0 } func strcpy(){ if(argtype(1)==1 && argtype(2)==1){ sprint($o1.s,$o2.s) return 1 } else if(argtype(1)==1 && argtype(2)==2){ sprint($o1.s,$s2) return 1 } return 0 } /////////////////////////////////////////////////////////// //utility functions func MIN(){ if($1 <= $2) return $1 return $2 } func MAX(){ if($1 >= $2) return $1 return $2 } //return 1 iff int($1) is a power of 2 //$o1 can be list or vector, returns //true iff their size,count is powof2 func powof2(){ local val if(argtype(1)==0){ val = int($1) } else if(isobj($o1,"Vector")){ val = $o1.size } else if(isobj($01,"List")){ val = $o1.count } else { printf("powof2 ERRA: invalid arg type\n") return -1 } if(val==1) return 1 if(val%2==1 || val<=0) return 0 while(val>=2){ if(val%2==1) return 0 val /= 2 } return 1 } //return closest powof2 >= $1 //$o1 can be list or vector, returns //closest powof2 >= their size,count func ceilpowof2(){ local ceilval,val if(argtype(1)==0){ val = $1 } else if(isobj($o1,"Vector")){ val = $o1.size } else if(isobj($o1,"List")){ val = $o1.count } else { printf("ceilpowof2 ERRA: invalid arg type\n") return -1 } ceilval = 1 while(ceilval < val) ceilval *= 2 return ceilval } //return closest powof2 <= $1 //$o1 can be list or vector, returns //closest powof2 <= their size,count func floorpowof2(){ local floorval,val if(argtype(1)==0){ val = $1 } else if(isobj($o1,"Vector")){ val = $o1.size } else if(isobj($o1,"List")){ val = $o1.count } else { printf("floorpowof2 ERRA: invalid arg type\n") return -1 } floorval = val while(!powof2(floorval) && floorval >= 2) floorval -= 1 while(floorval > val) floorval /= 2 return floorval } //discrete wavelet transform using db4 //$o1 = input vector //$2 = floor ? (if true use floor of pow of 2 of size, else ceil) //$3 = inverse transform //returns vector of 2^n dwt coefficients from d4t obfunc dwt(){ local sz,inv,flr localobj d4t,vt d4t = new Vector() if(!INSTALLED_d4t_wavelet){ printf("dwt ERRA: d4t not installed!\n") return d4t } if(!isobj($o1,"Vector")){ printf("dwt ERRB: arg 1 must be vector!\n") return d4t } if(numarg() > 1) flr = $2 else flr = 1 if(numarg() > 2) inv = $3 else inv = 1 if(powof2($o1)){ vt = $o1 sz = $o1.size } else { if(flr) sz = floorpowof2($o1) else sz = ceilpowof2($o1) vt = new Vector(sz) vt.samp($o1,sz) } d4t = new Vector(sz) d4t.d4t(vt,inv,0) return d4t } //zeroes a level of dwt coefficients (for filtering) //levels are 0 - (n-1) where 2^n is size of //dwt coeffs vec //$o1 = vector of dwt coefficients //$2 = level to zero out or vec of levels to zero out func zerodwtlevel(){ local idx,jdx,maxdx,offset,level localobj vlev if(!isobj($o1,"Vector")){ printf("zerodwtlevel ERRA: arg 1 must be vector!\n") return 0 } if(argtype(2)==0){ level = $2 offset = 2^level maxdx = 2*offset for(idx=offset;idx 1) rsz = $2 else rsz = -1 if(numarg() > 2) stp = $3 else stp = 0 nlevels = log($o1.size) / log(2) for(idx=0;idx 0){ if(stp){ vtmp2 = stepupsamp(vtmp,rsz) } else { vtmp2 = new Vector(rsz) vtmp2.samp(vtmp,rsz) } lv.append(vtmp2) } else { lv.append(vtmp) } } return lv } //takes list of vectors , returns vector with avgs obfunc GetListAvg(){ local idx,jdx,mx localobj vavg mx=0 for idx=0,$o1.count-1 if($o1.o(idx).size>mx) mx = $o1.o(idx).size if(mx==0) return nil else vavg = new Vector(mx) for idx=0,$o1.count-1 { for jdx=0,$o1.o(idx).size-1{ vavg.x(jdx) = vavg.x(jdx) + $o1.o(idx).x(jdx) } } vavg.div($o1.count) // return vavg } //intervals(TRAIN,OUTPUT) //$o1 spikes/voltages //$o2 interval vector func intervals () { if ($o1.size<=1) { printf("%s size <2 in intervals()\n",$o1) return 0} $o2.deriv($o1,1,1) return $o2.size } //return derivative of input vector //output vector has same size as input //$o1 = input vector //vp = output vector obfunc Deriv(){ localobj vp vp=new Vector($o1.size) if($o1.size < 2){ printf("Deriv ERRAA: input vec size < 2!\n") return vp } vp.deriv($o1,1,2) return vp } //return list of input vector ($o1), //and 1st & 2nd derivs obfunc Traj(){ localobj lv,vp,vpp lv = new List() vp = Deriv($o1) vpp = Deriv(vp) lv.append($o1) lv.append(vp) lv.append(vpp) return lv } //plot list.o(1) vs list.o(0) //and list.o(2) vs list.o(1) //return list of graphs obfunc PlotTraj(){ localobj lv,vp,vpp,lg lg = new List() lv = $o1 vp = lv.o(1) vpp = lv.o(2) vp.label("v'") vpp.label("v''") lg.append(new Graph()) vp.plot(lg.o(lg.count-1),lv.o(0)) lg.append(new Graph()) vpp.plot(lg.o(lg.count-1),vp) return lg } //sets up recording of spike times //$o1 = cell //$o2 = printlist obj //$s3 = string //$4 = spike thresh proc RecordCell(){ if(numarg()==3){ $o2 = new_printlist_nc($o1,0,$s3) } else if(numarg()==4){ $o2 = new_printlist_nc($o1,0,$s3,$4) } } //$o1 = vec //$2 = size //allocates memory for vector but resizes it to 0 proc VecMalloc(){ $o1 = new Vector() $o1.resize($2) $o1.resize(0) } proc PrintBurstInfo(){ if($o1.size < 4){ printf("invalid size for burst info vector\n") return } printf("num bursts = %d\n",$o1.x(0)) printf("spikes per burst = %d\n",$o1.x(1)) printf("inter-spike time = %g\n",$o1.x(2)) printf("inter-burst time = %g\n",$o1.x(3)) } //$o1 = spike times //$o2 = output vector[num_bursts,spikes_per_burst,inter_spike_time,inter_burst_time] func GetBurstInfo(){ local i,lg_thresh,sm_thresh,spikes_per_burst localobj v_inter_spike,v_inter_burst,v_intervals lg_thresh = 20 //min time btwn bursts sm_thresh = 3.55 //max time btwn spikes within a burst if($o1.size < 2){ $o2 = new Vector() $o2.resize(4) $o2.x(0)=$o2.x(1)=$o2.x(2)=$o2.x(3)=0 printf("need at least two spikes to get burst info\n") return 0 } v_intervals = new Vector() intervals($o1,v_intervals) //printf("here are the intervals:\n") //v_intervals.printf VecMalloc(v_inter_spike,v_intervals.size) VecMalloc(v_inter_burst,v_intervals.size) for(i=0;i= lg_thresh){ //printf("\tinter-burst time = %g\n",v_intervals.x(i)) v_inter_burst.append(v_intervals.x(i)) } else if(v_intervals.x(i) <= sm_thresh) { //printf("\tinter-spike time = %g\n",v_intervals.x(i)) v_inter_spike.append(v_intervals.x(i)) } } $o2 = new Vector() $o2.resize(4) //if no valid inter-spike / inter-burst found, return 0 if(v_inter_spike.size == 0 && v_inter_burst.size == 0) { printf("\tno valid inter-spike / inter-burst found\n") return 0 } //if( ((v_inter_burst.max-v_inter_burst.min) / v_inter_burst.max) >= 0.3){ //printf("\tno consistent inter-burst time\n") // return 0 //} $o2.x(0) = v_inter_burst.size() + 1 //# of bursts $o2.x(1) = $o1.size / $o2.x(0) //# of spikes per burst, assumes they are equally distributed if(v_inter_spike.size > 0) { $o2.x(2) = v_inter_spike.median() } //inter-spike time if(v_inter_burst.size > 0) { $o2.x(3) = v_inter_burst.median() } //inter-burst time //if no valid inter-spike / inter-burst found, return 0 //if($o2.x(2) == 0 && $o2.x(3) == 0) { // printf("\tno valid inter-spike / inter-burst found\n") // return 0 //} return 1 } //$o1 = stim //$2 = min amp //$3 = max amp //$4 = amp inc //$o5 = vector of # of bursts //$o6 = vector of # of spikes per burst //$o7 = inter-spike times //$o8 = inter-burst times //$o9 = cell func GetBurstInfoVecs(){ local curamp,minamp,maxamp,ampinc localobj cell_rec,v_burst RecordCell($o9,cell_rec,"cell.soma.v") minamp = $2 maxamp = $3 ampinc = $4 $o5 = new Vector() $o6 = new Vector() $o7 = new Vector() $o8 = new Vector() v_burst = new Vector() $o1.del = 40 $o1.dur = 400 tstop = 500 for(curamp=minamp;curamp<=maxamp;curamp+=ampinc){ $o1.amp = curamp printf("getting burst info for amp = %g\n",curamp) run() GetBurstInfo(cell_rec.tvec,v_burst) $o5.append(v_burst.x(0)) $o6.append(v_burst.x(1)) $o7.append(v_burst.x(2)) $o8.append(v_burst.x(3)) } return 1 } //$o1 = graph //$o2 = vector of # of bursts //$o3 = vector of # of spikes per burst //$o4 = inter-spike times //$o5 = inter-burst times //$o6 = amp //$7 , whether to label //$8 , whether to make new graph proc PlotBurstInfoVecs(){ if($8){ $o1 = new Graph() } if($7){ $o2.label("num bursts") $o3.label("spikes per burst") $o4.label("inter-spike time") $o5.label("inter-burst time") } $o3.plot($o1,$o6,1,1) //color brush $o5.plot($o1,$o6,2,1) $o2.plot($o1,$o6,3,1) $o4.plot($o1,$o6,4,1) // $o3.mark($o1,$o6,"+",6,1,1) //style size color brush // $o5.mark($o1,$o6,"t",6,2,1) // $o2.mark($o1,$o6,"s",6,3,1) // $o4.mark($o1,$o6,"o",6,4,1) $o1.flush() } //$o1 = voltage vector (x-axis=time, y-axis=voltage) //$o2 = output spike times //$3 = threshold for spike //$4 = minimum interspike time proc GetSpikeTimes() { local ii,v,dipthresh $o2 = new Vector($o1.size) $o2.resize(0) dipthresh = 1.5 * $3 for(ii=0;ii<$o1.size;ii+=1) { v = $o1.x(ii) if(v >= $3) { //is v > threshold? if($o2.size>0) { //make sure at least $4 time has passed if(dt*ii-$o2.x($o2.size-1) < $4) { continue } } while( ii+1<$o1.size) { //get peak of spike if( $o1.x(ii) > $o1.x(ii+1) ) { break } ii += 1 } $o2.append(dt*ii) //store spike location while(ii<$o1.size) { //must dip down sufficiently if($o1.x(ii) <= dipthresh) { break } ii += 1 } } } } //just moves 1.25 ms to left & right of spikes //returns vector with 1 if its in spike time window //and 0 otherwise //$o1 = voltage vector //$o2 = spike times //$3 = 1/2 time window around spikes [optional, default=1.25ms] obfunc GetSpikeWindow(){ local leftv,rightv,meanv,dthresh,left,right,w,idx,jdx,mint,st,twin2\ localobj vspikes,vvolt,vns vvolt = $o1 vspikes = $o2 if(numarg() > 2) twin2 = $3 else twin2 = 1.25 vns = new Vector(vvolt.size) // vns.copy(vvolt) for(idx = 0; idx < $o2.size; idx+=1){ st = vspikes.x(idx) left = st/dt - twin2/dt if(left < 0) left = 0 right = st/dt + twin2/dt if(right >= vvolt.size) right = vvolt.size-1 w = right - left if(w == 0) w = 0 leftv = vvolt.x(left) rightv = vvolt.x(right) for(jdx=left;jdx<=right;jdx+=1){ vns.x(jdx) = 1 // vns.x(jdx) = ((w-(jdx-left))*leftv)/w + ((w-(right-jdx))*rightv)/w } } return vns } //$o1 = voltage vector //$o2 = spike times obfunc CutOutSpikes(){ local leftv,rightv,meanv,dthresh,left,right,w,idx,jdx,mint,st\ localobj vspikes,vvolt,vns,vderiv vvolt = $o1 vspikes = $o2 vderiv = Deriv(vvolt) meanv = vderiv.mean dthresh = meanv+vderiv.stdev/4 printf("dthresh = %f\n",dthresh) vns = new Vector(vvolt.size) vns.copy(vvolt) for(idx = 0; idx < $o2.size; idx+=1){ st = vspikes.x(idx) left = st/dt - 5 if(left < 0) left = 0 right = st/dt + 5 if(right >= vderiv.size) right = vderiv.size-1 while(left > 0){ if(vderiv.x(left) < dthresh){ break } left-=1 } while(right < vvolt.size-1){ if(abs(vderiv.x(right)) < dthresh){ break } right+=1 } w = right - left if(w == 0) w = 0 leftv = vvolt.x(left) rightv = vvolt.x(right) for(jdx=left;jdx<=right;jdx+=1){ // vns.x(jdx) = 60 vns.x(jdx) = ((w-(jdx-left))*leftv)/w + ((w-(right-jdx))*rightv)/w } } return vns } //$o1 = voltage vector (x-axis=time, y-axis=voltage) //$o2 = spike time vector //$o3 = graph obj proc PlotSpikeTimes(){ local idx $o1.plot($o3,dt) for(idx=0;idx<$o2.size;idx+=1){ $o3.mark($o2.x(idx),$o1.x($o2.x(idx)/dt),1,4,red,1) } } //get interspike interval times //$o1 = spike train //$o2 = output ISI start times //$o3 = output ISI end times func GetISITimes(){ local idx,mindist,tmp mindist = 1.25 //min dist after & before spike to go $o2 = new Vector() $o3 = new Vector() if($o1.size < 2){ printf("need at least two spikes to get ISI\n") return 0 } for(idx=0;idx<$o1.size-1;idx+=1){ $o2.append($o1.x(idx)+mindist) $o3.append($o1.x(idx+1)-mindist) //swap if incorrect order due to mindist requirement if($o3.x($o3.size-1) <= $o2.x($o2.size-1)){ tmp = $o3.x($o3.size-1) $o3.x($o3.size-1) = $o2.x($o2.size-1) + dt $o2.x($o2.size-1) = tmp } } return 1 } //get trajectory v,v',v'' //$o1 = voltage vector //$2 = start time //$3 = end time //$o4 = output copy of v //$o5 = 1st deriv (v') //$o6 = 2nd deriv (v'') func GetTrajectory(){ local startt,endt $o4 = new Vector() $o5 = new Vector() $o6 = new Vector() startt = $2 endt = $3 if(startt >= endt){ printf("GetTrajectory ERRA: invalid time range (%f,%f)!\n",$2,$3) return 0 } endt = endt / dt startt = startt / dt $o4.copy($o1,startt,endt) //copy v if($o4.size < 2){ $o4.resize(0) printf("GetTrajectory ERRB: time range %f ms too small!\n",(endt-startt)) return 0 } $o5 = Deriv($o4) $o6 = Deriv($o5) return 1 } //get all trajectories from start/end time vecs //$o1 = voltage vector //$o2 = start times //$o3 = end times //$o4 = list of v //$o5 = list of v' //$o6 = list of v'' func GetTrajectories(){ local idx,allbad localobj v1,v2,v3 allbad = 1 for(idx=0;idx<$o2.size;idx+=1){ v1 = new Vector() v2 = new Vector() v3 = new Vector() if(GetTrajectory($o1,$o2.x(idx),$o3.x(idx),v1,v2,v3)){ $o4.append(v1) $o5.append(v2) $o6.append(v3) allbad = 0 } } return !allbad } //$o1 = graph1 //$o2 = graph2 //$o3 = v //$o4 = v' //$o5 = v'' func PlotTrajectory(){ if(!isassigned($o1)) $o1 = new Graph() $o4.label("v'") $o4.plot($o1,$o3) if(!isassigned($o2)) $o2 = new Graph() $o5.label("v''") $o5.plot($o2,$o4) return 1 } //$o1 = list of v //$o2 = list of v' //$o3 = list of v'' //$o4 = list of graphs func PlotTrajectories(){ local idx localobj mygv,mygvv for(idx=0;idx<$o1.count;idx+=1){ mygv=new Graph() mygvv=new Graph() PlotTrajectory(mygv,mygvv,$o1.o(idx),$o2.o(idx),$o3.o(idx)) $o4.append(mygv) $o4.append(mygvv) } return 1 } //euclid dist btwn 2 points in 3D space func EuclidDist(){ local x1,y1,z1,x2,y2,z2 x1=$1 y1=$2 z1=$3 x2=$4 y2=$5 z2=$6 return sqrt( (x1-x2)^2 + (y1-y2)^2 + (z1-z2)^2 ) } //$o1 = vec of x1 //$o2 = vec of y1 //$o3 = vec of z1 //$o4 = vec of x2 //$o5 = vec of y2 //$o6 = vec of z2 func VEuclidDist(){ localobj l1,l2 if(!use_samn_utils){ printf("VEuclidDist ERRA: samnutils.mod not available\n") return -1 } l1=new List() l2=new List() l1.append($o1) l1.append($o2) l1.append($o3) l2.append($o4) l2.append($o5) l2.append($o6) return LDist_sn(l1,l2)//in /usr/site/nrniv/local/mod/samnutils.mod } //$o1 = vec of x1 //$o2 = vec of y1 //$o3 = vec of z1 //$o4 = vec of x2 //$o5 = vec of y2 //$o6 = vec of z2 func VSQDist(){ localobj l1,l2 if(!use_samn_utils){ printf("VSQDist ERRA: samnutils.mod not available\n") return -1 } l1=new List() l2=new List() l1.append($o1) l1.append($o2) l1.append($o3) l2.append($o4) l2.append($o5) l2.append($o6) return LDist_sn(l1,l2,SQDIFF_sn)//in /usr/site/nrniv/local/mod/samnutils.mod } //resample a vec to new size using linear interpolation //$o1 = vec //$2 = new size func Resample(){ local newsz,idxdest,idxsrc,val,fctr,frac,last,lastset localobj vtmp vtmp = new Vector($2) fctr = $o1.size / $2 vtmp.x(0) = $o1.x(0) idxsrc = fctr for(idxdest=1;idxdest<$2-1;idxdest+=1){ idxsrc = idxdest * fctr frac = idxsrc - int(idxsrc) idxsrc = int(idxsrc) if(idxsrc+1>=$o1.size){ vtmp.x(idxdest) = $o1.x(idxsrc) continue } val = (1-frac) * $o1.x(idxsrc) + frac * $o1.x(idxsrc+1) vtmp.x(idxdest) = val } vtmp.x($2-1) = $o1.x($o1.size-1) $o1.resize($2) $o1.copy(vtmp) return 1 } //$o1 = stim //$o2 = voltage vector (x-axis = time , y-axis = volt) //$3 = min amp //$4 = max amp //$5 = amp inc //$6 = threshold for spike //$o7 = amp vec //$o8 = f vec //$o9 = cell proc GetIFVecs() { local minamp,maxamp,ampinc,totalt,curamp,thresh minamp = $3 maxamp = $4 ampinc = $5 thresh = $6 $o7 = new Vector() $o8 = new Vector() totalt = $o1.dur / 1000 for(curamp = minamp; curamp <= maxamp; curamp += ampinc) { $o1.amp = curamp RecordCell($o9,$o2,"soma.v",$6) run() $o7.append(curamp) $o8.append($o2.tvec.size * (1/totalt)) } } proc PlotIFVec(){ localobj g g = new Graph() $o1.label("Hz") $o2.label("nA") $o1.plot(g,$o2) } //$s1 = output file name //$o2 = amp vec //$o3 = freq vec func SaveIFCurve(){ localobj f f = new File() f.wopen($s1) if(!f.isopen()) { printf("couldn't open %s for writing\n",$s1) return 0 } if(!$o2.vwrite(f)){ printf("couldn't write amp vec to %s\n",$s1) return 0 } if(!$o3.vwrite(f)){ printf("couldn't write freq vec to %s\n",$s1) return 0 } f.close() return 1 } //$s1 = input file name //$o2 = amp vec //$o3 = freq vec func ReadIFCurve(){ localobj f f = new File() f.ropen($s1) if(!f.isopen()) { printf("couldn't open %s for reading\n",$s1) return 0 } $o2 = new Vector() if(!$o2.vread(f)){ printf("couldn't read amp vec from %s\n",$s1) return 0 } $o3 = new Vector() if(!$o3.vread(f)){ printf("couldn't read freq vec from %s\n",$s1) return 0 } f.close() return 1 } //writes vecs to file //$s1 = path to file //$o2 ... $on = vectors to be written to file func WriteVecs(){ local i localobj f f = new File() f.wopen($s1) if(!f.isopen()) { printf("couldn't open %s for writing\n",$s1) return 0 } for(i=2;i<=numarg();i+=1){ printf("writing vector %d\n",i-1) if(!$oi.vwrite(f)){ printf("couldn't write vector %d to %s\n",i-1,$s1) return 0 } } f.close() return 1 } //reads vecs from file //$s1 = path to file //$o2 ... $on = vectors to be read from file func ReadVecs(){ local i localobj f f = new File() f.ropen($s1) if(!f.isopen()) { printf("couldn't open %s for reading\n",$s1) return 0 } for(i=2;i<=numarg();i+=1){ printf("reading vector %d\n",i-1) if(!$oi.vread(f)){ printf("couldn't read vector %d from %s\n",i-1,$s1) return 0 } } f.close() return 1 } //$s1 = path to file //$2 = index of vector to read //$o3 = vector to read to func ReadVecX(){ local idx localobj f f = new File() f.ropen($s1) if(!f.isopen()) { printf("couldn't open %s for reading\n",$s1) return 0 } if(!isassigned($o3)) $o3 = new Vector() for(idx=0;idx<=$2;idx+=1){ if(f.eof()){ f.close() return 0 } $o3.vread(f) } f.close() return 1 } //tests whether file exists by opening in 'r' mode func FileExists(){ localobj f f = new File() f.ropen($s1) if(f.isopen()){ f.close() return 1 } return 0 } //reads vecs from file //$s1 = path to file //$o2 ... $on = vectors to be read from file /*func Read2DVec(){ local i localobj f,cv f = new File() f.ropen($s1) if(!f.isopen()) { printf("couldn't open %s for reading\n",$s1) return 0 } //first vector just has # of vectors in file cv = new Vector() if(!cv.vread(f)){ printf("couldn't get # vectors in file\n") return 0 } printf("there are %d vecs in file\n",cv.size) for(i=0;i1) w=$2 else w=5 myvtmp=new Vector(myv.size) myvtmp.copy(myv) for(idx=w;idx0) myvtmp.x(idx) = val / cnt } myv.copy(myvtmp) } proc Smooth2(){ local idx,w,val,jdx,cnt,wght,taus localobj myv,myvtmp myv=$o1 w = taus/2 wght=0 myvtmp=new Vector(myv.size) if(numarg()>1) taus=3/$2 else taus=3/dt // myvtmp.copy(myv) for(idx=0;idx<2*w;idx+=1) wght += exp(-abs(idx-w)/taus) for(idx=w;idx0) myvtmp.x(idx) = val / wght//cnt // if(cnt>0) myvtmp.x(idx) = val / exp(1) } myv.copy(myvtmp) } //does smoothing of 1d vector using exp kernel //$o1 = input vector , (also output) //$2 = 1/2 width of kernel //$3 = tstep proc ExpSmooth(){ local idx,w,val,jdx,wght,myt localobj myv,myvtmp myv = $o1 if(numarg()>1) w = $2 else w = 4 if(numarg()>2) tstep = $3 else tstep=1 wght = 0 myt=0 myvtmp=new Vector(myv.size) myt = tstep for(idx=0;idx thresh since it's probably //a problem with recording equipment ... assumes only 1 point //in a row will be an outlier (since it replaces point with //average of surrounding two neighbors) //$o1 = vector //$2 = thresh //$3 = whether to only fix endpoints //returns -1 on error, 1 if fixed any, 0 otherwise func FixEEGOutliers(){ local idx,thresh,med,ept,fixedany localobj vtmp if(numarg() < 1){ printf("FixEEGOutliers ERRA: incorrect # of args\n") return -1 } if(!isobj($o1,"Vector")){ printf("FixEEGOutliers ERRB: require vector arg\n") return -1 } vtmp = $o1 med = $o1.median thresh = 20000 fixedany = 0 if(numarg() > 1) if(argtype(2)==0) thresh = $2 ept = 0//default don't ONLY fix endpoints if(numarg() > 2) if(argtype(3)==0) ept = $3 if(mydbg) printf("FixEEGOutliers: thresh = %d\n",thresh) for(idx=0;idx=thresh){ fixedany = 1 printf("FixEEGOutliers: fixing val=%f at idx=%d, ",vtmp.x(idx),idx) //take average of surrounding two points if(idx + 1 < vtmp.size && idx > 0){ vtmp.x(idx) = ( vtmp.x(idx-1) + vtmp.x(idx+1) ) / 2 } else if(idx > 0){ //take value from left vtmp.x(idx) = vtmp.x(idx - 1) } else if(idx + 1 < vtmp.size){ //take value from right vtmp.x(idx) = vtmp.x(idx+1) } printf("new val=%f, med=%f\n",vtmp.x(idx),med) } if(ept && idx==0) idx = vtmp.size - 2 } return fixedany } /////////////////////////////////////////////////////////////////////////// //////////////////////// filter functions ///////////////////////////////// //$o1 = filter vector //$2 = size //$3 = tau //$4 = inc proc AlphaFilter(){ local idx,inc,tau,sz,myt sz = $2 tau = $3 myt = inc = $4 $o1 = new Vector(sz) printf("tau=%f inc=%f\n",tau,inc) for(idx=0;idx 1\n") return 0 } m1 = $o1.mean m2 = $o2.mean for(idx=0;idx<$o1.size;idx+=1){ sum += ($o1.x(idx)-m1)*($o2.x(idx)-m2) } sum = sum / (($o1.size-1)*$o1.stdev*$o2.stdev) return sum } //plot clusters in 2 dimensions //$o1 = list of vecs //$o2 = classes //$o3 = graph //$4 = dim1 //$5 = dim2 func plot_kmeans(){ local idx if($4 >= $o1.count || $5 >= $o1.count){ printf("idx out of bounds %d %d %d",$4,$5,$o1.count) return 0 } if(mydbg){ printf("$o1.o(%d).size=%d\n",$4,$o1.o($4).size) printf("$o1.o(%d).size=%d\n",$5,$o1.o($5).size) } if(mydbg){ for(idx=0;idx<$o2.size;idx+=1){ if(idx >= $o2.size){ printf("idx out of $o2 bounds %d %d\n",idx,$o2.size) continue } else if(idx >= $o1.o($4).size || idx >= $o1.o($5).size){ printf("idx out of $o1.o($4) or $o1.o($5) %d %d %d\n",idx,$o1.o($4).size,$o1.o($5).size) continue } $o3.mark($o1.o($4).x(idx),$o1.o($5).x(idx),"o",4,$o2.x(idx)+2,1) } } else { for(idx=0;idx<$o2.size;idx+=1){ if(idx >= $o2.size){ printf("idx out of $o2 bounds %d %d\n",idx,$o2.size) continue } else if(idx >= $o1.o($4).size || idx >= $o1.o($5).size){ printf("idx out of $o1.o($4) or $o1.o($5) %d %d %d\n",idx,$o1.o($4).size,$o1.o($5).size) continue } $o3.mark($o1.o($4).x(idx),$o1.o($5).x(idx),"o",4,$o2.x(idx)+2,1) } } return 1 } /////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// //The return value is //0 for numbers, //1 for objref, //2 for strdef, and //3 for pointers to numbers. //const for return codes from argtype() NUMBER_T = 0 OBJREF_T = 1 STRING_T = 2 POINTER_T = 3 ///////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////// /////////////////// fitness functions for ga ///////////////// //$o1 = spike train 1 //$o2 = spike train 2 func SpikeTrainFitness(){ local thresh,fitness,tmp,idx1,idx2,spiket1,spiket2,foundm,matchspikes /////////////////////////////////////////////////////////////////// //calculate fitness // //this will determine the "fitness", a measure of the similarity //between two spike trains thresh = 1.5 //max time between "matching" spikes fitness = 0 tmp = abs($o1.size-$o2.size) fitness -= (tmp*tmp*tmp) //penalty for diff # of spikes //find # of matching spikes from set 1 to set 2 matchspikes = 0 for(idx1 = 0; idx1 < $o1.size ; idx1 += 1){ spiket1 = $o1.x(idx1) foundm = 0 for(idx2 = 0; idx2 < $o2.size && !foundm; idx2 += 1){ spiket2 = $o2.x(idx2) if(abs(spiket1-spiket2)<=thresh){ matchspikes += 1 foundm = 1 break } } } //matching spikes add to fitness fitness += (matchspikes*matchspikes) tmp = $o1.size - matchspikes //unmatching spikes sub from fitness fitness -= (tmp*tmp) //find # of matching spikes from set 2 to set 1 matchspikes = 0 for(idx2 = 0; idx2 < $o2.size ; idx2 += 1){ spiket2 = $o2.x(idx2) foundm = 0 for(idx1 = 0; idx1 < $o1.size && !foundm; idx1 += 1){ spiket1 = $o1.x(idx1) if(abs(spiket1-spiket2)<=thresh){ matchspikes += 1 foundm = 1 break } } } fitness += (matchspikes*matchspikes) tmp = $o2.size - matchspikes fitness -= (tmp*tmp) return fitness /////////////////////////////////////////////////////////////////// } //$o1 = spike train 1 //$o2 = spike train 2 //$3 = cost per unit time to move spike maxspikes=512 double dtab[maxspikes][maxspikes] func SpikeTrainEditDist(){ local cost,nspi,nspj,row,col nspi = $o1.size nspj = $o2.size cost = $3 if(cost==0){ return abs(nspi-nspj) } else if(cost >= 9e24) { return nspi+nspj } if(nspi==0){ return nspj } else if(nspj==0){ return nspi } for(row=0;row $o4.o(idx2).size){ //resample $o4,5,6.o(idx) to size of $o1.o(idx) newsz = $o1.o(idx1).size tmp4 = new Vector(newsz) tmp4.samp($o4.o(idx2),newsz) tmp5 = new Vector(newsz) tmp5.samp($o5.o(idx2),newsz) tmp6 = new Vector(newsz) tmp6.samp($o6.o(idx2),newsz) dist = VSQDist($o1.o(idx1),$o2.o(idx1),$o3.o(idx1),tmp4,tmp5,tmp6) } else if($o1.o(idx1).size < $o4.o(idx2).size){ newsz = $o4.o(idx2).size tmp1 = new Vector(newsz) tmp1.samp($o1.o(idx1),newsz) tmp2 = new Vector(newsz) tmp2.samp($o2.o(idx1),newsz) tmp3 = new Vector(newsz) tmp3.samp($o3.o(idx1),newsz) dist = VSQDist(tmp1,tmp2,tmp3,$o4.o(idx2),$o5.o(idx2),$o6.o(idx2)) } else{ dist = VSQDist($o1.o(idx1),$o2.o(idx1),$o3.o(idx1),$o4.o(idx2),$o5.o(idx2),$o6.o(idx2)) } if(dist != -1 && dist < mindist){ mindist = dist if(mydbg){ printf("idx1=%d idx2=%d mindist_so_far=%f\n",idx1,idx2,mindist) } } } } return mindist } //returns sum of min distance between each ISI trajectory in first set to 2nd set //$o1 = list of v1 //$o2 = list of v1' //$o3 = list of v1'' //$o4 = list of v2 //$o5 = list of v2' //$o6 = list of v2'' //$&7 = best idx1 (optional) //$&8 = best idx2 (optional) func ISIDistance2(){ local idx1,idx2,dist,mindist,newsz,totaldist,savebestidx localobj tmp1,tmp2,tmp3,tmp4,tmp5,tmp6 if(numarg()==8) savebestidx = 1 else savebestidx = 0 // totaldist = 0 for(idx1=0;idx1<$o1.count;idx1+=1){ dist = -1.0 mindist = 9e25 for(idx2=0;idx2<$o4.count;idx2+=1){ if($o1.o(idx1).size > $o4.o(idx2).size){ //resample $o4,5,6.o(idx) to size of $o1.o(idx) newsz = $o1.o(idx1).size tmp4 = new Vector(newsz) tmp4.samp($o4.o(idx2),newsz) tmp5 = new Vector(newsz) tmp5.samp($o5.o(idx2),newsz) tmp6 = new Vector(newsz) tmp6.samp($o6.o(idx2),newsz) dist = VSQDist($o1.o(idx1),$o2.o(idx1),$o3.o(idx1),tmp4,tmp5,tmp6) } else if($o1.o(idx1).size < $o4.o(idx2).size){ newsz = $o4.o(idx2).size tmp1 = new Vector(newsz) tmp1.samp($o1.o(idx1),newsz) tmp2 = new Vector(newsz) tmp2.samp($o2.o(idx1),newsz) tmp3 = new Vector(newsz) tmp3.samp($o3.o(idx1),newsz) dist = VSQDist(tmp1,tmp2,tmp3,$o4.o(idx2),$o5.o(idx2),$o6.o(idx2)) } else{ dist = VSQDist($o1.o(idx1),$o2.o(idx1),$o3.o(idx1),$o4.o(idx2),$o5.o(idx2),$o6.o(idx2)) } if(dist != -1.0 && dist < mindist){ mindist = dist if(mydbg){ printf("idx1=%d idx2=%d mindist_so_far=%f\n",idx1,idx2,mindist) } if(savebestidx){ $&7 = idx1 $&8 = idx2 } } } if(mindist < 9e25) totaldist += mindist } return totaldist } ////////////////////////////////////////////////////////////// ///some templates... ////////////////////////////////////////////////////////////////////////////////////// //template for storing inter-spike interval information begintemplate isi_info external GetISITimes,GetTrajectories,GetTrajectory public start_times,end_times,lv1,lv2,lv3 objref start_times,end_times,lv1,lv2,lv3 //start,end isi times , v,v',v'' vectors public setup //$o1 = spike train //$o2 = voltage vector func setup(){ localobj spikes,voltvec if(numarg()!=2){ return 0 } spikes = $o1 voltvec = $o2 if(!GetISITimes(spikes,start_times,end_times)) return 0 lv1=new List() lv2=new List() lv3=new List() if(!GetTrajectories(voltvec,start_times,end_times,lv1,lv2,lv3)) return 0 return 1 } //$o1 = spike train //$o2 = voltage vector proc init(){ start_times=new Vector() end_times=new Vector() lv1=new List() lv2=new List() lv3=new List() if(numarg()==0){ return } else if(numarg()==2){ setup($o1,$o2) } } endtemplate isi_info ////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// //template for storing spike-related info , including inter-spike interval info begintemplate spike_info external GetSpikeTimes,GetISITimes,GetTrajectories,GetTrajectory public isi,spikes,setup objref isi,spikes //$o1 = voltage vector //$2 = spike threshold //$3 = min interspike time //$4 = whether to initialize isi info func setup(){ local sz if(numarg()!=4){ printf("invalid args to spike_info.setup\n") return 0 } spikes = new Vector($o1.size) sz = spikes.GetSpikeTimes($o1,$2,$3) spikes.resize(sz) if($4) return isi.setup(spikes,$o1) return 1 } //either give 0 or 4 arguments //$o1 = voltage vector //$2 = spike threshold //$3 = min interspike time //$4 = whether to initialize isi info proc init(){ local thresh,mintimediff,getisi localobj voltvec thresh = -20 mintimediff = 2 isi=new isi_info() spikes=new Vector() getisi = 1 if(numarg()==0){ return } else if(numarg()==4){ voltvec = $o1 thresh = $2 mintimediff = $3 getisi = $4 } setup(voltvec,thresh,mintimediff,getisi) } endtemplate spike_info /// //////////////////////////////////////////////////////////////////////////////////////