=pod =head1 NAME Lab::VISA::Tutorial - Tutorial on using Lab::VISA and related packages =head1 Introduction Lab::VISA and its related packages allow to perform test and measurement tasks with Perl scripts. It provides an interface to National Instruments' NI-VISA library, making the standard VISA calls available from within Perl programs. Dedicated instrument driver classes relieve the user from taking care for internal details and make measurements as easy as $voltage=$multimeter->read_voltage(). The Lab::... software is divided into three parts. They are built on top of each other and provide increasing comfort. Your measurement scripts can be based on each of these stages. The lowest level is C. It makes the NI-VISA library accessible from perl and therefor allows to make any standard VISA call. The modules in the C package make communication with instruments easier by silently handling the protocol involved. Package C is the highest abstraction layer. These modules provide support for writing good measurement scripts. They offer means of saving data and related meta information to disk, plotting data etc. This tutorial will explain how to write measurement scripts that build on any of these stages. However, this tutorial does not intend to teach the Perl language itself. Some introduction into VISA and GPIB terminology is given, but then some familarity also with these concepts is assumed. Not much is required. If you feel the need for more information on Perl or VISA/GPIB, please see the L section[1-6]. =head1 Measurement automation basics This section provides a very brief introduction to the terms VISA and GPIB. For a more detailed explanation of the VISA and GPIB standards, the involved communication principles and the available commands for your specific instruments, please refer to the literature[1-3]. Usage of the higher level modules from the C package requires almost no knowledge about VISA and GPIB at all. =head2 VISA Traditionally, test and measurement instruments can be connected and controlled via various standards and protocols. VISA, the Virtual Instrument Software Architecture[1,2], is an effort to provide a single standarised interface to communicate with instruments via several protocols. It was developed by the VXIplug&play Systems Alliance[4] and is currently maintained by the IVI foundation[5]. VISA can control VXI, GPIB, serial, or computer-based instruments and makes the appropriate driver calls depending on the type of instrument used. Hence, VISA is located in the application layer. The National Instruments NI-VISA library is one implementation of the VISA standard. In one word: VISA tries to make it unimportant, how an instrument is connected physically. =head2 GPIB GPIB (IEEE488)[3] is a lower lying standard invented by Hewlett-Packard. It describes a way of connecting instruments. The standard is divided into the physical layer IEEE488.1 that defines cables and signals and the command layer IEEE488.2 that describes a syntax for messages between communicating instruments. SCPI (Standard Commands for Programmable Instruments) is an extension of IEEE488.2 and refines the available commands further, with the goal of obtaining a language that is independent of the exact model of the instruments in use. This could be very useful, as, in theory, it would allow you to exchange one instrument in your setup with a similar one from another manufacturer, without having to change your measurement software. In practise however, not many instruments support this standard, and even if, small differences make things a pain. As described below, the Lab::Instrument package follows another route to achieve interchangeability by providing common interfaces for similar instruments at a much higher level (e.g. the Lab::Instrument::Source interface). In one word: GPIB tries to make communication with various instruments more similar. =head1 Architecture A schematic view of the various software layers between your perl measurement script and the instrument hardware looks like this: =begin latex \clearpage =end latex +-------------------------+ +---------------+ +------------------+ |Lab::Instrument::HP34401A| |L::I::KnickS252| |L::I::Yokogawa7651| +-----------------------+-+ +----+----------+ +----+-------------+ | | | | +--+-----------------+--+ | |Lab::Instrument::Source| | +---+-------------------+ | | +--+---------+--+ |Lab::Instrument| +-------+-------+ | +----+----+ |Lab::VISA| +----+----+ | +-------+-------+ |NI-VISA Library| +---+-------+---+ | | +----------+-+ +-+----+ |GPIB Library| | OS | +----------+-+ +-+----+ | | | |Serial connection GPIB connection| |TCP/IP connection | |USB connection | | +--------+-+ +-+--------+ |Instrument| |Instrument| +----------+ +----------+ The L module provides a perl binding for National Instruments' NI-VISA library. It makes the standard VISA calls available from within Perl programs. The L module builds on top of Lab::VISA and simplifies the routine tasks of opening VISA resources, sending and receiving messages. The instrument classes like L are specialized modules for certain instruments. Most other measurement software packages would call this a virtual instruments or an instrument drivers. Each such class provides methods that are specific for one instrument. The L class for example class is dedicated to a certain magnet power supply and therefore provides methods like C. Similar instruments (e.g. various voltage sources) however share common interfaces (e.g. L) to make interchangeability of similar instruments possible. =head1 Using pure VISA calls First we will see how to use the plain VISA interface and communicate with an instrument with standard VISA C and C calls. It will show that this method is rather laborious. Later we will learn how C makes life easier. All the examples in the following sections can be found in the Tutorials directory of the Lab::VISA package. #!/usr/bin/perl # example1.pl use strict; use Lab::VISA; # Initialize VISA system and # Open default resource manager my ($status,$default_rm)=Lab::VISA::viOpenDefaultRM(); if ($status != $Lab::VISA::VI_SUCCESS) { die "Cannot open resource manager: $status"; } # Open one resource (an instrument) my $gpib=24; # we want to open the instrument my $board=0; # with GPIB address 24 # connected to GPIB board 0 in our computer my $resource_name=sprintf("GPIB%u::%u::INSTR",$board,$gpib); ($status, my $instr)=Lab::VISA::viOpen( $default_rm, # the resource manager session $resource_name, # a string describing the $Lab::VISA::VI_NULL,# access mode (no special mode) $Lab::VISA::VI_NULL # time out for open (no time out) ); if ($status != $Lab::VISA::VI_SUCCESS) { die "Cannot open instrument $resource_name. status: $status"; } # We set a time out for communication with this instrument $status=Lab::VISA::viSetAttribute( $instr, # the session identifier $Lab::VISA::VI_ATTR_TMO_VALUE, # which attribute to modify 3000 # the new value ); if ($status != $Lab::VISA::VI_SUCCESS) { die "Error while setting timeout value: $status"; } # Clear the instrument my $status=Lab::VISA::viClear($instr); if ($status != $Lab::VISA::VI_SUCCESS) { die "Error while clearing instrument: $status"; } # Now we are going to send one command and read the result. # We send the simple SCPI command "*IDN?" which asks the instrument # to identify itself. Of course the instrument must support this # command, in order to make this example work. my $cmd="*IDN?"; ($status, my $write_cnt)=Lab::VISA::viWrite( $instr, # the session identifier $cmd, # the command to send length($cmd) # the length of the command in bytes ); if ($status != $Lab::VISA::VI_SUCCESS) { die "Error while writing: $status"; } # Now we will read the instruments reply ($status, # indicates if the operation was successful my $result, # the answer string my $read_cnt)= # the length of the answer in bytes Lab::VISA::viRead( $instr, # the session identifier 300 # read 300 bytes ); if ($status != $Lab::VISA::VI_SUCCESS) { die "Error while reading: $status"; } # The result string will be 300 bytes long, but only $read_cnt # bytes are part of the answer. We cut away the rest. $result=substr($result,0,$read_cnt); print "$result\n"; # As good citizens we'll cleanup now. # Close the instrument $status=Lab::VISA::viClose($instr); # And the resource manager $status=Lab::VISA::viClose($default_rm); __END__ First we have to open a resource manager. This manager can then provide us with a handle to one instrument. We try to open an instrument that is connected via GPIB to the GPIB board 0 in our computer and uses the GPIB address 24. This is specified by the resource name. We then ask the instrument for its identification string, read the answer and print it. We do so by sending the C<*IDN?> command. This is a standard SCPI command, that all instruments that support the SCPI language, will understand. Agilent instruments do so for example. We see that there is a lot of protocol overhead involved, that makes this very simple example a bit lengthy and ugly. These things should be factored out. The Lab::Instrument class can do all this dirty work for us, as we will learn in the next section. =head1 Using the Lab::Instrument class The Lab::Instrument class can do for us the routine work of connecting to certain instrument. #!/usr/bin/perl # example2.pl use strict; use Lab::Instrument; my $gpib=24; # we want to open the instrument my $board=0; # with GPIB address 24 # connected to GPIB board 0 in our computer # Create an instrument object my $instr=new Lab::Instrument($board,$gpib); my $cmd="*IDN?"; # Query the instrument # Query is a combined Write and Read my $result=$instr->Query($cmd); print $result; __END__ This program achieves exactly the same as C, but with only two lines of code: one to open the instrument, one to query it. We don't have to care about resource managers and string lengths and cleaning up. Lab::Instrument does it for us. Now that's already quite nice, eh? Let's see another example. This time we will send a great bunch of commands to an Agilent 81134A pulse generator, to set it up for pulse mode. #!/usr/bin/perl # example3.pl use strict; use Lab::Instrument; # Open instrument # We use the other form of the constructor here. my $instr=new Lab::Instrument({ GPIB_board => 0, GPIB_address => 10 }); # Send a bunch of commands to configure instrument for (( # Protect the DUT ':OUTP:CENT OFF', #disconnect channels # Set up the Instrument ':FUNC PATT', #set mode to Pulse/Pattern ':PER 20 ns', #set period to 20 ns # Set up Channel 1 ':FUNC:MODE1 PULSE', #set pattern mode to Pulse ':WIDT1 5 ns', #set width to 5 ns ':VOLT1:AMPL 2.000 V', #set ampl to 2 V ':VOLT1:OFFSET 1.5 V', #set offset to 1.5 V ':OUTP1:POS ON', #enable output channel 1 # Generate the Signals ':OUTP:CENT ON', #reconnect the channels ':OUTP0:SOUR PER', #use trigger mode Pulse ':OUTP0 ON', #enable trigger output )) { $self->{vi}->Write($_); } __END__ This example shows that Perl's great list handling makes it the ideal language for instrument control and data aquisistion tasks. By only using C you should already be able to do about everything that can be done the instruments in your lab. =head1 Using Lab::Instrument::xxx virtual instruments Many common tasks, like reading a voltage from a digital multimeter, require that a series of GPIB commands is sent to an instrument. These commands are different for similar instruments from different manufacturers. The virtual instrument classes in the C package attempt to hide these details from the user by providing high level methods like C and C. Additionally they provide an optional safety mechanism for voltage sources. This is used to protect sensitive samples which could be destoyed by sudden voltage changes. See the documentation of the L module for details. #!/usr/bin/perl # example4.pl use strict; use Lab::Instrument::HP34401A; my $gpib=24; # we want to open the instrument my $board=0; # with GPIB address 24 # connected to GPIB board 0 in our computer # Create an instrument object my $hp=new Lab::Instrument::HP34401A($board,$gpib); # Use the id method to query the instruments ID string my $result=$hp->id(); print $result; __END__ This example show the usage of a dedicated virtual instrument class, namely L, the driver for a Hewlett-Packard/Agilent 34401A digital multimeter. An instance of this class is created that is connected to one certain instrument. We use the C<-Eid> method that returns the instrument's id string again. TODO: Examples for C #!/usr/bin/perl # example5.pl use strict; use Lab::Instrument::Yokogawa7651; unless (@ARGV > 0) { print "Usage: $0 GPIB-address [goto_voltage]\n"; exit; } my ($gpib,$goto)=@ARGV; my $source=new Lab::Instrument::Yokogawa7651(0,$gpib); if (defined $goto) { $source->sweep_to_voltage($goto); } else { print $source->get_voltage(); } __END__ =head1 Using Lab::Tools With the tools introduced so far you should be able to easily write short individual scripts for your measurement tasks. These scripts will probably serve as well as all other home grown solutions using LabView or whatever. The modules in the C package now provide additional tools to write better measurement scripts. One main goal is to provide means to keep additional information stored along with the raw measured data. Additional information means all the notes that you would usually write down in your laboratory book, like date and time, settings of additional instruments, the environment temperature, the color of the shirt you were wearing while recording the data and everything else that might be of importance for a later interpretation of the data. In my experience, having to write these things in a book by hand is tedious and error-prone. It's the kind of job that computers were made for. Another goal is to free the laborant from having to repeat himself all the time when the data is used for analysis or presentation. Let us assume that, for example, you are measuring a very small current with the help of a current amplifier. This current amplifier will output a voltage that is proportional to the original current, so in fact you will be measuring a voltage that can be converted to the original current by multiplying it with a certain factor. The last paragraph has shown that the C modules will help you to keep track of this additional information I. But as long as the precise formula for this transformation is not stored together with the data, you will still find yourself repeatedly typing in the same expressions, whenever you work with the data. This is where the I concept comes into play. Already at the time you are preparing your measurement script, you define an I named I that stores the expression to calculate the current from the voltage. From there you work with the current-axis and will never have to care about the conversion again. And of course you can define many different axes. Read on! =head2 The Meta data The general concept is that a I is composed out of I and I, i.e. additional information about the I. This I is maintained by the L class and is usually stored in a file C, while the I is saved in C. The I file is stored in YAML or XML format and contains a number of elements which are defined in L. The most important ones are I, I, I and I. For the following discussion of these fields, let's assume a I file that looks like this: 0.01 2.0 3 0.01 2.1 3.4 0.01 2.2 2.9 0.02 2.0 1.7 0.02 2.1 2.4 0.02 2.2 2.2 This dataset shows an example where one quantity (third column) is measured in dependence of two others (first and second column). The data was recorded in two traces, where one input value is kept constant (1st column) and then for every setting of the other input value (2nd column) a datapoint is taken (3rd column). Then the the first input value is increased and the next trace is recorded. =head3 column The above example measurement has three columns. You will want to store additional information for each of these columns: What is being set or measured, what is the unit of the stored value etc. This information is stored in the I records of the I file. More details on the available fields is given in the L manpage. =head3 block The example data above was aquired in two traces or scans or sweeps, which are separated by an empty line in the I file now. C adopts the Gnuplot[7] terminology and calls these I. Along with every block, additional information like the time the trace was started can be saved. Most of this is done automatically. See the L and L manpages. =head3 axis Usually you will not want to work with the raw data as it is stored in the columns of the file. For example you could want to plot the sum of two columns. Also you might want to display the data using another unit. Therefor you can define a new axis, that is defined as the sum of these two columns times any factor (which can be saved as a constant, see below) for the right unit. The expression C defines an axis as the sum of two columns multiplied with a constant C. Additionally, axes have labels, ranges and such. =head3 plot With the plot element, default views on the data be defined. These views can then be plotted with a single command, using the L module and the script C. Because all the necessary information is stored in the I file, these plots will B and any other information you wish! Plots can already be defined at the time the measurement script is written, and can also be added later. If you use the L module, you can display any of these plots live, while the data is being aquired. Since this entire system can run on Linux, you can X-forward this graph to your remote desktop at the beach. Imagine the possibilities. =head3 constant This section of meta data can be used to store additional values that are important for the later interpretation of the raw data. Examples for such values could be amplification factors, voltage dividers etc. Constants have names that can be used in expressions of C definitions. =head2 The Lab::Measurement class The L class makes it easy to write a measurement script that takes advantage of the meta data system introduced above... =head2 Examples =head3 Example 2D mit Measurement #!/usr/bin/perl # example6.pl # Eine Spannungsquelle fahren, Leitfähigkeit (ohne Lock-In) messen use strict; use Lab::Instrument::KnickS252; use Lab::Instrument::HP34401A; use Time::HiRes qw/usleep/; use Lab::Measurement; ################################ my $start_voltage =-0.05; my $end_voltage =-0.25; my $step =-1e-3; my $knick_gpib =4; my $hp_gpib =24; my $v_sd =-300e-3/1000; my $amp =1e-9; # Ithaco amplification my $R_Kontakt =1089; my $sample ="S5c (81059)"; my $title ="QPC links unten"; my $comment =< 0, 'GPIB_address' => $knick_gpib, 'gate_protect' => 1, 'gp_max_volt_per_second' => 0.002, }); my $hp=new Lab::Instrument::HP34401A(0,$hp_gpib); my $measurement=new Lab::Measurement( sample => $sample, title => $title, filename_base => 'qpctest', description => $comment, live_plot => 'QPC current', constants => [ { 'name' => 'G0', 'value' => '7.748091733e-5', }, { 'name' => 'RKontakt', 'value' => $R_Kontakt, }, { 'name' => 'V_SD', 'value' => $v_sd, }, { 'name' => 'AMP', 'value' => $amp, }, ], columns => [ { 'unit' => 'V', 'label' => 'Gate voltage', 'description' => 'Applied to gates via low path filter.', }, { 'unit' => 'V', 'label' => 'Amplifier output', 'description' => "Voltage output by current amplifier set to $amp.", } ], axes => [ { 'unit' => 'V', 'expression' => '$C0', 'label' => 'V_{Gate}', 'min' => ($start_voltage < $end_voltage) ? $start_voltage : $end_voltage, 'max' => ($start_voltage < $end_voltage) ? $end_voltage : $start_voltage, 'description' => 'Gate voltage', }, { 'unit' => 'A', 'expression' => "abs(\$C1)*AMP", 'label' => 'I_{QPC}', 'description' => 'QPC current', }, { 'unit' => '2e^2/h', 'expression' => "(1/(V_SD/(-\$C2*AMP)-RKontakt))/G0", 'label' => "G_{QPC}", 'description' => "QPC conductance", 'min' => -0.1, 'max' => 7 }, ], plots => { 'QPC current' => { 'type' => 'line', 'xaxis' => 0, 'yaxis' => 1, 'grid' => 'xtics ytics', }, 'QPC conductance'=> { 'type' => 'line', 'xaxis' => 0, 'yaxis' => 3, 'grid' => 'ytics', } }, ); $measurement->start_block(); my $stepsign=$step/abs($step); for (my $volt=$start_voltage; $stepsign*$volt<=$stepsign*$end_voltage; $volt+=$step) { $knick->set_voltage($volt); usleep(500000); my $meas=$hp->read_voltage_dc(10,0.0001); $measurement->log_line($volt,$meas); } my $meta=$measurement->finish_measurement(); =head3 Beispiel for plotter.pl =head3 Example mit nur Writer =head1 References =over =item [1] NI-VISA User Manual (L) =item [2] NI-VISA Programmer Manual (L) =item [3] NI 488.2 User Manual (L) =item [4] L =item [5] L =item [6] L =item [7] L =back =head1 AUTHOR/COPYRIGHT This is $Id: Tutorial.pod 511 2006-09-25 19:03:36Z schroeer $ Copyright 2006 by Daniel Schröer. =cut