Basic spectroscopy measurements

This notebook is indended as a starting point into spectroscopic (frequency domain) measurements with qkit. We focus on measurements with vector network analyzers (VNAs) in the GHz regime. The notebook briefly covers the qkit startup, initialization of measurement devices and the use of a sample object. For a detailed view on these topic you will find more information in their respective example notebooks. After creating of an object of the spectrum class and parsing the device information to the object we can start measuring. The spectrum class offers frequency domain VNA measurements with up to two additional external sweep parameters. The data is stored in a hdf5 file and can be view and further analyzed.


In [ ]:
# start qkit and import the needed modules. we here assume an already configured qkit measurement environment
import qkit
qkit.start()

from qkit.measure.spectroscopy import spectroscopy
import qkit.measure.samples_class as sc

import numpy as np

In [ ]:
# initialize instruments; as an example we here work with a Keysight VNA, a Yokogawa current source, 
# and an Anritsu MW source
vna = qkit.instruments.create('vna', 'Keysight_VNA_E5071C', address='TCPIP::XXX.XXX.XXX.XXX')
yoko = qkit.instruments.create('yoko', 'Yokogawa_GS820', address='TCPIP::XXX.XXX.XXX.XXX')
mw_src = qkit.instruments.create('mw_src', 'Anritsu_MG37022', address='TCPIP::XXX.XXX.XXX.XXX')

In [ ]:
# create/load sample object; (optional), for more information see the example notebook on the sample class.
sample_filepath = r'\some\path\sample_1.sample'
smpl = sc.Sample(sample_filepath)

Creating a spectrum object. The init takes

  • vna: instrument object (mandatory)
  • exp_name: string (optional) for a brief name of the experiment
  • sample: sample object (optional)

In [ ]:
s = spectroscopy.spectrum(vna=vna, sample = smpl)

The general VNA parameters (probing frequencies, power, etc.) can be either set at the device or use the qkit instrument command. Using sample object attributes is possible as well.


In [ ]:
vna.set_centerfreq(smpl.fr)
vna.set_span(200e6)
vna.set_averages(10)
vna.set_Average(True)

Next we want to record the VNA trace. In the spectrum object the parameter comment can be used for all non-digital information. Any digitally available instrument settings are saved automatically.


In [ ]:
comment = """
    * -30dB attenuator @ VNA
    """

s.comment = comment
s.measure_1D()

For resonator measurements it is also possible to fit the probed resonance live while measureing. For the fits to converge the VNA parameters need to adjusted properly.


In [ ]:
comment = """
    * measure resonance in reflection
    * -30dB attenuator @ VNA
    """
s.set_resonator_fit(fit_function='circle_fit_reflection')
s.comment = comment
s.measure_1D()

A sweep parameter can be added to the spectum object and attributed to a sweep axis. In the example below we measure a resonator agains a applied current (ie for creating a magnetic field bias). The current is swept from 0 to 1A in 1mA steps. After the measurement the current is ramped down again. For one value of the x-parameter all VNA frequencies are probed before the next value of x is set.


In [ ]:
comment = """
    * resonator vs applied current
    * -30dB step attenuator @ VNA
    """
s.comment = comment
s.set_resonator_fit(fit_resonator=False)

# x_func gets called for every value of i. Here it would be not necessary to define a function for only the ramp fct,
# it will be useful in the next example.
def x_func(i):
    return yoko.ramp_current(i, 1e-3)

s.set_x_parameters(x_vec = np.arange(0, 1, 1e-3),
                  x_coordname = 'current',
                  x_set_obj = x_func,
                  x_unit = 'A')

s.measure_2D()
yoko.ramp_current(0, 1e-3)

In the next example the VNA power is changed in addition to the current. Depending on the applied power, the number of averages is changed.


In [ ]:
# the x/y-loops are interleaved, y changes "faster" than x: 
#     1) each VNA freq at y0 and x0
#     2) each VNA freq at y1 and x0
#     ...
#     3) each VNA freq at yN and x0
#     4) each VNA freq at y0 and x1
#     ...
#     5) each VNA freq at yN and xM

comment = """
    * resonator vs applied current at different power levels
    * -30dB step attenuator @ VNA
    """
s.comment = comment
s.set_resonator_fit(fit_resonator=False)

def x_func(i):
    return yoko.ramp_current(i, 1e-3)

# Here the called function features more commends, i.e. change the number of averages at different powers to shorten the
# measurement time.
def y_func(i):
    if i < -25: vna.set_averages(10)
    else: vna.set_averages(5)
    return vna.set_power(i)

s.set_x_parameters(x_vec = np.arange(0, 1.001, 1e-3),
                  x_coordname = 'current',
                  x_set_obj = x_func,
                  x_unit = 'A')

s.set_y_parameters(y_vec = np.arange(-35, 11, 5),
                  y_coordname = 'power',
                  y_set_obj = y_func,
                  y_unit = 'dBm')

s.measure_3D()
yoko.ramp_current(0, 1e-3)

The measure_iD() command executes the measurement. By default, the created data file is opened in qviewkit. After the measurement the created datasets are plotted with default matplotlib settings. A progress bar programmed in JavaScript shows the status during the measuremend and gives additional information i.e. a estimated end time for the measurement.


In [ ]: