#!/usr/bin/env python

#      Filename: ftqviz.py
#        Author: Darren Hart <dvhltc@us.ibm.com>
#   Description: Plot the time and frequency domain plots of a times and
#                counts log file pair from the FTQ benchmark.
# Prerequisites: numpy, scipy, and pylab packages.  For debian/ubuntu:
#                o python-numeric
#                o python-scipy
#                o python-matplotlib
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# Copyright (C) IBM Corporation, 2007
#
# 2007-Aug-30:  Initial version by Darren Hart <dvhltc@us.ibm.com>


from numpy import *
from numpy.fft import *
from scipy import *
from pylab import *
from sys import *
from getopt import *

NS_PER_S  = 1000000000
NS_PER_MS = 1000000
NS_PER_US = 1000

def smooth(x, wlen):
    if x.size < wlen:
        raise ValueError, "Input vector needs to be bigger than window size."

    # reflect the signal to avoid transients... ?
    s = r_[2*x[0]-x[wlen:1:-1], x, 2*x[-1]-x[-1:-wlen:-1]]
    w = hamming(wlen)

    # generate the smoothed signal
    y = convolve(w/w.sum(), s, mode='same')
    # recenter the the smoothed signal over the originals (slide along x)
    y1 = y[wlen-1:-wlen+1]
    return y1


def my_fft(x, sample_hz):
    X = abs(fftshift(fft(x)))
    freq = fftshift(fftfreq(len(x), 1.0/sample_hz))
    return array([freq, abs(X)/len(x)])


def smooth_fft(timefile, countfile, sample_hz, wlen):
    # The higher the sample_hz, the larger the required wlen (used to generate
    # the hamming window).  It seems that each should be adjusted by roughly the
    # same factor
    ns_per_sample = NS_PER_S / sample_hz

    print "Interpolated Sample Rate: ", sample_hz, " HZ"
    print "Hamming Window Length: ", wlen

    t = fromfile(timefile, dtype=int64, sep='\n')
    x = fromfile(countfile, dtype=int64, sep='\n')

    # interpolate the data to achieve a uniform sample rate for use in the fft
    xi_len = (t[len(t)-1] - t[0])/ns_per_sample
    xi = zeros(xi_len)
    last_j = 0
    for i in range(0, len(t)-1):
        j = (t[i] - t[0])/ns_per_sample
        xi[j] = x[i]
        m = (xi[j]-xi[last_j])/(j-last_j)
        for k in range(last_j + 1, j):
            xi[k] = m * (k - last_j) + xi[last_j]
        last_j = j

    # smooth the signal (low pass filter)
    try:
        y = smooth(xi, wlen)
    except ValueError, e:
        exit(e)

    # generate the fft
    X = my_fft(xi, sample_hz)
    Y = my_fft(y, sample_hz)

    # plot the hamming window
    subplot(311)
    plot(hamming(wlen))
    axis([0,wlen-1,0,1.1])
    title(str(wlen)+" Point Hamming Window")

    # plot the signals
    subplot(312)
    ts = arange(0, len(xi), dtype=float)/sample_hz # time signal in units of seconds
    plot(ts, xi, alpha=0.2)
    plot(ts, y)
    legend(['interpolated', 'smoothed'])
    title("Counts (interpolated sample rate: "+str(sample_hz)+" HZ)")
    xlabel("Time (s)")
    ylabel("Units of Work")

    # plot the fft
    subplot(313)
    plot(X[0], X[1], ls='steps', alpha=0.2)
    plot(Y[0], Y[1], ls='steps')
    ylim(ymax=20)
    xlim(xmin=-3000, xmax=3000)
    legend(['interpolated', 'smoothed'])
    title("FFT")
    xlabel("Frequency")
    ylabel("Amplitude")

    show()


def usage():
        print "usage: "+argv[0]+" -t times-file -c counts-file [-s SAMPLING_HZ] [-w WINDOW_LEN] [-h]"


if __name__=='__main__':

    try:
        opts, args = getopt(argv[1:], "c:hs:t:w:")
    except GetoptError:
        usage()
        exit(2)

    sample_hz = 10000
    wlen = 25
    times_file = None
    counts_file = None
    for o, a in opts:
        if o == "-c":
            counts_file = a
        if o == "-h":
            usage()
            exit()
        if o == "-s":
            sample_hz = long(a)
        if o == "-t":
            times_file = a
        if o == "-w":
            wlen = int(a)

    if not times_file or not counts_file:
        usage()
        exit(1)

    smooth_fft(times_file, counts_file, sample_hz, wlen)
