bug-gnucap
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Bug-gnucap] gnucap2gnuplot


From: Ian Jackson
Subject: [Bug-gnucap] gnucap2gnuplot
Date: Tue, 23 Mar 2004 23:05:55 +0000

I was tripped up by the lack of a graphical postprocessor for gnucap,
so I spent an little while writing a small script which converts
gnucap output to gnuplot input.

It's not very good or complete and the documentation is a sketchy head
comment, so I'll quite understand if you don't want to include it with
the gnucap distribution.  But I thought I should let you see it.

For now I have checked it into one of my CVS projects, and if a better
plan doesn't materialise I'll release it as part of the next version
of `chiark-utils' (a non-GNU ragbag collection of small utilities).

I'm going to go and keep using it now, and will probably discover more
bugs and/or add more features.  So if you decide to include it please
let me know so that I can send you the most recent version, and
obviously if you modify it please send me the diffs.

Thanks,
Ian.

#!/usr/bin/perl
# This is gnucap2gnuplot, which is Copyright 2004 Ian Jackson.
# It's a script to postprocess the output from gnucap and then run gnuplot.
#
# gnucap2gnuplot and its documentation are free software; you can
# redistribute them and/or modify them under the terms of the GNU
# General Public License as published by the Free Software Foundation;
# either version 2, or (at your option) any later version.
# 
# gnucap2gnuplot and its documentation are distributed in the hope that
# they 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.
# 
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

# usage:
#    gnucap2gnuplot [<options>] input-file
#
# Input file should be a .cir file (will be put through gnucap)
#  or an output file from gnucap.
#
# Produces various output files:
#  <input-file>.gnuplots.sh                     run this to display results
#  <input-file>,<Kind><N>.gnuplot-cmd           gnuplot script for displaying:
#  <input-file>,<Kind><N>-<M>.gnuplot-data      gnuplot-format input data
#  <input-file>,gnuplot-fifo                    working fifo for .gnuplots.sh
# where
#  <Kind> is Freq or Time (according to the type of analysis)
#  <N>    is the count, starting at 0, of which report this is from gnucap
#  <M>    is the individual column of Y data
#
# Options
#   -g          do run gnucap     ) default is run gnucap
#   -G          don't run gnucap  )  if input file ends in .cir
#   -o<prefix>  use <prefix> instead of <input-file> in output filenames
# If the input file is `-' then you may not specify -g and must use -o.
#
# Limitations
#
#  Only Freq (.AC) and Time (.TRAN) plots have been tested.  If
#   other types go wrong they can probably be fixed by adding code for
#   them to startplot().
#
#  Displaying voltages and currents on the same .TRAN graph won't work
#   well because they currently have to have the same Y scale.  This
#   could be fixed by assigning carefully to $mmm in startplot().
#
#  It's a bit clumsy.
#
#  There's no easy way to mess with the gnuplot settings.

sub fail ($) { die "gnucap2gnuplot: $_[0]\n"; }

while ($ARGV[0] =~ m/^\-./) {
    if (m/^\-\-$/) {
        last;
    } elsif (m/^\-g$/) {
        $rungnucap= 1;
    } elsif (m/^\-G$/) {
        $rungnucap= 0;
    } elsif (m/^\-o(.+)$/) {
        $ofb= $1;
    } else {
        fail("unknown option $_\n");
    }
}

if (@ARGV) {
    @ARGV==1 or fail("one input file only please");
    $if= shift @ARGV;
    $ofb= $if unless defined $ofb;
    $rungnucap= $if =~ m/\.cir$/i unless defined $rungnucap;
    open STDIN, $rungnucap ? "gnucap -b $if |" : "< $if"
        or fail("open $if: $!");
} else {
    fail("cannot run gnucap on stdin, run it yourself") if $rungnucap;
    fail("you must specify -o... when running from stdin") unless defined $ofb;
}

%facttimes= qw(f 1e-15
               p 1e-12
               n 1e-9
               u 1e-6
               m 1e-3
               K 1e3
               Meg 1e6
               G 1e9
               T 1e12);

$sof= "$ofb.gnuplots.sh";
open A, "> $sof" or die $!;
system 'chmod','+x',"$sof"; $? and die $?;
print A <<END
#!/bin/sh
set -e
fi=$ofb,gnuplot-fifo
rm -f \$fi
mkfifo -m 600 \$fi
END
    or die $!;
sub startplot () {
    open S, "> $ofb,$cplot.gnuplot-cmd" or die $!;
    print S <<END
set data style linespoints
set y2tics autofreq
set title '$cplot'
END
        or die $!;
    $mmm[0]= 'x';
    for ($yn=1; $yn<=$#columns; $yn++) {
        $mmm[$yn]= 'y';
    }
    undef %min;
    undef %max;
    if ($kind eq 'Freq') {
        for ($yn=1; $yn<=$#columns; $yn++) {
            die unless $columns[$yn] =~ m/.*([MP])\(\d+\)$/;
            $mmm[$yn]= 'y2' if $1 eq 'P';
        }
        print S "set logscale xy\n" or die $!;
    }
    for ($yn=1; $yn<=$#columns; $yn++) {
        open "O$yn", "> $ofb,$cplot-$yn.gnuplot-data" or die $!;
    }
}
sub endplot () {
    return unless defined $kind;
    foreach $mmm (keys %min) {
        print S "set ${mmm}range [$min{$mmm}:$max{$mmm}]\n" or die $!;
    }
    $sep= "plot ";
    for ($yn=1; $yn<=$#columns; $yn++) {
        close "O$yn" or die $!;
        $mmm[$yn] =~ m/^y2?$/ or die "$mmm[$yn]";
        $axes= $mmm[$yn]; $axes =~ s/^y$/y1/;
        $yoff= 1-$yn;
        print S "$sep\\\n".
            " '$ofb,$cplot-$yn.gnuplot-data'".
                " axes x1$axes title '$columns[$yn]'"
            or die $!;
        $sep= ',';
    }
    print S "\n\npause -1\n" or die $!;
    close S or die $!;
    print A "  gnuplot $ofb,$cplot.gnuplot-cmd <\$fi &\n" or die $!;
    $kind= undef;
}

while (<STDIN>) {
    s/\s+$//;
    if (m/^\#(\w+)/) {
        endplot();
        $kind= $1;
        @columns= split /\s+/;
        $cplot= $kind.($counter{$kind}++);
        startplot();
        next;
    } elsif (!defined $kind) {
        next;
    } elsif (s/^\s+//) {
        @numbers= split /\s+/;
        die unless @numbers == @columns;
        for ($yn=0; $yn<=$#columns; $yn++) {
            $_= $numbers[$yn];
            if (m/^(\-?\d+\.\d*)([A-Za-z]+)$/) {
                die "factor $2" unless exists $facttimes{$2};
                $_= $1*$facttimes{$2};
                $numbers[$yn]= $_;
            }
            $mmm= $mmm[$yn];
            $min{$mmm}= $_ unless exists($min{$mmm}) && $min{$mmm} <= $_;
            $max{$mmm}= $_ unless exists($max{$mmm}) && $max{$mmm} >= $_;
            if ($yn) {
                printf {"O$yn"} "%s %s\n", $numbers[0], $_
                    or die $!;
            }
        }
    } else {
        die "$_ ?";
    }
}
die "no plots" unless defined $kind;
endplot();
print A <<END
exec 3>\$fi
printf 'hit return to quit: '
read
exec 3>&-
END
    or die $!;
close A or die $!;
$?=0; close STDIN; $? and fail("gnucap failed (code $?)");
$sof= "./$sof" unless $sof =~ m,/,;
print ": generated ; $sof\n" or die $!;

# $Id: gnucap2gnuplot,v 1.2 2004/03/23 23:03:06 ianmdlvl Exp $




reply via email to

[Prev in Thread] Current Thread [Next in Thread]