chiark / gitweb /
readahead to cope with plusses; no y2tics if unneeded
[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 #
22 # Input file should be a .cir file (will be put through gnucap)
23 #  or an output file from gnucap.
24 #
25 # Produces various output files:
26 #  <input-file>.gnuplots.sh                     run this to display results
27 #  <input-file>,<Kind><N>.gnuplot-cmd           gnuplot script for displaying:
28 #  <input-file>,<Kind><N>-<M>.gnuplot-data      gnuplot-format input data
29 #  <input-file>,gnuplot-fifo                    working fifo for .gnuplots.sh
30 # where
31 #  <Kind> is Freq or Time (according to the type of analysis)
32 #  <N>    is the count, starting at 0, of which report this is from gnucap
33 #  <M>    is the individual column of Y data
34 #
35 # Options
36 #   -g          do run gnucap     ) default is run gnucap
37 #   -G          don't run gnucap  )  if input file ends in .cir
38 #   -o<prefix>  use <prefix> instead of <input-file> in output filenames
39 # If the input file is `-' then you may not specify -g and must use -o.
40 #
41 # Limitations
42 #
43 #  Only Freq (.AC) and Time (.TRAN) plots have been tested.  If
44 #   other types go wrong they can probably be fixed by adding code for
45 #   them to startplot().
46 #
47 #  Displaying voltages and currents on the same .TRAN graph won't work
48 #   well because they currently have to have the same Y scale.  This
49 #   could be fixed by assigning carefully to $mmm in startplot().
50 #
51 #  It's a bit clumsy.
52 #
53 #  There's no easy way to mess with the gnuplot settings.
54
55 sub fail ($) { die "gnucap2gnuplot: $_[0]\n"; }
56
57 while ($ARGV[0] =~ m/^\-./) {
58     if (m/^\-\-$/) {
59         last;
60     } elsif (m/^\-g$/) {
61         $rungnucap= 1;
62     } elsif (m/^\-G$/) {
63         $rungnucap= 0;
64     } elsif (m/^\-o(.+)$/) {
65         $ofb= $1;
66     } else {
67         fail("unknown option $_\n");
68     }
69 }
70
71 if (@ARGV) {
72     @ARGV==1 or fail("one input file only please");
73     $if= shift @ARGV;
74     $ofb= $if unless defined $ofb;
75     $rungnucap= $if =~ m/\.cir$/i unless defined $rungnucap;
76     open STDIN, $rungnucap ? "gnucap -b $if |" : "< $if"
77         or fail("open $if: $!");
78 } else {
79     fail("cannot run gnucap on stdin, run it yourself") if $rungnucap;
80     fail("you must specify -o... when running from stdin") unless defined $ofb;
81 }
82
83 %facttimes= qw(f 1e-15
84                p 1e-12
85                n 1e-9
86                u 1e-6
87                m 1e-3
88                K 1e3
89                Meg 1e6
90                G 1e9
91                T 1e12);
92
93 $sof= "$ofb.gnuplots.sh";
94 open A, "> $sof" or die $!;
95 system 'chmod','+x',"$sof"; $? and die $?;
96 print A <<END
97 #!/bin/sh
98 set -e
99 fi=$ofb,gnuplot-fifo
100 rm -f \$fi
101 mkfifo -m 600 \$fi
102 END
103     or die $!;
104 sub startplot () {
105     open S, "> $ofb,$cplot.gnuplot-cmd" or die $!;
106     print S <<END
107 set data style linespoints
108 set title '$cplot'
109 END
110         or die $!;
111     $mmm[0]= 'x';
112     for ($yn=1; $yn<=$#columns; $yn++) {
113         $mmm[$yn]= 'y';
114     }
115     undef %min;
116     undef %max;
117     if ($kind eq 'Freq') {
118         for ($yn=1; $yn<=$#columns; $yn++) {
119             die unless $columns[$yn] =~ m/.*([MP])\(\d+\)$/;
120             $mmm[$yn]= 'y2' if $1 eq 'P';
121         }
122         print S "set logscale xy\nset y2tics autofreq\n" or die $!;
123     }
124     for ($yn=1; $yn<=$#columns; $yn++) {
125         open "O$yn", "> $ofb,$cplot-$yn.gnuplot-data" or die $!;
126     }
127 }
128 sub endplot () {
129     return unless defined $kind;
130     foreach $mmm (keys %min) {
131         print S "set ${mmm}range [$min{$mmm}:$max{$mmm}]\n" or die $!;
132     }
133     $sep= "plot ";
134     for ($yn=1; $yn<=$#columns; $yn++) {
135         close "O$yn" or die $!;
136         $mmm[$yn] =~ m/^y2?$/ or die "$mmm[$yn]";
137         $axes= $mmm[$yn]; $axes =~ s/^y$/y1/;
138         $yoff= 1-$yn;
139         print S "$sep\\\n".
140             " '$ofb,$cplot-$yn.gnuplot-data'".
141                 " axes x1$axes title '$columns[$yn]'"
142             or die $!;
143         $sep= ',';
144     }
145     print S "\n\npause -1\n" or die $!;
146     close S or die $!;
147     print A "  gnuplot $ofb,$cplot.gnuplot-cmd <\$fi &\n" or die $!;
148     $kind= undef;
149 }
150
151 $readahead= <STDIN>;
152 for (;;) {
153     $linesofar= $readahead;
154     for (;;) {
155         $readahead= <STDIN>;
156         last unless $readahead =~ s/^\+//;
157         die unless length $linesofar;
158         $linesofar =~ s/\n$//;
159         $linesofar .= $readahead;
160     }
161     $_= $linesofar;
162     last unless length;
163     s/\s+$//;
164     
165     if (m/^\#(\w+)/) {
166         endplot();
167         $kind= $1;
168         @columns= split /\s+/;
169         $cplot= $kind.($counter{$kind}++);
170         startplot();
171         next;
172     } elsif (!defined $kind) {
173         next;
174     } elsif (s/^\s+//) {
175         @numbers= split /\s+/;
176         die unless @numbers == @columns;
177         for ($yn=0; $yn<=$#columns; $yn++) {
178             $_= $numbers[$yn];
179             if (m/^(\-?\d+\.\d*)([A-Za-z]+)$/) {
180                 die "factor $2" unless exists $facttimes{$2};
181                 $_= $1*$facttimes{$2};
182                 $numbers[$yn]= $_;
183             }
184             $mmm= $mmm[$yn];
185             $min{$mmm}= $_ unless exists($min{$mmm}) && $min{$mmm} <= $_;
186             $max{$mmm}= $_ unless exists($max{$mmm}) && $max{$mmm} >= $_;
187             if ($yn) {
188                 printf {"O$yn"} "%s %s\n", $numbers[0], $_
189                     or die $!;
190             }
191         }
192     } else {
193         die "$_ ?";
194     }
195 }
196 die "no plots" unless defined $kind;
197 endplot();
198 print A <<END
199 exec 3>\$fi
200 printf 'hit return to quit: '
201 read
202 exec 3>&-
203 END
204     or die $!;
205 close A or die $!;
206 $?=0; close STDIN; $? and fail("gnucap failed (code $?)");
207 $sof= "./$sof" unless $sof =~ m,/,;
208 print ": generated ; $sof\n" or die $!;
209
210 # $Id: gnucap2gnuplot,v 1.3 2004-03-24 01:00:50 ianmdlvl Exp $