#!/bin/sh
#
# powersp - calculate and plot power spectrum for waveforms in run
#
# Usage:  powersp [-w wfnum] [-f freq] [-r st,en] [-v] [-t type] [-n fftsize]
#		[-o overlap] [-w win] [-p plttype] runfile ...
#
# where:  -w wfnum	specifies the waveform number for the marked up bursts
#			or a list of waveform numbers separated by commas
#			(default is 0)
#	  -f freq	specifies frequency to which you want each waveform
#			downsampled, where frequencies up to half of this will
#			be plotted (default is the full sample rate of each WF)
#	  -r st,en	specifies start and end of the analysis range, in sec.
#			(default is taken from analysis parameters, or all)
#	  -v, -vv	specifies extra verbosity from fft program
#			(default is minimal output)
#	  -t type	specifies type of power spectrum plotted: ps (power
#			spectrum V-squared), psd (spectral density V-sqared/Hz),
#			ls (linear spectrum V), lsd (spectral density V/sqrtHz),
#			dbs (spectrum in dB), dbsd (density in dB of V/sqrtHz)
#			(default is dbs, for spectrum in dB)
#	  -n fftsize	specifies size of calculated FFT output, which is twice
#			the number of frequency points in the output plot, and
#			must be a power of 2 between 128 and 524288
#			(default is 1024, or less for smaller waveform sections)
#	  -o overlap	specifies the amount of overlap in the fft calculation:
#			1 (0%), 2 (50%), 4 (75%), 8 (87.5%), 16 (93.75%)
#			(default is 2, for 50%)
#	  -w win	specifies the apodization windowing function to smooth
#			the beginning and end of the sample, as described in
#			http://en.wikipedia.org/wiki/Apodization_function
#			choices: rectangular, hann, hamming, gauss, blackman,
#			nuttall, blackman-harris, blackman-nuttall, flat-top
#			(default is hann)
#			note that the same -w option has two uses, depending
#			on whether it's followed by a waveform number (as above)
#			or a function name (as described here)
#	  -p plttype	specifies type of plot file generated: plt, gif, png,
#			svg, eps, or pdf (default is plt, for HPGL output)
#			you can also use "x" to display the plot via xhpgl,
#			rather than saving it, or "-" to send HPGL to stdout,
#			and append ",log" to any of these to get a logarithmic
#			scale for the X axis generated via the gnuplot program,
#			or append ",gnu" to get a linear scale via gnuplot
#	  runfile	specifies one or more run file names to be measured
#			(no default, runfile must be specified)
#
# powersp performs a Fast Fourier Transform analysis on the specified waveforms
# in each runfile, or on the specified range for each waveform, and plots the
# resulting power spectrum graph. For each waveform, the calculated data points
# (frequency on X, power on Y) are stored in runfile-wnn-fft.csv, and the HPGL
# graph is stored in runfile-wnn-fft.plt, where nn is the 2-digit waveform
# number. It will append -rst-en after the waveform number, if a time range
# is given with the -r option, where st and en are the start and end times.
#
# The FFT is calculated using the fft program for Linux described here:
# http://sidstation.loudet.org/fft-en.xhtml
#
# E.g.:  powersp -w 0,7 -n 512 aojedro4damp02
#	 powersp -v -p svg,log -w 4 -f 2000 -r 8,20 cell8-05
#
# Copyright (c) 2012, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

lwfnum=0
ropt=
gwfopt=
fftopt=
plttype=plt
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	#-w)	shift; lwfnum="$1"; shift ;;
	-w[0-9]*)	lwfnum=`expr "x$1" : 'x-w\(.*\)'`; shift ;;
	-f)	shift; gwfopt="$gwfopt -f$1"; shift ;;
	-f[0-9]*)	gwfopt="$gwfopt $1"; shift ;;
	-r)	shift; gwfopt="$gwfopt -r$1"; ropt="-r$1"; shift ;;
	-r[0-9]*)	gwfopt="$gwfopt $1"; ropt="$1"; shift ;;
	-v*)	fftopt="$fftopt $1"; shift ;;
	-t)	shift; fftopt="$fftopt -t$1"; shift ;;
	-t[A-Za-z]*)	fftopt="$fftopt $1"; shift ;;
	-n)	shift; fftopt="$fftopt -n$1"; shift ;;
	-n[0-9]*)	fftopt="$fftopt $1"; shift ;;
	-[Oo])	shift; fftopt="$fftopt -O$1"; shift ;;
	-[Oo][0-9]*)	fftopt="$fftopt -O`expr x$1 : 'x-[Oo]\(.*\)'`"; shift ;;
	#-w)	shift; fftopt="$fftopt -w$1"; shift ;;
	-w[A-Za-z]*)	fftopt="$fftopt $1"; shift ;;
	-w)	shift;
		case "$1" in
		[0-9]*)	lwfnum="$1" ;;
		*)	fftopt="$fftopt -w$1" ;;
		esac
		shift ;;
	-p)	shift; plttype="$1"; shift ;;
	-p[A-Za-z]*)	plttype=`expr "x$1" : 'x-p\(.*\)'`; shift ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done

case "$#" in
0)	echo "Usage:  powersp [-w wfnum] [-f freq] [-r st,en] [-v] [-t type] [-n fftsize]
		[-o overlap] [-w win] [-p plttype] runfile ...
	or powersp --help	for detailed usage information" >&2; exit 1 ;;
esac

case "$lwfnum" in
[0-9]*)	;;
*)	echo "$0: Invalid waveform number or list of numbers: -w $lwfnum" >&2
	exit 1
	;;
esac

ofilter=cat
gpterm='hpgl 8'
gpopt=`expr "$plttype" : '.*,\(.*\)'`
gplt=0
plttype=`expr "$plttype" : '\([^,]*\),*.*'`
case "$plttype" in
-)	;;
x)	ofilter=xhpgl plttype=- ;;
plt)	;;
gif)	ofilter=hpgl2gif gpterm='gif' gplt=3 ;;
png)	ofilter=hpgl2png gpterm='png' gplt=3 ;;
svg)	ofilter=hpgl2svg gpterm='svg dynamic' gplt=3 ;;
eps)	ofilter=hpgl2cps gpterm='postscript eps solid color' gplt=3 ;;
pdf)	ofilter=hpgl2pdf gpterm='postscript eps solid color' gplt=3 ;;
*)	echo "$0: Invalid plottype: -p $plttype" >&2
	exit 1
	;;
esac

xlabel="Frequency (Hz)"
ylabel="Power (dB)"
case "$fftopt" in
*\ -tpsd*)	ylabel="Power Spectral Density (V2/Hz)" ;;
*\ -tps*)	ylabel="Power (V2)" ;;
*\ -tlsd*)	ylabel="Linear Spectral Density (V/sqrt-Hz)" ;;
*\ -tls*)	ylabel="Linear Spectrum (V)" ;;
*\ -tdbsd*)	ylabel="Spectral Density dB (V/sqrt-Hz)" ;;
esac

results=0
numruns=$#
ropt=`echo "$ropt" | tr ',' '-'`
lwfnum=`echo "$lwfnum" | tr ',' ' '`
#numwfs=`echo "$lwfnum" | wc -w`
for run
do
    test $# -gt 1 && echo "Analysing $run..." >&2
    rfile=`echo "$run" | sed 's/\.frm$//'`
    for wfnum in $lwfnum
    do
	fwf=$wfnum
	case "$fwf" in [0-9])	fwf="0$fwf" ;; esac
	ofile="$rfile-w$fwf$ropt-fft.csv"
	pfile="$rfile-w$fwf$ropt-fft.$plttype"
	case "$plttype" in
	-)	case "$gpopt" in
		"")	pfile="/dev/stdout" ;;
		*)	pfile="|$ofilter" ;;
		esac ;;
	pdf)	case "$gpopt" in
		?*)	pfile="| gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=- -g4600x3520 -c save pop -f - > $pfile" ;;
		esac ;;
	esac
	echo "Calculating $ofile..." >&2
	getwfdata -h $gwfopt "$rfile" "$wfnum" |
	    awk '/getwfdata.* -f/ {
			f=$0; sub(/^.* -f/, "", f); sub(/ .*/, "", f);
			r=1.0/f;
		 }
		 NR>2 { print (NR-2)*r, $0 / 1000.0; }' |
	    fft $fftopt -o "$ofile"
	if [ -s "$ofile" ]
	then
		results=`expr $results + 1`
		# clean up fft output into proper CSV file:
		sed -i -e 's/[ 	][ 	]*$//;
			   s/^[ 	][ 	]*//;
			   s/[ 	][ 	]*/, /g' "$ofile"
		lscopt=
		case "$gpopt" in
		"")	genplot -xf"$ofile" -xc1 -yf"$ofile" -yc2 -yp2 -yw0 \
			    -xh"$xlabel" -yh"$ylabel" | "$ofilter" > "$pfile"
			continue ;;
		log*)	lscopt="set logscale x" ;;
		esac
		gnuplot <<!
set terminal $gpterm
set output "$pfile"
set border 3
set xtics nomirror
set ytics nomirror
set tics out
set title
set xlabel "$xlabel"
set ylabel "$ylabel"
$lscopt
plot "$ofile" with line lt $gplt notitle
!
		case "$plttype" in
		svg)	if ! grep -s "xmlns=" "$pfile" >/dev/null
			then
				# add missing style info to gnuplot svg output:
				sed -i -e \
		's,xmlns:,xmlns="http://www.w3.org/2000/svg" &,' "$pfile"
			fi ;;
		esac
	fi
    done
    numruns=`expr $numruns - 1`
    test $numruns -gt 0 && echo "" >&2
done

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