# Ex2: Measured 190 GHz Active 2-Port¶

The Vector Fitting feature is demonstrated using a 2-port S-matrix of an active circuit measured from 140 GHz to 220 GHz. Additional explanations and background information can be found in the Vector Fitting tutorial.

[1]:

import skrf
import numpy as np
import matplotlib.pyplot as mplt


This example is a lot more tricky to fit, because the responses contain a few “bumps” and noise from the measurement. In such a case, finding a good number of initial poles can take a few iterations.

Load the Network from a Touchstone file and create the Vector Fitting instance:

[2]:

nw = skrf.network.Network('./190ghz_tx_measured.S2P')
vf = skrf.VectorFitting(nw)


First attempt: Perform the fit using 4 real poles and 4 complex-conjugate poles:

[3]:

vf.vector_fit(n_poles_real=4, n_poles_cmplx=4)


The function plot_convergence() can be helpful to examine the convergence and see if something was going wrong. In this case, the results converged reasonably fast (less than 30 iterations):

[4]:

vf.plot_convergence()


Checking the results by comparing the model responses to the original sampled data indicates a successful fit:

[5]:

fig, ax = mplt.subplots(2, 2)
fig.set_size_inches(12, 8)
vf.plot_s_mag(0, 0, ax=ax[0][0]) # s11
vf.plot_s_mag(0, 1, ax=ax[0][1]) # s12
vf.plot_s_mag(1, 0, ax=ax[1][0]) # s21
vf.plot_s_mag(1, 1, ax=ax[1][1]) # s22
fig.tight_layout()
mplt.show()


It is a good idea to also check the model response well outside the original frequency range. This reveals a large dc component, which might not be ideal for some cases:

[6]:

freqs = np.linspace(0, 500e9, 501) # plot model response from dc to 500 GHz
fig, ax = mplt.subplots(2, 2)
fig.set_size_inches(12, 8)
vf.plot_s_mag(0, 0, freqs=freqs, ax=ax[0][0]) # s11
vf.plot_s_mag(0, 1, freqs=freqs, ax=ax[0][1]) # s12
vf.plot_s_mag(1, 0, freqs=freqs, ax=ax[1][0]) # s21
vf.plot_s_mag(1, 1, freqs=freqs, ax=ax[1][1]) # s22
fig.tight_layout()
mplt.show()


Second attempt: Maybe an even better fit without that large dc “spike” can be achieved, so let’s try again. Unwanted spikes at frequencies outside the fitting band are often caused by unnecessary poles. Let’s reduce the number of real starting poles to 3 (similarly, one could also try reducing the number of complex-conjugate starting poles instead):

[7]:

vf.vector_fit(n_poles_real=3, n_poles_cmplx=4)
vf.plot_convergence()


This fit took many more iterations, but it converged nevertheless and it matches the network data very well inside the fitting band. More importantly, the large dc spike is gone:

[8]:

fig, ax = mplt.subplots(2, 2)
fig.set_size_inches(12, 8)
vf.plot_s_mag(0, 0, freqs=freqs, ax=ax[0][0]) # s11
vf.plot_s_mag(0, 1, freqs=freqs, ax=ax[0][1]) # s12
vf.plot_s_mag(1, 0, freqs=freqs, ax=ax[1][0]) # s21
vf.plot_s_mag(1, 1, freqs=freqs, ax=ax[1][1]) # s22
fig.tight_layout()
mplt.show()


This looks good, so let’s export the model as a SPICE subcircuit. For example:

vf.write_spice_subcircuit_s('/home/vinc/Desktop/190ghz_tx.sp')

The subcircuit can then be simulated in SPICE with the same AC simulation setup as in the ring slot example: