#!/bin/sh
#
# spfrqpeel - calculate time constant for spike frequency curve
#
# Usage:  spfrqpeel [-n sec] [-c wfnum] [-s wfnum] [-t thresh] [-h hyst] [-d] \
#		[-r st,en] [-p|-g|-v|-a|-f] runfile ...
#
# where:  -n sec	specifies the number of seconds to skip from the
#			start of the current burst
#			(default is 5)
#	  -c wfnum	specifies waveform number for current injected
#			(default is 0)
#	  -s wfnum	specifies waveform number for spikes to measure
#			(default is 1)
#	  -t thresh	specifies spike threshold, as a differential
#			(default is 500)
#	  -h hyst	specifies spike hysteresis, as a 2nd differential
#			i.e. relative to threshold above
#			(default is 0 for no hysteresis)
#	  -d		specifies that spike triggering will not be on a
#			differential waveform, and threshold above will be
#			an actual waveform level
#	  -r st,en	specifies the start and end of the analysis range,
#			overriding the range determined from the injected
#			current waveform
#	  -p		specifies that an HPGL plot file of the frequency curve
#			be generated for each runfile
#	  -g		specifies that a GIF plot file of the frequency curve
#			be generated for each runfile
#	  -v		specifies that a plot of the frequency curve be viewed
#			via xhpgl for each runfile
#	  -a		specifies that an ASCII text file of the times (x)
#			and frequencies (y) be output for each runfile
#			as comma-separated values (.csv file)
#	  -f		specifies that a frame file (-freq.frm) be generated
#			for each runfile, representing the frequency curve as
#			mV, for further analysis by the peel program
#	  runfile	specifies one or more run file names to be measured
#			(no default, runfile must be specified)
#
# spfrqpeel first looks at the injected current waveform, to determine the
# range of samples to be analyzed.  It then backs off the end point (when
# current is turned off) by 0.2 ms, to avoid spikes that are artifacts of
# the current being switched off.  It then skips the specified number of
# seconds from the start of the injected current, and calculates the time
# constant for the frequency curve of the spikes in the remaining range.
#
# Output will be of the form:
# "Filename", Start, End, Spikes, Current, Slope, Intercept, r, Tau
# The time constant Tau is output in ms, as are the start and end.
# The current is output in the units for which the waveform was calibrated.
#
# Copyright (c) 2005-6, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

nsecskip=5 cwfnum=0 swfnum=1 sthresh=500 hyst=0 diff=y range=
aopt= vopt= popt= gopt= fopt= plot=
T=/tmp/psf$$
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	-debug|--debug)	shift; T=psf.out. ;;
	-n)	shift; nsecskip="$1"; shift ;;
	-c)	shift; cwfnum="$1"; shift ;;
	-s)	shift; swfnum="$1"; shift ;;
	-t)	shift; sthresh="$1"; shift ;;
	-h)	shift; hyst="$1"; shift ;;
	-d)	shift; diff=n ;;
	-r)	shift; range="$1"; shift ;;
	-p)	shift; popt=y; plot=y ;;
	-g)	shift; gopt=y; plot=y ;;
	-v)	shift; vopt=y; plot=y ;;
	-a)	shift; aopt=y; plot=y ;;
	-f)	shift; fopt=y; plot=y ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done
ascript=${T}a
diags=${T}b
anafile=${T}c
rfile=${T}d
dfile=${T}e
pfile=${T}f
ffile=${T}g

case "$#" in
0)	echo "Usage:  spfrqpeel [-n sec] [-c wfnum] [-s wfnum] [-t thresh] [-h hyst] [-d] \\
		[-r st,en] [-p|-g|-v|-a|-f] runfile ...
	or spfrqpeel --help	for detailed usage information" >&2; exit 1 ;;
esac

case "$nsecskip" in
[0-9]*|-[0-9]*|.[0-9]*|-.[0-9]*)	;;
*)	echo "$0: Invalid number of seconds to skip: -n $nsecskip" >&2
	exit 1
	;;
esac

case "$cwfnum" in
[0-9]*)	;;
*)	echo "$0: Invalid number for current waveform: -c $cwfnum" >&2
	exit 1
	;;
esac

case "$swfnum" in
[0-9]*)	;;
*)	echo "$0: Invalid number for spike waveform: -s $swfnum" >&2
	exit 1
	;;
esac

case "$sthresh" in
[0-9]*|-[0-9]*)	;;
*)	echo "$0: Invalid number for spike threshold: -t $sthresh" >&2
	exit 1
	;;
esac

case "$hyst" in
[0-9]*|-[0-9]*)	;;
*)	echo "$0: Invalid number for spike hysteresis: -h $hyst" >&2
	exit 1
	;;
esac

range=`echo "$range" | tr -d ' '`
case "$range" in
"")
	;;
[Aa][Ll][Ll])
	start=0 end=max
	;;
[0-9]*\,[0-9]* | [0-9]*\,[Mm][Aa][Xx])
	start=`echo "$range" | sed 's/^\([-0-9.e+]*\),.*/\1/'`
	end=`echo "$range" | sed 's/^[^,]*, *\([-0-9.e+MmAaXx]*\) *$/\1/'`
	case "$start,$end" in
	[0-9]*\,[0-9Mm]*)	;;
	*)	echo "$0: Invalid range specified: -r $range" >&2
		exit 1
		;;
	esac
	;;
*)	echo "$0: Invalid range specified: -r $range" >&2
	exit 1
	;;
esac

case "$plot" in
y)	;;
*)	dfile=; pfile= ;;
esac

sortflags="+0n"
sort $sortflags </dev/null 2>/dev/null || sortflags="-k 1n"

case "${T}" in
/tmp/*)	trap "rm -f ${T}[abcef] ${T}[dg].???" 0	# cleanup on exit
	trap "exit 1" 1 2 3 15			# exit, & cleanup, if killed
	;;
esac

results=0
hdr="\"Filename\", Start, End, Spikes, Current, Slope, Intercept, r, Tau"
for run
do
	if [ ! -z "$hdr" ]
	then
		echo "$hdr"
		hdr=
	fi
	sysvecho "\"$run\", \c"
	case "$range" in
	"")	crange=`sysvecho "w$cwfnum\nsaaqcvadqqqec/dev/stdout\nyqqnqyn" |
			TERM=dumb DISPLAY= analysis "$run" 2>/dev/null | tail -1`
		cstart=`echo "$crange" | sed 's/^\([-0-9.e+]*\),.*/\1/'`
		cend=`echo "$crange" | sed 's/^[^,]*, *\([-0-9.e+]*\) *$/\1/'`
		case "$cstart" in
		[0-9]*)	start=`sysvecho "scale=4\n$cstart + ($nsecskip * 1000.00)" | bc 2>/dev/null` ;;
		*)	echo "\"No single current burst on W.F. $cwfnum\""
			continue
			;;
		esac
		case "$cend" in
		[0-9]*)	end=`sysvecho "scale=4\n$cend - 0.2" | bc 2>/dev/null` ;;
		*)	echo "\"No single current burst on W.F. $cwfnum\""
			continue
			;;
		esac
		;;
	esac
	rm -f "$rfile".???
	copyrun "$run" "$rfile"
	# find first available W.F., preferably w/o having to erase one
	fwf=
	for dwfnum in 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 9999
	do
		if [ $dwfnum -ne $cwfnum -a $dwfnum -ne $swfnum ]
		then
			if [ ! -r "$rfile.w$dwfnum" ]
			then
				break
			fi
			if [ -z "$fwf" ]
			then
				fwf=$dwfnum
			fi
		fi
	done
	if [ $dwfnum -eq 9999 ]
	then
		dwfnum=$fwf
	fi
	: > $ascript
	if [ -r "$rfile.w$dwfnum" ]
	then
		sysvecho "me$dwfnum\nq\c" >> $ascript
	fi
	dwfnum=`expr $dwfnum + 0`	# remove leading 0
	cat <<! >> $ascript
agavfrsrs$start
e$end
qcw-1
qgnnqswn$dwfnum
qqmianqqdn+ x y\n
qqw$dwfnum
sv$swfnum
${diff}ss$sthresh
e$hyst
qqqy
b
agwvaslwn$cwfnum
qqgb1
qdnPEAK y\n
qqb
srs0
e$cstart
qdnREF y\n
qqb
qyn
!

	if TERM=dumb DISPLAY= analysis "$rfile" < $ascript > $anafile 2> $diags
	then
		awk 'BEGIN {
			   n = 0; sum_x = 0.0; sum_x2 = 0.0;
			   sum_xy = 0.0; sum_y = 0.0; sum_y2 = 0.0;
			   dfile = "'"$dfile"'";
		     }
		     /^ *PEAK *[-0-9.e+]* *$/ { pcurr = $2 }
		     /^ *REF *[-0-9.e+]* *$R/ { rcurr = $2 }
		     /^ *\+ *[-0-9.e+]* *[-0-9.e+]* *$/ && $3 > 0.0 {
			   x = $2; y = log($3);
			   xd[n] = x; yd[n] = $3;
			   sum_x += x;  sum_x2 += x * x;
			   sum_xy += x * y;
			   sum_y += y;  sum_y2 += y * y;
			   n++;
		     }
		     END {
			   printf("'"$start"', '"$end"', %d, %g, ", n, pcurr-rcurr);
			   if (n > 0)
				denom = sum_x2 - sum_x*sum_x / n;
			   if (n == 0 || denom == 0.0)
				print "\"Error in regression calculation\""
			   else {
				slope = (sum_xy - sum_x*sum_y / n) / denom;
				intcept = sum_y/n - slope * (sum_x/n);
				printf("%g, %g, ", slope, intcept);
				denom2 = (sum_x2 - sum_x*sum_x / n) * (sum_y2 - sum_y*sum_y / n);
				if (denom2 <= 0.0)
				    print "\"Error in correlation coefficient calculation\""
				else {
				    r = (sum_xy - sum_x*sum_y / n) / sqrt(denom2);
				    printf("%g, ", r);
				    if (slope == 0.0)
					print "\"Error in Tau calculation\""
				    else
					printf("%g\n", -1.0 / slope);
				}
			   }
			   if (dfile != "") {
				for (i = 0; i < n; i++) {
				    if (denom == 0.0)
					y = -1000000
				    else
					y = exp(xd[i]*slope + intcept);
				    printf("%g %g %g\n", xd[i], yd[i], y) > dfile
				}
			   }
		     }' $anafile
		if [ ! -z "$dfile" -a -s "$dfile" ]
		then
		    yrange=`awk '{print $2, $3}' "$dfile" | tr -s ' ' '\012' | \
			      grep -v '^-1000000' | sort $sortflags | \
			      sed -n '1s/$/,/p; $p' | tr -d ' \012'`
		    genplot -xf"$dfile" -xc1 -yf"$dfile" -yc2 -yr"$yrange" \
			-xp1 -yp2 -xh"Time (ms)" -yh"Freq (Hz)" > "$pfile"
		    genplot -xf"$dfile" -xc1 -yf"$dfile" -yc3 -yr"$yrange" \
			-xp0 -yp3 -yw0 >> "$pfile"
		    opfile=$run
		    case "$opfile" in
		    *.frm)	opfile=`expr "$opfile" : '\(.*\)\.frm'` ;;
		    esac
		    case "$popt" in
		    y)	cat "$pfile" > "$opfile.plt" ;;
		    esac
		    case "$gopt" in
		    y)	hpgl2gif "$pfile" > "$opfile.gif" ;;
		    esac
		    case "$aopt" in
		    y)	awk '{print $1 ", " $2}' "$dfile" > "$opfile.csv" ;;
		    esac
		    case "$fopt" in
		    y)	awk '{t[NR] = $1; f[NR] = $2}
			     END {
				#s = '"$start"'; e = '"$end"'+10; incr = 10;
				s = t[1]; e = t[NR]+10; incr=10;
				r = 1; n = 0;
				while (s <= e) {
				    while (r < NR-1 && t[r+1] < s)
					++r;
				    m = (s-t[r]) / (t[r+1]-t[r]);
				    print (f[r] + (f[r+1]-f[r])*m) * 0.001;
				    s += incr;
				}
			     }' "$dfile" |
			    asc2run -c 1 -f 100 - "$ffile" 2>/dev/null
			length=`dumprun "$ffile" | sed -n 's/^Run length:[ 	]*\([0-9]*\).*/\1/p'`
			length=`expr "$length" - 1`
			rm -f "$opfile-freq.frm"
			sysvecho "awcscw-1\nqaww$length p\nqb1\npyqqby$opfile-freq.frm\n\nqyn" |
			    TERM=dumb DISPLAY= analysis "$ffile" 2>/dev/null
			;;
		    esac
		    case "$vopt" in
		    y)	xhpgl "$pfile" ;;
		    esac
		fi
		results=`expr $results + 1`
	else
		sed -n -e "s/Spike W\.F\. # $dwfnum/Spike W.F. # $swfnum/" \
			-e 's/FATAL ERROR: *\(.*\)/"\1"/p' $diags
		#sed -n -e 's/FATAL ERROR: /analysis: /p' $diags >&2
		#echo "$0: analysis failed!" >&2
		#echo
	fi
done

test "$results" -gt 0 || exit 2
