DC Sweep Analysis#

Compute the DC operating point while sweeping an independent source.

import os
import sys
from pathlib import Path

# Set working directory to the PDK root if running from scripts/
if Path.cwd().name == "scripts":
    os.chdir(Path.cwd().parent)

# Ensure ngspice shared library can be found (macOS homebrew)
if sys.platform == "darwin" and "/opt/homebrew/lib" not in os.environ.get(
    "DYLD_LIBRARY_PATH", ""
):
    os.environ["DYLD_LIBRARY_PATH"] = "/opt/homebrew/lib:" + os.environ.get(
        "DYLD_LIBRARY_PATH", ""
    )

import numpy as np
import pandas as pd
import holoviews as hv
from nyancad.watch import watch_project_dir, file_schematic
from nyancad.netlist import inspice_netlist
from nyancad.plot import sweepplot
from InSpice import Simulator

hv.extension("bokeh")
scipy not available, fft plots will not work

Parameters#

SCHEMATIC = "inverter"  # stem of the .nyancir file
CORNER = "mos_tt"

# -- DC sweep parameters --
SOURCE = "VV2"  # name of the source to sweep
START = 0  # start value (V or A)
STOP = 5  # stop value (V or A)
STEP = 0.1  # step size

# -- Vectors to plot --
# Leave empty to auto-select all node voltages after simulation.
VECTORS = []

Load schematic and build netlist#

project = watch_project_dir(".")
schem_data = await file_schematic(project, SCHEMATIC)
spice = await inspice_netlist(SCHEMATIC, schem_data, corner=CORNER)
print(spice)
Duplicated lib ('ihp/models/ngspice/models/cornerMOSlv.lib', 'mos_tt')
.title schematic
.lib /Users/pepijndevos/code/IHP/ihp/models/ngspice/models/cornerMOSlv.lib mos_tt
VV1 W2 GND DC 1.8
VV2 W3 GND DC 0.9 AC 1 sin(0.9 0.5 1k)
XM1 W6 W3 GND GND sg13_lv_nmos l={0.13 * 1e-6} m=1 ng=1 w={0.15 * 1e-6}
XM2 W2 W3 W6 W2 sg13_lv_pmos l={0.13 * 1e-6} m=1 ng=1 w={0.15 * 1e-6}
CC1 W6 GND 1u
print("Netlist nodes:", list(spice.node_names))
print("Netlist elements:", list(spice.element_names))
Netlist nodes: ['0', 'W2', 'GND', 'W3', 'W6']
Netlist elements: ['VV1', 'VV2', 'XM1', 'XM2', 'CC1']

Run DC sweep#

simulator = Simulator.factory(simulator="ngspice-shared")

for osdi in [
    "ihp/models/ngspice/osdi/psp103.osdi",
    "ihp/models/ngspice/osdi/psp103_nqs.osdi",
    "ihp/models/ngspice/osdi/r3_cmc.osdi",
    "ihp/models/ngspice/osdi/mosvar.osdi",
]:
    simulator._ngspice_shared.exec_command(f"osdi {osdi}")

simulation = simulator.simulation(spice)
analysis = simulation.dc(**{SOURCE: slice(START, STOP, STEP)})
print("DC sweep complete.")
Warning: can't find the initialization file spinit.
Newer Ngspice version that could be unsupported 46
DC sweep complete.

Results#

available = [*analysis.nodes.keys(), *analysis.branches.keys()]
print("Available vectors:", available)

if not VECTORS:
    VECTORS = list(analysis.nodes.keys())
    print("Auto-selected:", VECTORS)

df = pd.DataFrame(index=np.array(analysis.sweep))
for vec in VECTORS:
    df[vec] = np.array(analysis[vec])
df
Available vectors: ['n.xm1.nsg13_lv_nmos#SI', 'n.xm1.nsg13_lv_nmos#GP', 'n.xm1.nsg13_lv_nmos#NOI', 'n.xm2.nsg13_lv_pmos#SI', 'n.xm2.nsg13_lv_pmos#GP', 'n.xm2.nsg13_lv_pmos#NOI', 'w6', 'w3', 'w2', 'v-sweep', 'vv1', 'vv2']
Auto-selected: ['n.xm1.nsg13_lv_nmos#SI', 'n.xm1.nsg13_lv_nmos#GP', 'n.xm1.nsg13_lv_nmos#NOI', 'n.xm2.nsg13_lv_pmos#SI', 'n.xm2.nsg13_lv_pmos#GP', 'n.xm2.nsg13_lv_pmos#NOI', 'w6', 'w3', 'w2', 'v-sweep']
n.xm1.nsg13_lv_nmos#SI n.xm1.nsg13_lv_nmos#GP n.xm1.nsg13_lv_nmos#NOI n.xm2.nsg13_lv_pmos#SI n.xm2.nsg13_lv_pmos#GP n.xm2.nsg13_lv_pmos#NOI w6 w3 w2 v-sweep
0.0 0.0 6.965056e-10 0.0 0.0 1.376240e-10 0.0 1.800000e+00 0.0 1.8 0.0
0.1 0.0 1.000000e-01 0.0 0.0 1.000000e-01 0.0 1.800000e+00 0.1 1.8 0.1
0.2 0.0 2.000000e-01 0.0 0.0 2.000000e-01 0.0 1.799994e+00 0.2 1.8 0.2
0.3 0.0 3.000000e-01 0.0 0.0 3.000000e-01 0.0 1.799899e+00 0.3 1.8 0.3
0.4 0.0 4.000000e-01 0.0 0.0 4.000000e-01 0.0 1.798347e+00 0.4 1.8 0.4
0.5 0.0 5.000000e-01 0.0 0.0 5.000000e-01 0.0 1.785391e+00 0.5 1.8 0.5
0.6 0.0 6.000000e-01 0.0 0.0 6.000000e-01 0.0 1.739928e+00 0.6 1.8 0.6
0.7 0.0 7.000000e-01 0.0 0.0 7.000000e-01 0.0 1.629709e+00 0.7 1.8 0.7
0.8 0.0 8.000000e-01 0.0 0.0 8.000000e-01 0.0 1.084613e+00 0.8 1.8 0.8
0.9 0.0 9.000000e-01 0.0 0.0 9.000000e-01 0.0 1.621298e-01 0.9 1.8 0.9
1.0 0.0 1.000000e+00 0.0 0.0 1.000000e+00 0.0 6.295796e-02 1.0 1.8 1.0
1.1 0.0 1.100000e+00 0.0 0.0 1.100000e+00 0.0 2.906256e-02 1.1 1.8 1.1
1.2 0.0 1.200000e+00 0.0 0.0 1.200000e+00 0.0 1.207761e-02 1.2 1.8 1.2
1.3 0.0 1.300000e+00 0.0 0.0 1.300000e+00 0.0 3.685119e-03 1.3 1.8 1.3
1.4 0.0 1.400000e+00 0.0 0.0 1.400000e+00 0.0 5.700681e-04 1.4 1.8 1.4
1.5 0.0 1.500000e+00 0.0 0.0 1.500000e+00 0.0 3.810609e-05 1.5 1.8 1.5
1.6 0.0 1.600000e+00 0.0 0.0 1.600000e+00 0.0 2.139360e-06 1.6 1.8 1.6
1.7 0.0 1.700000e+00 0.0 0.0 1.700000e+00 0.0 1.429718e-07 1.7 1.8 1.7
1.8 0.0 1.800000e+00 0.0 0.0 1.800000e+00 0.0 4.057214e-08 1.8 1.8 1.8
1.9 0.0 1.900000e+00 0.0 0.0 1.900000e+00 0.0 5.167813e-08 1.9 1.8 1.9
2.0 0.0 2.000000e+00 0.0 0.0 2.000000e+00 0.0 7.708216e-08 2.0 1.8 2.0
2.1 0.0 2.100000e+00 0.0 0.0 2.100000e+00 0.0 1.130805e-07 2.1 1.8 2.1
2.2 0.0 2.200000e+00 0.0 0.0 2.200000e+00 0.0 1.619090e-07 2.2 1.8 2.2
2.3 0.0 2.300000e+00 0.0 0.0 2.300000e+00 0.0 2.263713e-07 2.3 1.8 2.3
2.4 0.0 2.400000e+00 0.0 0.0 2.400000e+00 0.0 3.094189e-07 2.4 1.8 2.4
2.5 0.0 2.500000e+00 0.0 0.0 2.500000e+00 0.0 4.140394e-07 2.5 1.8 2.5
2.6 0.0 2.600000e+00 0.0 0.0 2.600000e+00 0.0 5.431828e-07 2.6 1.8 2.6
2.7 0.0 2.700000e+00 0.0 0.0 2.700000e+00 0.0 6.997208e-07 2.7 1.8 2.7
2.8 0.0 2.800000e+00 0.0 0.0 2.800000e+00 0.0 8.864527e-07 2.8 1.8 2.8
2.9 0.0 2.900000e+00 0.0 0.0 2.900000e+00 0.0 1.106181e-06 2.9 1.8 2.9
3.0 0.0 3.000000e+00 0.0 0.0 3.000000e+00 0.0 1.362042e-06 3.0 1.8 3.0
3.1 0.0 3.100000e+00 0.0 0.0 3.100000e+00 0.0 1.657197e-06 3.1 1.8 3.1
3.2 0.0 3.200000e+00 0.0 0.0 3.200000e+00 0.0 1.995189e-06 3.2 1.8 3.2
3.3 0.0 3.300000e+00 0.0 0.0 3.300000e+00 0.0 2.379896e-06 3.3 1.8 3.3
3.4 0.0 3.400000e+00 0.0 0.0 3.400000e+00 0.0 2.819709e-06 3.4 1.8 3.4
3.5 0.0 3.500000e+00 0.0 0.0 3.500000e+00 0.0 3.327254e-06 3.5 1.8 3.5
3.6 0.0 3.600000e+00 0.0 0.0 3.600000e+00 0.0 3.908957e-06 3.6 1.8 3.6
3.7 0.0 3.700000e+00 0.0 0.0 3.700000e+00 0.0 4.571385e-06 3.7 1.8 3.7
3.8 0.0 3.800000e+00 0.0 0.0 3.800000e+00 0.0 5.321231e-06 3.8 1.8 3.8
3.9 0.0 3.900000e+00 0.0 0.0 3.900000e+00 0.0 6.165291e-06 3.9 1.8 3.9
4.0 0.0 4.000000e+00 0.0 0.0 4.000000e+00 0.0 7.110448e-06 4.0 1.8 4.0
4.1 0.0 4.100000e+00 0.0 0.0 4.100000e+00 0.0 8.163651e-06 4.1 1.8 4.1
4.2 0.0 4.200000e+00 0.0 0.0 4.200000e+00 0.0 9.331901e-06 4.2 1.8 4.2
4.3 0.0 4.300000e+00 0.0 0.0 4.300000e+00 0.0 1.062224e-05 4.3 1.8 4.3
4.4 0.0 4.400000e+00 0.0 0.0 4.400000e+00 0.0 1.204171e-05 4.4 1.8 4.4
4.5 0.0 4.500000e+00 0.0 0.0 4.500000e+00 0.0 1.359740e-05 4.5 1.8 4.5
4.6 0.0 4.600000e+00 0.0 0.0 4.600000e+00 0.0 1.529636e-05 4.6 1.8 4.6
4.7 0.0 4.700000e+00 0.0 0.0 4.700000e+00 0.0 1.714565e-05 4.7 1.8 4.7
4.8 0.0 4.800000e+00 0.0 0.0 4.800000e+00 0.0 1.915229e-05 4.8 1.8 4.8
4.9 0.0 4.900000e+00 0.0 0.0 4.900000e+00 0.0 2.132329e-05 4.9 1.8 4.9
5.0 0.0 4.999999e+00 0.0 0.0 5.000000e+00 0.0 2.366559e-05 5.0 1.8 5.0
sweepplot(df).opts(responsive=True, height=500)