This page was generated from docs/examples/driver_examples/Qcodes example with keithley 2450.ipynb. Interactive online version: Binder badge.

QCoDeS Example with Tektronix Keithley 2450 Source Meter

In this example we will setup a number of four-wire measurements with the 2540 source meter. We attach a variable resistor to the front terminals and determine if we can measure the correct resistance.

[1]:
from pyvisa import VisaIOError

from qcodes.dataset import (
    Measurement,
    initialise_database,
    new_experiment,
    plot_dataset,
)
from qcodes.instrument_drivers.Keithley import Keithley2450
[2]:
keithley = Keithley2450("keithley", "GPIB0::18::INSTR")
Connected to: KEITHLEY INSTRUMENTS 2450 (serial:04451117, firmware:1.6.7c) in 0.08s
[3]:
keithley.reset()

Single point measurements

Attach a variable resistor to the front and source a current

[4]:
keithley.terminals("front")
keithley.source.function("current")
keithley.source.current(1E-6)  # Put 1uA through the resistor
current_setpoint = keithley.source.current()

voltage = keithley.sense.function("voltage")
with keithley.output_enabled.set_to(True):
    voltage = keithley.sense.voltage()

print("Approx. resistance: ",  voltage/current_setpoint)
Approx. resistance:  1022.3210000000001

We can also directly measure the resistance

[5]:
voltage = keithley.sense.function("resistance")
with keithley.output_enabled.set_to(True):
    resistance = keithley.sense.resistance()

print("Measured resistance: ",  resistance)
Measured resistance:  996.9845

In ‘current’ mode, we cannot set/get a voltage and vice versa

[6]:
try:
    keithley.source.voltage()
except AttributeError:
    function = keithley.source.function()
    print(f"In the '{function}' source mode the source module does not have a 'voltage' attribute")
In the 'current' source mode the source module does not have a 'voltage' attribute

This goes for both the source and sense subsystems

[7]:
try:
    keithley.sense.current()
except AttributeError:
    function = keithley.sense.function()
    print(f"In the '{function}' sense mode the sense module does not have a 'current' attribute")
In the 'resistance' sense mode the sense module does not have a 'current' attribute

We also need to make sure the output is enabled for use the measure (or ‘sense’) a current or voltage

Sweeping measurements

The instrument has a build-in sweep system. For the first measurement, we drive a current through the resistor and measure the voltage accross it.

[8]:
initialise_database()
experiment = new_experiment(name='Keithley_2450_example', sample_name="no sample")

Sweep the current from 0 to 1uA in 10 steps and measure voltage

[9]:
keithley.sense.function("voltage")
keithley.sense.auto_range(True)

keithley.source.function("current")
keithley.source.auto_range(True)
keithley.source.limit(2)
keithley.source.sweep_setup(0, 1E-6, 10)

keithley.sense.four_wire_measurement(True)
[10]:
meas = Measurement(exp=experiment)
meas.register_parameter(keithley.sense.sweep)

with meas.run() as datasaver:
    datasaver.add_result((keithley.source.sweep_axis, keithley.source.sweep_axis()),
                         (keithley.sense.sweep, keithley.sense.sweep()))

    dataid = datasaver.run_id

plot_dataset(datasaver.dataset)
Starting experimental run with id: 188.
[10]:
([<matplotlib.axes._subplots.AxesSubplot at 0x1ce9f5622c8>], [None])
../../_images/examples_driver_examples_Qcodes_example_with_keithley_2450_19_2.png

Sweep the voltage from 10mV in 10 steps and measure current

[11]:
keithley.sense.function("current")
keithley.sense.range(1E-5)
keithley.sense.four_wire_measurement(True)

keithley.source.function("voltage")
keithley.source.range(0.2)
keithley.source.sweep_setup(0, 0.01, 10)
[12]:
meas = Measurement(exp=experiment)
meas.register_parameter(keithley.sense.sweep)

with meas.run() as datasaver:
    datasaver.add_result((keithley.source.sweep_axis, keithley.source.sweep_axis()),
                         (keithley.sense.sweep, keithley.sense.sweep()))

    dataid = datasaver.run_id

plot_dataset(datasaver.dataset)
Starting experimental run with id: 189.
[12]:
([<matplotlib.axes._subplots.AxesSubplot at 0x1cea1677a88>], [None])
../../_images/examples_driver_examples_Qcodes_example_with_keithley_2450_22_2.png

To perform measurements with user-defined reading buffer

[13]:
keithley.reset()

By default, when performing measurement, the value is stored in the default buffer “defbuffer1”.

[14]:
keithley.sense_function('current')
with keithley.output_enabled.set_to(True):
    data_point01 = keithley.sense.current()
    data_point02 = keithley.sense.current()
    data_point03 = keithley.sense.current()
print(f"The current measurements are {data_point01}, {data_point02}, {data_point03} A.")
The current measurements are -1.608374e-08, -1.818495e-08, -1.950789e-08 A.

We can use a user-defined reading buffer for measurement. The following example is to do a sweep measurement, and read extra data elements in addition to the measurement value with the new method “elements”.

[15]:
buffer_name = 'userbuff1'
buffer_size = 100
with keithley.buffer(buffer_name, buffer_size) as buff1:
    buff1.elements(['time', 'date', 'measurement', 'source_value_formatted'])
    keithley.source.sweep_setup(0, 1E-6, 10, buffer_name=buff1.buffer_name)
    data = keithley.sense.sweep()
    all_data = keithley.sense.sweep.get_selected()

“data” includes the numerical value of the measurement:

[16]:
data
[16]:
array([-1.772451e-08, -2.088747e-08, -2.159876e-08, -2.161518e-08,
       -2.155486e-08, -2.154403e-08, -2.157010e-08, -2.107971e-08,
       -2.079369e-08, -2.079450e-08])

“all_data” includes extra information specified by the “elements()” method:

[17]:
all_data
[17]:
['14:14:29',
 '06/10/2020',
 '-1.772451E-08',
 '+00.00507 mV',
 '14:14:29',
 '06/10/2020',
 '-2.088747E-08',
 '+00.00200 mV',
 '14:14:29',
 '06/10/2020',
 '-2.159876E-08',
 '+00.00116 mV',
 '14:14:30',
 '06/10/2020',
 '-2.161518E-08',
 '+00.00187 mV',
 '14:14:30',
 '06/10/2020',
 '-2.155486E-08',
 '+00.00098 mV',
 '14:14:30',
 '06/10/2020',
 '-2.154403E-08',
 '+00.00116 mV',
 '14:14:31',
 '06/10/2020',
 '-2.157010E-08',
 '+00.00190 mV',
 '14:14:31',
 '06/10/2020',
 '-2.107971E-08',
 '+00.00209 mV',
 '14:14:31',
 '06/10/2020',
 '-2.079369E-08',
 '+00.00269 mV',
 '14:14:32',
 '06/10/2020',
 '-2.079450E-08',
 '+00.00273 mV']

By using “with … as …:” to perform the measurement, there user-defined buffer is automatically removed after the measurement. This is the recommanded way to use the user-defined buffer.

[18]:
try:
    buff1.size()
except VisaIOError as err:
    print(err)
('VI_ERROR_TMO (-1073807339): Timeout expired before operation completed.', 'asking ":TRACe:POINts? \'userbuff1\'" to <Keithley2450: keithley>', 'getting keithley_userbuff1_size')

And we can still access the data in the default buffer:

[19]:
buffer_name = 'defbuffer1'
buffer = keithley.buffer(buffer_name)
[20]:
print(f"There are {buffer.number_of_readings()} data points in '{buffer_name}'.")
There are 3 data points in 'defbuffer1'.

The last reading is:

[21]:
buffer.get_last_reading()
[21]:
'-1.950789E-08'

We can get all 3 previously measured data as following:

[22]:
buffer.get_data(1,3)
[22]:
[-1.608374e-08, -1.818495e-08, -1.950789e-08]

And the original infomration are still there:

[23]:
buffer.elements(["time", "measurement_formatted"])
buffer.get_data(1, 3)
[23]:
['14:14:28',
 '-016.084 nA',
 '14:14:28',
 '-018.185 nA',
 '14:14:28',
 '-019.508 nA']

This is all the available elements, if none is requested, “measurement” will be used:

[24]:
buffer.available_elements
[24]:
{'date',
 'fractional_seconds',
 'measurement',
 'measurement_formatted',
 'measurement_status',
 'measurement_unit',
 'relative_time',
 'seconds',
 'source_value',
 'source_value_formatted',
 'source_value_status',
 'source_value_unit',
 'time',
 'timestamp'}

If the user gives a incorrect element name, error message will show which ones are correct:

[25]:
try:
    buffer.elements(['dates'])
except ValueError as err:
    print(err)

("'dates' is not in {'measurement', 'measurement_status', 'source_value_formatted', 'seconds', 'source_value_unit', 'timestamp', 'source_value_status', 'measurement_formatted', 'relative_time', 'source_value', 'time', 'fractional_seconds', 'date', 'measurement_unit'}; ", "setting keithley_defbuffer1_elements to ['dates']")
[ ]: