#!/usr/bin/perl -w
# tek-fft - Fast Fourier Transform for the Tektronix THS Family Oscilloscope
# (C)2003 Max Baker <max@warped.org>

use FindBin;
use lib $FindBin::Bin;

use Device::Tektronix;
use Math::FFT;
use Getopt::Long;

use vars qw/$scale $VERSION/;

$VERSION = 0.1;
# ChangeLog
# 0.1 - 12/13/03 - Initial Release

# Default Values
$output  = 'spectra.csv';
$data    = 'fft.csv';

$channel = 1;
$MaxFreq = 250e3;
$window  = 'hamm';

$baud    = 38400;
$port    = 'com1';

$batch   = 0;
$debug   = 0;
$usage   = 0;

GetOptions('o|output=s'  => \$output,
           'f|data=s'    => \$data,
           'b|baud=i'    => \$baud,
           'c|channel=i' => \$channel,
           'm|maxfreq=i' => \$MaxFreq,
           'd|debug'     => \$debug,
           'i|batch'     => \$batch,
           'p|port=s'    => \$port,
           'h|help|?'    => \$usage,
           'w|window'    => \$window,
           );

$usage and die &usage;

print "tek-fft - Fast Fourier Transform for Tektronix THS Series Oscilloscopes\n\n";

unless ($batch){
    print "Please get the waveform steady on the screen of the scope,\n";
    print "with the timebase set to show at least a couple repetions.\n";
    print "Set Volts/Div to show largest complete waveform.\n\n";
    print "Press enter to continue > ";
    my $null = <STDIN>;
}

print "Connecting to Scope on port $port at $baud baud.\n";
my $tek = new Device::Tektronix(debug => $debug,
                             port  => $port, 
                             baud  => $baud
                            )   
     or die "Couldn't load Device::Tektronix module.\n";
$tek->connect() or die "Can't connect to the serial port. ".$tek->error()."\n";

open (OUT,">$output") or die "Couldn't open $output for output. $!\n";
open (DATA,">$data") or die "Couldn't open $data for output. $!\n";

print "Configuring Scope\n";
my @data = getdata($tek);

print "Calculating FFT\n";
my $fft = new Math::FFT(\@data);

my $spectrum = $fft->spctrm(overlap => 1,window=>$window);

print "Sending output to $output.  Data logged to $data.\n";

# To convert from the resulting Bin to a frequency scale:
# Freq of Bin = Bin_Number * .01 / (scale)
for (my $i=0;$i<1025;$i++){
    my $val = $spectrum->[$i];

    # Data seems to be about 2 bins off
    my $freq = .01 * ($i+2) / ($scale);
    
    last if $freq > $MaxFreq;
    printf OUT "%2.2e,%f\n",$freq,$val;
}

sub getdata {
    my $tek = shift;

    # Setup Waveform output
    $tek->waveform->encoding('ulsb');   # signed, MSB first
    $tek->waveform->source("ch$channel");
    $tek->waveform->start(1);
    $tek->waveform->stop(2049);
    $tek->waveform->width(8);
    
    # Setup Channel
    $tek->channel->bandwidth($channel,'full');
    $tek->channel->invert($channel,'off');
    $tek->channel->position($channel,0);
    $scale = $tek->time->scale;  
    #$tek->channel->scale($channel,2); #volt

    # Setup Trigger
    # TODO - Hangs
    #$tek->trigger->source('ch1');
    # TODO - Doesnt work
    #$tek->trigger->couple('noise');
    $tek->trigger->auto_set;

    $tek->diag->lock('none');

    my $data = $tek->waveform->get;

    print "Data is ",length($data)," bytes long.\n" if $debug;

    # The unsigned data gives the range of the screen, center 
    # Screen is at 127, so each datapoint is offset by that amount.
    my @data = map( { $_-127 } unpack('C*',$data));
    
    # Dump data to output file
    for (my $i=0; $i< @data ;$i++){
        print DATA "$data[$i]\n";
    }

    return @data;
}

sub usage {
    return <<"end_usage";
tek-fft - Fast Fourier Transform for Tektronix THS Series Oscilloscopes

    Command Line Arguments              Default Values
------------------------------------------------------------------------
    -o  Output File for FFT                 ($output)
    -f  File for Data Logging of Waveform   ($data)

    -m  Maximum Frequency for Spectral Data ($MaxFreq Hz)
    -c  Channel To Use                      (Channel $channel)
    -w  Window Type : bartlett,hamm,welch   ($window)

    -p  COM Port                            ($port)
    -b  BAUD Rate                           ($baud)

    -i  Batch Mode (no interactive)
    -d  Debug Mode

    * The Output file has frequency,power per line CSV format
      Output is the Power Spectral Density. See Math::FFT for details.
    * The data file has one entry per line that makes up the waveform.
    * Uses Math::FFT with Overlap and Barttlet Windowing
    * Output limited to 250Mhz.  A 100Mhz scope is not going to give 
      much more useful frequency content past that.  Maybe make it 
      500 Mhz for a THS730.
end_usage
}

=pod

Copyright (C) 2003 by Max Baker

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.1 or,
at your option, any later version of Perl 5 you may have available.

=cut
