// $Id: decnqs.hoc,v 1.21 2007/06/14 20:14:52 billl Exp $
load_file("nqs.hoc")
objref nq[5]
//** prl2nqs(NQS[,min,max,nointerp]) -- transfer printlist to NQS
proc rename () {}
// eg proc rename () { sprint($s1,"P%d",objnum($s1)) }
proc prl2nqs () { local tstep localobj st
st=new String2()
if (!isassigned($o1)) $o1=new NQS() else $o1.resize(0)
if (numarg()>=2) min=$2 else min=0
if (numarg()>=3) max=$3 else max=printlist.count-1
if (numarg()>=4) interp=$4 else interp=0 // no interp when looking at spk times
if (interp) $o1.resize(max-min+2)
if (interp) {
tstep=0.1 // 0.1 ms step size for interpolation
$o1.s[0].s="time"
$o1.v[0].indgen(0,printlist.object(0).tvec.max,tstep)
for ii=min,max {
XO=printlist.object(ii)
$o1.s[ii+1-min].s = XO.var
rename($o1.s[ii+1-min].s)
$o1.v[ii+1-min].resize($o1.v.size)
$o1.v[ii+1-min].interpolate($o1.v[0],XO.tvec,XO.vec)
}
} else {
for ii=min,max {
XO=printlist.object(ii)
st.s=XO.name
sprint(st.t,"%s-time",XO.name)
rename(st.s) rename(st.t)
$o1.resize(st.s,st.t)
$o1.setcols(XO.vec,XO.tvec)
}
}
}
//** pvp2nqs(NQS) -- transfer grvec data file to NQS
proc pvp2nqs () { local tstep,tv1,v1
if (! read_vfile(1,$s1)) { printf("Can't open %s\n",$s1) return }
if (numarg()>=3) min=$3 else min=0
if (numarg()>=4) max=$4 else max=panobj.llist.count-1
if (numarg()>=5) interp=$5 // no interp when looking at spk times
if (interp) $o2.resize(max-min+2) else $o2.resize(2*(max-min+1))
if (interp) {
tv1=v1=allocvecs(2) v1+=1
tstep=0.1 // 0.1 ms step size for interpolation
$o2.s[0].s="time"
for ii=min,max {
XO=panobj.llist.object(ii)
$o2.s[ii+1-min].s = XO.name
rename($o2.s[ii-min+1].s)
panobj.tmpfile.seek(XO.loc)
mso[tv1].vread(panobj.tmpfile)
mso[v1].vread(panobj.tmpfile) // or use rv_readvec
if (ii-min==0) $o2.v[0].indgen(0,mso[tv1].max,tstep)
$o2.v[ii+1-min].resize($o2.v.size)
$o2.v[ii+1-min].interpolate($o2.v[0],mso[tv1],mso[v1])
}
dealloc(tv1)
} else for ii=min,max {
XO=panobj.llist.object(ii)
$o2.s[2*(ii-min)].s = XO.name
rename($o2.s[2*(ii-min)].s)
sprint($o2.s[2*(ii-min)].s,"%s-time",$o2.s[2*(ii-min)].s)
$o2.s[2*(ii-min)+1].s = XO.name
rename($o2.s[2*(ii-min)+1].s)
panobj.tmpfile.seek(XO.loc)
$o2.v[2*(ii-min)].vread(panobj.tmpfile)
$o2.v[2*(ii-min)+1].vread(panobj.tmpfile)
}
}
//** veclist2nqs(nqs[,STR1,STR2,...])
proc veclist2nqs () { local flag,i
if (numarg()==0) {printf("veclist2nqs(nqs[,STR1,STR2,...])\n") return}
$o1.resize(veclist.count)
if (numarg()==1+$o1.m) flag=1 else flag=0
for ltr(XO,veclist) {
$o1.v[i1].copy(XO)
if (flag) {i=i1+2 $o1.s[i1].s=$si} else {sprint(tstr,"v%d",i1) $o1.s[i1].s=tstr}
}
$o1.cpout()
}
// fudup(vec[,nq,#CUTS,LOGCUT,MIN]) -- use updown() to find spikes
// LOC(0) PEAK(1) WIDTH(2) BASE(3) HEIGHT(4) START(5) SLICES(6) SHARP(7) INDEX(8) FILE(9)
// other options
pos_fudup=1 // set to 1 to move whole curve up above 0
maxp_fudup=0.95 // draw top sample at 95% of max
minp_fudup=0.05 // draw bottom sample at 5% of max
over_fudup=1 // turn over and try again if nothing found
allover_fudup=0 // turn over and add these locs (not debugged)
verbose_fudup=0 // give messages, can also turn on DEBUG_VECST for messages from updown()
obfunc fudup () { local a,ii,npts,logflag,min,x,sz localobj bq,cq,v1,v2,v3,bb,tl
if (verbose_fudup) printf("MAXTIME appears to be %g (dt=%g)\n",$o1.size*dt,dt)
npts=10 // n sample locations
tl=new List()
bq=new NQS("LOC","PEAK","WIDTH","BASE","HEIGHT","START","SLICES","SHARP","INDEX","FILE")
if (numarg()>1) cq=$o2 else cq=new NQS()
if (cq.m!=10) { cq.resize(0)
cq.resize("LOC","PEAK","WIDTH","BASE","HEIGHT","START","SLICES","SHARP","INDEX","FILE") }
if (numarg()>2) npts=$3
if (numarg()>3) logflag=$4 else logflag=0
if (numarg()>4) {
if (npts!=$o5.size) printf("Correcting npts from %d to %d\n",npts,npts=$o5.size)
if ($o5.ismono(1)) $o5.reverse
if (! $o5.ismono(-1)) {printf("fudup: Arg 5 (%s) must be monotonic\n",$o5) return}
}
bq.listvecs(bb)
bq.pad(5000)
a=allocvecs(npts+3,2e4)
v1=mso[a+0] v2=mso[a+1] v3=mso[a+2]
for ii=0,npts-1 tl.append(mso[ii+a+3])
v1.copy($o1)
if (pos_fudup) {
min=v1.min
v1.sub(min) // make it uniformly positive
} else min=0
if (numarg()>4) v2.copy($o5) else {
v2.indgen(2,2+npts-1,1) // sampling at npts points, start at 2 to avoid log(1)=0
if (logflag) v2.log() // log sampling
v2.scale(-maxp_fudup*v1.max,-minp_fudup*v1.max) v2.mul(-1)
}
v1.updown(v2,tl,bb)
if (pos_fudup) { bq.v[1].add(min) bq.v[3].add(min) }
cq.append(bq)
sz=bq.size(1)
if (allover_fudup) { // do it upside down as well
v1.mul(-1) // v2 will be upside-down
if (pos_fudup) {min=v1.min v1.sub(min)}
if (0) { // can't see a rationale to recalc sampling points
v2.indgen(2,2+npts-1,1) // sampling at npts points
if (logflag) v2.log() // log sampling
v2.scale(-0.95*v1.max,-0.05*v1.max) v2.mul(-1)
}
v1.updown(v2,tl,bb)
bq.v[8].add(sz) bq.v[4].mul(-1) // turn HEIGHT upside down
cq.append(bq)
} else if (over_fudup && sz==0) { // turn it over an try again
print "fudup() checking upside-down"
v1.mul(-1) // v2 will be upside-down
v1.updown(v2,tl,bb)
}
for case(&x,0,2,5) cq.v[x].mul(dt)
nqsdel(bq)
dealloc(a)
return cq
}
//** listsort(LIST[,START,REV]) sorts list of strings numerically
// optional start gives a regexp to start at
proc listsort () { local x,rev localobj nq,st,xo
if (numarg()==0) {
print "listsort(LIST[,RXP,REV]) numerically, optional RXP starts after there" return}
if (numarg()==3) if ($3) rev=-1 else rev=0
nq=new NQS("STR","NUM") nq.strdec("STR")
st=new String()
for ltr(xo,$o1) {
if (numarg()>=2) sfunc.tail(xo.s,$s2,st.s) else st.s=xo.s
if (sscanf(st.s,"%g",&x)!=1) print "listsort ERR: num not found in ",st.s
nq.append(xo.s,x)
}
nq.sort("NUM",rev)
$o1.remove_all
for nq.qt(st.s,"STR") $o1.append(new String(st.s))
}
// stat(VEC) print stats for the vector
// stat(VEC1,VEC2) append stats of VEC1 on VEC2
// stat(VEC1,NQS) append stats of VEC1 on NQS (create if necessary)
proc stat () { local ok
if ($o1.size<2) ok=0 else ok=1
if (!ok) printf("decnqs::stat() WARN: %s size %d\n",$o1,$o1.size)
if (numarg()==1 && ok) {
printf("Sz:%d\tmax=%g; min=%g; mean=%g; stdev=%g\n",$o1.size,$o1.max,$o1.min,$o1.mean,$o1.stdev)
} else {
if (!isassigned($o2)) { $o2=new NQS("SIZE","MAX","MIN","MEAN","STDEV")
} else if (isobj($o2,"NQS")) {
if ($o2.m!=5) {$o2.resize(0) $o2.resize("SIZE","MAX","MIN","MEAN","STDEV")}
} else if (isobj($o2,"Vector")) revec($o2)
if (ok) {$o2.append($o1.size,$o1.max,$o1.min,$o1.mean,$o1.stdev) // .append for Vector or NQS
} else $o2.append($o1.size,$o1.max,$o1.min,$o1.min,0) // will not be accurate for size 2
}
}
//* fil2nqs(FILE,NQS) reads lines of file and places all numbers in NQS
func fil2nqs () { local a,n localobj v1
$o2.clear
a=allocvecs(v1)
tmpfile.ropen($s1)
for (n=1;tmpfile.gets(tstr)!=-1;n+=1) {
if (n%1e3==0) printf("%d ",n)
parsenums(tstr,v1)
if (v1.size!=$o2.m) {
printf("Wrong size at line %d (%d) ",n,v1.size) vlk(v1)
return
}
$o2.append(v1)
}
dealloc(a)
return $o2.size(1)
}
//** plnqs(file,NQS) reads output of txt2num.pl
// format ascii 'rows cols' then binary contents
proc plnqs () { local a,rows,cols localobj v1,v2
a=allocvecs(v1,v2)
tmpfile.ropen($s1)
tmpfile.gets(tstr)
sscanf(tstr,"%d %d",&rows,&cols)
printf("%s: %d rows x %d cols\n",$s1,rows,cols)
v1.fread(tmpfile,rows*cols) // could now use .transpose
v2.indgen(0,rows*cols,cols)
$o2.resize(cols,rows)
for ii=0,cols-1 {
v2.add(ii)
$o2.v[ii].index(v1,v2)
}
dealloc(a)
}
// DEST=maxem(SRC,MIN,WIDTH) -- keep looking for maxima till get down to min
obfunc maxem () { local a,min,wid,ii,ix,beg,end localobj v1,aq
a=allocvecs(v1)
aq=new NQS("max","loc") aq.clear(v1.size/2)
v1.copy($o1)
min=$2 wid=$3
while(v1.max>min) {
aq.append(v1.max,ix=v1.max_ind)
beg=ix-wid if (beg<0) beg=0
end=ix+wid if (end>=v1.size) end=v1.size-1
for ii=beg,end v1.x[ii]=-1e9
}
dealloc(a)
return aq
}
// nqo=percl(nq,"COLA", ..) generates NQS of percentile values (10..90) for these cols
// nqo=percl(nq,min,max,step,"COLA", ..) -- eg percl(nq,50,70,5,"COLA","COLB")
obfunc percl () { local i,ii,a,p localobj v1,v2,v3,aq,xo
a=allocvecs(v1,v2,v3)
aq=new NQS(numarg())
if (argtype(2)==0) {
v3.indgen($2,$3,$4)
aq.resize(aq.size(1)-3)
i=5 j=4 // start at arg i and aq col #j
} else {
v3.indgen(10,90,10)
i=2 j=1
}
aq.setcol(0,"PERCL",v3)
for (;i<=numarg();i+=1) {
$o1.getcol($si,v1)
v1.sort()
v2.resize(0)
for vtr(&ii,v3) {ii/=100 v2.append(v1.x[round(ii*v1.size)])}
aq.setcol(i-j,$si,v2)
}
dealloc(a)
return aq
}
// pqunq(NQS) returns columns of sorted nique values corresponding to the arg
// NB: does not produce a rectangular array
obfunc pqunq () { local a localobj v1,v2,aq
aq=new NQS()
a=allocvecs(v1,v2,1e5)
aq.sethdrs($o1)
aq.resize(-2)
for ii=0,aq.m-1 {
$o1.getcol(ii,v1)
v1.sort
v2.redundout(v1)
aq.v[ii].copy(v2)
}
dealloc(a)
return aq
}
//** aa=seqind(ind) -- find beginning and end of sequential indices with
obfunc seqind () { local a,n,skip,ii,x,last localobj vi,oq
vi=$o1
if (numarg()>=2) skip=$2+1 else skip=1
if (numarg()>=3) oq=$o3
if (!isassigned(oq)) {oq=new NQS() if (numarg()>=3) $o3=oq}
if (oq.m!=3) { oq.resize(0) oq.resize("beg","end","diff") }
oq.clear()
n=last=0
for ii=1,vi.size(1)-1 {
if (vi.x[ii]-vi.x[ii-1]>skip) {
if (n>0) oq.append(vi.x[last],vi.x[ii-1],0)
last=ii
n=0
} else n+=1
}
if (n>0) oq.append(vi.x[last],vi.x[ii-1],0)
oq.pad()
oq.calc("<diff>.copy(<end>.c.sub(<beg>))")
return oq
}
//** list_transpose
proc list_transpose () { localobj aq,mat,xo,inlist,outlist
aq=new NQS() inlist=$o1 outlist=$o2
if (!isojt(outlist,inlist)) {outlist=new List() $o2=outlist}
for ltr(xo,inlist) aq.resize("",xo)
mat=aq.tomat(1) // transpose
aq.frmat(mat)
outlist.remove_all
aq.listvecs(outlist)
delnqs(aq)
}