import qcodes as qc
from qcodes.dataset import do0d, initialise_database, new_experiment, plot_dataset
from qcodes.instrument_drivers.Keithley import Keithley2614B
# Create a station to hold all the instruments
station = qc.Station()
# instantiate the Keithley and add it to the station
keith = Keithley2614B('keithley', 'USB0::0x05E6::0x2614::4305420::INSTR')
station.add_component(keith)
Connected to: Keithley Instruments Inc. 2614B (serial:4305420, firmware:3.2.2) in 0.77s
'keithley'
The Keithley 2600 has two channels, here called smua
and smub
in agreement with the instrument manual.
The two channels are basically two separate instruments with different integration times (nplc
), operation modes (mode
) etc.
# Get an overview of the settings
#
# You will notice that the two channels have identical parameters but
# potentially different values for them
#
keith.print_readable_snapshot()
keithley: parameter value -------------------------------------------------------------------------------- IDN : {'vendor': 'Keithley Instruments Inc.', 'model': '2614B', '... display_settext : None timeout : 5 (s) keithley_smua: parameter value -------------------------------------------------------------------------------- curr : 8.7023e-07 (A) fastsweep : Not available limiti : 0.1 (A) limitv : 20 (V) linefreq : 50 (Hz) measure_autorange_i_enabled : False measure_autorange_v_enabled : True measurerange_i : 0.1 (A) measurerange_v : 200 (V) mode : current nplc : 0.05 output : True res : 2.2985e+07 (Ohm) source_autorange_i_enabled : True source_autorange_v_enabled : False sourcerange_i : 0.1 (A) sourcerange_v : 20 (V) time_axis : Not available (s) timetrace : Not available (A) timetrace_dt : 0.001 (s) timetrace_mode : current timetrace_npts : 500 volt : 20.002 (V) keithley_smub: parameter value -------------------------------------------------------------------------------- curr : -1.8239e-12 (A) fastsweep : Not available limiti : 0.1 (A) limitv : 20 (V) linefreq : 50 (Hz) measure_autorange_i_enabled : True measure_autorange_v_enabled : True measurerange_i : 1e-07 (A) measurerange_v : 0.2 (V) mode : voltage nplc : 1 output : False res : 3.5934e+07 (Ohm) source_autorange_i_enabled : True source_autorange_v_enabled : True sourcerange_i : 1e-07 (A) sourcerange_v : 0.2 (V) time_axis : Not available (s) timetrace : Not available (A) timetrace_dt : 0.001 (s) timetrace_mode : current timetrace_npts : 500 volt : -6.3276e-05 (V)
Each channel operates in either voltage
or current
mode. The mode controls the source behaviour of the instrument, i.e. voltage
mode corresponds to an amp-meter (voltage source, current meter) and vice versa.
# Let's set up a single-shot current measurement
# on channel a
keith.smua.mode('voltage')
keith.smua.nplc(0.05) # 0.05 Power Line Cycles per measurement. At 50 Hz, this corresponds to 1 ms
keith.smua.sourcerange_v(20)
keith.smua.measurerange_i(0.1)
#
keith.smua.volt(1) # set the source to output 1 V
keith.smua.output('on') # turn output on
curr = keith.smua.curr()
keith.smua.output('off')
print(f'Measured one current value: {curr} A')
Measured one current value: -3.40939e-06 A
Onboard the Keithley 2600 sits a small computer that can interpret Lua
scripts. This can be used to make fast IV- or VI-curves and is supported by the QCoDeS driver. To make IV- or VI-curves the driver has the ArrayParameter fastsweep, which have 3 modes: 'IV','VI' and 'VIfourprobe'. The Modes 'IV' and 'VI'are two probe measurements, while the mode 'VIfourprobe' makes a four probe measuremnt.
Let's make a fast IV curve by sweeping the voltage from 1 V to 2 V in 500 steps (when making this notebook, nothing was connected to the instrument, so we just measure noise)
First we need to prepare the sweep by spesifyring the start, stop, number of points and the mode
keith.smua.fastsweep.prepareSweep(1, 2, 500, mode='IV')
When the sweep parameters are set, we can use a "do0d" to preform the sweep
do0d(keith.smua.fastsweep, do_plot = True)
Starting experimental run with id: 154.
(results #154@C:\Users\Farzad\experiments.db ------------------------------------------- keithley_smua_Voltage - array keithley_smua_iv_sweep - array, [<AxesSubplot:title={'center':'Run #154, Experiment tutorial_exp (no sample)'}, xlabel='keithley_smua_Voltage (V)', ylabel='current (μA)'>], [None])
We can likewise do a VI two- or four-probe measurement
keith.smua.fastsweep.prepareSweep(0.001, 0.1, 500, mode='VI')
do0d(keith.smua.fastsweep, do_plot = True)
Starting experimental run with id: 155.
(results #155@C:\Users\Farzad\experiments.db ------------------------------------------- keithley_smua_Current - array keithley_smua_vi_sweep - array, [<AxesSubplot:title={'center':'Run #155, Experiment tutorial_exp (no sample)'}, xlabel='keithley_smua_Current (mA)', ylabel='voltage (V)'>], [None])
keith.smua.fastsweep.prepareSweep(0.001, 0.1, 500, mode='VIfourprobe')
do0d(keith.smua.fastsweep, do_plot = True)
Starting experimental run with id: 156.
(results #156@C:\Users\Farzad\experiments.db ------------------------------------------- keithley_smua_Current - array keithley_smua_vi_sweep_four_probe - array, [<AxesSubplot:title={'center':'Run #156, Experiment tutorial_exp (no sample)'}, xlabel='keithley_smua_Current (mA)', ylabel='voltage (V)'>], [None])
do0d(keith.smua.fastsweep, do_plot = True)
# Finally, tear down the instrument
keith.close()
We can measure current or voltage as a function of time, as well. Let us consider the case in which we would like to have the time trace of current. We, then, first set our trace mode accordingly
keith.smua.timetrace_mode('current')
The latter should not be confused with the channel mode. Next, we register our parameter
timemeas = qc.Measurement()
timemeas.register_parameter(keith.smua.timetrace)
<qcodes.dataset.measurements.Measurement at 0x1cb25ae9eb0>
The total time interval is returned by time_axis
method in accordance with the integration time dt
and the total number of points npts
with default values of 1 ms and 500, respectively. Specifically, the time trace will be obtained for an interval of [0, dt*npts]
. Thus, for the default values, we shall have a time trace of current for 500 ms
calculated at 500 steps.
keith.smua.timetrace_dt()
0.001
keith.smua.timetrace_npts()
500
initialise_database()
new_experiment(name='tutorial_exp', sample_name="no sample")
with timemeas.run() as datasaver:
somenumbers = keith.smua.timetrace.get()
datasaver.add_result((keith.smua.timetrace, somenumbers),
(keith.smua.time_axis, keith.smua.time_axis.get()))
data = datasaver.dataset
plot_dataset(data)
Starting experimental run with id: 157.
([<AxesSubplot:title={'center':'Run #157, Experiment tutorial_exp (no sample)'}, xlabel='Time (ms)', ylabel='Current (μA)'>], [None])
Let us get another trace for 2ms integration time with 600 steps
keith.smua.timetrace_dt(0.002)
keith.smua.timetrace_npts(600)
with timemeas.run() as datasaver:
somenumbers = keith.smua.timetrace.get()
datasaver.add_result((keith.smua.timetrace, somenumbers),
(keith.smua.time_axis, keith.smua.time_axis.get()))
data = datasaver.dataset
plot_dataset(data)
Starting experimental run with id: 158.
([<AxesSubplot:title={'center':'Run #158, Experiment tutorial_exp (no sample)'}, xlabel='Time (s)', ylabel='Current (μA)'>], [None])
Similarly, we can get the time trace for voltage via changing the mode
keith.smua.timetrace_mode('voltage')
In this case, one should re-register the time trace parameter to have the correct units and labels.
Sometimes it happens that Keithley SMU measures a different value from what was assigned as the setpoint; e.g. when setting the voltage to -2 mV
, the SMU would measure an output of -1.85 mV
. This likely calls for recalibration of the Keithley SMU against e.g. a calibrated DMM. After this recalibration the measured value matches the setpoint.
Below is a description of using a calibration routine that is based off the information from the instrument manual about performing the calibration.
To run this routine, connect the Keithley SMU HI voltage output to the DMM voltage HI input, and the SMU LO output to the DMM voltage LO input (note that this is a different setup as indicated in the Keithley manual).
#%% Imports
# The calibration functions and utils
from qcodes.calibrations.keithley import (
calibrate_keithley_smu_v,
calibrate_keithley_smu_v_single,
save_calibration,
setup_dmm,
)
# QCoDeS functions for running a measurement
from qcodes.dataset import do1d, load_or_create_experiment
# Keithley SMU driver
from qcodes.instrument_drivers.Keithley import Keithley2614B
# Keysight DMM driver
from qcodes.instrument_drivers.Keysight import Keysight34470A
#%% Load the SMU instrument
smu = Keithley2614B("smu", "USB0::0x05E6::0x2614::4347170::INSTR")
#%% Load DMM instrument
dmm = Keysight34470A("dmm", "TCPIP0::10.164.54.211::inst0::INSTR")
#%% Calibrate both channels
calibrate_keithley_smu_v(smu, dmm)
for smun in smu.channels:
smun.volt(0)
#%% Calibrate single channel in specific range, e.g. SMU A
smun = smu.smua # e.g. SMU A
setup_dmm(dmm)
dmm.range(1.0)
calibrate_keithley_smu_v_single(smu, smun.short_name, dmm.volt, "200e-3")
smun.volt(0)
#%% Check calibration by measuring voltage with DMM while sweeping with SMU
smun = smu.smua # e.g. SMU A
smun.sourcerange_v(200e-3)
smun.measurerange_v(200e-3)
smun.volt(0)
smun.output("on")
dmm.aperture_time(0.1)
dmm.range(1)
dmm.autozero("OFF")
dmm.autorange("OFF")
load_or_create_experiment(
"MeasurementSetupDebug", "no_sample", load_last_duplicate=True
)
do1d(
smun.volt,
-0.1e-3,
0.1e-3,
101,
0.3,
dmm.volt,
smun.curr,
measurement_name=f"{smun.full_name} calibration check",
)
smun.volt(0)
smun.output("off")
#%% Save calibrations
save_calibration(smu)