-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathREADME
445 lines (322 loc) · 13.9 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
NAME
PDpost - an interactive language for post-processing and plotting of SPICE files
Synopsis
Richard Walker
released under GPL v2.0
Post can do math on piece-wise-linear SPICE waveforms. Plot gives
you an interactive shell where you can type expressions like:
gr db((v1-v2)/v3) ; graph log of (v1-v2)/v3
gr versus(v1,mod(time,100p)) ; graph a 10Gb/s eye diagram
gr integral(v2) ; graph the integral of v2
gr v1, delay(v2,1n) ; graph v1 and a delayed v2 on same graph
gr mag(v1), im(v2) ; magnitude of v1, imaginary part of v2
Functions:
avg() db() cos() dt() exp() greater() lpf() im() integral()
pha() less() ln() log10() log re() mag() mod() min() max()
pause() pow sin() sqrt() warp() versus() delay() ui()
xcross() xcrossn() xcrossp()
Commands:
gr gs ci di ls pr print quit exit bye
This version defaults to use the pdplot(1) program for plotting.
gr v1 logx ; logx
gr db(v1) logf ; logf
gr db(v1) yl 0,10 ; ylimit
gr db(v1) xl 0,10 ; xlimit
Gnuplot(1) can be used instead by specifying the -g option. However,
no further development with gnuplot is anticipated. It doesn't behave
nicely on my system (grabbing the focus and relocating the window after
each plot), so pdplot(1) is preferred. Eventually, I plan to integrate
the plotting engine into the same source as post to avoid the slow
transmission of large data sets between separate programs using pipes.
Some preliminary experiments show that 10x speedups are possible by
plotting only visible pixels and not sending the complete dataset to the
plotter.
In either case, you will need to install your graphing program of
choice.
--
Rick Walker
QUICK START
----------
For a quick start, type "make depend" and then "make". If you like
what you see, then run "make install" with sufficient permission to
write in "/usr/local/bin".
Post does it's graphing with either pdplot() or gnuplot() which you will
need to install first. Pdplot is preferred because it was developed
together with post and is optimized for the application. Gnuplot() is
used when the "-g" option is specified.
Run post with "post [-g] [-r <rawfile>] [scriptfilenames...]".
You might try the included "run" script. If given the basename of a
spice .cki file, it will check to see if a .raw file already exists that
is newer than the .cki file. If not, it will build it. Then it will
invoke post(1) on the .raw file.
Post(1) will start up interactively if given no arguments. You'll get a
":" prompt in your terminal window. If you want Post to simply run a
script and exit, you can invoke it with the name of the file. If you'd
like Post to load up a particular rawfile before giving you a prompt,
you can use the "-r <rawfile>" command.
Post(1) has command line editing in interactive mode. Emacs is the
default, but I switch it to "vi" mode by having a .inputrc file in my home
directory which looks like:
-------------- cut here ---------------
# this is the gnu-readline configuration file
set editing-mode vi
set keymap vi
-------------- cut here ---------------
If you have written some nice waveform definitions for post you can put
them in file and load them at start up time with "post mydefs -". Post
will load all listed files into memory. The final "-" drops you into
interactive mode after loading everything.
Of course, the most important feature is loading spice raw files.
You can get a list of loadable spice raw files with "ls".
You can load a rawfile with
: ci "file"
The filename must be in quotes. You can list the loaded variables
with "di". In addition to dependant variables from the SPICE deck,
there will be a synthetic time variable that can be used for making
calculations as a function of the time axis.
Post ignores anything from a "#" character to the end of the line.
C-style comments "/* .... */" are also recognized and can be used in
scripts to comment out multiple lines.
NUMBERS
-------
Numbers can be real or complex. All numbers are cast to double precision.
Reference to an undefined name automatically creates a zero-valued
variable.
Engineering notation is supported.
Starting with A,a for "atto" or 10^-18, permitted suffixes are:
F,f (10^-15), P,p (10-^12), N,n (10^-9), U,u (10^e-6), "%" (10e-2),
k,K (10^3), MEG,meg (10^6), G,g (10^9) and T,t (10^12).
Some examples of valid numbers are:
.1
1.0
-1.3e-7
1f
10P
8meg
The variable name "i" and "I" are both equal to the imaginary number
sqrt(-1). You can create a pure imaginary number with "3i", or "3*i".
Mixed numbers are written as "1+i" or 1+3*i" or "1+3i".
Examples:
:i
i
:3i
3i
:3n*i
3e-09i
:1p+i
1e-12+i
VARIABLES
---------
Variables names must start with any alphabetic character or the "_"
character. The remainder of the variable name must be composed of
any alphanumeric character, or the characters "_<>".
Piecewise linear waveforms can be defined by
:a = {0,0; 1,4; 3,4; 4,3}
a list of independant value, dependant value pairs. It is required that
the independant value be in strict monotonic rising order. For many
engineering applications the independant variable will be either time or
frequency, however it can also represent space, or any other parameter
such as a resistor values in circuit.
As implemented, a PWL can be thought of as both a data-type and a
function. if a is defined as above then a(1) will return 4. a(2) also
returns 4 by interpolation. a(sqrt(4)) will return 4.0. This
functional notation replaces the yvalue() function of HP's post.
Expressions are fairly obvious, read below for details. You can
graph any number of expressions on the same graph with "gr".
: gr a,b,c
You can plot two groups of variables on separate axes with
: gr a,b,c ; d, e, f
You can limit the xaxis range with "xl <start>,<stop>". This
will apply to all axes. If xl is used twice on a command line,
the last one will take precedence:
: gr a,b ; d,e xl .1,1.8
Finally, each graph can have its yaxis range set with "yl <min>,<max>"
: gr a,b yl -1,1; d,e yl -2,2 xl .1,1.8
The rule is that each expression or PWL name must be separated from any
other PWL or expression by either a "," or a ";". A semicolon creates
second plot.
Piecewise linear (PWL) variables can be treated like normal scalars.
Generally post will do the obvious, most useful thing. Adding two PWLs
with
: c=a+b
will add them point by point, cross-interpolating where necessary. The
output PWL will always include a value at every independant variable
point defined in either of the input PWLs.
The output PWL is defined only at the intersection of the of the
span of each PWL's independant variable. For instance, you can
define two PWL's with
: a = {0,0; 1,1}
: b = {0.5,1; 1.5,2}
and the addition of a,b yields
: pr a+b
{
0.5,1;
1,1.5;
}
Which is only defined over the overlap of a,b.
There is currently only one fundamental data type in post(). This
is the DATUM which is currently defined as a doubly linked list:
typedef struct datum {
double iv; /* independant variable, usually time or freq */
double re; /* real part */
double im; /* imaginary part */
struct datum *next;
struct datum *prev;
} DATUM
Simple scalars like "0.0", "1+2i", "-4i" are just DATUMS with *next
pointing to NULL. A piece-wise linear (PWL) such as "a = {0,0; 1,1;
2,i}" is implemented as a doubly-linked list of datums defined in such a
way that appending new items is fast. (this is done by keeping the
*prev link of the first element pointing at the last element so we don't
have to walk the list to add a new element to the end).
In the summaries below, a single scalar is notated as "d" and a PWL list
is notated as "p".
In general, when a math operation is performed on two PWLs, the
operation is done point by point with cross interpolation whenever the
two PWLs differ in their independant variables. A math operation
between a PWL and a scalar DATUM generally takes the DATUM value as
applying over all time or frequency.
Operations between two scalar DATUMs is just the ordinary math that one
would expect.
In cases where complex definitions are awkward, the real value is used.
An example is the max(p1,p2) function. In most cases, it is expected
that it is the maximum real value that is compared. Although only the
real value is compared, the entire complex value of the maximum segment
is copied to the output. This allows the max/min functions to be used
as a multiplexer.
/* given two real signals siga, sigb, and select signal */
/* "mux" that is greater than 0 when we want to select siga, */
/* a multiplexor can be implemented as: */
a=re(siga)*i+re(mux)
b=re(sigb)*i+0.0
output = i*max(a,b)
# AVERAGE
p3=avg(p1,p2) ;p3(k) = (p1(k)+p2(k))/2
d3=avg(d1,d2) ;d3 = (d1+d2)/2
p3=avg(d1,p1) ;p3(k) = (p1(k)+d1)/2
p3=avg(p1,d1) ;p3(k) = (p1(k)+d1)/2
d=avg(p) ;compute average value of a single PWL
# DECIBEL
p=db(p) ;return 20*log10(mag(p))
d=db(d) ;return 20*log10(mag(d))
# DERIVATIVE
p2=dt(p1) ;uses global variable DT, default = 1u
;p2 = (warp(p1,-DT/2)-warp(p1,DT/2))/DT
# EXPONENTIAL
p2=exp(p1) ;p2(k) = e^p1(k)
# INTEGRAL
p2=integral(p1) ;return the running integral of p1*dt
;definite integral from a to b = p2(b)-p2(a)
# LOGARITHM
p2=ln(p1) ;p2(k) = ln(p1(k))
p2=log10(p1) ;p2(k) = ln(p1(k))/ln(10)
p2=log(p1) ;p2(k) = ln(p1(k))/ln(10)
# MAGNITUDE
p2=mag(p1) ;p2(k) = sqrt( (p1(k).re)^2 + (p1(k).im)^2 )
# MODULUS
p2=mod(p1,p2) ;p3.re = fmod(p1.re, p2.re)
;p3.im = 0.0;
# MAXIMUM/MINIMUM
p3=max(p1,p2) ;p3 = (p1(k).re > p2(k).re)?p1(k):p2(k)
d=max(p1) ;find k where p1(k).re is maximum, return p1(k)
;note: decision is made on real value, but
;complex value is returned.
min(p1,p2) ;p3 = (p1(k).re < p2(k).re)?p1(k):p2(k)
d=min(p1) ;find k where p1(k).re is minimum, return p1(k)
;note: decision is made on real value, but
;complex value is returned.
# PAUSE
pause(<expression>) ;post will sleep(2) for expression.re seconds.
;If an interrupt (usually ^C) is received, the
;pause will be aborted, returning to normal
;command flow. Pause is handy inside a script
;for putting between graph commands so the user
;can page through multiple graph results with ^C.
;pause() returns the number of seconds remaining
;to wait. If you don't want this number printed
;then assign it to a scratch variable eg:
;"tmp=pause(10000)"
# PHASE
p2=pha(p) ;p2(k) = atan2(p(k).im, p(k).re)
d2=pha(d) ;d2 = atan2(d.im, d.re)
# POWER
p3=pow(p1,p2) ;p3(k) = p1(k)^p2(k)
p3=pow(p1,d2) ;p3(k) = p1(k)^d
d=pow(d1,d2) ;d = d1^d2
p3=p1^p2 ;alternative ways of computing a^b
d3=d1^d2
d3=p1^d1
# PRINT print [<exp> | <string> | ","]*
Print any combination of expressions and strings. Combining
terms without a comma "," results in concatenation of the fields.
Using a comma will pad the fields with a space.
pr <exp> ;print the value of expression
print <exp> ;print the value of expression
Examples:
> a=5
> print a
5
> print "a=" a
a=5
> print "a =", a
a = 5
# PLOT
gr <exp> ;graph an expression on a new graph
gs <exp> ;graph on the same graph (currently not implemented)
gn <exp> ;graph on next y-graph (currently not implemented)
;for example you can graph a,b on top
;plot and d,c on bottom plot with
; "gr a; gs b; gn c; gs d"
# REAL/IMAGINARY PART
p2=re(p1) ;p2(k) = p1(k).re
d2=re(d) ;d2 = d.re
p2=im(p1) ;p2(k) = imaginary part of p1(k)
d2=im(d) ;d2 = d.im
# SPICE RAW FILES
ls ; list all raw files in the current directory
ci "file.raw" ; load the raw file "file". Quotes are required
di ; display the names of all loaded variables
# SQUARE ROOT
p2=sqrt(p1) ; same as pow(p,0.5)
# TIME DELAY
p3=warp(p1,d) ; timeshift a signal by delay d
; p3(k+d) = p1(k)
p3=warp(p1,p2) ; use one PWL to phase modulate another
; the delay amount is read from p2(k)
; p3(k+p2(k).re) = p1(k)
p3=delay(p1,d) ; delay is a synonym for warp...
# VERSUS (making eye diagrams)
gr versus(p1,p2) ; return a new PWL with the re/im part determined by
; p1, and the independant variable (time/frequency)
; set by p2.re.
gr versus(p1,mod(time, 160p))
; plots the p1 waveform with modular time axis
; (an eye diagram)...
gr versus(p1,mod(time+82p, 160p))
; shifts the center of the eye diagram by 82p
; since versus() returns a PWL with a non-monotonic
; independant variable, it will not usually be useful
; to do anything other than plot the result.
# ZERO CROSSING MEASUREMENT
p3=xcross(p1,p2)
p3=xcrossp(p1,p2)
p3=xcrossn(p1,p2) ; let n=(int)p2.re, find nth zero crossing (xcross),
; nth negative-going zero crossing (xcrossn), or
; nth positive going zero crossing (xcrossp) of
; p1(xc).re. set p3.re=xc. If n==0, return all
; zero crossings as a PWL with iv set to n, .re
; set to crossing time. Can then extract nth
; crossing with p3(n). If n is negative, will return
; nth crossing counted from the end of the waveform
p2=ui(p1) ; compute the value of the unit interval as a function of time:
; for every pair of positive zero crossings in p1, create
; a data point in p2 with iv set to the iv of the second zero
; crossing and the dv set to the time between the two crossings.
; eg: for a VCO, frequency can be approximated by 1/ui(vout)
# resampling / filtering
p2 = lpf(p1, tau) ; filters a (possibly unevenly sampled) PWL p1
; with RC time constant tau. returns a new
; filtered PWL that is evenly sampled in time
; with spacing = tau/16.0. A high-pass coupling
; can be created with "1-lpf()".