#!/bin/sh
#
# spfrqramps - calculate spike frequency and current min/max for current ramps
#
# Usage:  spfrqramps [-n num] [-c wfnum] [-ct thresh] [-cd delay] [-s wfnum] \
#		[-t thresh] [-h hyst] [-d] [-r st,en] [-a] runfile ...
#
# where:  -n num	specifies the number of samples of the current
#			waveform that will be averaged, centered at each
#			spike start time, to obtain the corresponding
#			current level
#			(default is 1)
#	  -c wfnum	specifies waveform number for current injected
#			(default is 0)
#	  -ct thresh	specifies current threshold for burst detection
#			(default is automatic detection using mean level,
#			 or value previously set in waveform parameters)
#	  -cd delay	specifies minimum crossing delay for burst detection
#			(default 800, ideal is about half of expected burst
#			 duration in ms)
#	  -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
#	  -r mult	specifies that multiple bursts of current will be
#			looked at on the injected current waveform, and each
#			burst will be processed and reported
#	  -r st,en,mult	specifies the start and end of the analysis range,
#			and specifies that multiple bursts in that range will
#			be analysed
#	  -a		specifies that an ASCII text file of the currents (x)
#			and frequencies (y) be output for each runfile
#			as comma-separated values (.csv file)
#	  runfile	specifies one or more run file names to be measured
#			(no default, runfile must be specified)
#
# spfrqramps 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 analyses the spike frequencies
# and current levels up and down the current ramp.
#
# Output will be of the form:
# "Filename", RampNo, Nspikes, MinIup, MinIdown, MaxI, MinFQup, MinFQdown, MaxFQ
# The spike frequencies (FQ) are in Hz, and the current (I) is in the units
# for which that waveform was calibrated.
#
# Copyright (c) 2005-8, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

maxvalidfrq=250
ncursamp=1
cwfnum=0 cthresh= cdelay=800 swfnum=1 sthresh=500 hyst=0 diff=y range=
aopt= vopt= popt= gopt=
T=/tmp/rsf$$
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	-debug|--debug)	shift; T=rsf.out. ;;
	-n)	shift; ncursamp="$1"; shift ;;
	-c)	shift; cwfnum="$1"; shift ;;
	-ct)	shift; cthresh="$1"; shift ;;
	-cd)	shift; cdelay="$1"; shift ;;
	-s)	shift; swfnum="$1"; shift ;;
	-t)	shift; sthresh="$1"; shift ;;
	-st)	shift; sthresh="$1"; shift ;;
	-h)	shift; hyst="$1"; shift ;;
	-d)	shift; diff=n ;;
	-r)	shift; range="$1"; shift ;;
	-a)	shift; aopt=y; plot=y ;;
#	-p)	shift; popt=y; plot=y ;;
#	-g)	shift; gopt=y; plot=y ;;
#	-v)	shift; vopt=y; plot=y ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done
ascript=${T}a
diags=${T}b
anafile=${T}c
rfile=${T}d

case "$#" in
0)	echo "Usage:  spfrqramps [-n num] [-c wfnum] [-ct thresh] [-cd delay] [-s wfnum] \\
		[-t thresh] [-h hyst] [-d] [-r st,en] [-a] runfile ...
	or spfrqramps --help	for detailed usage information" >&2; exit 1 ;;
esac

case "$ncursamp" in
[01])	ncursamp= ;;
[0-9]*)	h=`expr "$ncursamp" / 2`
	ncursamp="w${ncursamp}p
d-${h}p
"
	;;
*)	echo "$0: Invalid number of current samples: -n $ncursamp" >&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 "$cthresh" in
"")	;;
[0-9]*|-[0-9]*)	cthresh="s$cthresh\n" ;;
*)	echo "$0: Invalid number for current threshold: -ct $cthresh" >&2
	exit 1
	;;
esac

case "$cdelay" in
"")	;;
[0-9]*)	cdelay="d$cdelay\n" ;;
*)	echo "$0: Invalid number for crossing delay: -ct $cdelay" >&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

start=0 end=max
range=`echo "$range" | tr -d ' '`
case "$range" in
""|[Mm][Uu][Ll]*|[Aa][Ll][Ll])
	;;
[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

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

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

results=0
hdr="\"Filename\", RampNo, Nspikes, MinIup, MinIdown, MaxI, MinFQup, MinFQdown, MaxFQ"
for run
do
    if [ ! -z "$hdr" ]
    then
	echo "$hdr"
	hdr=
    fi
    nbursts=1
    burstn=1
    # refstart=0
    # prevcend=0
    case "$range" in
    ""|*[Mm][Uu][Ll]*)
	bursts=`sysvecho "w$cwfnum\nsas$start\ne$end\nqc${cthresh}${cdelay}vadqqqec/dev/stdout\nyqqnqyn" |
		TERM=dumb DISPLAY= analysis "$run" 2>/dev/null`
	nbursts=`echo "$bursts" | sed -n '2s/n = //p'`
	bindex=4
	crange=`echo "$bursts" | sed -n "${bindex}p"`
	start=`echo "$crange" | sed 's/^\([-0-9.e+]*\),.*/\1/'`
	cend=`echo "$crange" | sed 's/^[^,]*, *\([-0-9.e+]*\) *$/\1/'`
	end=$cend
	case "$cend" in
	[0-9]*)	;; # end=`sysvecho "scale=4\n$cend - 0.2" | bc 2>/dev/null` ;;
	*)	echo "\"$run\", 0, 0, \"No single current burst on W.F. $cwfnum\""
		continue
		;;
	esac
	;;
    esac
    case "$aopt$popt$gopt$vopt" in
    y)	opfile=$run
	case "$opfile" in
	*.frm)	opfile=`expr "$opfile" : '\(.*\)\.frm'` ;;
	esac
	case "$aopt" in
	y)	: > "$opfile.csv" ;;
	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
    while [ "$nbursts" -gt 0 ]
    do
	case "$range" in
	*[Mm][Uu][Ll]*)
		crange=`echo "$bursts" | sed -n "${bindex}p"`
		start=`echo "$crange" | sed 's/^\([-0-9.e+]*\),.*/\1/'`
		cend=`echo "$crange" | sed 's/^[^,]*, *\([-0-9.e+]*\) *$/\1/'`
		end=$cend
		# end=`sysvecho "scale=4\n$cend - 0.2" | bc 2>/dev/null`
		# refstart=$prevcend
		# prevcend=$cend
		# if [ "$refstart" = 0 ]
		# then
			# # avoid incomplete first burst
			# refstart=`sysvecho "scale=4\nh=($end-$start)/2\nr=0\nif($start>250 && $start>h)r=$start-h\nr" | bc 2>/dev/null`
		# fi
		bindex=`expr "$bindex" + 1`
		nbursts=`expr "$nbursts" - 1`
		rm -f "$rfile".p$dwfnum
		;;
	*)
		nbursts=0
		;;
	esac
	: > $ascript
	if [ -r "$rfile.w$dwfnum" ]
	then
		sysvecho "me$dwfnum\nq\c" >> $ascript
	fi
	nlzdwfnum=`expr $dwfnum + 0`	# remove leading 0
	cat <<! >> $ascript
agawfrsrs$start
e$end
qcw-1
qlwn$cwfnum
${ncursamp}qqswn$nlzdwfnum
qqmianqqdn+ x y\n
qqw$nlzdwfnum
sv$swfnum
${diff}ss$sthresh
e$hyst
qqqy
b
qyn
!

	sysvecho "\"$run\", $burstn, \c"
	burstn=`expr "$burstn" + 1`
	if TERM=dumb DISPLAY= analysis "$rfile" < $ascript > $anafile 2> $diags
	then
		maxfrq=`grep '^ *+ *[-0-9.e+]* *[-0-9.e+]* *$' $anafile | awk '$3 < '"$maxvalidfrq"' {print $3}' | sort $sortflags | head -1`
		maxcur=`grep '^ *+ *[-0-9.e+]* *[-0-9.e+]* *$' $anafile | awk '$3 < '"$maxvalidfrq"' {print $2}' | sort $sortflags | head -1`
		if [ -z "$maxfrq" -o -z "$maxcur" ]
		then
			echo "0, \"No spike frequencies found for W.F. $swfnum from $start to $end ms\""
			continue
		fi
		awk 'BEGIN {
			maxf = '"$maxfrq"'; maxi = '"$maxcur"'
			minfup = maxf; miniup = maxi
			minfdn = maxf; minidn = maxi
			n = 0; fup = 1; iup = 1
		     }
		     /^ *\+ *[-0-9.e+]* *[-0-9.e+]* *$/ && $3 < '"$maxvalidfrq"' {
			if (fup) {
			    if ($3 == maxf)
				fup = 0
			    else if (minfup > $3)
				minfup = $3
			} else {
			    if (minfdn > $3)
				minfdn = $3
			}
			if (iup) {
			    if ($2 == maxi)
				iup = 0
			    else if (miniup > $2)
				miniup = $2
			} else {
			    if (minidn > $2)
				minidn = $2
			}
			++n
		     }
		     END {
			print n ", " miniup ", " minidn ", " maxi ", "minfup ", " minfdn ", " maxf
		     }' $anafile
		case "$aopt" in
		y)	awk '/^ *\+ *[-0-9.e+]* *[-0-9.e+]* *$/ && $3 < '"$maxvalidfrq"' {
				print $2 ", " $3
			     }
			     END {
				print ""
			     }' $anafile >> "$opfile.csv" ;;
		esac
	else
		sed -n -e "s/Spike W\.F\. # $nlzdwfnum/Spike W.F. # $swfnum/" \
			-e 's/FATAL ERROR: *\(.*\)/0, "\1"/p' $diags
		#sed -n -e 's/FATAL ERROR: /analysis: /p' $diags >&2
		#echo "$0: analysis failed!" >&2
		#echo
	fi
    done
done

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