This code example provides meaningful output (i.e. a scaled waveform plot) as simply as possible without bad practices. It is useful for testing the installation and configuration of a Python environment for development of remote instrument control code. It demonstrates best practice event status checking, command synchronization, waveform acquisition, waveform data transfer, waveform scaling, and waveform plotting using Python 3.5 and PyVISA v1.8 and Matplotlib v1.5.1. Default setup and auto-set are compromises for convenience. Because the exercised features are fairly universal to Tektronix oscilloscopes, this example should work across a wide range of models without any modification.
For TDS2k, TPS2k, and TBS1k series oscilloscopes, see Python: TBS Simple Plot
Code: Select all
# mdo simple plot
# python v3.8.3, pyvisa v1.10.1
# should work with MSO70k, DPO7k, MSO5k, MDO4k, MDO3k, and MSO2k series
# 5/6 Series MSO
# incompatible with TDS2k and TBS1k series (see tbs simple plot)
import time # std module
import visa # http://github.com/hgrecco/pyvisa
import matplotlib.pyplot as plt # http://matplotlib.org/
import numpy as np # http://www.numpy.org/
visa_address = 'tcpip::10.2.1.130::instr'
rm = visa.ResourceManager()
scope = rm.open_resource(visa_address)
scope.timeout = 10000 # ms
scope.encoding = 'latin_1'
scope.read_termination = '\n'
scope.write_termination = None
scope.write('*cls') # clear ESR
scope.write('header OFF') # disable attribute echo in replies
print(scope.query('*idn?'))
# prompt
input("""
ACTION:
Connect probe to oscilloscope Channel 1 and the probe compensation signal.
Press Enter to continue...
""")
# default setup
scope.write('*rst')
t1 = time.perf_counter()
r = scope.query('*opc?') # sync
t2 = time.perf_counter()
print('reset time: {}'.format(t2 - t1))
# autoset
scope.write('autoset EXECUTE')
t3 = time.perf_counter()
r = scope.query('*opc?')
t4 = time.perf_counter()
print('autoset time: {} s'.format(t4 - t3))
# acquisition
scope.write('acquire:state OFF') # stop
scope.write('acquire:stopafter SEQUENCE;state ON') # single
t5 = time.perf_counter()
r = scope.query('*opc?')
t6 = time.perf_counter()
print('acquire time: {} s'.format(t6 - t5))
# curve configuration
scope.write('data:encdg SRIBINARY') # signed integer
scope.write('data:source CH1')
scope.write('data:start 1')
acq_record = int(scope.query('horizontal:recordlength?'))
scope.write('data:stop {}'.format(acq_record))
scope.write('wfmoutpre:byt_n 1') # 1 byte per sample
# data query
t7 = time.perf_counter()
bin_wave = scope.query_binary_values('curve?', datatype='b', container=np.array, chunk_size = 1024**2)
t8 = time.perf_counter()
print('transfer time: {} s'.format(t8 - t7))
# retrieve scaling factors
wfm_record = int(scope.query('wfmoutpre:nr_pt?'))
pre_trig_record = int(scope.query('wfmoutpre:pt_off?'))
t_scale = float(scope.query('wfmoutpre:xincr?'))
t_sub = float(scope.query('wfmoutpre:xzero?')) # sub-sample trigger correction
v_scale = float(scope.query('wfmoutpre:ymult?')) # volts / level
v_off = float(scope.query('wfmoutpre:yzero?')) # reference voltage
v_pos = float(scope.query('wfmoutpre:yoff?')) # reference position (level)
# error checking
r = int(scope.query('*esr?'))
print('event status register: 0b{:08b}'.format(r))
r = scope.query('allev?').strip()
print('all event messages: {}'.format(r))
# disconnect
scope.close()
rm.close()
# create scaled vectors
# horizontal (time)
total_time = t_scale * wfm_record
t_start = (-pre_trig_record * t_scale) + t_sub
t_stop = t_start + total_time
scaled_time = np.linspace(t_start, t_stop, num=wfm_record, endpoint=False)
# vertical (voltage)
unscaled_wave = np.array(bin_wave, dtype='double') # data type conversion
scaled_wave = (unscaled_wave - v_pos) * v_scale + v_off
# plotting
plt.plot(scaled_time, scaled_wave)
plt.title('channel 1') # plot label
plt.xlabel('time (seconds)') # x label
plt.ylabel('voltage (volts)') # y label
print("look for plot window...")
plt.show()
print("\nend of demonstration")