Work with subcircuits
Although SLiCAP is intended to be used for relatively small circuits, it supports unlimited netsing of subcircuits. The function makeCircuit()
recursively expands subcircuits until the final circuit comprises devices with stamp models only (see Work with models). Working with subcircuits, usually simplifies the design and is strongly recommended in the following cases:
The circuit consists of a number of topologically identical building blocks comprising multiple devices
Examples are the built-in subcircuits for small-signal models of active devices and operational amplifiers.
Below the built-in definition (in
SLiCAPmodels.lib
) of the small-signal model of a MOS transistor88* MOSFET 89.subckt M d g s b gm=1m gb=0 go=0 cgs=0 cdg=0 cgb=0 cdb=0 csb=0 ; default values 90Gm d s g s g value={gm} 91Gb d s b s g value={gb} 92Go d s d s g value={go} 93Cgs g s {cgs} 94Cdg d g {cdg} 95Cgb g b {cgb} 96Cdb d b {cdb} 97Csb s b {csb} 98.ends
The circuit consists of a number of building blocks that comprise multiple parameters with complex expressions
Examples are the built-in subcircuits for MOS devices with EKV model equations that relate their small-signal parameters to geometry parameters (e.g. W, L) and operating point parameters (e.g ID).
Below the built-in definition (in
SLiCAP.lib
) of the small-signal model of an CMOS18 NMOS transistor with its small-signal circuit parameters related to its geometry and operating conditions.134.subckt CMOS18N drain gate source bulk W={W} L={L} ID={ID} 135* EKV model of transistor without bulk resistances 136* Voltage dependency of bulk capacitances not modeled 137* Operating in forward saturation region 138* 139M1 drain gate source bulk CMOS18N 140 141.model CMOS18N M 142+ gm = {g_m} 143+ go = {g_o} 144+ gb = {g_b} 145+ cgs = {c_gs} 146+ cdg = {c_dg} 147+ cgb = {c_gb} 148+ cdb = {c_db} 149+ csb = {c_sb} 150.param 151* device equations EKV model 152* See Binkley: "Tradeoffs and Optimization in Analog CMOS Design" 153+ IC_CRIT = {1/(4*(N_s_N18*U_T)*(Theta_N18+1/L/E_CRIT_N18))^2} 154+ g_m = {ID/(N_s_N18*U_T*sqrt(IC*(1+IC/IC_CRIT)+0.5*sqrt(IC*(1+IC/IC_CRIT))+1))} 155+ g_o = {g_CLM + g_DIBL} 156+ g_CLM = {ID/(VAL_N18*L*sqrt(L/L_min_N18))} ; 157+ g_DIBL = {-g_m*DVTDIBL_N18*(L_min_N18/L)^DVTIDBLEXP_N18} 158+ g_b = {(N_s_N18-1)*g_m} 159+ c_gs = {(2-x)/3*W*L*C_OX_N18 + CGSO_N18*W} 160+ c_dg = {CGSO_N18*W} 161+ c_gb = {W*L*C_OX_N18*(1+x)/3*(N_s_N18-1)/N_s_N18+CGBO_N18*2*L} 162+ c_db = {CJB0_N18*W*LDS_N18} 163+ c_sb = {CJB0_N18*W*LDS_N18} 164+ IC_i = {ID*L/W/I_0_N18} ; Initial estimate of inversion coefficient 165+ IC = {IC_i*(1+3*(IC_i/IC_CRIT))**(1/3)} ; Correction for short-channel effects 166+ V_GS = {2*N_s_N18*U_T*ln(exp(sqrt(IC_i*(1+IC_i/IC_CRIT)))-1) + Vth_N18} 167+ f_T = {g_m/2/pi/c_iss} 168+ c_iss = {c_gs+c_dg+c_gb} 169+ x = {(sqrt(IC + 0.25) + 1.5)/(sqrt(IC + 0.25) + 0.5)^2} 170.ends
The circuit consists of an anti-series connection of two identical circuits.
These circuits belong to the class of ‘balanced circuits’. Nodal voltages and branch currents in these circuits can be resolved in differential-mode and common-mode quantities. SLiCAP can decompose a balanced circuit into common-mode and differential-mode equivalent circuits. To this end, it needs pairing information for nodes and branches, which is easy to provide if the balanced circuit consists of the anti-series connection of two identical sub circuits. For more information see: Work with balanced circuits
SLiCAP output displayed on this manual page, is generated with the script: subcircuits.py
, imported by Manual.py
.
1#!/usr/bin/env python3
2# -*- coding: utf-8 -*-
3
4"""
5subcircuits.py: SLiCAP scripts for the HTML help file
6"""
7import SLiCAP as sl
8
9###############################################################################
10# work with subcircuits
11###############################################################################
Subcircuit expansion
Below a schematic diagram of a circuit with nested subcircuits. The main circuit comprises one subcircuit “XA: bigAmp”. This subcircuit comprises two identical “smallAmp” subcircuits “X1” and “X2”.
Subcircuit “XA” has two parameters that can be set by the parent circuit: “A_i”, the voltage gain of “X1” and “R_o” the output resistance of both “X1” and “X2”. The resistance of “R1” of “XA” is defined symbolically as \(R_i\) to which no numeric value has been assigned.
Below the manually created netlist of the circuit.
1hierarchy
2
3V1 1 0 V value={V_s}
4R1 1 2 R value={R_s}
5R2 4 0 R value={R_L}
6XA 2 0 4 0 bigAmp A_i={A_i} R_o={R}
7
8.param V_s=1 R_s=50 R=50
9
10.subckt bigAmp inP inN ouP outN A_i=30 R_o=30
11R1 inP inN R value={R_i}
12X1 inP inN 3 0 smallAmp A_v={A_i} R_o=40
13X2 3 0 outP outN smallAmp A_v=10 R_o={R_o}
14
15.subckt smallAmp inP inN outP outN A_v={A} R_o=10
16E1 1 outN inP inN E value={A_v}
17R1 1 outP R value={R_o}
18.ends ; smallAmp
19
20.ends ; bigAmp
21
22.end
At the creation of a circuit object, SLiCAP expands or “flattens” this circuit. It converts the hierarchically structured netlist into a circuit that comprises devices with stamp models only (see Work with models). The MNA matrix equation will be constructed from this “flattened” circuit.
Reference designators of expanded circuit elements
The table below shows the element data of the expanded circuit.
The first column of this table shows the reference designators of the expanded circuit elements.
important
The reference designator of a subcircuit element in its expanded parent is that of the subcircuit element appended with _<refX>
, where refX
is the reference designator of the parent subcircuit.
Hence, the reference designator of “R1” in “XA” becomes “R1_XA” in its expanded parent.
This naming process is recursive, so “R1” in “X1” of “XA” becomes “R1_X1_XA” in the expanded parent of “XA”.
ID |
Nodes |
Refs |
Model |
Param |
Symbolic |
Numeric |
---|---|---|---|---|---|---|
V1 |
1 0 |
V |
value |
\(V_{s}\) |
\(1\) |
|
dc |
\(0\) |
\(0\) |
||||
dcvar |
\(0\) |
\(0\) |
||||
noise |
\(0\) |
\(0\) |
||||
R1 |
1 2 |
R |
value |
\(R_{s}\) |
\(50\) |
|
dcvar |
\(0\) |
\(0\) |
||||
noisetemp |
\(0\) |
\(0\) |
||||
noiseflow |
\(0\) |
\(0\) |
||||
dcvarlot |
\(0\) |
\(0\) |
||||
R2 |
4 0 |
R |
value |
\(R_{L}\) |
\(R_{L}\) |
|
dcvar |
\(0\) |
\(0\) |
||||
noisetemp |
\(0\) |
\(0\) |
||||
noiseflow |
\(0\) |
\(0\) |
||||
dcvarlot |
\(0\) |
\(0\) |
||||
R1_XA |
2 0 |
R |
value |
\(R_{i XA}\) |
\(R_{i XA}\) |
|
dcvar |
\(0\) |
\(0\) |
||||
noisetemp |
\(0\) |
\(0\) |
||||
noiseflow |
\(0\) |
\(0\) |
||||
dcvarlot |
\(0\) |
\(0\) |
||||
E1_X1_XA |
1_X1_XA 0 2 0 |
E |
value |
\(A_{i}\) |
\(A_{i}\) |
|
R1_X1_XA |
1_X1_XA 3_XA |
R |
value |
\(40\) |
\(40\) |
|
dcvar |
\(0\) |
\(0\) |
||||
noisetemp |
\(0\) |
\(0\) |
||||
noiseflow |
\(0\) |
\(0\) |
||||
dcvarlot |
\(0\) |
\(0\) |
||||
E1_X2_XA |
1_X2_XA 0 3_XA 0 |
E |
value |
\(10\) |
\(10\) |
|
R1_X2_XA |
1_X2_XA outP_XA |
R |
value |
\(R\) |
\(50\) |
|
dcvar |
\(0\) |
\(0\) |
||||
noisetemp |
\(0\) |
\(0\) |
||||
noiseflow |
\(0\) |
\(0\) |
||||
dcvarlot |
\(0\) |
\(0\) |
Expanded circuit node names
The name of a connecting node of a subcircuit, will be that of the connecting parent node. Unconnected nodes remain local. Their node names will be modified in a similar way as the element reference designator.
The name of a local node becomes <nodeID>_<refX>
, where nodeID
is the node name in the subcircuit, and refX
is the reference designator of the subcircuit in the parent circuit.
Expanded circuit parameter names
Parents can pass parameter values or expression to child subcircuits. If so, all instances of this parameter in element expression in the subcircuit, in parameter definitions in the subcircuit, and in model definitions in the subcircuit, are substituted with the value or expression passed by the parent.
Parents can only pass parameters that are declared a value or expression in the subcircuit definition. See line 10 from the netlist above:
10.subckt bigAmp inP inN ouP outN A_i=30 R_o=30
Hence, the parent can pass a value or expression to \(A_i\) and to \(R_o\) to an instance of the subcircuit “bigAmp”.
All other parameters will remain local and all instances of local parameters in subcircuit element expressions, in subcircuit parameter definitions, and in subcircuit model definitions, will be substituted with a new variable:
new_param = sympy.Symbol(str(old_param) + "_" + refX)
# new_param is the new parameter name
# old_param is the old parameter name (type = sympy.Symbol)
# refX is the reference designator of the subcircuit in the parent circuit
The tables below show how this applies to the circuit from above.
Name |
Symbolic |
Numeric |
---|---|---|
\(V_{s}\) |
\(1\) |
\(1\) |
\(R_{s}\) |
\(50\) |
\(50\) |
\(R\) |
\(50\) |
\(50\) |
Name |
---|
\(A_{i}\) |
\(R_{L}\) |
\(R_{i XA}\) |
Subcircuit creation
Aside from using built-in subcircuits, the user can create subcircuits. There are two ways to create subcircuits:
Include a subcircuit definition in a circuit file
Create a subcircuit definition in a library file and store it in the
lib/
folder of the project directory
Both methods can be done by manually editing circuit .cir
files, the latter one can also be performed with a schematic capture program.
The manual approach is elucidated above.
Create subcircuits with KiCAD
KiCAD supports hierarchical design, but the approach differs from the subcircuit approach outlined above. SLiCAP subcircuits must be created as follows:
Create a KiCAD schematic for the subcircuit and put a command with the subcircuit decraration on the schematic. The subcircuit definition for “smallAmp” looks as depicted below.
With the
.subckt
directive on the schematic,makeNetlist()
creates a library file in thelib/
folder in the project directory. The name of this file defaults to the subcircuit name with extension.lib
.15# Create a subcircuit library file: <sl.ini.user_lib_path>smallAmp.lib 16smallAmp = sl.makeCircuit("kicad/smallAmp/smallAmp.kicad_sch")
The contents of
lib/smallAmp.lib
is:1smallAmp 2.subckt smallAmp inP inN outP outN A_v={A} r_o={R} 3E1 1 outN inP inN E value={A_v} 4R1 1 outP R value={r_o} noisetemp=0 noiseflow=0 dcvar=0 dcvarlot=0 5.ends 6.end
Important
SLiCAP library files are like circuit netlists. The first line is taken as title and the last line must be
.end
.Now create the subcircuit
bigAmp
. Use a 4-pin subcircuit symbol forsmallAmp
, or create a symbol yourself. Don’t forget to include the library withsmallAmp.lib
.The subcircuit symbol must have four pins and the pin sequence must be according to the subcircuit definition: “inP”, “inN”, “outP”, “outN”. The SLiCAP KiCAD symbol
Xamp4
can be used for this purpose, it has the correct pin sequence.Parameters to be passed to the subcircuit must added as symbol properties. The property name is the parameter name and the value can be any because it will be overruled by the definition in the
.subckt
directive.
The following instruction creates the
bigAmp
library file.18# Create a subcircuit library file: <sl.ini.user_lib_path>bigAmp.lib 19bigAmp = sl.makeCircuit("kicad/bigAmp/bigAmp.kicad_sch")
The contents of
lib/bigAmp.lib
is:1bigAmp 2.subckt bigAmp inP inN outP outN A_i=30 R_o=30 3.lib smallAmp.lib 4R1 inP inN R value={R_i} noisetemp=0 noiseflow=0 dcvar=0 dcvarlot=0 5X1 inP inN 1 0 smallAmp A_v={A_i} r_o=40 6X2 1 0 outP outN smallAmp A_v=10 r_o={R_o} 7.ends 8.end
Now create the main circuit and again use the
Xamp4
symbol forbigAmp
.The following instruction creates the main circuit object .
17# Create the main circuit 18mainAmp = sl.makeCircuit("kicad/mainAmp/mainAmp.kicad_sch")
The netlist of
cir/mainAmp.cir
is:1mainAmp 2.lib bigAmp.lib 3.param V_s=1 R_s=50 R=50 4R1 1 2 R value={R_s} noisetemp=0 noiseflow=0 dcvar=0 dcvarlot=0 5R2 3 0 R value={R_L} noisetemp=0 noiseflow=0 dcvar=0 dcvarlot=0 6V1 1 0 V value={V_s} noise=0 dc=0 dcvar=0 7XA 2 0 3 0 bigAmp A_i={A_i} R_o={R} 8.end
The expanded circuit data and the parameter definitions are as above:
Table 10 Expanded netlist data of mainAmp.cir ID
Nodes
Refs
Model
Param
Symbolic
Numeric
R1
1 2
R
value
\(R_{s}\)
\(50\)
noisetemp
\(0\)
\(0\)
noiseflow
\(0\)
\(0\)
dcvar
\(0\)
\(0\)
dcvarlot
\(0\)
\(0\)
R2
3 0
R
value
\(R_{L}\)
\(R_{L}\)
noisetemp
\(0\)
\(0\)
noiseflow
\(0\)
\(0\)
dcvar
\(0\)
\(0\)
dcvarlot
\(0\)
\(0\)
V1
1 0
V
value
\(V_{s}\)
\(1\)
noise
\(0\)
\(0\)
dc
\(0\)
\(0\)
dcvar
\(0\)
\(0\)
R1_XA
2 0
R
value
\(R_{i XA}\)
\(R_{i XA}\)
noisetemp
\(0\)
\(0\)
noiseflow
\(0\)
\(0\)
dcvar
\(0\)
\(0\)
dcvarlot
\(0\)
\(0\)
E1_X1_XA
1_X1_XA 0 2 0
E
value
\(A_{i}\)
\(A_{i}\)
R1_X1_XA
1_X1_XA 1_XA
R
value
\(40\)
\(40\)
noisetemp
\(0\)
\(0\)
noiseflow
\(0\)
\(0\)
dcvar
\(0\)
\(0\)
dcvarlot
\(0\)
\(0\)
E1_X2_XA
1_X2_XA 0 1_XA 0
E
value
\(10\)
\(10\)
R1_X2_XA
1_X2_XA 3
R
value
\(R\)
\(50\)
noisetemp
\(0\)
\(0\)
noiseflow
\(0\)
\(0\)
dcvar
\(0\)
\(0\)
dcvarlot
\(0\)
\(0\)
Table 11 Expanded circuit parameter definitions Name
Symbolic
Numeric
\(V_{s}\)
\(1\)
\(1\)
\(R_{s}\)
\(50\)
\(50\)
\(R\)
\(50\)
\(50\)
Table 12 Expanded circuit undefined parameters Name
\(A_{i}\)
\(R_{L}\)
\(R_{i XA}\)
Display circuit data on HTML pages and in LaTeX documents
The report module Create reports, discusses how HTML snippets and LaTeX snippets can be created for variables, expressions, equations and tables.
As a matter of fact, tables and figures on this page are created with this module:
24# Generate RST snippets for the Help file
25rst = sl.RSTformatter()
26
27rst.elementData(cir, caption="Expanded netlist data of hierarchy.cir").save(
28 "table-hierarchy-expanded")
29rst.parDefs(cir, caption="Expanded circuit parameter definitions").save(
30 "table-hierarchy-pardefs")
31rst.params(cir, caption="Expanded circuit undefined parameters").save(
32 "table-hierarchy-params")
33rst.elementData(mainAmp, caption="Expanded netlist data of mainAmp.cir").save(
34 "table-mainamp-expanded")
35rst.parDefs(mainAmp, caption="Expanded circuit parameter definitions").save(
36 "table-mainamp-pardefs")
37rst.params(mainAmp, caption="Expanded circuit undefined parameters").save(
38 "table-mainamp-params")