Measuring Material Properties in Waveguide

I saw Dielectric constant measurement for thin material at microwave frequencies and wanted to give it a try. This was done in WR-42 waveguide from 18 to 26.5 GHz. Samples were cut to 0.17 x 0.42 inches to fit the waveguide.

Relative Permittivity (Er)

Er of samples

Material Thickness Er (measured) Er (ref)
Polypropylene (pp) 736 μm 2.14 2.26 at 9.4 GHz
Polycarbonate (pc) 583 μm 2.7 2.77 at 11 GHz
Rogers RO4350B 509 μm 3.59 3.48/3.66 at 10 GHz
OSHPark 4 layer prepreg 205 μm 3.3 3.26 - 4.01
OSHPark 4 layer core 531 μm 4.02 3.26 - 4.01
GE Silicone II (white) 1.875 mm 2.64 unspecified

The OSHPark 4 layer PCBs are made from Isola FR408. As shown in this document, the thicker cores and prepregs have higher glass content and thus higher Er. The 47 mil thick core is not listed in the above PDF, but would presumably be the heaviest glass and have an Er of around 4.0. The prepreg used for the outer layers is a fine glass weave with high resin content, so the measured value of 3.3 seems reasonable. The prepreg sample is very thin and has some taper, so that value may be the least reliable of the group. The core and prepreg samples were obtained by mechanically delaminating a finished PCB.


The RO4350B has a 10 GHz dielectric constant of 3.48 +- 0.05 using a clamped stripline method that tends to underestimate Er on hard materials like RO4350B. The recommended value for design is 3.66, so this measured value of 3.59 seems reasonable.

Silicone II

This is white caulk from a hardware store which I had purchased for my bathtub. The data on this one is questionable as it was hard to cut a precise block of this soft material. A silicone might be interesting as a directional coupler overlay.

Loss Tangent

These values are less reliable and noisy as the dissipation loss of the samples is on the order of 0.015 dB. The polypropylene has such low loss that errors are causing it to appear to have a negative loss tangent. The waveguide shim used as a sample holder was bare brass which certainly didn't help repeatability. The spikes in the silicone and osh_core traces are likely due to resonance within the sample as the section of guide containing the sample can support higher order modes.

loss tangent of samples

Approximation not valid

Plot of
  differing results with approximate solution and exact solution

The plot above shows the amount of error introduced by the assumption in the paper that the samples are thin. The data with _est uses the approximations for small values, \(\sin(kz_2\tau) \approx kz_2\tau\). With the smaller guide and higher frequencies used here versus the original paper, the assumption is not valid with reasonable thickness samples.

The value of Er is solved for using SciPy optimize.minimize. It's a bit ugly as it doesn't directly handle complex numbers, but gets the job done.

Future work

Try to do something similar in 7 mm coax.


The SParameter library (used for opening .s2p files, wgsection, S parameter concatenation) has not yet been released, so this is only useful for reference. The library is in C++ with SWIG wrappers and will be released as open source (GPLv3) when it is ready.

#!/usr/bin/env python3
import numpy as np
import matplotlib.pyplot as plt
import sys
import SParameter as scpp
from scipy.constants import c, inch
import scipy.optimize

a = 0.42 * inch # wide waveguide dimension in meters

samples = [ # file name, thickness in meters
    ['pc.s2p', 583.0e-6],
    ['pp.s2p', 736.0e-6],
    ['ro4350b.s2p', 509e-6],
    ['osh_prepreg.s2p', 229e-6],
    ['osh_core.s2p', 531e-6],
    ['silicone.s2p', 1875e-6],

for sample in samples:
    fn = sample[0]
    t = sample[1] # thickness
    sp = scpp.SParameter(fn)
    sp.reducefreqrange(50e6, 18e9, 26.5e9)
    # add an air filled section of guide the length of the sample
    te = scpp.wgsection(sp, a, t)
    sp = scpp.SParameter(te, sp)
    s = np.array(sp.s)
    s21 = 0.5 * (s[1::4] + s[2::4]) # average of s21, s12
    f = np.array(sp.f)
    e = np.zeros(len(f), dtype=complex)

    for i in range(len(f)):
        wavelength = c / f[i] # free space wavelength
        kz = (np.pi/(wavelength*a)) * np.sqrt( 4.0*np.square(a)-np.square(wavelength))

        def func(z):
            c = s21[i] - 1.0 / (np.cos(z) + 0.5j*kz*t*(1+np.square(z/(kz*t))) * np.sin(z)/(z))
            return c.real*c.real + c.imag*c.imag

        b0 = [a.real, a.imag] # estimate, assumes Er = 1.0
        res = scipy.optimize.minimize(lambda z: func(complex(z[0],z[1])), b0, tol=1e-6)
        kz2 = complex(res.x[0], res.x[1])/t
        e[i] = (np.square(kz2 * wavelength * a / np.pi) + np.square(wavelength))/(4*a*a)

    if sys.argv[1] != 'loss':
        plt.plot(f/1e9,np.real(e), label=fn)
        losstan = -np.imag(e)/np.real(e)
        plt.plot(f/1e9,losstan, label=fn)
        plt.ylabel('loss tangent')

plt.xlabel('Frequency (GHz)')

Unit Testing VNA Calibration Code

The Problem

There are an alphabet soup of VNA calibration types (SOLT, TRL, LRL, TRM, SOLR, QSOLT, many more), some of which will be supported by the Harmon Instruments VNA and run by the end user. Testing all of the supported calibration types through the normal user interface and measuring verification components for each could easily take an entire day. Using physical calibration standards, uncertainties would be limited to those of the standards. An additional concern with testing on hardware is the wear and tear on the fragile and expensive calibration standards.

Photo of VNA Calibration Standards

Breaking it Down

The data path from ADC values to corrected S-parameters for display is split into layers with independent test coverage. The lowest level, implemented in an FPGA, taking signals from the ADCs has test coverage using the excellent CocoTB package. The next layer, written in C++, takes integer vector voltage data from the FPGA and produces raw S-parameters. These first two layers are relatively simple mathematical operations. The final layer, correcting the raw S-parameters, is where the complexity lies and is what will be discussed here.

Modeling the VNA and Calibration Standards

For simplicity, we will focus on a 2 port VNA calibrations using an 8 term error model (TRL, SOLR, similar). This model contains a fictitious 2 port "error adapter" to either side of the device under test (DUT). These represent internal leakages, losses, gain imbalances, etc as well as the test port cables. The raw S-parameters are simply those of the DUT in cascade with the two error adapters. In a calibration, sufficient standards are measured to solve for the error adapters.

Knowing the contents of the error adaptors, it is possible to run the calibration backwards and calculate the raw S-parameters from the true S-parameters of the devices being measured. Realistic models of the calibration standards are used with airlines, opens and shorts having loss. Simulated raw data is genereated for the required set of standards as well as a few challenging DUTs and the data is sent throught the calibration acquisition and correction software. The corrected data is compared with the originals and verified to be within reasonable rounding error. The tests on the calibration algorithms complete in less than 1 second and run every time the software is built causing the build to fail if any test does.

For the purposes of testing the calibration software, the VNA is presumed to be linear and time invariant. In the future, for uncertainty analysis, it may be desirable to add drift and nonlinearity based on characterization of real hardware.

Offline Processing of Acquired Data

By saving raw data for many types of calibration and verification standards, it is possible to generate corrected S-parameters using any calibration type using those standards. QSOLT had not yet been coded when this data set was aquired, but it is possible to generate QSOLT corrected data as all of the required standards are present in the data dumps. This is mostly useful to see how the algorithms compare with imperfect standards.

Plot of
  Maury Microwave 60 mm airline S22 with QSOLT, TRL, TRM and data
  based QSOLT calibrataions

The above plot shows significant differences between calibrations assuming the load standards are ideal (QSOLT, TRM), TRL which uses airlines rather than loads and a data based QSOLT calibration which uses more accurate models of the short, open and load. These differences are not due to software, but the physical standards and their definitions.


The S-parameter handling code (C++) on the Harmon Instruments VNA has a SWIG generated Python wrapper and the Python unit testing framework is used to run the tests. Google Test would have been another option. Python works well here due to libraries like NumPy, SciPy and Matplotlib providing mathematical functions and plotting. For instance, to test a C++ implementation of the Kaiser window, I added a test to compare it with one generated by SciPy.