Finding the electrical length of the branches of an N type T – #4

Finding the electrical length of the branches of an N type T – #1 posed a problem, this article looks at one solution.

For convenience, here is the problem.

An interesting problem arises in some applications in trying to measure the electrical length of each branch of a N type T piece.

Let's make some assumptions that the device is of quality, that the connection from each connector to the internal junction is a uniform almost lossless transmission line of Zo=50Ω. Don't assume that the left and right branches above are of the same length (though they often are) and we should not assume that the nearest branch is of the same length as the others (and they are often not).

Before we start, we will calibrate the VNA entering the offsets appropriate to the OPEN and SHORT cal parts. In the case of my nanoVNA, measurement above 900MHz is very noisy, so the scan will be 100-890MHz (to avoid a glitch at 900MHz due to harmonic mode switching).

So, the problem is all the uncertain things that connect to the internal T junction. Lets connect a calibration quality 50Ω termination to the left hand port. We now know that the path from the male port to the remaining female port comprises lengths l2 and l1 of low loss 50Ω transmission line with a 50Ω resistor shunting at the junction of l1 and l2.

Now lets connect a calibration quality short (SC) to the right hand female port, and measure the X component of the impedance looking into the male port. So, the instrument measuring Z at the male connector sees two sections of low loss 50Ω line to the 50Ω load, and the right hand SC stub shunting at the internal T junction.

Let's predict

Above is a Simsmith simulation of Xin to 900MHz using lengths very close to the DUT. The shape of the curve is due to all configuration factors, the assumed constraints and l1 and l2. We expect Xin vs frequency to be quite similar to above.

Let's measure

 

Without the 50Ω shunting at the internal T junction, Zin would simply be that of a low loss SC stub, and would be a tan curve turning upwards to a peak at a frequency where l2 is 90°.

Above is the Smith chart of the sweep. From that we can extract the Xin vs frequency dataset for curve fitting. We save this sweep as a .s1p file.

Let's curve fit

A Python script was written to extract Xin from the .s1p file, and fit a model of the transmission line structure to the measured data, finding l1 and l2.

Above is the measured and modelled curve fit.

1-Port Network: 'T-N-nanoVNA01',  100000000.0-890000000.0 Hz, 101 pts, z0=[50.+0.j]

Model t: t1= 87.3ps, t2=100.8ps
      σ: σ1= 0.41ps, σ2= 0.21ps

Model l: l1= 26.2mm, l2= 30.2mm
      σ: σ1= 0.12mm, σ2= 0.06mm

Above are the calculated model values, l1=26.2mm with σ=0.12mm, and l2=30.2mm with σ=0.063mm. This is quite a good model.

Don't forget to then adjust for the offset of the SC used.

Python script

#!/usr/bin/python3
import os,sys
import csv
from scipy import stats
import getopt
import numpy
import math
import cmath
import skrf as rf
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def usage():
  print("Usage: "+sys.argv[0]+"")
  sys.exit(1)

try:
    opts, args = getopt.getopt(sys.argv[1:], "ho:vl:u:", ["help", "output="])
except getopt.GetoptError as err:
    # print help information and exit:
    print(err)  # will print something like "option -a not recognized"
    usage()
#    sys.exit(2)
output = None
verbose = False
for o, a in opts:
    if o == "-v":
        verbose = True
    elif o in ("-h", "--help"):
        usage()
        sys.exit()
    else:
        assert False, "unhandled option"
try:
  pass
  infile=args[0]
except:
  usage()
  
nw1=rf.Network(infile)
print(nw1)
print()
f=numpy.array(nw1.f)
x=numpy.array(nw1.z_im[:,0,0])

c0=299792458
zo=nw1.z0[0][0]

def t_xin(freq,t1,t2):
  p=1/freq*1e12
  z=zo*numpy.tan(t1/p*2*math.pi)*1j
  z=1/(1/z+1/zo)
  x=(zo*(z+zo*numpy.tan(t2/p*2*math.pi)*1j)/(zo+z*numpy.tan(t2/p*2*math.pi)*1j)).imag
  return x

popt,pcov=curve_fit(t_xin,f,x,bounds=(0, [150,150]),method='trf')
perr=numpy.sqrt(numpy.diag(pcov))
print('Model t: t1=%5.1fps, t2=%5.1fps' % tuple(popt))
print('      \u03C3: \u03C31=%5.2fps, \u03C32=%5.2fps' % tuple(perr))
print()
print('Model l: l1=%5.1fmm, l2=%5.1fmm' % tuple(popt*1e-9*c0))
print('      \u03C3: \u03C31=%5.2fmm, \u03C32=%5.2fmm' % tuple(perr*1e-9*c0))

plt.figure(figsize=(8, 6), dpi=128)
plt.plot(f/1e6,x, 'r-', label='measured')
plt.plot(f/1e6,t_xin(f,*popt),'k:',label='fit: t1=%5.2fps, t2=%5.2fps' % tuple(popt))
plt.xlabel('Freq (MHz)')
plt.ylabel('X ($\Omega$)')
plt.legend()
plt.title('T characterisation: '+nw1.name)
plt.ylim(bottom=0)
plt.xlim(left=0)
plt.savefig(nw1.name+'.png')