#!/bin/sh
#
# lininterp - perform linear interpolation of data in ASCII (or CSV) file
#
# Usage:  lininterp [-c column] [-m mult] [-s start] [-e end] [-i incr] file ...
#
# where:  -c column	specifies the column number for time base
#			(default is 1)
#	  -m mult	specifies the multiplier for scaling interpolated data
#			(default is 1)
#	  -s start	specifies the starting time for the interpolated data
#			(default is the original start time rounded up to the
#			 next step increment)
#	  -e end	specifies the ending time for the interpolated data
#			(default is the original end time rounded down to the
#			 previous step increment)
#	  -i incr	specifies the time increment for the interpolated data
#			(default is the average time interval in the input data
#			 rounded down to the closest power of 10)
#	  file		specifies one or more ASCII file names to be processed
#			(no default, file must be specified, - for std input)
#
# Interpolates data points in one or more columns of input by sorting the
# data based on the time base column, which can be irregularly spaced, and
# generating an evenly spaced time series in its place.  New data points will
# be generated in other columns based on linear interpolation of data between
# points given in original time series.  Multiplier will be applied to all
# columns except specified time base column.  Input and output is in ASCII
# format, separated by space, tab or comma.
#
# Copyright (c) 2006, Gilles Detillieux, Spinal Cord Research Centre,
# University of Manitoba.  All Rights Reserved.
#

copt=1 mopt=1
sopt= eopt= iopt=
while :
do
	case "$1" in
	-\?|-help|--help)	sed -n '3,/^# Univ/s/^#/ /p' "$0"; exit ;;
	-c[0-9]*)	copt=`expr "x$1" : 'x-c\(.*\)'`; shift ;;
	-c)	shift; copt="$1"; shift ;;
	-m[0-9]*)	mopt=`expr "x$1" : 'x-m\(.*\)'`; shift ;;
	-m)	shift; mopt="$1"; shift ;;
	-s[0-9]*)	sopt=`expr "x$1" : 'x-s\(.*\)'`; shift ;;
	-s)	shift; sopt="$1"; shift ;;
	-e[0-9]*)	eopt=`expr "x$1" : 'x-e\(.*\)'`; shift ;;
	-e)	shift; eopt="$1"; shift ;;
	-i[0-9]*)	iopt=`expr "x$1" : 'x-i\(.*\)'`; shift ;;
	-i)	shift; iopt="$1"; shift ;;
	-)	break ;;
	-*)	set --; break ;;
	*)	break ;;
	esac
done

case "$#" in
0)	echo "Usage:  lininterp [-c column] [-m mult] [-s start] [-e end] [-i incr] file ...
	or lininterp --help	for detailed usage information" >&2; exit 1 ;;
esac

case "$copt" in
[1-9]*)	col0orig=`expr "$copt" - 1` ;;
*)	echo "$0: Invalid column number for time base: -c $copt" >&2
	exit 1
	;;
esac

case "$mopt" in
[.0-9]*|-[.0-9]*)	;;
*)	echo "$0: Invalid number of scaling factor: -m $mopt" >&2
	exit 1
	;;
esac

sortflags="+${col0orig}n"
sort $sortflags </dev/null 2>/dev/null || sortflags="-k `expr $col0orig + 1`n"

sed -e '/^[ 	]*[^-0-9.e+]/d; /^[ 	]*$/d; s/,\([^ 	]\)/, \1/g' ${@+"$@"} |
 sort $sortflags |
 sed -e '1{h;s/^[ 	]*[-0-9.e+]*\([^-0-9.]*\).*/\1/p;g;}; s/,/ /g' |
 awk 'BEGIN {
	mult = '"$mopt"';
	tcolumn = '"$copt"';
	startt = "'"$sopt"'";
	endt = "'"$eopt"'";
	tstep = "'"$iopt"'";
	colsep = ",";
	ncols = 0;
	nrows = 0;
      }
      NR == 1 && /^..*$/ {
	colsep = $0;
      }
      NR > 1 {
	if (ncols == 0) {
	    ncols = NF;
	}
	for (i = 1; i <= ncols; i++) {
	    data[nrows, i] = $(i);
	    if (i == tcolumn) {
		if (nrows == 0 || mint > $(i))
		    mint = $(i);
		if (nrows == 0 || maxt < $(i))
		    maxt = $(i);
	    }
	}
	++nrows;
      }
      END {
	if (tstep == "") {
	    if (nrows <= 0)
		avgt = 1;
	    else
		avgt = (maxt-mint) / nrows;
	    tstep = 1000000000.0;
	    while (tstep > avgt)
		tstep /= 10.0;
	}
	if (startt == "")
	    startt = (int(mint / tstep) + 1) * tstep;
	if (endt == "")
	    endt = maxt;
	nsteps = int((endt-startt) / tstep);
	while (startt + nsteps*tstep <= endt)
	    ++nsteps;
	r = 0;
	for (n = 0; n < nsteps; ++n) {
	    t = startt + n*tstep;
	    while (r < nrows-2 && data[r+1, tcolumn] < t)
		++r;
	    tscale = (t-data[r, tcolumn]) / (data[r+1, tcolumn]-data[r, tcolumn]);
	    for (i = 1; i <= ncols; i++) {
		if (i > 1)
		    printf("%s", colsep);
		if (i == tcolumn) {
		    printf("%s", t);
		} else {
		    printf("%g", (data[r, i] + (data[r+1, i]-data[r, i])*tscale) * mult);
		}
	    }
	    #printf("%s%s%s%s", colsep, data[r, tcolumn], colsep, data[r+1, tcolumn]);
	    printf("\n");
	}
      }'
