Operating Point Analysis#
Find the DC operating point of an IHP circuit using ngspice. Capacitors are opened and inductors are shorted.
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
from nyancad.watch import watch_project_dir, file_schematic
from nyancad.netlist import inspice_netlist
from InSpice import Simulator
Parameters#
SCHEMATIC = "inverter" # stem of the .nyancir file
CORNER = "mos_tt"
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
Run operating point analysis#
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.operating_point()
print("Operating point analysis complete.")
Warning: can't find the initialization file spinit.
Newer Ngspice version that could be unsupported 46
Operating point analysis complete.
Results#
print("Node voltages:")
for node in analysis.nodes.keys():
print(f" {node} = {np.array(analysis[node]).item():.6g} V")
print("\nBranch currents:")
for branch in analysis.branches.keys():
print(f" {branch} = {np.array(analysis[branch]).item():.6g} A")
Node voltages:
n.xm1.nsg13_lv_nmos#SI = 0 V
n.xm1.nsg13_lv_nmos#GP = 0.9 V
n.xm1.nsg13_lv_nmos#NOI = 0 V
n.xm2.nsg13_lv_pmos#SI = 0 V
n.xm2.nsg13_lv_pmos#GP = 0.9 V
n.xm2.nsg13_lv_pmos#NOI = 0 V
w6 = 0.162154 V
w3 = 0.9 V
w2 = 1.8 V
Branch currents:
vv1 = -2.16629e-05 A
vv2 = 4.20063e-14 A