esrf

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

#%TITLE% LAKESHORE#$)_ADDONDS.MAC - addtional functions for Lakeshore 340 temperature controller
#%UU% [percentage]
#%MDESC% Without argument, reads and prints the manual heater output value. With argument, sets the manual heater output to the specified value
def lsmout '{
        local reply,heater,flag

        flag = 0

        if($# == 0){
                # Display
                reply = _ls_read_mout()
                if(reply=="LSREADERROR"){
                        printf("Error reading lakeshore\n")
                        exit
                }
                printf("Manual heater output is %5.2f\n",reply)
                flag = 1
        }

        if($# == 1){
                # Set
                if (($1<0) || ($1>100)) {
                  print "manual heater output can be in range 0 to 100 only."
                  exit
                }
                reply = _ls_set_mout("$1")
                if(reply=="LSREADERROR"){
                        printf("Error reading lakeshore\n")
                        exit
                }
                comment "Lakeshore manual heater output set to  %5.2f" reply
                flag=1
        }

        if(flag==0){
                printf("Syntax : lsmout [<range>]\n")
                exit
        }
}'
#%IU% ()
#%MDESC% Read and return the manual heater output.
def _ls_read_mout() '{
        local rtn
        rtn = _ls_read("MOUT? 1")
        return rtn
}'
#%IU% (percentage)
#%MDESC% Set heater 1 to specified percentage.
def _ls_set_mout(percentage) '{
        local rtn

        rtn = _ls_send(sprintf("MOUT 1,%f",percentage))
        if(rtn=="LSREADERROR")
                return rtn
        rtn = _ls_read_mout()
        return rtn
}'
#%UU% 
#%MDESC% Read and display the total heater output (PID + manual offset) 
def lshtr '{
        local reply, flag

        flag = 0

        if($# == 0){
                # Display
                reply = _ls_read_htr()
                if(reply=="LSREADERROR"){
                        printf("Error reading lakeshore\n")
                        exit
                }
                printf("Total heater output is %5.2f\n",reply)
                flag = 1
        }

        if(flag==0){
                printf("Syntax : lshtr \n")
                exit
        }
}'
#%IU% ()
#%MDESC% Read and return the total heater output (PID+manual offset)
def _ls_read_htr() '{
        local rtn
        rtn = _ls_read("HTR?")
        return rtn
}'
def lspower '{
local loopnr htrrange
  if ($#==0) {loopnr=1}
  else {loopnr=$1}
  htrrange=_ls_read_heater()
  printf("%.2f percent heater power (incl. %.2f percent manual) of heater range %d.\n",_ls_read_htr(), _ls_read_mout(),htrrange)
  reply=_ls_read(sprintf("CDISP? %d",loopnr))
  replyitems=split(reply,myparts,",")
  storedR=__lsRvalue(myparts[1])
  printf("Stored heater resistance is %d Ohm.\n",storedR)
  reply=_ls_read(sprintf("CLIMIT? %d",loopnr))
  replyitems=split(reply,myparts,",")
  curval=myparts[3]*1  
  if (curval==1) {max_curr=0.25}
  else if (curval==2) {max_curr=0.5}
  else if (curval==3) {max_curr=1}
  else if (curval==4) {max_curr=2}
  else {
    reply=_ls_read("CLIMI?")
    max_curr=reply*1.0 
  }
  printf("Maximal heater current is set to %.2f A (for heater range 5, less in the other ranges).\n",max_curr)
  if (htrrange!=5) { 
    if (htrrange==4) {reducedmax=maxcurr/sqrt(10)}
    else if (htrrange==4) {reducedmax=maxcurr/sqrt(10)}
    else if (htrrange==3) {reducedmax=maxcurr/10}
    else if (htrrange==2) {reducedmax=maxcurr/10/sqrt(10)}
    else if (htrrange==1) {reducedmax=maxcurr/100}
    printf("Now, with heater range %d, the maximum current is %.2f\n",htrrange,reducedmax)
  }
  else {reducedmax=max_curr}
  max_power=reducedmax*reducedmax*storedR
  curr_power=max_power*_ls_read_htr()/100.0
  printf("Current power thus %f Watt. Maximum at 100 percent: %f Watt.\n",curr_power,max_power)  
}'
def ls_cset '{
local reply, inputchan,unitdigit,powerstate,powerupenable,loopnr
local flag
  flag=0
  if ($#==0) {
    flag=1
    print "Loop 1:"
    reply=_ls_read("CSET? 1")
    print reply
    print "Loop 2:"
    reply=_ls_read("CSET? 2")
    print reply
  }
  else if ($#==1) {
    if (($1==1) || ($1==2)) {
      print "Loop ",$1,":"
      reply=_ls_read(sprintf("CSET? %d",$1))
      print reply
      flag=1
    }
  }
  else if ($#==5){
    flag=1
    if (($1==1) || ($1==2)) {loopnr=$1}
    else {flag=0}
    if (($2=="B") || ($2=="A")) {inputchan="$2"}
    else {flag=0}
    if (($3>=1) && ($3<=3)) {unitdigit=$3}
    else if ("$3"=="K") {unitdigit=1}
    else if ("$3"=="C") {unitdigit=2}
    else if ("$3"=="Ohm") {unitdigit=3}
    else if ("$3"=="Sensor") {unitdigit=3}
    else {flag=0}
    if (("$4"=="on") || ("$4"=="ON")) {powerstate=1}
    else if (("$4"=="off") || ("$4"=="OFF")) {powerstate=0}
    else if (($4==0) || ($4==1)) {powerstate=$4}
    else {flag=0}
    if (("$5"=="on") || ("$5"=="ON")) {powerupenable=1}
    else if (("$5"=="off") || ("$5"=="OFF")) {powerupenable=0}
    else if (($5==0) || ($5==1)) {powerupenable=$5}
    else {flag=0}
    if (flag==1) {
      cmdstr=sprintf("CSET %d,%s,%d,%d,%d",loopnr,inputchan,unitdigit,powerstate,powerupenable)
      _ls_send(cmdstr)
      print "Loop ",$1,":"
      reply=_ls_read(sprintf("CSET? %d",$1))
      print reply
    }   
  }
  if (flag==0) {
    print "Usage is: ls_cset [control_loop] to query the control loop parameters."
    print "or:       ls_cset control_loop input_channel unit on/off power_up_enable"
  }
}'


def __lsRvalue(rstr) '{
local ii startdigit
  for (ii=1;ii<=3;ii++){
    if (substr(rstr,ii,1)=="0") {
      startdigit=ii+1
    }
  }
  return 1.0*substr(rstr,startdigit)
}'

def ls_heaterresistance '{
local reply, replyitmes, myparts
  flag=0
  if ($#==0) {
    flag=1
    print "Loop 1:"
    reply=_ls_read("CDISP? 1")
    replyitems=split(reply,myparts,",")
    print "Heater resistance is ",__lsRvalue(myparts[1])
    print "Loop 2:"
    reply=_ls_read("CDISP? 2")
    replyitems=split(reply,myparts,",")
    print "Heater resistance is ",__lsRvalue(myparts[1])
  }
  else if ($#==1) {
    if (($1==1) || ($1==2)) {
      print "Loop ",$1,":"
      reply=_ls_read(sprintf("CDISP? %d",$1))
      print reply
      replyitems=split(reply,myparts,",")
      print myparts
      print myparts[1]
      print "Heater resistance is ",__lsRvalue(myparts[1])
      flag=1
    }
  }
  else if ($#==2) {
    if (($1==1) || ($1==2)) {
      print "Loop ",$1,":"
      reply=_ls_read(sprintf("CDISP? %d",$1))
      replyitems=split(reply,myparts,",")
      print "Current heater resistance is ",__lsRvalue(myparts[1])
      if (($2>0) && ($2<9999)) {
        myparts[1]=sprintf("%d",int($2+0.5))
        answer=""
        for (ii=0;ii<replyitems;ii++) {
          answer=sprintf("%s,%s",answer,myparts[ii])
        }
        answer=sprintf("CDISP %d%s\n",$1,answer)
        _ls_send(answer)
        sleep(.1)
        reply=_ls_read(sprintf("CDISP? %d",$1))
        replyitems=split(reply,myparts,",")
        print "Now heater resistance is ",__lsRvalue(myparts[1])
        flag=1 
      }
    }
  }

#  if (flag==0) {
#    printf("Usage is: %s [loopnr [resistance in Ohm]]\n",$0)
#    printf("      eg: %s 1 25 \n",$0)
#  }

}'


#%IU%
#%MDESC% Switch from PID to open loop control, keeping the heater output constant. Old version, which does stays in PID mode, but with P=I=D=0. Obsolete.
def lsfreezeold '{
  local heaterout manualout
  global LSHTR LSMOUT LSP LSI LSD

  heaterout=_ls_read_htr()
  LSHTR=heaterout
  printf("heater was at %5.2f percent power.\n",heaterout)  
  manualout=_ls_read_mout() 
  LSMOUT=manualout
  printf("the manual output was at %5.2f percent power.\n",manualout)  

  print "change temporarily PID values to P=0, I=0, D=0, but remember the old ones."
    
  reply=_ls_read_pid(LS_LOOP)
  LSP=reply[0]
  LSI=reply[1]
  LSD=reply[2]

  lspid 0 0 0
  eval(sprintf("lsmout %f \n",heaterout))
  printf("The manual output is set to %5.2f percent power \n.",heaterout)

  print "LAkeshore is no more regulating, just delivering constant heater power."
  print "Previuous heater outputs and PID values are stored in variables"
  print "LSP, LSI, LSD, LSHTR and LSMOUT"
  print "type \'lsunfreeze\' to recover regulation"

}'
#%IU%
#%MDESC% Switch back from open loop to PID control. Old version that recovers PID from above. Obsolete.
def lsunfreezeold '{

  eval(sprintf("lsmout %f \n",LSMOUT))
  lspid LSP LSI LSD
  printf("PID values back to %d %d %d .\n",LSP,LSI,LSD)
  printf("Manual output back to %5.2f percent.\n",LSMOUT)

}'
#UU% <counter_mne>
#%MDESC% Defines <counter_mne> as pseudo-counter for the heater output in Watts.
def ls_heaterctr_setup '{
   if ($# != 1 ) {
      print "Usage: ls_heaterctr_setup watt_ctr"
      exit
   }
   watt_num  = cnt_num("$1")

   if (watt_num == -1) {
      print "Check counter for power calculations. Must be defined in config"
      exit
   }
   cdef("user_getcounts",sprintf("ls_heaterctr_getpos %d \n", watt_num), "$1", 0x22)
}'
#%IU% 
#%MDESC% Macro that actually makes the calculation of the power
def ls_heaterctr_getpos '{
  local htrrange maxcurr maxpower
  htrrange=_ls_read_heater()
  if (htrrange==0) {maxcurr=0}
  if (htrrange==1) {maxcurr=0.0025}
  if (htrrange==2) {maxcurr=0.0079}
  if (htrrange==3) {maxcurr=0.025}
  if (htrrange==4) {maxcurr=0.079}
  if (htrrange==5) {maxcurr=0.25}
  maxpower=maxcurr*maxcurr*83          #P=U*I and U+R*I makes P=R*I^2
  S[$1] =  _ls_read_htr()/100*maxpower
}'
#%UU%
#%MDESC% Switch from PID control to open loop, keeping the heater power constant. New version.
def lsfreeze '{
  local heaterout manualout
  global LSHTR LSMOUT LSRANGE
  heaterout=_ls_read_htr()
  LSHTR=heaterout
  manualout=_ls_read_mout() 
  LSMOUT=manualout
  LSRANGE=_ls_read_heater()
  lsmode 3 
  eval(sprintf("lsmout %f \n",heaterout))
  if (_ls_read_heater()==0) {eval(sprintf("lsheater %f \n",LSRANGE));print "reput heater range to " LSRANGE}
  #printf("The manual output is set to %5.2f percent power in open loop\n.",heaterout)
}'
#%UU%
#%MDESC% Switch back from open loop to PID control. New version.
def lsunfreeze '{
  if (_ls_read_heater()==0) {eval(sprintf("lsheater %f \n",LSRANGE));print "Occurance 5: reput heater range to " LSRANGE}
  lsmode 1
  eval(sprintf("lsmout %f \n",LSMOUT))
  if (_ls_read_heater()==0) {eval(sprintf("lsheater %f \n",LSRANGE));print "Occurance 6: reput heater range to " LSRANGE}
  #printf("Manual PID again with manual output back to %5.2f percent.\n",LSMOUT)
}'
#%UU% <target temperature> <error margin> <time window>
#%MDESC% Waits until the sample temperature is within <target_temperature> +/- <error margin> for <time window>.
def lswaitT '{
local actT finalT errormargin stabletime t0

  if ($#!=3){
    print" Usage is \'lswaitT finalT[K] errormargin[K] stabletime[sec]\' "
    exit
  }
  if (($1>=4) && ($1<=350)) {finalT=$1}
  else {
    print" Usage is \'lswaitT finalT errormargin stabletime\' "
    print" finalT must be in range 4 to 350."
    exit
  }
  if (($2>=0.001) && ($2<=50)) {errormargin=$2}
  else{ 
    print" Usage is \'lswaitT finalT errormargin stabletime\' "
    print" errormargin must be in range 0.001 to 50."
    exit
  }
  if (($3>=1) && ($3<=3600)) {stabletime=$3}
  else{ 
    print" Usage is \'lswaitT finalT errormargin stabletime\' "
    print" stabletimen must be in range 1 to 3600."
    exit
  }

  t0 = -1;
  while(1) {  
    actT=_ls_readsensor_k(0)
    printf("Current T is %6.3f K. ",actT) 
    if (fabs(actT-finalT)>=errormargin){t0=-1; printf("error is %6.3f K.                 ",actT-finalT)}
    else if (t0==-1) {t0=time()}
    else if (time()-t0>stabletime) {break}
    else {printf("Stable in between error for %4.1f seconds.",time()-t0)}
    printf("\r");sleep(1);
  }
  printf("...temperature is stable.                                         \n");
}'

#%UU%
#%MDESC% Reads a calibration curve from the controllers memory.
def lsreadcurve '{
local ii curve_num dummy header
  if ($#!=1){
    print "Usage is: lsreadcurve <curve number>"
    exit
  }
  curve_num=$1
  dummy=sprintf("CRVHDR? %d",curve_num)
  header=_ls_read(dummy)
  print header
  if (split(ans, curve, ",") != 5) {
    eprint "Funny answer from controller for curve", crv "."
  }
  for(ii=1;ii<=300;ii++){
    dummy=sprintf("CRVPT? %d,%d",curve_num,ii);
    printf("%3d: ",ii)
    print _ls_read(dummy)
  }
}'

#%UU%
#%MDESC% Communicates a calibration curve to the controller.This version is based on the lakeshore340.mac 
#%version, but features some improvements. Especially, deleting the previously stored curve, which is important
#%At ID06, all curves should be stored in the /data/id06/inhouse/lakeshore directory.
#%if the new curve has less data points.
def lswritecurve '{
local i, j, ii, dummy, crv, fname
local curve[], textline, field[], ans

  if ($# == 0) {
    print "Use macro lslistallcurves to get a list of already stored curves!"
    crv   = getval("Number of curve to be written?",21)
    print "At ID06, many curves are at /data/id06/inhouse/lakeshore ."
    printf("Current directory is: ");unix("pwd")   
    fname = getval("Filename of temperature curve?","X12379.340")
  } 
  else if ($# == 2) {
    crv = $2
    fname = "$1"
  } 
  else {
    print "Please give two or no args"
    exit
  }

  if ( (crv < 21) || (crv > 60)) {
    print "Curve number out of range."
    print "Only curves 21 to 60 may be written by the user."
    exit
  }
  if (!file_info(fname)) {
    print "File: ",fname,"does not exist!"
    exit
  }

  print "It seems better to delete previous curve now. Deleting curve ",crv
  dummy=sprintf("CRVDEL %d",crv)
  print _ls_send(dummy) 

  # this reads the existing entry
  {
    local ans
	  curve_units[1] = "mV/K"
	  curve_units[2] = "V/K"
	  curve_units[3] = "Ohm/K"
	  curve_units[4] = "log(Ohm)/K"
	  curve_units[5] = "log(Ohm)/log(K)"

	  curve_coeff[1] = "negative"
	  curve_coeff[2] = "positive"

    fmt = "%2s %-15s %-10s %-10s %-10s %-10s\n"

	  print "Readings from actual curve", crv, "in LakeShore 340 :"
	  ans = _ls_read(sprintf("CRVHDR? %d",crv))
	  if(ans == "LSREADERROR"){
		  eprint "Error reading curve header", crv
		  exit
	  }

    if (split(ans, curve, ",") != 5) {
		  eprint "Funny answer from controller for curve", crv "."
		  exit
	  }

    printf(fmt, "", curve[0], curve[1], curve_units[curve[2]], \
      curve[3], curve_coeff[curve[4]])
  }

  # scan in the informations from the head of the .340 file.
  print "reading header of data file"
  {
    local stype, sernum, dfmt, sp_lim, coeff, npts
    dfmt = sp_lim = coeff = npts = -1
	  open(fname)
	  i = 0
    textline = getline(fname, 0)
	  while(1) {
      if (split(textline, field, ":") == 1)  break # no : stop!
      # treat contents here, is that a new yacc :-)
      if (field[0] == "Sensor Model")             sscanf(field[1], "%s", stype)
      if (field[0] == "Serial Number")            sscanf(field[1], "%s", sernum)
      if (field[0] == "Data Format")              sscanf(field[1], "%d", dfmt)
      if (field[0] == "SetPoint Limit")           sscanf(field[1], "%f", sp_lim)
      if (field[0] == "Temperature coefficient")  sscanf(field[1], "%d", coeff)
      if (field[0] == "Number of Breakpoints")    sscanf(field[1], "%d", npts)
      textline = getline(fname)
    }

    # Some input checking on Rudolfs request
    if (stype == "") {
      eprint "Data file", fname, "does not have expected line for \"Sensor Model\"!"
      eprint "Aborted !"
      exit
    } else if (sernum == "") {
      eprint "Data file", fname, "does not have expected line for \"Serial Number\"!"
      eprint "Aborted !"
      exit
    } else if (dfmt == -1) {
      eprint "Data file", fname, "does not have expected line for \"Data Format\"!"
      eprint "Aborted !"
      exit
    } else if (sp_lim == -1) {
      eprint "Data file", fname, "does not have expected line for \"SetPoint Limit\"!"
      eprint "Aborted !"
      exit
    } else if (coeff == -1) {
      eprint "Data file", fname, "does not have expected line for \"Temperature coefficient\"!"
      eprint "Aborted !"
      exit
    }

    dummy = sprintf("CRVHDR %d,%s,%s,%d,%f,%d\r\n", crv, stype,\
      sernum, dfmt, sp_lim, coeff)
    print "...sending command:", dummy
	  ans = _ls_send(dummy)
	  if(ans != "LSOK"){
		  eprint "Error listing curve number ", crv "."
		  exit
	  }
  }
  # Well now, to enable for Rudolf to add a header to a simple 2-column file, we have
  # to juggle with sscanf.
  {
    local loop, ii, valunits, val_temp
    loop = 1 # index of point, valid entries 1 - 200
	  while((textline = getline(fname)) != -1) {
      if (sscanf(textline, "%d %g %g", ii, valunits, val_temp) == 3) {
        if (ii == 0 && valunits == 0 && val_temp == 0)
          continue
      } else if (sscanf(textline, "%g %g", valunits, val_temp) == 2) {
        if (valunits == 0 && val_temp == 0)
          continue
      } else {
        continue # thats probably a text line. just forget
      }

	    dummy = sprintf("CRVPT %d,%d,%1.5f,%3.3f\r\n", crv, loop, valunits, val_temp)
	    ans = _ls_send(dummy)
	    if(ans != "LSOK"){
		    eprint "Error listing curve number ", crv "."
		    exit
	    }
      print dummy
      printf(".")
      loop ++
    }
    print
    print "...sent ", loop-1, " data points"
  }
  close(fname)
  print
  print "Curve", crv, "was written to the LakeShore model 340 temperature controller."; print

  # this reads the new entry
  {
    local ans
	  curve_units[1] = "mV/K"
	  curve_units[2] = "V/K"
	  curve_units[3] = "Ohm/K"
	  curve_units[4] = "log(Ohm)/K"
	  curve_units[5] = "log(Ohm)/log(K)"

	  curve_coeff[1] = "negative"
	  curve_coeff[2] = "positive"

    fmt = "%2s %-15s %-10s %-10s %-10s %-10s\n"

	  print "Readings from actual curve", crv, " in LakeShore 340 :"
	  ans = _ls_read(sprintf("CRVHDR? %d",crv))
	  if(ans == "LSREADERROR"){
		  eprint "Error reading curve header", crv
		  exit
	  }

    if (split(ans, curve, ",") != 5) {
		  eprint "Funny answer from controller for curve", crv "."
		  exit
	  }

    printf(fmt, "", curve[0], curve[1], curve_units[curve[2]], \
      curve[3], curve_coeff[curve[4]])
  }

  print "The curve will now be saved to the flash memory of the LakeShore 340."
  print "To do so, I execute the command: _ls_send(\"CRVSAV\")"
  ans = _ls_send("CRVSAV")
  if (ans != "LSOK"){
    print "Error saving curve number ", crv "."
    exit
  } 
  else {
    print "Saved curve number ", crv "."
  }
  print "To make sure the curve was written correctly you might check it on the front panel"
}'

#%MACROS%
#%IMACROS%
#%AUTHOR: Thomas Roth, 17/07/2009%