About a year ago, my new project requires a lot of data captured from the Tek oscilloscope. I started with doing the data capture with a USB drive. But it didn’t take long for me figured that I need some better way to do it. After years of working in engineering world, I have learned a good rule of thumb: if you need to do some task repeatedly, it is better to automate it with some programming. The initial investment in time is in general well worth it. You can avoid human errors more easily under pressure or boredom. So I decided to work on it.

The Tektronix provided interfaces for instruments control via GPIB, USB, etc. They use a standard interface protocol (VISA, or virtual instrument software architecture) for this purpose. If you have Matlab Instrument Control Toolbox license, you can use Matlab. Otherwise, there is a Python package “PyVisa” you can use to do your job.

Here are how you do it.

Download and Install TekVisa Driver

You can download the drive from Textronix website (TekVisa.exe).

Interface Using Matlab

Because the VISA interface is independent of the choice of the language, it is very handy to have this programming manual with you.

Open Device

Before open the device, you need to find the VISA brand and address information from Matlab Instrument Control Tool. Some more information can be found here.

Here is the source code for “tek_openDevice.m”.

function dpo = tek_openDevice() ;

%% Variables, You need to get the visa brand and address from Matlab (YZYZ)
visa_brand = 'AGILENT';
visa_address = 'USB0::0x0699::0x0415::c030883::0::INSTR';
buffer = 2E6;

%% Code
dpo = visa(visa_brand,visa_address,'InputBufferSize',buffer,'OutputBufferSize',buffer);

% Align the Endian for the Device and Interface to voids dividing by 256 and byte flip order
set(dpo, 'ByteOrder', 'bigEndian');

Acquire Data

To simplify the code, I manually setup the Trigger source and level in the Oscilloscope. You can also use the code to program it if you intend to do more sophisticated control. So the source code for “tek_acquire.m” only allow to run and stop the trigger.

function tek_acquire(dpo, Run_nStop )

if Run_nStop == 0
    fwrite(dpo,[':acquire:state stop;']);
    fwrite(dpo,[':acquire:state run;']);

Capture Data

Once the trigger is tripped, you can capture the data from it. Here is the code for “tek_captureData.m”. The input channels is an array for selected channel to capture (eg. [1, 3, 4]). One thing to note is that the oscilloscope will clip the data if the display is out-of-sight, so make sure to scale the channel and move it up/down to make sure it doesn’t get clipped. You can put them all in the middle if you don’t care of the looking in the real oscilloscope. The data captured are integers, so we need to do some conversion (details in the programming manual).

function [ scaled_time, scaled_wave, titles] = tek_captureData(dpo, channels )
%function [ scaled_time, scaled_wave, titles] = tek_captureData(dpo, channels )

for idx = 1:length(channels)
    mychannel = channels(idx); 
    %query(dpo,':data:source ch1;:data?;') % set source before wfmo
    query(dpo,[':data:source ch',num2str(mychannel),';:data?;']) % set source before wfmo, YZYZ
    %query(dpo,':data:stop max;:data:stop?;')
    reco = query(dpo,':hor:reco?;'); %find record lenght
    fwrite(dpo,[':data:start 1;stop ' reco(1:end-1) ';']);
    % retrieve vertical scaling informaiton
    yof = query(dpo,':wfmo:yof?;','%s','%E');
    ymu = query(dpo,':wfmo:ymu?;','%s','%E');
    yze = query(dpo,':wfmo:yze?;','%s','%E');
    % retrieve horizontal scaling information
    nrp = query(dpo,':wfmo:nr_p?;','%s','%E');
    xin = query(dpo,':wfmo:xin?;','%s','%E');
    xze = query(dpo,':wfmo:xze?;','%s','%E');
    % get string values
    details = query(dpo,':wfmo:wfi?;');
    % get time from trigger
    a = sprintf('%80s', details) ;
    titles(idx,:) = a ; 
    % retrieve raw waveform data
    wave = int16(binblockread(dpo,'int16'));
    scaled_wave(idx,:) = (double(wave')-yof).*ymu+yze;    
    scaled_time = linspace(xze,xze+(xin*nrp),nrp);
    %scaled_time(idx,:) = linspace(xze,xze+(xin*nrp),nrp);


Draw the Waveform

Here is the code that I used to draw the waveform.

function tek_drawWaveform(channels, scaled_time, scaled_wave, titles, color_spec ) 
%function tek_drawWaveform(channels, scaled_time, scaled_wave, titles ) 

if nargin < 5
    color_spec = 'b' ; 

for idx=1:length(channels)
    subplot(length(channels),1, idx);
    %wfmgraph = stairs(scaled_time(idx,:),scaled_wave(idx,:), color_spec);
    wfmgraph = stairs(scaled_time,scaled_wave(idx,:), color_spec);
    %set(1,'NumberTitle','off','Name','my wave');
    xlabel('time (s)');
    ylabel('voltage (v)');
    %ylim([min(scaled_wave) max(scaled_wave)]); delete(maxline,minline);
    %xlim([min(scaled_time(idx,:)) max(scaled_time(idx,:))]);
    xlim([min(scaled_time) max(scaled_time)]);
    % trigger point annotation
    trigline = line([0 0],[max(scaled_wave(idx,:)) min(scaled_wave(idx,:))],[0 0],'Color','red','LineStyle',':');
    % max annotation
    %maxline = line([min(scaled_time(idx,:)) max(scaled_time(idx,:))],[max(scaled_wave(idx,:)) max(scaled_wave(idx,:))],[0 0],'Color','cyan','LineStyle','--');
    maxline = line([min(scaled_time) max(scaled_time)],[max(scaled_wave(idx,:)) max(scaled_wave(idx,:))],[0 0],'Color','cyan','LineStyle','--');
    % min annotation
    %minline = line([min(scaled_time(idx,:)) max(scaled_time(idx,:))],[min(scaled_wave(idx,:)) min(scaled_wave(idx,:))],[0 0],'Color','cyan','LineStyle','--');
    minline = line([min(scaled_time) max(scaled_time)],[min(scaled_wave(idx,:)) min(scaled_wave(idx,:))],[0 0],'Color','cyan','LineStyle','--');
    % scaled grid
    grid on


Save the Data

In this function “tek_saveData.m”, I did something extra to automatically increment the file name and allow to add note in the mat file.

function tek_saveData(channels, scaled_time, scaled_wave, titles, notes) 

dest_dir = './MAT_data' ;
config_str = '' ; 

cur = ls([dest_dir, '/*.mat']);
if size(cur,1)==0
    fidx = 1 ; 
    last_fn = cur(size(cur,1),:);
    fidx = str2num( last_fn(4:7) ) + 1 ; 

if fidx < 10
    str_idx = ['000', num2str(fidx)];
elseif fidx < 100 
    str_idx = ['00', num2str(fidx)];    
elseif fidx < 1000 
    str_idx = ['0', num2str(fidx)];    
    str_idx = num2str(fidx);    
fn = sprintf('%s/lab%s_%s%s.mat', dest_dir, str_idx, notes, config_str)  
save(fn, 'channels', 'scaled_time', 'scaled_wave', 'titles', 'notes');

Close the Device

function tek_closeDevice(dpo) ; 
%% reset
clear all

Top Level Example

% Open Device
dpo = tek_openDevice() ; 

% Set the Trigger
tek_acquire(dpo, 1); 

%% Do something to let it trigger

%% After trigger 
channels = [1 3 4] ; 
[scaled_time, scaled_wave, titles] = tek_captureData(dpo, channels) ;
tek_saveData(channels, scaled_time, scaled_wave, titles, 'NotesHere', 0 )
tek_drawWaveform(channels, scaled_time, scaled_wave, titles, 'b') ;

%% After you finished all captures

Interface Using PyVisa (Python)

If you prefer to use the free tools. You can use PyVisa. It should work along with any Python distributions (Python, WinPython, Anaconda, Enthought Canopy, etc). You can find some example code here: http://www1.tek.com/forum/viewtopic.php?t=4389. Again the programming manual is the best reference.

Something to watch out if the PyVisa version you downloaded. There are some difference in API functions.
For example, in Version 1.4, this code works:

rm = visa.ResourceManager()
res = visa.get_instruments_list()
print("Find following resources: ")
scope = visa.instrument(res[0])

while in Version 1.7 and later, you would need to use this:

rm = visa.ResourceManager()
res = rm.list_resources() ;
print("Find following resources: ")
scope = rm.get_instrument(res[0]) ;

Read through the documents for PyVisa.

Hope this post helps.

How to Control Tektronix Oscilloscope (DPO 3054) with Matlab and Python
Tagged on:         

Please tell us what's in your mind ...

%d bloggers like this: