# 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:

1. 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 transistor

         38* MOSFET
         39.subckt M d g s b gm=1m gb=0 go=0 cgs=0 cdg=0 cgb=0 cdb=0 csb=0 ; default values
         40Gm d s g s g value={gm}
         41Gb d s b s g value={gb}
         42Go d s d s g value={go}
         43Cgs g s {cgs}
         44Cdg d g {cdg}
         45Cgb g b {cgb}
         46Cdb d b {cdb}
         47Csb s b {csb}
         48.ends

2. 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.

         346.subckt CMOS18N drain gate source bulk W={W} L={L} ID={ID}
         347* EKV model of transistor without bulk resistances
         348* Voltage dependency of bulk capacitances not modeled
         349* Operating in forward saturation region
         350*
         351M1 drain gate source bulk CMOS18N
         352
         353.model CMOS18N M
         354+ gm      = {g_m}
         355+ go      = {g_o}
         356+ gb      = {g_b}
         357+ cgs     = {c_gs}
         358+ cdg     = {c_dg}
         359+ cgb     = {c_gb}
         360+ cdb     = {c_db}
         361+ csb     = {c_sb}
         362.param
         363* device equations EKV model
         364* See Binkley: "Tradeoffs and Optimization in Analog CMOS Design"
         365+ IC_CRIT = {1/((4*N_s_N18*U_T)*(Theta_N18+1/L/E_CRIT_N18))^2}
         366+ g_m     = {ID/(N_s_N18*U_T*sqrt(IC_g+0.5*sqrt(IC_g)+1))}
         367+ g_o     = {g_CLM + g_DIBL}
         368+ g_CLM   = {ID/(VAL_N18*(L+2*L_min_N18))} ;
         369+ g_DIBL  = {-g_m*DVTDIBL_N18*(L_min_N18/L)^DVTIDBLEXP_N18}
         370+ g_b     = {(N_s_N18-1)*g_m}
         371+ c_gs    = {(2-x)/3*W*L*C_OX_N18 + CGSO_N18*W}
         372+ c_dg    = {CGSO_N18*W}
         373+ c_gb    = {W*L*C_OX_N18*(1+x)/3*(N_s_N18-1)/N_s_N18+CGBO_N18*2*L}
         374+ c_db    = {CJB0_N18*W*LDS_N18}
         375+ c_sb    = {CJB0_N18*W*LDS_N18}
         376+ IC      = {ID*L/W/I_0_N18}
         377+ IC_g    = {IC*(1+(IC/IC_CRIT))}
         378+ IC_v    = {IC*(1+(IC/4/IC_CRIT)^beta_N18)^(1/beta_N18)}
         379+ V_GS    = {2*N_s_N18*U_T*ln(exp(sqrt(IC_v))-1) + Vth_N18}
         380+ f_T     = {g_m/2/pi/c_iss}
         381+ c_iss   = {c_gs+c_dg+c_gb}
         382+ x       = {(sqrt(IC + 0.25) + 1.5)/(sqrt(IC + 0.25) + 0.5)^2}
         383.ends

3. 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”.

Table 7 Expanded netlist data of hierarchy.cir
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.

Table 8 Expanded circuit parameter definitions
Name | Symbolic | Numeric
--- | --- | ---
\(V_{s}\) | \(1\) | \(1\)
\(R_{s}\) | \(50\) | \(50\)
\(R\) | \(50\) | \(50\)

Table 9 Expanded circuit undefined parameters
Name
\(R_{i XA}\)
\(A_{i}\)
\(R_{L}\)

## Subcircuit creation

Aside from using built-in subcircuits, the user can create subcircuits. There are two ways to create subcircuits:

1. Include a subcircuit definition in a circuit file

2. 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:

1. 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.

2. With the `.subckt` directive on the schematic, `makeNetlist()` creates a library file in the `lib/` 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`.

3. Now create the subcircuit `bigAmp`. Use a 4-pin subcircuit symbol for `smallAmp`, or create a symbol yourself. Don’t forget to include the library with `smallAmp.lib`.

   1. 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.

   2. 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

4. Now create the main circuit and again use the `Xamp4` symbol for `bigAmp`.

   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
   \(R_{i XA}\)
   \(A_{i}\)
   \(R_{L}\)

## 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")