#DistZilla: +PodWeaver
#PODNAME: Lab::Measurement::Legacy::Tutorial
#ABSTRACT: Old Tutorial on using the historical/deprecated API of the Lab::Measurement package stack

__END__

=pod

=encoding utf-8

=head1 NAME

Lab::Measurement::Legacy::Tutorial - Old Tutorial on using the historical/deprecated API of the Lab::Measurement package stack (deprecated)

=head1 VERSION

version 3.899

=head1 Introduction

This file belongs to a deprecated legacy module stack, frozen and not under development anymore. Please port your code to the new API;
its documentation can be found on the Lab::Measurement homepage, L<https://www.labmeasurement.de/>.

The Lab::Measurement package stack allows to perform test and measurement
tasks with Perl scripts. It provides an interface several hardware driver
backends. Dedicated instrument driver classes relieve the user from taking
care for internal details and make measurements as easy as

  $voltage=$multimeter->get_voltage().

The Lab::Measurement software stack consists of several parts that are built on
top of each other. This modularization allows support for a wide range of
hardware on different operating systems. As hardware drivers vary in API
details, each supported one is encapsulated into perl modules of types Lab::Bus
and Lab::Connection. Normally you won't have to care about this; at most, your
Instrument object (see below) gets different initialization parameters. 

A typical measurement script is based on the high-level interface provided by
the modules Lab::Instrument and Lab::Measurement. The former silently handles
all the protocol overhead. You can write commands to an instrument and read the
result. Drivers for specific devices are included, implementing their specific
command syntax; more can easily be added to provide high-level functions. The
latter includes tools for metadata handling (what was that amplifier setting in
the measurement again?!), data plotting, and similar. 

This tutorial will explain how to write measurement scripts. 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. 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 various ways of connecting
measurement instruments to your control PC. We focus on the methods not so
well-known to average PC users, i.e. VISA and GPIB programming. Usage of the
higher level modules from the L<Lab::Instrument> package requires almost no
knowledge about VISA and GPIB at all, though.

=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.

=head2 RS232

RS232 is the abbreviation for the serial port that used to be built into each
PC. It provides a point-to-point connection to one instrument.

=head1 Architecture

A schematic view of the various software layers between your perl
measurement script and the instrument hardware is depicted in the graphics
L<https://www.labmeasurement.de/structure.png>.

The lowermost layer is provided by the hardware driver library and its Perl
binding. One option for this is under Linux the package LinuxGPIB, which comes
wth its own Perl bindings module. Alternatively, National Instruments NI-VISA
can be used. In that case, the module L<Lab::VISA> is required to access the
library functions from Perl; it makes the standard VISA calls available
from within Perl programs. This layer is not part of the Lab::Measurement
distribution, but must be installed separately. 

Each hardware backend is encapsulated into a class of the L<Lab::Bus> type.
A Bus can be imagined as a cable, connecting your control computer with several
measurement hardware components. On top of the Bus classes, classes of type
L<Lab::Connection> operate. Each connection, well, connects one measurement
instrument with your script. Usually, the handling of Bus and Connection is
transparent; as long as you dont want to add more backends or enhance the
functionality, you will never have any need to directly address these levels.

The L<Lab::Instrument> classes build on top and simplify the routine tasks of
opening a connection to an instrument, sending and receiving messages.
This is the level where usually customized measurement scripts access the
protocol stack. Classes derived from L<Lab::Instrument> as e.g.
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) can share common interfaces
(e.g. L<Lab::Instrument::Source>) to make interchangeability of similar
instruments possible.

The highest abstraction layer is provided by the L<Lab::Measurement> class,
which contains methods for data and metadata handling, plotting and rudimentary
keyboard control.

=head1 Using the Lab::Instrument class

The L<Lab::Instrument> class can do for us the routine work of connecting to
an instrument.

  #!/usr/bin/perl
  
  use strict;
  use Lab::Instrument;
  
  ################################
  
  unless (@ARGV > 0) {
  	print "Usage: $0 GPIB-address\n";
  	exit;
  }
  
  my $gpib=$ARGV[0];
  
  print "Querying ID of instrument at GPIB address $gpib\n";
  
  my $i=new Lab::Instrument(
  	connection_type=>'LinuxGPIB',
  	gpib_address => $gpib,
  	gpib_board=>0,
  );
  
  my $id=$i->query('*IDN?');
  
  print "Query result: \"$id\"\n";

This program opens a GPIB instrument for communication, sends the command *IDN?
and reads out its response, the identification string of the instrument. All
handling of GPIB boards, resource managers etc. is done within the
Lab::Instrument class; we don't have to care about string lengths and cleaning
up. Lab::Instrument does it for us. Now that's already quite nice, eh?

By only using L<Lab::Instrument> you should already be able to do about
everything that can be done with 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
  
  use strict;
  use Lab::Instrument::HP34401A;
  
  ################################
  
  unless (@ARGV > 0) {
  	print "Usage: $0 GPIB-address\n";
  	exit;
  }
  
  my $hp_gpib=$ARGV[0];
  
  print "Reading voltage from HP34401A at GPIB address $hp_gpib\n";
  
  my $hp=new Lab::Instrument::HP34401A(
  	connection_type=>'LinuxGPIB',
  	gpib_address => $hp_gpib,
  	gpib_board=>0,
  );
  
  my $volt=$hp->$get_voltage_dc(10,0.00001);
  
  print "Result: $volt V\n";

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<get_voltage_dc()> method that configures the multimeter for dc voltage
measurement in the range given by the parameters, triggers one measurement, and
returns the measured voltage value.

Next we show 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
  
  use strict;
  use Lab::Instrument::Yokogawa7651;
  
  unless (@ARGV > 0) {
  	print "Usage: $0 GPIB-address [Target-voltage]\n";
  	exit;
  }
  
  my ($gpib,$goto)=@ARGV;
  
  my $source=new Lab::Instrument::Yokogawa7651(
  	connection_type=>'LinuxGPIB',
  	gpib_address => $gpib,
  	gpib_board=>0,
  	gate_protect=>1,
  	gp_max_unit_per_second=>0.05,
  	gp_max_unit_per_step=>0.005
  	gp_max_step_per_second=>10,
  );
  
  if (defined $goto) {
  	$source->set_voltage($goto);
  } else {
  	print $source->get_voltage();
  }

Here the gate_protect mechanism limits the step size of the voltage source to
0.005mV, and the sweep speed to at most 10 such steps per second. This is
implemented automatically within the C<set_voltage($goto)> command; after we
have set the parameters in the initialization phase, we do not have to take
care of it anymore.

=head1 Using the high-level Lab::Measurement and related classes

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 C<Lab::Measurement> class together with the related C<Lab::Data:...> classes
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 experimenter 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. 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 concept of sweeps

The L<Sweep|Lab::XPRESS::Sweep> classes provide a high-level interface for measurement
automation. The following script explains the basic use of sweeps. This
example shows a two-dimensional L<Voltage Sweep|Lab::XPRESS::Sweep::Voltage>: The I<master sweep> controls
the gate voltage. For each value of the gate voltage we perform a 
I<slave sweep> of the source-drain voltage.

We perform a measurement
task at each grid point. This is done by providing a callback subroutine.
In our example, the callback reads the value of a
multimeter and logs to a DataFile object.

  #-------- 1. Import Lab::Measurement -------
  
  use warnings;
  use strict;
  use 5.010;
  
  use Lab::Measurement::Legacy;
  
  
  #-------- 2. Some constants ----------------
  
  my $gain = -1e-9;         # A/V amplifier sensit.
  my $stepwidthbias = 0.05; # step width bias
  my $stepwidthgate = 0.1;  # step width gate
  my $NPLC=2;               # integration time, 2*20ms
  
  
  #-------- 3. Initialize Instruments --------
  
  my $gate_source = Instrument('YokogawaGS200', 
      {
      connection_type => 'VISA_GPIB',
      gpib_address => 2,
      gate_protect => 0
      });
  
  my $bias_source = Instrument('YokogawaGS200', 
      {
      connection_type => 'VISA_GPIB',
      gpib_address => 6,
      gate_protect => 0
      });
  
  my $DMM_I = Instrument('HP34401A', 
      {
      connection_type => 'VISA_GPIB',
      gpib_address => 14,
      nplc => $NPLC
      });
  	
  
  #-------- 4. Define the Sweeps -------------
  
  my $bias_sweep = Sweep('Voltage', 
      {
      mode => 'step',                # step, list, sweep/continuous
      instrument => $bias_source,
      points => [-1,1],              # starting point, end point
      stepwidth => [$stepwidthbias],
      rate => [1, 0.005],            # rate to approach start, sweep rate 
                                     #  for measurement (unused), V/s
      jump => 1,                     # jump to next point, no sweep
      delay_before_loop => 3         # settle 3s before starting
      });
  
  my $gate_sweep = Sweep('Voltage', 
      {
      mode => 'step',                # step, list, sweep/continuous
      instrument => $gate_source,
      points => [-0.5,0.5],          # starting point, end point
      stepwidth => [$stepwidthgate],
      rate => [0.03, 0.03],          # rate to approach start, sweep rate
                                     #  for measurement (unused), V/s
      jump => 1                      # jump to next point, no sweep
      });
  
  
  #-------- 5. Create a DataFile -------------
   
  my $DataFile = DataFile('DCDiamond');
  
  $DataFile->add_column('Gate');
  $DataFile->add_column('Bias');
  $DataFile->add_column('Current');
  
  $DataFile->add_plot({
      'type' => 'pm3d',
      'x-axis' => 'Gate',
      'y-axis' => 'Bias', 
      'cb-axis' => 'Current',
      'refresh' => 'block'
     });
  
  
  #-------- 6. Measurement Instructions -------

  # Define the callback. This subroutine will be called at each point of the
  # parameter grid.
  my $my_measurement = sub {
      # this is run for each measurement point
  
      my $sweep = shift;

      # read_mode => 'cache' means use the value last written by Perl to the
      # device, but do not query the instrument.
      my $value1 = $gate_source->get_value({read_mode => 'cache'});
      my $value2 = $bias_source->get_value({read_mode => 'cache'});

      
      my $value3 = $DMM_I->get_value() * $gain;
  	
      $sweep->LOG({
          Gate => $value1,
          Bias => $value2,
          Current => $value3,
          });
  };
  
  
  #-------- 7. Put everything together -------
  
  $DataFile->add_measurement($my_measurement);
  
  $bias_sweep->add_DataFile($DataFile);
  
  my $frame=Frame();
  $frame->add_master($gate_sweep);
  $frame->add_slave($bias_sweep);
  
  
  #-------- 8. And GO! -----------------------
  
  $frame->start();

For full details, see the documentation of the various sweep
classes.

=head2 Examples

To be done

=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 COPYRIGHT AND LICENSE

This software is copyright (c) 2021 by the Lab::Measurement team; in detail:

  Copyright 2006       Daniel Schroeer
            2010       Daniel Schroeer
            2011-2012  Andreas K. Huettel
            2016       Andreas K. Huettel, Simon Reinhardt
            2017       Andreas K. Huettel
            2018       Andreas K. Huettel, Simon Reinhardt


This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.

=cut
