Transfer Function Analysis#

Compute DC small-signal transfer function, input resistance, and output resistance.

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"

# -- Transfer function parameters --
OUTPUT_VAR = "v(net0)"  # output variable (e.g. "v(out)", "i(vload)")
INPUT_SOURCE = "VV2"  # input source name

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 transfer function 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.transfer_function(
    outvar=OUTPUT_VAR,
    insrc=INPUT_SOURCE,
)
print("Transfer function analysis complete.")
Warning: can't find the initialization file spinit.
Newer Ngspice version that could be unsupported 46
Transfer function analysis complete.

Results#

print("Transfer function results:")
for key in analysis.nodes.keys():
    val = np.array(analysis[key]).item()
    print(f"  {key} = {val:.6g}")
Transfer function results:
  output_impedance_at_V(net0) = 1
  vv2#Input_impedance = 4.94306e+11
  Transfer_function = 0