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”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
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); fopen(dpo); % 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.
1 2 3 4 5 6 7 |
function tek_acquire(dpo, Run_nStop ) if Run_nStop == 0 fwrite(dpo,[':acquire:state stop;']); else fwrite(dpo,[':acquire:state run;']); end |
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).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
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,':wfmo?;') query(dpo,':data?;') %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 fwrite(dpo,':curve?;'); 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); end |
Draw the Waveform
Here is the code that I used to draw the waveform.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
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' ; end 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'); title(titles(idx,:)); %title(details); 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 %delete(1) end |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
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 ; else last_fn = cur(size(cur,1),:); fidx = str2num( last_fn(4:7) ) + 1 ; end if fidx < 10 str_idx = ['000', num2str(fidx)]; elseif fidx < 100 str_idx = ['00', num2str(fidx)]; elseif fidx < 1000 str_idx = ['0', num2str(fidx)]; else str_idx = num2str(fidx); end 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
1 2 3 4 5 6 7 8 |
function tek_closeDevice(dpo) ; %% reset fclose(dpo); close(instrfindall) delete(instrfindall) clear all clc |
Top Level Example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
% 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 tek_closeDevice(dpo); |
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:
1 2 3 4 5 |
rm = visa.ResourceManager() res = visa.get_instruments_list() print("Find following resources: ") print(res) scope = visa.instrument(res[0]) |
while in Version 1.7 and later, you would need to use this:
1 2 3 4 5 |
rm = visa.ResourceManager() res = rm.list_resources() ; print("Find following resources: ") print(res) scope = rm.get_instrument(res[0]) ; |
Read through the documents for PyVisa.
Hope this post helps.