This page was generated from docs/examples/driver_examples/Qcodes example with Keysight 344xxA.ipynb. Interactive online version: .
QCoDeS Example with Keysight 344xxA¶
344xxA
models of Keysight digital multimeters have similar QCoDeS drivers. In this tutorial, Keysight_34465A
is chosen for showcasing the usage of the instrument.
Note however that not every feature/parameter is available on all 344xxA
models. This, when possible, is reflected in the instantiated driver object. Also note that models like 34465A
have options (like DIG
and MEM
) that can either be enabled or disabled on a particular instrument; this also has impact on availability of some features/parameters and/or their settings. In general, refer to the instrument’s manual for detailed information.
NOTE: Beginning with firmware revision 3.0, the digitizing and advanced triggering option, referred to as “DIG”, for models 34465A-DIG/34470A-DIG, is now standard.
The driver does not cover all the features of the instrument. At present, the driver only supports being used to measure DC Voltage
[1]:
import time
import numpy
from qcodes.dataset import Measurement, plot_dataset
from qcodes.instrument_drivers.Keysight import Keysight34465A
[2]:
dmm = Keysight34465A("dmm", "TCPIP0::172.20.2.182::inst0::INSTR")
Connected to: Keysight Technologies 34465A (serial:MY54505281, firmware:A.03.00-02.40-03.00-00.52-02-01) in 0.61s
[3]:
dmm.reset()
Parameters and methods overview¶
Here is an overview (not exhaustive) of the parameters and methods that are available in the driver.
The driver is not only comprised of root-level parameters and methods but also contains submodules which logically group some functionality.
Measurements
dmm.init_measurement()
dmm.fetch()
dmm.read()
dmm.volt
- immediately measure one (the present) voltage value
Time trace measurements
dmm.timetrace
- covered in more detail belowdmm.time_axis
dmm.timetrace_dt
dmm.timetrace_npts
Range settings
dmm.range
dmm.autorange
dmm.autorange_once()
Triggering
dmm.trigger.source
dmm.trigger.delay
dmm.trigger.auto_delay_enabled
dmm.trigger.count
dmm.trigger.slope
dmm.trigger.level
dmm.trigger.force()
Sample settings
dmm.sample.count
dmm.sample.source
dmm.sample.timer
dmm.sample.pretrigger_count
Display control
dmm.display.text
dmm.display.clear()
dmm.display.enabled
Measurement type
dmm.sense_function
Measurement accuracy (NB: DC Voltage mode only)
dmm.NPLC
dmm.resolution
dmm.line_frequency
dmm.aperture_mode
dmm.aperture_time
dmm.autozero
As an extra, let’s print the readable snapshot of the instrument.
[4]:
dmm.print_readable_snapshot(update=True)
dmm:
parameter value
--------------------------------------------------------------------------------
IDN : {'vendor': 'Keysight Technologies', 'model': '34465A', 'seri...
NPLC : 10 (NPLC)
aperture_mode : OFF
aperture_time : 0.1
autorange : ON
autozero : ON
line_frequency : 50 (Hz)
range : 0.1
resolution : 1e-08 (V)
sense_function : DC Voltage
time_axis : Not available (s)
timeout : 5 (s)
timetrace : Not available
timetrace_dt : 0.1 (s)
timetrace_npts : 500
volt : 2.8814e-05 (V)
dmm_display:
parameter value
--------------------------------------------------------------------------------
enabled : True
text :
dmm_trigger:
parameter value
--------------------------------------------------------------------------------
auto_delay_enabled : True
count : 1
delay : 0.00016 (s)
level : 0 (V)
slope : NEG
source : IMM
dmm_sample:
parameter value
--------------------------------------------------------------------------------
count : 1
pretrigger_count : 0
source : IMM
timer : 1 (s)
timer_minimum : 0.43913 (s)
Single value reading¶
If one simpy wants to measure a single voltage value right now, the convenient volt
parameter can be used. This parameter will always return a voltage reading, even if the instrument is set up to measure something else than voltage. The instrument state is left untouched by getting this parameter.
This is a convenience parameter that does not utilize the full power of the instrument. In the next two sections, we will present more prowerful and robust ways of performing measurements.
[5]:
dmm.volt()
[5]:
-7.49454636e-05
Time trace type measurements¶
For the commonly occuring case were one would like to measure N voltage points equidistantly spaced in time, the Keysight DMM driver offers the convenient timetrace
parameter. It comes with three associated (helper) parameters:
timetrace_dt
- the time spacing between the acquired pointstimetrace_npts
- the number of pointstime_axis
- the corresponding time axis (np.array, starts at 0)timetrace
- the array of voltage values
Note that changing timetrace_dt
and timetrace_npts
does not change any corresponding setting on the instrument before timetrace.get
is called. Once that happens, the state of the instrument is temporarily switched into one compatible with performing a time trace measurement. This specifically means that we set
trigger.count
to 1trigger.source
to “BUS” (internal trigger - no other trigger can be used)sample.timer
totimetrace_dt
sample.count
totimetrace_npts
After the acquisition has completed, the previous instrument settings are restored. This behaviour guarantees that calling timetrace.get
always works, irrespective of instrument state. The only exception is if the specified timetrace_dt
can not be realized with the present dmm.NPLC
and/or dmm.aperture_time
settings. If that is the case, the timetrace.get
method will raise a RuntimeError
with an instructive error message. The user may manually compare the value of
sample.timer_minimum
to the value of timetrace_dt
.
The usage is straightforward.
[6]:
meas = Measurement()
meas.register_parameter(dmm.timetrace)
dmm.NPLC(0.006)
dmm.timetrace_dt(0.02)
dmm.timetrace_npts(500)
print(f"Minimal allowable dt: {dmm.sample.timer_minimum()} s")
with meas.run() as datasaver:
datasaver.add_result(
(dmm.timetrace, dmm.timetrace()), (dmm.time_axis, dmm.time_axis())
)
time_trace_ds = datasaver.dataset
Minimal allowable dt: 0.015525 s
Starting experimental run with id: 381
[7]:
axs, cbs = plot_dataset(time_trace_ds)
General guide: Multivalue triggered measurements¶
NOTE: Refer to the instrument manual for more information on how to perform measurements with the instrument; here, only the most basic and frequently used ones are demonstated.
Measurements with the instrument are performed in the following way: the instrument’s settings are set for a particular kind of measurement, then the measurement is started/initialized, then after all the data has been acquired, it is retrieved from the instrument. Below is an example of such a measurement.
Use range
, autorange
parameters or autorange_once
method to set the measurement range. Disabling autorange is recommended by the instrument’s manual for speeding up the measurement.
[8]:
dmm.autorange_once()
In order to set up the accuracy of the measurements and related settings, set up NPLC
or aperture_*
parameters (if available).
[9]:
dmm.aperture_mode("ON")
dmm.aperture_time(2e-5)
Set up triggering mechanism. Note that trigger settings and methods are inside trigger
submodule of the instrument driver. Here, we will use immediate triggering (the measurement is triggered uppon measurement initialization, that is when init_measurement
is called) with 1 trigger without any delays. Consulm the instrument’s manual for more information on various triggering options.
[10]:
dmm.trigger.source("IMM")
dmm.trigger.count(1)
dmm.trigger.delay(0.0)
Set up sampling settings. Note that sampling parameters and method are inside sample
submodule of the instrument driver. Here, we set to measure 15 samples.
[11]:
dmm.sample.count(15)
dmm.sample.pretrigger_count(0)
We are also going to set the sample source to timer (not avaliable in all models) so that the instrument ensures that the samples are taken with fixed periods between them. The timer
parameter allows to set the value of that fixed period. For simplicity, we are going to let the instrument deduce the minimum value of it according to the current instrument configuration (!) and set it.
[12]:
dmm.sample.source("TIM")
dmm.sample.timer("MIN")
It turns out that commands are executed faster when the display of the instrument is disabled or is displaying text. One of the further section expands on it. Here, we will just set the display to some text.
[13]:
dmm.display.text("Example with 15 samples")
In order to initiate the measurement, call init_measurement
method of the driver. In the case of this example, the instrument will get into “wait-for-trigger” mode but because the trigger source is “immediate”, the instrument will immediately start measuring the 15 samples.
[14]:
dmm.init_measurement()
The instrument is going to measure 15 samples and save them to its memory. Once the measurement is completed, we can call fetch
method of the driver to retreive the acquired data.
While the measurement is going, there are two things we can do. One is to sleep
until the end of the measurement, and then call fetch
. The other one is to call fetch
immediately after the measurement has been initiated - this way the instrument will return the acquired data right when the measurement is finished. This sounds pretty useful, however there are two considerations to keep in mind: the instrument manual hints that calling fetching immediately after initiation may be slower
than waiting for the measurement to complete; if the measurement takes longer than the VISA command timeout, the code may raise a VISA timeout exception while the measurement is properly running (e.g. waiting for a trigger). To overcome the latter problem, one can temporarily change the VISA timeout value during the data fetching:
new_timeout = old_timeout + n_samples * time_per_sample
# where, n_samples == dmm.sample.count(),
# and time_per_sample == dmm.sample.timer()
with dmm.timeout.set_to(new_timeout):
data = dmm.fetch()
Assuming that we’ve just slept or waited enough for the measurement to complete, let’s fetch
the data from the instrument. Note that due to the nature of the fetch
command of the instrument, one can fetch the same measured data more than once (until, for example, a new measurement has been initiated; refer to the instrument’s manual for more information on this).
[15]:
data = dmm.fetch()
data
[15]:
array([ 0.0092552 , 0.00434024, -0.00366329, -0.00219105, 0.00356022,
0.01169778, -0.00892942, 0.00458304, -0.00102581, -0.00295006,
-0.00042901, -0.0006983 , -0.02305963, 0.00703878, 0.00509042])
Note that there is also a read
method. It’s difference from fetch
is that it also initiates the new measurement. Using read
might be convenient for some cases while init_measurement
+ fetch
definitely allow for more control.
Since the measurement is finished, let’s bring back the display to life.
[16]:
dmm.display.clear()
If needed, it is straightforward to calculate a vector of times when the acquired data points were measured; for example, like this:
[17]:
n = dmm.sample.count()
t = dmm.sample.timer()
setpoints = numpy.linspace(0, n * t, n)
setpoints # in seconds
[17]:
array([0. , 0.00063, 0.00126, 0.00189, 0.00252, 0.00315, 0.00378,
0.00441, 0.00504, 0.00567, 0.0063 , 0.00693, 0.00756, 0.00819,
0.00882])
Note that for this simple type of measurement with measurement times being equidistantly spaced, the timetrace
parameter is preferred.
Special values of some parameters¶
Some parameters can be set to special values like MIN
/MAX
/DEF
which usually mean minimum/maximum/default, respectively.
In order to obtain the actual value of the parameter that gets set when setting it to one of these special values, just call the get method of the parameter.
[18]:
# Find out what the maximum value of `sample_timer` can be
dmm.sample.timer("MAX")
dmm.sample.timer()
[18]:
3600.0
[19]:
# Find out what the default value of `sample_timer` is
dmm.sample.timer("DEF")
dmm.sample.timer()
[19]:
1.0
[20]:
# Find out what the recommended minumum value of `sample_timer` is
dmm.sample.timer("MIN")
dmm.sample.timer()
[20]:
0.000588
[21]:
# Alternatively, if available, use a conveniently implemented
# get-only parameter to find out the actual value,
# for example, for MIN value of `sample_timer` there is such
# a convenient get-only parameter:
dmm.sample.timer_minimum()
[21]:
0.000588
Display state impacts command execution speed¶
To improve the execution speed of commands on the instrument, the user may disable the display’s updates. When the display is not updating, it may show a static message of up to 40 characters. The timetrace
parameter (see above) makes use of this functionality to execute faster and at the same time display a message that a measurement is in progress.
The driver provides display
submodule with text
parameter that displays a given text on the insrturment, and a clear
method that clears the text from display.
The driver’s display
submodule also provides enabled
parameter. When it is set to False
, the state of the display is such that it does not show anything. Note, however, that displaying text is still possible when the display.enabled
is False
(when display.enabled
is False
, display.clear
clears the text from the screen but does not enable it).
[22]:
# Displays the text
dmm.display.text("Hello, World!")
[23]:
# Returns display to its normal state
dmm.display.clear()
[24]:
# Note that a call to `display_clear` also updates
# the value of the `display_text` parameter:
assert dmm.display.text() == ""
[25]:
# Display can also be cleared by setting
# `display_text` to an empty string
dmm.display.text("some text") # Displays some text
time.sleep(0.5)
dmm.display.text("") # Returns display to its normal state
[26]:
# Disables the display, which makes it turn black
dmm.display.enabled(False)
[27]:
# Shows some text on a disabled display
dmm.display.text("I'm disabled but still showing text")
[28]:
# Enabling display in this state
# won't change what's being displayed
dmm.display.enabled(True)
[29]:
# ... but since the display is now enabled,
# clearing the display will not only remove the text
# but also show all the normal display indicators.
dmm.display.clear()
Error handling¶
Use the following methods to read the error queue of the instrument. The instrument has an error queue of length up to 20 messages. The queue message retrieval is first-in-first-out.
[30]:
# Retrieve the first (i.e. oldest) error message
# in the queue (and thereby remove from the queue)
dmm.error()
[30]:
(0, 'No error')
[31]:
# The entire queue can be flushed out
# using `flush_error_queue` method.
# Printing the messages in enabled by default
# and can be disables with the `verbose` kwarg.
# generate a few errors
for _ in range(3):
dmm.write("produce an error!")
[32]:
dmm.flush_error_queue(verbose=True)
-113 Undefined header
-113 Undefined header
-113 Undefined header
0 No error
[ ]: