chiark / gitweb /
904649e20f6d5c4fa021d368151e83fe31d7ade7
[chiark-utils.git] / scripts / gnucap2gnuplot
1 #!/usr/bin/perl
2 # This is gnucap2gnuplot, which is Copyright 2004 Ian Jackson.
3 # It's a script to postprocess the output from gnucap and then run gnuplot.
4 #
5 # gnucap2gnuplot and its documentation are free software; you can
6 # redistribute them and/or modify them under the terms of the GNU
7 # General Public License as published by the Free Software Foundation;
8 # either version 2, or (at your option) any later version.
9
10 # gnucap2gnuplot and its documentation are distributed in the hope that
11 # they will be useful, but WITHOUT ANY WARRANTY; without even the
12 # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 # PURPOSE.  See the GNU General Public License for more details.
14
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 # usage:
20 #    gnucap2gnuplot [<options>] input-file
21 # Input file should be a .cir file (will be put through gnucap)
22 #  or an output file from gnucap.
23 # Produces various output files:
24 #  <input-file>.gnuplots.sh                     run this to display results
25 #  <input-file>,<Kind><N>.gnuplot-cmd           gnuplot script for displaying:
26 #  <input-file>,<Kind><N>-<M>.gnuplot-data      gnuplot-format input data
27 #  <input-file>,gnuplot-fifo                    working fifo for .gnuplots.sh
28 # where
29 #  <Kind> is Freq or Time (according to the type of analysis)
30 #  <N>    is the count, starting at 0, of which report this is from gnucap
31 #  <M>    is the individual column of Y data
32 #
33 # Limitations
34 #
35 #  Only Freq (.AC) and Time (.TRAN) plots have been tested.  If
36 #   other types go wrong they can probably be fixed by adding code for
37 #   them to startplot().
38 #
39 #  Displaying voltages and currents on the same .TRAN graph won't work
40 #   well because they currently have to have the same Y scale.  This
41 #   could be fixed by assigning carefully to $mmm in startplot().
42 #
43 #  It's a bit clumsy.
44 #
45 #  There's no easy way to mess with the gnuplot settings.
46
47 sub fail ($) { die "gnucap2gnuplot: $_[0]\n"; }
48
49 while ($ARGV[0] =~ m/^\-./) {
50     if (m/^\-\-$/) {
51         last;
52     } elsif (m/^\-g$/) {
53         $rungnucap= 1;
54     } elsif (m/^\-G$/) {
55         $rungnucap= 0;
56     } elsif (m/^\-o(.+)$/) {
57         $ofb= $1;
58     } else {
59         fail("unknown option $_\n");
60     }
61 }
62
63 if (@ARGV) {
64     @ARGV==1 or fail("one input file only please");
65     $if= shift @ARGV;
66     $ofb= $if unless defined $ofb;
67     $rungnucap= $if =~ m/\.cir$/i unless defined $rungnucap;
68     open STDIN, $rungnucap ? "gnucap -b $if |" : "< $if"
69         or fail("open $if: $!");
70 } else {
71     fail("cannot run gnucap on stdin, run it yourself") if $rungnucap;
72     fail("you must specify -o... when running from stdin") unless defined $ofb;
73 }
74
75 %facttimes= qw(f 1e-15
76                p 1e-12
77                n 1e-9
78                u 1e-6
79                m 1e-3
80                K 1e3
81                Meg 1e6
82                G 1e9
83                T 1e12);
84
85 $sof= "$ofb.gnuplots.sh";
86 open A, "> $sof" or die $!;
87 system 'chmod','+x',"$sof"; $? and die $?;
88 print A <<END
89 #!/bin/sh
90 set -e
91 fi=$ofb,gnuplot-fifo
92 rm -f \$fi
93 mkfifo -m 600 \$fi
94 END
95     or die $!;
96 sub startplot () {
97     open S, "> $ofb,$cplot.gnuplot-cmd" or die $!;
98     print S <<END
99 set data style linespoints
100 set y2tics autofreq
101 set title '$cplot'
102 END
103         or die $!;
104     $mmm[0]= 'x';
105     for ($yn=1; $yn<=$#columns; $yn++) {
106         $mmm[$yn]= 'y';
107     }
108     undef %min;
109     undef %max;
110     if ($kind eq 'Freq') {
111         for ($yn=1; $yn<=$#columns; $yn++) {
112             die unless $columns[$yn] =~ m/.*([MP])\(\d+\)$/;
113             $mmm[$yn]= 'y2' if $1 eq 'P';
114         }
115         print S "set logscale xy\n" or die $!;
116     }
117     for ($yn=1; $yn<=$#columns; $yn++) {
118         open "O$yn", "> $ofb,$cplot-$yn.gnuplot-data" or die $!;
119     }
120 }
121 sub endplot () {
122     return unless defined $kind;
123     foreach $mmm (keys %min) {
124         print S "set ${mmm}range [$min{$mmm}:$max{$mmm}]\n" or die $!;
125     }
126     $sep= "plot ";
127     for ($yn=1; $yn<=$#columns; $yn++) {
128         close "O$yn" or die $!;
129         $mmm[$yn] =~ m/^y2?$/ or die "$mmm[$yn]";
130         $axes= $mmm[$yn]; $axes =~ s/^y$/y1/;
131         $yoff= 1-$yn;
132         print S "$sep\\\n".
133             " '$ofb,$cplot-$yn.gnuplot-data'".
134                 " axes x1$axes title '$columns[$yn]'"
135             or die $!;
136         $sep= ',';
137     }
138     print S "\n\npause -1\n" or die $!;
139     close S or die $!;
140     print A "  gnuplot $ofb,$cplot.gnuplot-cmd <\$fi &\n" or die $!;
141     $kind= undef;
142 }
143
144 while (<STDIN>) {
145     s/\s+$//;
146     if (m/^\#(\w+)/) {
147         endplot();
148         $kind= $1;
149         @columns= split /\s+/;
150         $cplot= $kind.($counter{$kind}++);
151         startplot();
152         next;
153     } elsif (!defined $kind) {
154         next;
155     } elsif (s/^\s+//) {
156         @numbers= split /\s+/;
157         die unless @numbers == @columns;
158         for ($yn=0; $yn<=$#columns; $yn++) {
159             $_= $numbers[$yn];
160             if (m/^(\-?\d+\.\d*)([A-Za-z]+)$/) {
161                 die "factor $2" unless exists $facttimes{$2};
162                 $_= $1*$facttimes{$2};
163                 $numbers[$yn]= $_;
164             }
165             $mmm= $mmm[$yn];
166             $min{$mmm}= $_ unless exists($min{$mmm}) && $min{$mmm} <= $_;
167             $max{$mmm}= $_ unless exists($max{$mmm}) && $max{$mmm} >= $_;
168             if ($yn) {
169                 printf {"O$yn"} "%s %s\n", $numbers[0], $_
170                     or die $!;
171             }
172         }
173     } else {
174         die "$_ ?";
175     }
176 }
177 die "no plots" unless defined $kind;
178 endplot();
179 print A <<END
180 exec 3>\$fi
181 printf 'hit return to quit: '
182 read
183 exec 3>&-
184 END
185     or die $!;
186 close A or die $!;
187 $?=0; close STDIN; $? and fail("gnucap failed (code $?)");
188 $sof= "./$sof" unless $sof =~ m,/,;
189 print ": generated ; $sof\n" or die $!;