In [1]:
from IPython.display import *
%nbtoc
This example demonstrates a macgyver-ish shortcut you can take if you are measuring a device that is reciprocal and symmetric on a switch-less three-receiver system. For more information about error correction this type of architecture, see Calibration With Three Receivers.
In general, full error correction of a 2-port network on a switchless three-receiver architecture requires each DUT to measured in two orientations. However, if the DUT is known to be reciprocal ($S_{21}=S_{12}$) and symmetric ($S_{11}=S_{22}$), then measurements in both orientations produce the same response, and therefore are unnecesary.
The following worked example compares the corrected response of a 10dB attenuator at WR-12 as corrected using full error correction and psuedo-full error correction using:
In [2]:
Image('pics/macgyver.jpg', width='50%')
Out[2]:
These measurements where taken on a Agilent PNAX with a set of VDI WR-12 TXRX-RX Frequency Extender heads. The measurements of the calibration standards and DUT's were downloaded from the VNA by saving touchstone files of the raw s-parameter data to disk.
In the code that follows a TwoPortOnePath calibration is created from corresponding measured and ideal responses of the calibration standards. The measured networks are read from disk, while their corresponding ideal responses are generated using scikit-rf. More information about using scikit-rf to do offline calibrations can be found here.
In [3]:
from skrf.calibration import TwoPortOnePath
from skrf.media import RectangularWaveguide
from skrf import two_port_reflect as tpr
from skrf import mil
import skrf as rf
raw = rf.read_all_networks('data/')
# pull frequency information from measurements
frequency = raw['short'].frequency
# the media object
wg = RectangularWaveguide(frequency=frequency, a=120*mil, z0=50)
# list of 'ideal' responses of the calibration standards
ideals = [wg.short(nports=2),
tpr(wg.delay_short( 90,'deg'), wg.match()),
wg.match(nports=2),
wg.thru()]
# corresponding measurments to the 'ideals'
measured = [raw['short'],
raw['quarter wave delay short'],
raw['load'],
raw['thru']]
# the Calibration object
cal = TwoPortOnePath(measured = measured, ideals = ideals )
With the calibration created above, we compare the corrected response of WR-12 10dB attenuator using Full, Psuedo-Full, and Partial Correction. Each correction algorithm is described below.
In [4]:
Image('pics/symmetric DUT.jpg', width='75%')
Out[4]:
Full correction on this type of architecture has been called TwoPortOnePath. In scikit-rf
using this correction algorithm requires the device to be measured in both orientations, forward and reverse, and passing them both to the apply_cal()
function as a tuple
. Neglecting the connector uncertainty, this type of correction is identical to full two-port SOLT calibration.
If we assume the DUT is reciprocal and symmetric, then measuring the device in both orientations will produce the same result. Therefore, the reverse orientation measurment may be replaced by a copy of the forward orientation measurement. We refer to this technique as the Fake Flip.
If you pass a single measurement to the apply_cal()
function, then the calibration will employ partial correction. This type of correction is known as EnhancedResponse
. While the Fake Flip technique assumes the device is reciprocal and symmetric, the EnhancedResponse
algorithm implicitly assumes that the port 2 of the device is perfectly matched. The accuracy of the corrected result produced with either of these algorithms depends on accuracy of the assumptions.
In [5]:
dutf = raw['attenuator (forward)']
dutr = raw['attenuator (reverse)']
# note the correction algorithm is different depending on what is passed to
# apply_cal
corrected_full = cal.apply_cal((dutf, dutr))
corrected_fakeflip = cal.apply_cal((dutf,dutf))
corrected_partial = cal.apply_cal(dutf)
f, ax = subplots(2,2, figsize=(8,8))
for m in [0,1]:
for n in [0,1]:
ax_ = ax[m,n]
ax_.set_title('$S_{%i%i}$'%(m+1,n+1))
corrected_full.plot_s_db(m,n, label='Full Correction',ax=ax_ )
corrected_fakeflip.plot_s_db(m,n, label='Psuedo-full Correction', ax=ax_)
if n==0:
corrected_partial.plot_s_db(m,n, label='Partial Correction', ax=ax_)
tight_layout()
In [6]:
from IPython.core.display import HTML
def css_styling():
styles = open("../styles/plotly.css", "r").read()
return HTML(styles)
css_styling()
Out[6]:
In [6]: