This page was generated from docs/examples/driver_examples/Qcodes example with keithley 2450.ipynb. Interactive online version: .
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])
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])
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']")
[ ]: