10.4.1. SPICE OPUS simulator interface¶
This demo shows how to use the SPICE OPUS simulator interface. Let us first take a look at the files in the folder.
File demo/evaluation/01-simulator-spiceopus/cmos180n.lib
defines two MOSFET
models: nmosmod
is a NMOS model and pmosmod
is a PMOS model. A total of
5 variants of these two models are defined in the sections of the library file:
tm
- a typical mean model
wp
- worst power model
ws
- worst speed model
wo
- worst one model
wz
- worst zero model
wcd
- Monte Carlo model for worst case and worst case distance analysis
File demo/evaluation/01-simulator-spiceopus/mosmm.inc
defines the wrappers
around nmosmod
and pmosmod
.
* Mismatch model of NMOS and PMOS, Spice Opus
* w, l, m ... MOS parameters
* vtmm, u0mm ... normalized mismatch (+1 means +1 sigma)
.subckt submodn drain gate source bulk param: w l m=1 vtmm=0 u0mm=0
.param sqrtarea=sqrt(w*l*m)
.param vvt=vtmm*(5e-3*1e-6/sqrtarea/sqrt(2))
.param vu0r=u0mm*(1.04e-2*1e-6/sqrtarea/sqrt(2))
vgmm (gate gate_int) dc={vvt}
m0 (drain gate_int source bulk) nmosmod w={w*(1+vu0r)} l={l} m={m} ad={w*0.18u} as={w*0.18u} pd={2*(w+0.18u)} ps={2*(w+0.18u)} nrs={0.18u/w} nrd={0.18u/w}
.ends
.subckt submodp drain gate source bulk param: w l m=1 vtmm=0 u0mm=0
.param sqrtarea=sqrt(w*l*m)
.param vvt=vtmm*(5.49e-3*1e-6/sqrtarea/sqrt(2))
.param vu0r=u0mm*(0.99e-2*1e-6/sqrtarea/sqrt(2))
vgmm (gate gate_int) dc={vvt}
m0 (drain gate_int source bulk) pmosmod w={w*(1+vu0r)} l={l} m={m} ad={w*0.18u} as={w*0.18u} pd={2*(w+0.18u)} ps={2*(w+0.18u)} nrs={0.18u/w} nrd={0.18u/w}
.ends
Every wrapper is a parameterized subcircuit. Parameters w
, l
, and m
specify the channel dimensions and the device multiplier. Parameters vtmm
and u0mm
specify the normalized mismatch in terms of normal distribution’s
standard deviation (+1 corresponds to sigma and -1 to -sigma). The typical mean
model is obtained by setting vtmm
and u0mm
to 0.
The circuit is described in file
demo/evaluation/01-simulator-spiceopus/opamp.cir
.
* Simple opamp, 0.18u, 1.8V, SpiceOpus
* Any include or lib that is set from PyOPUS (specified in problem definition)
* must not be specified here.
* Any parameter that is set from PyOPUS (specified in problem definition)
* must not be specified here.
* Include files - fixed
.include 'mosmm.inc'
* Operating conditions - fixed
.param lev1=0
.param lev2=0.5
.param tstart=1e-9
.param tr=1e-9
.param tf=1e-9
.param pw=500e-9
.param ibias=1.000000000000e-004
.param rfb=1e6
.param rin=1e6
* Design parameters - fixed
.param out_w=4.800592541419e-005
.param out_l=3.750131780858e-007
.param load_w=3.486243671853e-005
.param load_l=2.572996921261e-006
.param dif_w=7.728734451428e-006
.param dif_l=1.082371380389e-006
.param c_out=8.211596855053e-012
.param r_out=1.968986740568e+001
* inp inn out vdd vss bias slp slpx
.subckt amp 3 4 5 1 2 7 11 12
xmp1 9 10 1 1 submodp w={load_w} l={load_l} m=2
xmp2 10 10 1 1 submodp w={load_w} l={load_l} m=2
xmp1s 9 12 1 1 submodp w=1u l=0.5u
xmp3 5 9 1 1 submodp w={out_w} l={out_l} m=16
xmn2 9 3 8 2 submodn w={dif_w} l={dif_l}
xmn3 10 4 8 2 submodn w={dif_w} l={dif_l}
xmn1s 7 11 2 2 submodn w=1u l=0.5u
xmn1b 7 7 2 2 submodn w={mirr_w} l={mirr_l} m=2
xmn1 8 7 2 2 submodn w={mirr_w} l={mirr_l} m=2
xmn4 5 7 2 2 submodn w={mirr_w} l={mirr_l} m=16
cout 5a 9 c={c_out}
rout 5 5a r={r_out}
.ends
* Test topology
x1 (inp inn out vdd 0 bias 0 vdd) amp
vdd (vdd 0) dc={vdd}
ibias (vdd bias) dc={ibias}
rfb (out inn) r={rfb}
rin (in inn) r={rin}
vcom (inp 0) dc={vdd/2}
vin (in inp) dc=0 acmag=1 pulse=({lev1} {lev2} {tstart} {tr} {tf} {pw})
rload (out 0) r=100k
cload (out 0) c=0.5p
* This file is included in the main simulator input file.
* Do not add .end - it is added by PyOPUS to the main input file.
The file follows the standard SPICE OPUS netlist syntax, except for the missing
.end
statement which is added later by PyOPUS.
The following Python script constructs 5 OP analyses (jobs) and passes them to
the simulator interface. The vdd
and the temperature
parameter are
specified in the job descriptions. The simulator interface optimizes the order of
evaluation in such manner that the number of simulator calls is minimized. During
this process the jobs are grouped in job groups. The job groups are printed.
The two circuit parameters (mirr_w
and mirr_l
) are not specified in the
netlist. They are passed to the simulator interface. Finally, every job groups is
run and the results are collected. For every job some of the results are printed.
In the end all intermediate files generated by the simulator interface and the simulator are deleted.
File: demo/evaluation/01-simulator-spiceopus/runme.py
# Test SpiceOpus simulator interface
from pyopus.simulator import simulatorClass
if __name__=='__main__':
# Job list for simulator
jobList=[
{ # First job - op analysis
'name': 'dcop',
'definitions': [
{ 'file': 'cmos180n.lib', 'section': 'tm' },
{ 'file': 'opamp.cir' }
],
'params': {
'vdd': 1.8,
'temperature': 25
},
'options': {
'method': 'trap'
},
'saves': [
],
'command': 'op()'
},
{ # Second job - op analysis with different temperature
'name': 'dcop100',
'definitions': [
{ 'file': 'cmos180n.lib', 'section': 'tm' },
{ 'file': 'opamp.cir' }
],
'params': {
'vdd': 1.6,
'temperature': 100
},
'options': {
'method': 'trap'
},
'saves': [
],
'command': 'op()'
},
{ # Third job - op analysis with different supply voltage
'name': 'dcopv33',
'definitions': [
{ 'file': 'cmos180n.lib', 'section': 'tm' },
{ 'file': 'opamp.cir' }
],
'params': {
'vdd': 2.0,
'temperature': 25
},
'options': {
'method': 'trap'
},
'saves': [
],
'command': 'op()'
},
{ # Fourth job - op analysis with different library
'name': 'dcopff',
'definitions': [
{ 'file': 'cmos180n.lib', 'section': 'ws' },
{ 'file': 'opamp.cir' }
],
'params': {
'vdd': 2.0,
'temperature': 25
},
'options': {
'method': 'trap'
},
'saves': [
],
'command': 'op()'
},
{ # Fifth job - op analysis with different library
'name': 'dcopff100',
'definitions': [
{ 'file': 'cmos180n.lib', 'section': 'ws' },
{ 'file': 'opamp.cir' }
],
'params': {
'vdd': 2.0,
'temperature': 100
},
'options': {
'method': 'trap'
},
'saves': [
],
'command': 'op()'
}
]
# Input parameters
inParams={
'mirr_w': 7.46e-005,
'mirr_l': 5.63e-007
}
# Create simulator
sim=simulatorClass("SpiceOpus")(debug=10)
# Set job list and optimize it
sim.setJobList(jobList)
# Print optimized job groups
ngroups=sim.jobGroupCount()
print("\nJob Groups:")
for i in range(ngroups):
group=sim.jobGroup(i)
gstr=''
for j in group:
gstr+=" %d (%s), " % (j, jobList[j]['name'])
print(" %d: %s" % (i, gstr))
print("")
# Set input parameters
sim.setInputParameters(inParams)
# Go through all job groups, write file, run it and collect results
for i in range(ngroups):
# Run jobs in job group.
(jobIndices, status)=sim.runJobGroup(i)
print("")
for j in jobIndices:
# Job name
jobName=jobList[j]['name']
# Load results
res=sim.readResults(j, status)
# Print results
if res is not None:
print("Job %d (%s): Vout=%e" % (j, jobName, res.v("out")))
else:
print("Job %d (%s): no results" % (j, jobName))
print("")
sim.cleanup()