Keysight Instruments
How to control Keysight oscilloscopes, DMMs, and signal generators with PyVISA. Connection snippets, examples, and vendor quirks.
Control Keysight oscilloscopes, DMMs, and signal generators with PyVISA. One connect snippet, one example per instrument type.
Supported Models
| Family | Models | Interface |
|---|---|---|
| DMMs | 34461A, 34470A (Truevolt), 34401A (legacy) | USB, LAN |
| Oscilloscopes | InfiniiVision 1000X/2000X/3000X/4000X, Infiniium 90000X/Z-Series | USB, LAN |
| Signal generators | 33500B (function/arb), E8257D/E8267D (PSG), N5182A (MXG) | USB, LAN, GPIB |
| Network analyzers | E5071C, E5063A (ENA), N9918A (FieldFox), P9372A | LAN, USB |
| Power supplies | E36300 (triple), N6700/N6900 (modular), U8000 series | USB, LAN |
Connect to a Keysight Instrument
Keysight's USB vendor ID is 0x2A8D. You can filter list_resources() to find them.
import pyvisa
rm = pyvisa.ResourceManager()
# Find all Keysight USB instruments
resources = rm.list_resources()
keysight = [r for r in resources if "0x2A8D" in r]
for r in keysight:
inst = rm.open_resource(r)
print(f"{r}: {inst.query('*IDN?').strip()}")
inst.close()For LAN connections:
import pyvisa
rm = pyvisa.ResourceManager()
# Raw socket (fastest, most Keysight instruments listen on 5025)
inst = rm.open_resource("TCPIP0::192.168.1.100::5025::SOCKET")
inst.read_termination = '\n'
inst.write_termination = '\n'
# VXI-11 (more compatible, auto-discovers termination)
inst = rm.open_resource("TCPIP0::192.168.1.100::inst0::INSTR")Track test results across instruments
TofuPilot records measurements from your Keysight instruments, tracks pass/fail rates per serial number, and generates compliance reports. Free to start.
DMM (34461A / 34470A)
High-accuracy DC voltage, then a fast burst read.
import pyvisa
import time
rm = pyvisa.ResourceManager()
dmm = rm.open_resource("USB0::0x2A8D::0x0101::MY53220001::INSTR")
dmm.timeout = 10000
dmm.write("*RST")
# High-accuracy single reading
dmm.write("CONF:VOLT:DC")
dmm.write("VOLT:DC:RANG 10")
dmm.write("VOLT:DC:NPLC 100")
dmm.write("VOLT:DC:ZERO:AUTO ON")
voltage = float(dmm.query("READ?"))
print(f"High-accuracy: {voltage:.8f} V")
# Fast burst: 100 readings at max speed
dmm.write("VOLT:DC:NPLC 0.02")
dmm.write("VOLT:DC:ZERO:AUTO OFF")
dmm.write("SAMP:COUN 100")
start = time.time()
response = dmm.query("READ?")
elapsed = time.time() - start
values = [float(x) for x in response.split(",")]
print(f"{len(values)} readings in {elapsed:.2f} s")
dmm.close()
rm.close()Oscilloscope (InfiniiVision)
Capture a waveform and read automated measurements.
import pyvisa
import numpy as np
rm = pyvisa.ResourceManager()
scope = rm.open_resource("USB0::0x2A8D::0x0001::MY52345678::INSTR")
scope.timeout = 30000
scope.chunk_size = 1024 * 1024
scope.write("*RST")
scope.write(":CHAN1:DISP ON")
scope.write(":CHAN1:SCAL 1.0") # 1 V/div
scope.write(":TIM:SCAL 1E-3") # 1 ms/div
scope.write(":TRIG:EDGE:SOUR CHAN1")
scope.write(":TRIG:EDGE:LEV 0.5")
# Single acquisition
scope.write(":SING")
scope.query("*OPC?")
# Automated measurements
vpp = float(scope.query(":MEAS:VPP? CHAN1"))
freq = float(scope.query(":MEAS:FREQ? CHAN1"))
print(f"Vpp: {vpp:.3f} V, Freq: {freq:.1f} Hz")
# Download waveform data
scope.write(":WAV:FORM BYTE")
scope.write(":WAV:SOUR CHAN1")
scope.write(":WAV:POIN 1000")
preamble = scope.query(":WAV:PRE?").split(",")
y_inc = float(preamble[7])
y_orig = float(preamble[8])
y_ref = float(preamble[9])
raw = scope.query_binary_values(":WAV:DATA?", datatype='B', container=np.array)
voltage = (raw - y_ref) * y_inc + y_orig
scope.close()
rm.close()Signal Generator (33500B)
Generate a sine wave and a frequency sweep.
import pyvisa
rm = pyvisa.ResourceManager()
gen = rm.open_resource("USB0::0x2A8D::0x0001::MY52345678::INSTR")
gen.timeout = 10000
gen.write("*RST")
# 1 kHz sine, 2 Vpp
gen.write("SOUR1:FUNC SIN")
gen.write("SOUR1:FREQ 1000")
gen.write("SOUR1:VOLT 2.0")
gen.write("OUTP1 ON")
# Frequency sweep: 100 Hz to 10 kHz over 10 seconds
gen.write("SOUR1:FREQ:START 100")
gen.write("SOUR1:FREQ:STOP 10000")
gen.write("SOUR1:SWE:TIME 10")
gen.write("SOUR1:SWE:STAT ON")
gen.write("OUTP1 ON")
print("Sweep running")
# Clean up
# gen.write("OUTP1 OFF")
# gen.close()
# rm.close()Keysight Quirks
| Quirk | Details | Workaround |
|---|---|---|
| Slow display updates | GUI rendering slows SCPI throughput | SYST:DISP:UPD OFF during fast acquisition |
| LAN socket needs termination | Raw socket (port 5025) doesn't auto-detect termination | Set read_termination = '\n' and write_termination = '\n' |
| Legacy Agilent IDN | Older instruments return "Agilent Technologies" in *IDN? | Match both "Keysight" and "Agilent" in detection code |
| Long self-test | *TST? can take 30+ seconds | Set timeout = 60000 before calling |
| Output protection trip | Overload triggers protection, silently disables output | Check OUTP:PROT:TRIP? after enabling output |
| Binary byte order | Default is big-endian on some models | Verify with FORM:BORD?, set to NORM or SWAP as needed |
| Chunk size for waveforms | Default 20 KB chunk size is too small for long records | Set inst.chunk_size = 1024 * 1024 |