Skip to content

omnister/post

Repository files navigation

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
walker@omnisterra.com


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()".
			

About

Post: interactive graphic shell for doing math on SPICE piece-wise-linear waveforms

Resources

License

GPL-2.0, Unknown licenses found

Licenses found

GPL-2.0
COPYING
Unknown
license.c

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published