Inductor tap S-parameters: vector fitted model vs. Touchstone data

load "resistor.osdi"
load "capacitor.osdi"

include "inductor-tap.inc"

model vsrc vsource
model r resistor

x1 (p1 p2 p3) inductor_tap

vp1 (a1 0) vsrc dc=0
rp1 (a1 p1) r r=50

vp2 (a2 0) vsrc dc=0
rp2 (a2 p2) r r=50

vp3 (a3 0) vsrc dc=0
rp3 (a3 p3) r r=50

control
  analysis sp1 acsp ports=["vp1", "rp1", "vp2", "rp2", "vp3", "rp3"] from=0 to=60G mode="lin" points=400

  postprocess(PYTHON, "runme.py")
endc

embed "runme.py" <<<FILE
import os
import numpy as np
import matplotlib.pyplot as plt
import skrf as rf
from rawfile import rawread

# The Touchstone file sits next to this netlist, not necessarily in the
# simulator's working directory, so locate it via SIM_PARENT_FILE_DIR.
s3pPath = os.path.join(os.environ.get("SIM_PARENT_FILE_DIR", "."), "inductor-tap.s3p")
network = rf.Network(s3pPath)

plot = rawread('sp1.raw').get()
freqAcsp = np.real(plot['frequency'])/1e9
freqS3p = network.f/1e9

fig, axs = plt.subplots(3, 3, figsize=(12, 10), sharex=True)
fig.suptitle('Inductor tap S-parameters: acsp (lines) vs. Touchstone (dots)')

for ax, (i, j) in zip(axs.flat, [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)]):
    sAcsp = plot[f's({i},{j})']
    sTs = network.s[:, i - 1, j - 1]
    ax.plot(freqAcsp, 20*np.log10(np.abs(sAcsp)), '-', label='acsp')
    ax.plot(freqS3p, 20*np.log10(np.abs(sTs)), '.', label='s3p')
    ax.set_title(f'S{i}{j}')
    ax.set_xlabel('f [GHz]')
    ax.set_ylabel('Magnitude [dB]')
    ax.grid(True)
    ax.legend()

fig.tight_layout()
plt.show()
>>>FILE
