esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE%  lockin.mac
#%NAME% 
#   Stanford Research SR830 Lockin-Amplifier
#
#%CATEGORY% Other hardware
#
#%LOG%
#$Revision: 1.2 $
#$Log: lockin.mac,v $
#Revision 1.2  2008/07/17 15:08:38  rey
#documentation changes
#
#Revision 1.1  2007/10/05 11:35:26  claustre
#Initial revision
#
#%DESCRIPTION%
# These macros allow you to read out the  Stanford Research SR830
# Lockin-Amplifier via GPIB interface and to define its two channels
# as "software counters".

#%SETUP% 
# Configure SPEC for GPIB:
# Make sure that the GPIB-ENET software is correctly installed.
# Run the diagnostics program "/usr/bin/ibtsta". %BR%
# In "config", press "c" to go to the "Interface Configuration" menu.
# Under GPIB enter "y" for YES. Under TYPE press "+" and choose
# "Nat Inst GPIB-ENET (shared)" for the menu. DEVICE should be "gpib0".
# After saving with "w" and exiting with "Control-C" you shoud se the message
# "Using National Instruments GPIB."
# %BR%
# Define a new counter in "config". Type "c" until you to get to the
# "Scaler (Counter) Configuration" menu. Increment "Number of counters" by 1
# and rename "counter n" by "adc1". "Device" should be NONE, "Unit" and
# "Chan" 0, "Ase As" should be "counter" and "Scale factor" 1.
# %BR%
# After exiting the "config" editor type "setup" and include into your setup
# file a line like the following:
#%PRE%
#  lockin_define gpib=8 channel=1 adc1
#%PRE%
# The factory preset GPIB address is 8. You can chage it via the SETUP button
# on the front panel.
#
#%END%

#%UU% gpib=n channel=1|2 counter
#%MDESC% associates a SPEC counter mnemonic to one of the channels channels
# A or B of the ADC module.
# %BR%
# Use this macro in your "setup" file.

def lockin_define '
{
  local usage address channel ch delay state command t

  usage = "usage: $0 gpib=n channel=1|2 counter"

  if ($# != 3) { print usage; exit }
  if (sscanf("$1","gpib=%s",address) != 1)    { print usage; exit }
  if (sscanf("$2","channel=%s",channel) != 1) { print usage; exit }
  if (! (channel == "1" || channel == "2"))   { print usage; exit }
  else if (cnt_num("$3") == -1)
  {
    print "$0: Did you define \"$3\" as a counter in \"config\"?\n"; exit
  }

  global LOCKIN[]
  LOCKIN ["$3/address"] = address
  LOCKIN ["$3/channel"] = channel

  # define necessary hook macros for a "software counter"
  cdef ("","","$3","delete")
  cdef ("user_getcounts",command = "lockin_read $3\n","$3",0x02)
  cdef ("config_mac","lockin_check $3\n","$3",0x02)
  # flag 0x02 = only include if key is a counter mnemonic and the
  # counter is not disabled.
}'

#%UU%
#%MDESC% print status info

def lockin_info '{
  local n t i w[] mne c disabled address addresses[] channel a b
  global LOCKIN[]

  for (i in LOCKIN) n++

  if (n>0) print "\nStanford Research SR830 lock-in amplifier\n\n"
  else print "no lock-in amplifier software counters are currently defined"

  for (i in LOCKIN)
  {
    if (index(i,"/channel") != 0)
    {
      split (i,w,"/"); mne = w[0]
      c = cnt_num(mne)
      disabled = counter_par(c,"disable")
      address = LOCKIN[t=mne"/address"]
      channel = LOCKIN[i]
      printf (t="GPIB="address", channel="channel": counter \""mne"\"")
      print disabled?" (disabled)":""
    }
  }
  print "\n"

  for (i in LOCKIN) if (index(i,"/address")) addresses[LOCKIN[i]] = 1

  for (address in addresses)
  {
    printf ("GPIB=%s: ",address)
    if (LOCKIN[t=address"/error"] == 1)
      print "unavailable (try \"reconfig\" to recover)"
    else
    {
      HDW_ERR = -1 # do not return to command prompt on error
      n = gpib_put(address,"*IDN?")
      if (n > 0) print gpib_get(address)
      else print "unavailable (try \"reconfig\")"
    }
  }
}'


#%IU% counter
#%MDESC% Hook macro for "reconfig"
#%BR%
#checks whether device is accessible on the GPIB bus and clears the error
# status, if necessary.

def lockin_check '{
  local c address HDW_ERR t c n
  global LOCKIN[]

  address = LOCKIN["$1/address"]

  if (address)
  {
    HDW_ERR = -1 # do not abort macro on hardware error
    n = gpib_put(address,"\r")

    # With a shared GPIB-ENET the error condition "Not CIC or lost CIC during
    # command" occurs frequently. In this case the error code is 4 (=transient).
    if (HDW_ERR == 4) {HDW_ERR = -1; n = gpib_put(address,"\r")}
    
    if (n > 0)
    {
      delete LOCKIN[t=address"/error"]
    }
    else
    {
      LOCKIN[t=address"/error"] = 1
      print "RS830 Lock-In Amplifier (GPIB="address") is unusable."
      c = cnt_num("$1")
      if (c != -1) {S[C] = NaN; counter_par(c,"disable",1)}
    }
  }
}'

#%UU%
#%MDESC% undo "lockin_define"

def lockin_undefine '{
  local i w[] mne c
  global LOCKIN[]

  for (i in LOCKIN)
  {
    split(i,w,"/"); mne = w[0]
    cdef ("","",mne,"delete")
    c = cnt_num(mne)
    if (c != -1) {S[c] = NaN}
  }
  unglobal LOCKIN
}'


#%UU%
#%MDESC% disable all Lock-in amplifier software counters

def lockin_off '{
  local i w[] mne c
  global LOCKIN[]

  for (i in LOCKIN)
  {
    split(i,w,"/"); mne = w[0]
    c = cnt_num(mne)
    if (c != -1)
    {
      counter_par(c,"disable",1)
      S[c] = 0
    }
  }
}'

#%UU%
#%MDESC% undo "lockin_off" - re-enable all Lock-in amplifier software counters

def lockin_on '{
  local i w[] mne c
  global LOCKIN[]

  for (i in LOCKIN)
  {
    split(i,w,"/"); mne = w[0]
    c = cnt_num(mne)
    if (c != -1) counter_par(c,"disable",0)
  }
}'

#%IU% counter
#%MDESC% hook macro for "user_getcounts" ,
# called implicitly when you use "ct", "count" or a scan macro.
# Reads the lock-in amplifier output via GPIB. %BR%
# The result is stored in the global array S in S[counter].

def lockin_read '
{
  local c channel address

  c = cnt_num ("$1")

  if (c != -1)
  {
    channel = LOCKIN["$1/channel"]
    address = LOCKIN["$1/address"]

    if (channel && address && !LOCKIN[t=address"/error"])
    {
      S[c] = lockin_voltage (address,channel) * counter_par (c,"scale")
    }
    else S[c] = 0

    if (isNaN (S[c])) S[c] = 0
  }
}'

#%IU% (gpib_address,channel)
#%MDESC% Reads the lock-in amplifier output via GPIB and returns the result.
# Channel can be "A" or "B".
# Which parameter is read (X,Y,R,theta) is detemined by the front panel settings.
# The result can be a voltage in units of V, a current in units of A or a phase
# in deg.
# If an error occurrs NaN (not a number) is returned.

def lockin_voltage (address,channel) '{
  local HDW_ERR query counts t n voltage

  if (! (channel == "1" || channel == "2")) return NaN

  LOCKIN[t=address"/error"] = 1

  HDW_ERR = -1 # do not reset to command prompt on error
  n = gpib_put(address,query="OUTR?"channel)
  # With a shared GPIB-ENET the error condidtion "Not CIC or lost CIC during
  # command" occurs frequently. In this case try again.
  if (HDW_ERR == 4 ) n = gpib_put(address,query="OUTR?"channel)
  if (n == -1) return NaN
  voltage = gpib_get(address)
  if (voltage == "") return NaN

  delete LOCKIN[t=address"/error"]

  return voltage
}'

#%IU% %MDESC% "Not a Number" - placeholder for invalid numeric value

def NaN '(1e1000/1e1000)'

#%IU% (x)
#%MDESC% check whether x is an ivalid numeric value, "Not a Number"

def isNaN(x) '{return(x+1e1000==x)}'

#%MACROS% %IMACROS%

#%INTERNALS%
# The following GPIB command is used:
#%DL%
#%DT% OUTR?i
#%DD% Read the value of the CH1 or CH2 display. The parameter i selects the 
# display (i=1 or 2). Values are returned as ASCII floating point numbers 
# with units of the display.
#%XDL%
#%BR%

#%AUTHOR% Friedrich Schotte, 29 Mar 2000