esrf

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

#%NAME% LOCKIN.MAC - Stanford Research SR830 Lockin-Amplifier
#%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.

#%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 '{
  global LOCKIN_PAR[]
  local usage aux1 aux2 address average
  local cnts ncnts tcnts[] ii radix
	local lockin_cnt[] mne

  LOCKIN_PAR[1]  = "X"
  LOCKIN_PAR[2]  = "Y"
  LOCKIN_PAR[3]  = "R"
  LOCKIN_PAR[4]  = "th"
  LOCKIN_PAR[5]  = "in1"
  LOCKIN_PAR[6]  = "in2"
  LOCKIN_PAR[7]  = "in3"
  LOCKIN_PAR[8]  = "in4"
  LOCKIN_PAR[9]  = "freq"
  LOCKIN_PAR[10] = "tr1"
  LOCKIN_PAR[11] = "tr2"
  LOCKIN_PAR[12] = "tr3"
  LOCKIN_PAR[13] = "tr4"
  
  aux1 = "usage: $0 gpib=n average=yes|no counters=i,j.. cnt_radix"
	aux2 = "\"counters\" parameter is a list of integer separated by coma (see manual p. 6-23)"
	usage = sprintf("%s\n\n%s\n", aux1, aux2)

  if ($# != 4) { print usage; exit }
  if (sscanf("$1","gpib=%s",address) != 1)    { print usage; exit }
  if (sscanf("$2","average=%s",average) != 1) { print usage; exit }
  if (sscanf("$3","counters=%s",cnts) != 1) { print usage; exit }
  if (! (average == "yes" || average == "no"))   { print usage; exit }

  radix = "$4"
	
  ncnts = split(cnts,tcnts,",")
  for (ii=0 ; ii<ncnts ; ii++) {
    if ((tcnts[ii] < 1) && (tcnts[ii] > 13)) {
      print usage
      exit
    } else {
		  mne = sprintf("%s_%s", radix, LOCKIN_PAR[tcnts[ii]])
      if (cnt_num(mne) == -1) {
			  printf("$0: Define \"%s\" as a counter in \"config\"\n",mne)
				exit
		  }
		  lockin_cnt[ii]["index"] = tcnts[ii]
			lockin_cnt[ii]["mne"]   = mne
		}
  }
  
	lockin_delcnt
	
	LOCKIN_PAR["address"] = address
  LOCKIN_PAR["average"] = average
	LOCKIN_PAR["counters"]   = cnts
	LOCKIN_PAR["ncnt"]    = ncnts
	for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
    LOCKIN_PAR[ii]["index"] = lockin_cnt[ii]["index"]
    LOCKIN_PAR[ii]["mne"]   = lockin_cnt[ii]["mne"]
	  LOCKIN_PAR[ii]["value"] = 0
	  LOCKIN_PAR[ii]["count"] = 0
	}
}'


#%UU%
#%MDESC% clear lockin parameter structure
def lockin_delcnt '{
  local ii
	
	for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
	  delete LOCKIN_PAR[ii]["index"]
	  delete LOCKIN_PAR[ii]["mne"]
	  delete LOCKIN_PAR[ii]["value"]
	  delete LOCKIN_PAR[ii]["count"]
  }
	LOCKIN_PAR["ncnt"] = 0
}'

#%UU%
#%MDESC% print status info

def lockin_info '{
  local ii c disabled
	
  if (LOCKIN_PAR["ncnt"] != 0)
	  print "\nStanford Research SR830 lock-in amplifier\n\n"
  else
	  print "no lock-in amplifier software counters are currently defined"

  printf("GPIB address : %s\n", LOCKIN_PAR["address"])
	printf("COUNTERS :\n")
  for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
    c = cnt_num(LOCKIN_PAR[ii]["mne"])
		disabled = counter_par(c,"disable")
		printf("  \"%s\" %s\n", LOCKIN_PAR[ii]["mne"], disabled?"(disabled)":"")
  }
}'


#%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 n

  address = LOCKIN_PAR["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_PAR["error"]
    } else {
      LOCKIN_PAR["error"] = 1
      printf("RS850 Lock-In Amplifier (GPIB=%d) is unusable.", address)
			
			for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
        c = cnt_num(LOCKIN_PAR[ii]["mne"])
        if (c != -1) {
				  S[c] = 0
					counter_par(c,"disable",1)
				}
      }
    }
	}
}'

#%UU%
#%MDESC% undo "lockin_define"
def lockin_undefine '{
  local ii c

  cdef ("","","lockin","delete")

	for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
    c = cnt_num(LOCKIN_PAR[ii]["mne"])
    if (c != -1) {
			S[c] = 0
			counter_par(c,"disable",1)
		}
  }

  unglobal LOCKIN_PAR
}'


#%UU%
#%MDESC% disable all Lock-in amplifier software counters
def lockin_off '{
  local ii c

  cdef ("","","lockin","delete")

	for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
    c = cnt_num(LOCKIN_PAR[ii]["mne"])
    if (c != -1) {
			S[c] = 0
			counter_par(c,"disable",1)
		}
  }
}'

#%UU%
#%MDESC% undo "lockin_off" - re-enable all Lock-in amplifier software counters
def lockin_on '{
  local ii c

  cdef("user_getpangles", "lockin_getpangles\n", "lockin")  
  cdef("user_checkall", "lockin_checkall\n", "lockin")  
  cdef("user_precount", "lockin_precount\n", "lockin")
  cdef("user_getcounts", "lockin_getcounts\n", "lockin")
  cdef("user_pollcounts", "lockin_getcounts\n", "lockin")
  cdef("config_mac","lockin_check\n","lockin")
	
	for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
    c = cnt_num(LOCKIN_PAR[ii]["mne"])
    if (c != -1)
			counter_par(c,"disable",0)
  }
}'

#%IU%
#%MDESC% hook macro for "user_getpangles"
def lockin_getpangles '{
    local n 
    local motnum
    motnum = motor_num("lkf") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], "freq ?\n")
        A[motnum]= gpib_get(LOCKIN_PAR["address"])
    }

    motnum = motor_num("lkp") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], "phas ?\n")
        A[motnum]= gpib_get(LOCKIN_PAR["address"])
    }

    motnum = motor_num("lks") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], "sens ?\n")
        A[motnum]= gpib_get(LOCKIN_PAR["address"])
    }

    motnum = motor_num("lko") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], "oflt ?\n")
        A[motnum]= gpib_get(LOCKIN_PAR["address"])
    }

    motnum = motor_num("lka") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], "slvl ?\n")
        A[motnum]= gpib_get(LOCKIN_PAR["address"])
    }
}'

#%IU%
#%MDESC% hook macro for "user_checkall"
def lockin_checkall '{
    local n 
    local motnum
    motnum = motor_num("lkf") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], sprintf("freq %.3f\n", A[motnum]))
    }

    motnum = motor_num("lkp") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], sprintf("phas %.4f\n", A[motnum]))
    }

    motnum = motor_num("lks") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], sprintf("sens %d\n", A[motnum]))
    }

    motnum = motor_num("lko") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], sprintf("oflt %d\n", A[motnum]))
    }

    motnum = motor_num("lka") 
    if (motnum >= 0){
        n=gpib_put(LOCKIN_PAR["address"], sprintf("slvl %.4f\n", A[motnum]))
    }
}'

#%IU% counter
#%MDESC% hook macro for "user_precount" ,
# called implicitly when you use "ct", "count" or a scan macro.
# Initialize Reads the lock-in amplifier output via GPIB. %BR%
def lockin_precount '{
  local ii

  if (LOCKIN_PAR["average"] == "yes") {

    for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
      LOCKIN_PAR[ii]["value"] = 0
			LOCKIN_PAR[ii]["count"] = 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_getcounts '{
  local comm aux ii mne n tval[] val

  if (!LOCKIN_PAR["error"]) {
		for (ii=0 ; ii<LOCKIN_PAR["ncnt"] ; ii++) {
		  comm = sprintf("OUTP?%d", LOCKIN_PAR[ii]["index"])
  	 	val = lockin_read(comm)
  		if (isNaN(val)) 
        val = 0
		  mne = cnt_num(LOCKIN_PAR[ii]["mne"])
	  	val *= counter_par(mne,"scale")

			if (LOCKIN_PAR["average"] == "yes") {
      	LOCKIN_PAR[ii]["value"] += val
      	LOCKIN_PAR[ii]["count"] += 1
				if (LOCKIN_PAR[ii]["count"] != 0)
				  S[mne] = LOCKIN_PAR[ii]["value"] / LOCKIN_PAR[ii]["count"]
			} else {
        S[mne] = val
		  }
    }
  }
}'

#%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_read(comm) '{
  local HDW_ERR query n ret

  HDW_ERR = -1 # do not reset to command prompt on error
	
	query = sprintf("%s\n", comm)
	
  n = gpib_put(LOCKIN_PAR["address"],query)
	
  # 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(LOCKIN_PAR["address"],query)
		 
  if (n == -1)
	  return(NaN)
		
  ret = gpib_get(LOCKIN_PAR["address"])
  if (ret == "")
	  return(NaN)

  delete LOCKIN_PAR["error"]

  return(ret)
}'

#%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)}'


def lockin_talk '{
  local comm addr n query ret
  
  if ($# != 2) {
    p "Usage : lockin_talk [GPIB addr] [command]"
    exit
  }
  
  addr = "$1"
  comm = "$2"

  query = sprintf("%s\n", comm)
  n = gpib_put(addr,query)
  printf("Send command .. : %s\n",comm)
  if (index(comm, "?") != 0) {
    ret = gpib_get(addr)
    printf("Return value . : %s\n", ret)
  }
}'

def lockin_scan_on '{
  cdef("measure0", "lockin_scan_start\n", "lockin_scan")
	cdef("measure1", "lockin_scan_read\n", "lockin_scan")
}'

def lockin_scan_off '{
	cdef("", "", "lockin_scan", "delete")
}'

def lockin_scan_setup '{
  local addr
	
	if ($# != 3) {
	  p "Usage : lockin_scan_setup [scan time] [sample time] [sleep time]"
		exit
  }
	
  LOCKIN_PAR["time"] = $1
	LOCKIN_PAR["sample"] = $2
	LOCKIN_PAR["wait_time"] = $3
	
	addr = LOCKIN_PAR["address"]
	
	gpib_put(addr, sprintf("SLEN%d\n", LOCKIN_PAR["time"]))
	gpib_put(addr, sprintf("SRAT%d\n", LOCKIN_PAR["sample"]))
	gpib_put(addr, "SEND0\n")
}'

def lockin_getparam '{
  local addr res_str fname
	
	ct
	getE
	temp=hc_over_e/LAMBDA
	addr = LOCKIN_PAR["address"]
	fname = sprintf("%s.lockin", DATAFILE)
	
	res_str = "#PAR "
	res_str = sprintf("%sI0=%g ", res_str, S[37])
	res_str = sprintf("%sNRJ=%g  ", res_str, temp)

	open(fname)
	fprintf(fname, "\n%s", res_str)
  close(fname)

  res_str = "#PAR "
	
  gpib_put(addr, "IGAN?\n")
	res_str = sprintf("%sIGAN=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "ICPL?\n")
	res_str = sprintf("%sICPL=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "FMOD?\n")
	res_str = sprintf("%sFMOD=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "FREQ?\n")
	res_str = sprintf("%sFREQ=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "RSLP?\n")
	res_str = sprintf("%sRSLP=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "SLVL?\n")
	res_str = sprintf("%sSLVL=%g  ", res_str, gpib_get(addr))

	open(fname)
	fprintf(fname, "\n%s\n", res_str)
  close(fname)
	
  res_str = "#PAR "
	
  gpib_put(addr, "SENS?\n")
	res_str = sprintf("%sSENS=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "RSRV?\n")
	res_str = sprintf("%sRSRV=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "OFLT?\n")
	res_str = sprintf("%sOFLT=%g  ", res_str, gpib_get(addr))
	
  gpib_put(addr, "OFSL?\n")
	res_str = sprintf("%sOFSL=%g  ", res_str, gpib_get(addr))

	open(fname)
	fprintf(fname, "%s\n", res_str)
  close(fname)
}'

def lockin_scan '{
	local fname
#$#
	
	if ($# == 2) {
	  mne = "$1"
		ct_time = $2
		
		if (cnt_num(mne) == -1) {
		  printf("Counter \"%s\" not define, exit !!!\n")
			exit
		}
	}
	
#	lockin_getparam

  if ($# == 2) {
  	waitcount ; get_counts
		count_em ct_time
		waitcount ; get_counts
	  fname = sprintf("%s.lockin", DATAFILE)
		open(fname)
		fprintf(fname, "\n#I0  %s=%g  time=%g\n", mne, S[cnt_num(mne)], ct_time)
  	close(fname)
  }
	
  lockin_scan_start
	
	lockin_scan_read

  if ($# == 2) {
  	waitcount ; get_counts
		count_em ct_time
		waitcount ; get_counts
	  fname = sprintf("%s.lockin", DATAFILE)
		open(fname)
		fprintf(fname, "\n#I0  %s=%g  time=%g\n", mne, S[cnt_num(mne)], ct_time)
  	close(fname)
  }
}'

def lockin_scan_start '{
  local addr
	
	addr = LOCKIN_PAR["address"]

	LOCKIN_PAR["start_time"] = time()

	gpib_put(addr, "REST\n")
	gpib_put(addr, "STRT\n")
}'

def lockin_scan_read '{
  local sleep_time nbp str_aux stp beg rep_str[] parnum ii fname
	local par1[] par2[] par3[] par4[]

	fname = sprintf("%s.lockin", DATAFILE)
	open(fname)
	
	fprintf(fname, "\n#S %d\n", ++LOCKIN_PAR["SCAN_N"])
	fprintf(fname, "#ASPEC %d %d\n", SCAN_N, NPTS)
	fprintf(fname, "#PAR SCAN_TIME=%g  SAMPLE_RATE=%d POLARIZATION=%g",\
                              LOCKIN_PAR["time"], LOCKIN_PAR["sample"], \
                              _nhq204m_get())
	close(fname)
        lockin_getparam
        open(fname)
        
	sleep_time = LOCKIN_PAR["time"] \
	             - (time()-LOCKIN_PAR["start_time"])  \
							 + LOCKIN_PAR["wait_time"]

	if(sleep_time>0)
		sleep(sleep_time) 
	
	addr = LOCKIN_PAR["address"]
	
	gpib_put(addr, "SPTS?1\n")
	nbp = gpib_get(addr)
	fprintf(fname, "#P %d\n", nbp)
	fprintf(fname, "#C X Y R Theta\n")
	
  for (parnum=1 ; parnum<=4 ; parnum++) {
		for(rep_str[parnum]="",stp=30,beg=0,i=int(nbp/stp)+1 ; i ; i--) {
			gpib_put(addr, sprintf("TRCA?%d,%d,%d", parnum, beg,(i!=1)?stp:(nbp%stp)))
  		str_aux = gpib_get(addr)
			if (substr(str_aux, length(str_aux), 1) == ",\n") {
				print "ERROR: unable to get "stp" values from LOCKIN"
				print "giving up (hint: try to request less values)"
				exit
			}
			rep_str[parnum] = sprintf("%s%s", rep_str[parnum], str_aux)
			beg+=stp
		}
  }
	
	split(rep_str[1], par1, ",")
	split(rep_str[2], par2, ",")
	split(rep_str[3], par3, ",")
	split(rep_str[4], par4, ",")
	
  for (ii=0 ; ii<nbp ; ii++)
	  fprintf(fname, "%g %g %g %g\n", par1[ii], par2[ii], par3[ii], par4[ii])

	close(fname)
}'

#%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