=pod

=head1 NAME

Lab::VISA::Tutorial - Tutorial on using Lab::VISA and related packages

=head1 Introduction

L<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 L<Lab::VISA>. It makes the NI-VISA library accessible
from perl and therefor allows to make any standard VISA call.

The modules in the L<Lab::Instrument> package make communication with
instruments easier by silently handling the protocol involved.

Package L<Lab::Tools> 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</References> 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 L<Lab::Instrument> 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 L<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<Lab::VISA> module provides a perl binding for National
Instruments' NI-VISA library. It makes the standard VISA calls available
from within Perl programs.

The L<Lab::Instrument> 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<Lab::Instrument::KnickS252> 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<Lab::Instrument::IPS120_10> class for example
class is dedicated to a certain magnet power supply and therefore provides
methods like C<set_target_field>. Similar instruments (e.g. various voltage
sources) however share common interfaces (e.g.
L<Lab::Instrument::Source>) 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<viRead> and C<viWrite> calls. It will
show that this method is rather laborious. Later we will learn how C<Lab::Instrument>
makes life easier.

All the examples in the following sections can be found in the Tutorials
directory of the L<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 L<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<example1.pl>, 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 L<Lab::Instrument> 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 L<Lab::Instrument> package attempt to
hide these details from the user by providing high level methods like
C<set_voltage($voltage)> and C<get_voltage()>.

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<Lab::Instrument::Source> 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<Lab::Instrument::HP34401A>, 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<id()> method that returns the instrument's id string again.

Next we see an example on how to use the safety mechanism of L<Lab::Instrument::Source>
that is inherited by voltage sources like L<Lab::Instrument::Yokogawa7651>.

  #!/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<Lab::Tools> 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 L<Lab::Tools> modules will help you to keep track of this
additional information I<current amplifier constant of proportionality>. 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<axis>
concept comes into play. Already at the time you are preparing your measurement script,
you define an I<axis> named I<current> 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<dataset> is composed out of I<data> and
I<metadata>, i.e. additional information about the I<data>. This I<metadata>
is maintained by the L<Lab::Data::Meta> class and is usually
stored in a file C<dataset_filename.META>, while the I<data> is saved in
C<dataset_filename.DATA>.

The I<meta> file is stored in YAML or XML format and contains a number of
elements which are defined in L<Lab::Data::Meta>. The most
important ones are I<column>, I<block>, I<axis> and I<plot>. For the
following discussion of these fields, let's assume a I<data> 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<column> records of the I<meta> file. More details on the
available fields is given in the L<Lab::Data::Meta> 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<data> file now. L<Lab::Data::Meta>
adopts the Gnuplot[7] terminology and calls these I<blocks>. 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<Lab::Data::Meta> and L<Lab::Measurement>
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<amp * ($C1 + 10 * $C2)>
defines an axis as the sum of two columns multiplied with a constant C<amp>.
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<Lab::Data::Plotter> module
and the script C<plotter.pl>. Because all the necessary information is stored in
the I<meta> file, these plots will automatically contain the right axes, ranges, labels,
units 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<Lab::Measurement> 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<axis> definitions.

=head2 The Lab::Measurement class

The L<Lab::Measurement> class makes it easy to write a measurement
script that takes advantage of the meta data system introduced above...

=head2 Examples

    #!/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         =<<COMMENT;
    Strom von 12 nach 14; V_{SD,DC}=$v_sd V; Lüftung an; Ca. 25mK.
    Ithaco: Amplification $amp, Supression 10e-10 off, Rise Time 0.3ms.
    Fahre Ghf4 (Yoko04)
    COMMENT
    
    ################################
    
    my $knick=new Lab::Instrument::KnickS252({
        'GPIB_board'    => 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();
    

TODO: more examples

=head1 References

=over

=item [1] NI-VISA User Manual
(L<http://www.ni.com/pdf/manuals/370423a.pdf>)

=item [2] NI-VISA Programmer Manual
(L<http://www.ni.com/pdf/manuals/370132c.pdf>)

=item [3] NI 488.2 User Manual
(L<http://www.ni.com/pdf/manuals/370428c.pdf>)

=item [4] L<http://www.vxipnp.org/>

=item [5] L<http://www.ivifoundation.org/>

=item [6] L<http://perldoc.perl.org/>

=item [7] L<http://www.gnuplot.info/>

=back

=head1 AUTHOR/COPYRIGHT

This is $Id: Tutorial.pod 607 2010-04-11 21:12:09Z schroeer $

Copyright 2006 by Daniel Schröer.

=cut
