TRAINING - Interfacing with the Vector Network Analyzer#

In this exercise, we will practice using Python to communicate with the vector network analyzer (VNA), which allows us to probe the microwave cavity’s frequency response. In short, the VNA acts as both a signal generator and a receiver. Within a defined frequency sweep, \(\omega\in[\omega_1,\omega_2]\), it sends a signal at frequency \(\omega\) and measures the reflected power off the cavity. When \(\omega\) is resonant with the cavity’s resonance frequency \(\omega_c\), i.e. \(\omega=\omega_c\), the reflected power would be minimal. This will be covered in more details in the textbook. For now, we will focus on writing a small piece of code to send commands to the VNA, and collecting the relevant measurement data, \(S_{21}\).

1. Installing the VNA GUI#

The GUI software for the VNA can be downloaded here: jankae/LibreVNA

You may download either the latest version or pre-release.

You may also designate one person whose laptop/computer will be installed with the software. However, each person still needs to submit their own code.

2. Familiarize with the GUI#

Make sure the VNA is USB-connected to your computer. Then, open the LibreVNA-GUI. In the “Device” tab, you should be able to see the VNA’s device ID in “Connect To”. Select the device, and you should be seeing four quadrants, each representing a S-parameter. For the experiment you will be running, only \(S_{21}\) is needed. You may enlarge the “S21” screen by dragging its boundaries.

In the top bar, make sure the “Sweep type” is Frequency. You can define the frequency sweep range by either setting (1) Start and Stop, or (2) Center and Span.

Right-clicking on the plot and selecting “Axis Setup” allows you to select “Auto” for the axes’ range. This is important if you want to monitor signals with changing amplitudes and/or after you change the frequency sweep range.

Note that Ports 1 & 2 of the VNA are not connected to anything at the moment, so you should just be seeing noise in the “S21” plot.

3. Establish connection with the VNA via Python#

3.1 Download the Python file below. Make sure it is either in the same directory as this Jupyter notebook or modify the directory path when importing.#

Click here to download.

3.2 Next, try running the next code block.#

# RUN ME
from libreVNA import libreVNA
import matplotlib.pyplot as plt
---------------------------------------------------------------------------
ModuleNotFoundError                       Traceback (most recent call last)
Cell In[1], line 3
      1 # RUN ME
      2 from libreVNA import libreVNA
----> 3 import matplotlib.pyplot as plt

ModuleNotFoundError: No module named 'matplotlib'

3.3 Connecting to the VNA#

If the above block runs without an issue, run the next code block to establish connection. After creating a handle to the VNA, you will notice there are two methods to communicate with the device.vna.query(XXX) and vna.command(XXX). The former sends a command to the VNA and asks for a response (aka query), and the latter only sends a command. The input XXX to either of these methods is a SCPI (Standard Commands for Programmable Instruments). For a complete of list of SCPI commands for the VNA, consult the Programming Guide below:

Click here to download.

# RUN ME

# Establish VNA connection
# note: remember to communicate with the VNA, the GUI must be running

# Create the control instance
vna = libreVNA('localhost', 19542)

# Quick connection check (should print "LibreVNA-GUI")
print(vna.query("*IDN?"))

# Make sure we are connecting to a device (just to be sure, with default settings the LibreVNA-GUI auto-connects)
vna.cmd(":DEV:CONN")
dev = vna.query(":DEV:CONN?")
if dev == "Not connected":
    print("Not connected to any device, aborting")
    exit(-1)
else:
    print("Connected to "+dev)

4. Setting the VNA parameters#

Write a Python script that does the following:

  1. Sets the frequency sweep range from 2.93 GHz to 2.95 GHz

  2. Sets the sweep with 51 frequency points

  3. Sets the intermediate frequency bandwidth to 1 kHz

  4. Sets the number of average to 1

# Your code goes here

# 1
vna.cmd(":VNA:FREQuency:CENTer 2940000000")
vna.cmd(":VNA:FREQuency:SPAN 20000000")

# 2
vna.cmd(":VNA:ACQ:POINTS 51")

# 3
vna.cmd(":VNA:ACQ:IFBW 1000")

# 4
vna.cmd(":VNA:ACQ:AVG 1")

5. Grabbing data off the VNA#

Write a Python script that extracts \(S_{21}\) data vector, and plots both the amplitude and phase entries. You may find the method vna.parse_VNA_trace_data(...) helpful.

# Your code goes here

import numpy as np
import matplotlib.pyplot as plt

# grab the data of trace S21
data = vna.query(":VNA:TRACE:DATA? S21")

S21 = vna.parse_VNA_trace_data(data)
freqs = S21[:][0]
amp = np.abs(S21[:][1])**2
phase = np.angle(S21[:][1])

# Plot amplitude and phase
fig, ax1 = plt.subplots(figsize=(8, 8))
ax2 = ax1.twinx()

ax1.plot(freqs,amp)
ax1.set_xlabel('Frequency')
ax1.set_ylabel('Amplitude (a.u.)')
ax2.plot(freqs,phase)
ax2.set_ylabel('Phase (deg)')