1509 lines
40 KiB
Igor
1509 lines
40 KiB
Igor
#pragma rtGlobals=3 // Use modern global access method and strict wave access.
|
|
#pragma version = 0.1
|
|
#pragma IgorVersion = 6.2
|
|
#pragma ModuleName = PearlAnneal
|
|
#include "pearl-epics"
|
|
|
|
/// @file
|
|
/// @brief ramp generator for sample annealing
|
|
///
|
|
/// the ramp generator increases/decreases the heating power
|
|
/// according to piecewise target function defined by the user in a set of waves.
|
|
/// each row of these waves describes one ramp phase.
|
|
/// the rows are processed sequentially.
|
|
///
|
|
/// target waves define when a ramp phase ends.
|
|
/// when a target is reached, the generator starts to process the next one.
|
|
/// the end point of the current phase will become the start point of the next phase.
|
|
///
|
|
/// the power target is interpolated linearly between the start and end points of a phase.
|
|
/// the ramp speed is given by the difference of the target values of the previous and current phases,
|
|
/// and the duration of the phase.
|
|
/// the power target values must be filled and be greater or equal to zero.
|
|
///
|
|
/// the temperature targets are kept constant.
|
|
/// once a temperature target has been reached, the phase ends.
|
|
/// temperature targets are not enforced.
|
|
/// the phase will end unconditionally when the power target is reached.
|
|
/// if you need to reach a temperature target,
|
|
/// make sure that the power target is high enough, and that the ramp is slow enough
|
|
/// so that the temperature is reached before the phase ends.
|
|
/// temperature targets can be disabled by entering NaN.
|
|
///
|
|
/// limits are not enforced.
|
|
/// if a limit is exceeded, the ramp will pause (while the power remains at its last setting).
|
|
/// the ramp resumes when the value falls below the limit.
|
|
/// limit checking can be disabled by entering NaN.
|
|
/// limits remain constant during the phase.
|
|
///
|
|
/// trips cause the ramp to stop, and the power to be turned off.
|
|
/// trip checking can be disabled by entering NaN.
|
|
/// trip values remain constant during the phase.
|
|
/// caution: do not rely on these trips for protection of equipment or the sample!
|
|
/// there may be a considerable lag between the occurrence of a trip condition
|
|
/// and the execution of a power reset!
|
|
/// either use a suitable hardware trip mechanism, or include an appropriate safety margin.
|
|
///
|
|
/// @arg minutes: minimum duration of the ramp phase in minutes.
|
|
/// determines the ramping speed.
|
|
/// the phase may take longer if pressure or temperature limits are reached.
|
|
/// required, must be greater than zero except for the first phase.
|
|
/// @arg target_watts: power setpoint at the end of the phase.
|
|
/// required, must be greater or equal to zero.
|
|
/// @arg target_tempA: temperature target of Lakeshore channel A in Kelvin.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg target_tempB: temperature target of Lakeshore channel B in Kelvin.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg target_tempPy: temperature target of the pyrometer in Kelvin.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg limit_pressure: vacuum pressure limit in mbar.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg trip_tempA: trip temperature of sensor A in Kelvin.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg trip_tempB: trip temperature of sensor B in Kelvin.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg trip_tempPy: trip temperature of pyrometer in Kelvin.
|
|
/// optional, specify NaN to disable.
|
|
/// @arg trip_pressure: trip pressure in mbar.
|
|
/// optional, specify NaN to disable.
|
|
///
|
|
/// at the beginning of the table, a row with the current setpoints (normally zero at the beginning of a ramp) and zero duration must be included.
|
|
/// note that the power supply will remain at its last setpoint after the ramp.
|
|
/// thus, the last row should bring the power supply to a safe end value, e.g. zero.
|
|
///
|
|
/// @pre
|
|
/// run-time requirements for online mode at the beamline
|
|
/// * EPICS.XOP of Paul Scherrer Institut, version 0.3.0 (March 2015) or later, must be loaded.
|
|
/// * caRepeater.exe program (from EPICS distribution) must be running.
|
|
///
|
|
/// @author matthias muntwiler, matthias.muntwiler@psi.ch
|
|
///
|
|
/// @copyright 2015 Paul Scherrer Institut @n
|
|
/// Licensed under the Apache License, Version 2.0 (the "License"); @n
|
|
/// you may not use this file except in compliance with the License. @n
|
|
/// You may obtain a copy of the License at
|
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
/// @namespace PearlAnneal
|
|
/// @brief ramp generator for sample annealing
|
|
///
|
|
/// PearlAnneal is declared in @ref pearl-anneal.ipf.
|
|
///
|
|
|
|
static strconstant package_name = "pearl_anneal"
|
|
static strconstant package_path = "root:packages:pearl_anneal:"
|
|
// semicolon-separated list of persistent variable, string, and wave names
|
|
static strconstant prefs_objects = ""
|
|
|
|
static function AfterCompiledHook()
|
|
// initializes package data once when the procedure is first loaded
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
variable do_init = 1
|
|
if (DataFolderExists(package_path))
|
|
setdatafolder $(package_path)
|
|
nvar /z init_done
|
|
if (nvar_exists(init_done))
|
|
if (init_done)
|
|
do_init = 0
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
if (do_init)
|
|
init_package()
|
|
load_prefs()
|
|
setdatafolder $(package_path)
|
|
variable /g init_done = 1
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|
|
|
|
/// initialize the package data folder
|
|
///
|
|
/// create the package data folder, and all necessary control and data objects.
|
|
/// reset all variables.
|
|
static function init_package()
|
|
dfref savedf = getdatafolderdfr()
|
|
setdatafolder root:
|
|
newdatafolder /o/s packages
|
|
newdatafolder /o/s $package_name
|
|
|
|
// configuration (persistent)
|
|
string /g graphname = "graph_anneal_tracker"
|
|
string /g dataname = "anneal"
|
|
|
|
// recently used (persistent)
|
|
|
|
// recently used (volatile)
|
|
|
|
// run-time variables (volatile)
|
|
string /g controls, monitors
|
|
variable /g psu_connected = 0
|
|
variable /g ls_connected = 0
|
|
variable /g pyro_connected = 0
|
|
variable /g vac_connected = 0
|
|
|
|
// channel ID
|
|
variable /g chidSetVolts = 0
|
|
variable /g chidGetVolts = 0
|
|
variable /g chidSetAmps = 0
|
|
variable /g chidGetAmps = 0
|
|
variable /g chidGetWatts = 0
|
|
variable /g chidSetOnOff = 0
|
|
variable /g chidGetOnOff = 0
|
|
variable /g chidStatCC = 0
|
|
variable /g chidStatCV = 0
|
|
variable /g chidGetRemote = 0
|
|
|
|
variable /g chidGetTempA = 0
|
|
variable /g chidGetTempB = 0
|
|
variable /g chidGetPyro1 = 0
|
|
variable /g chidGetPyroQ = 0
|
|
|
|
variable /g chidGetPressure = 0
|
|
|
|
// current PV values
|
|
variable /g curGetVolts = 0
|
|
variable /g curSetVolts = 0
|
|
variable /g curGetAmps = 0
|
|
variable /g curSetAmps = 0
|
|
variable /g curGetWatts = 0
|
|
variable /g curSetWatts = 0
|
|
variable /g curGetOnOff = 0
|
|
variable /g curStatCC = 0
|
|
variable /g curStatCV = 0
|
|
|
|
variable /g curGetTempA = 0
|
|
variable /g curGetTempB = 0
|
|
variable /g curGetPyro1 = 0
|
|
variable /g curGetPyroQ = 0
|
|
|
|
variable /g curGetPressure = 0
|
|
|
|
// current phase indicators
|
|
variable /g curTargetWatts = nan
|
|
variable /g curTargetTempA = nan
|
|
variable /g curTargetTempB = nan
|
|
variable /g curTargetTempPy = nan
|
|
variable /g curTripTempA = nan
|
|
variable /g curTripTempB = nan
|
|
variable /g curTripTempPy = nan
|
|
variable /g curLimitPressure = nan
|
|
variable /g curTripPressure = nan
|
|
variable /g curPhaseMinutes = 0
|
|
|
|
// chart control and data
|
|
make /n=500 /o recVolts, recAmps, recWatts, recTemp, recPressure, recMinutes
|
|
variable /g recPoint
|
|
variable /g recMinutesStart
|
|
recPoint = 0
|
|
recMinutesStart = datetime / 60
|
|
|
|
// ramp status: 1 = running, 0.5 = paused, 0 = off
|
|
variable /g ramp_status
|
|
// index of the current ramp phase
|
|
variable /g ramp_phase
|
|
// ramping direction +1 = up, -1 = down
|
|
variable /g ramp_dir
|
|
// system time in minutes at the start of the current phase
|
|
variable /g minutes_start
|
|
// system time in minutes at the time of the previous step
|
|
variable /g minutes_previous
|
|
// status message for user
|
|
string /g ramp_message
|
|
|
|
ann_new_ramp_table(edit_table=0)
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
static function save_prefs()
|
|
// saves persistent package data to the preferences file
|
|
dfref saveDF = GetDataFolderDFR()
|
|
|
|
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
|
|
fullPath += package_name
|
|
NewPath/O/C/Q tempPackagePrefsPath, fullPath
|
|
fullPath += ":preferences.pxp"
|
|
|
|
SetDataFolder root:packages
|
|
SetDataFolder $package_name
|
|
SaveData /O /Q /J=prefs_objects fullPath
|
|
|
|
KillPath/Z tempPackagePrefsPath
|
|
|
|
SetDataFolder saveDF
|
|
end
|
|
|
|
static function load_prefs()
|
|
// loads persistent package data from the preferences file
|
|
// the preferences file is an Igor packed experiment file in a special preferences folder
|
|
dfref saveDF = GetDataFolderDFR()
|
|
|
|
variable result = -1
|
|
setdatafolder root:
|
|
NewDataFolder /O/S packages
|
|
NewDataFolder /O/S $package_name
|
|
string fullPath = SpecialDirPath("Packages", 0, 0, 0)
|
|
fullPath += package_name
|
|
|
|
GetFileFolderInfo /Q /Z fullPath
|
|
if (V_Flag == 0) // Disk directory exists?
|
|
fullPath += ":preferences.pxp"
|
|
GetFileFolderInfo /Q /Z fullPath
|
|
if (V_Flag == 0) // Preference file exist?
|
|
LoadData /O /R /Q fullPath
|
|
result = 0
|
|
endif
|
|
endif
|
|
|
|
SetDataFolder saveDF
|
|
return result
|
|
end
|
|
|
|
/// save current ramp table
|
|
///
|
|
/// WORK IN PROGRESS
|
|
static function save_ramp()
|
|
dfref saveDF = GetDataFolderDFR()
|
|
|
|
SetDataFolder root:packages
|
|
SetDataFolder $package_name
|
|
|
|
wave minutes
|
|
wave target_watts
|
|
wave target_tempA
|
|
wave target_tempB
|
|
wave target_tempPy
|
|
wave trip_tempA
|
|
wave trip_tempB
|
|
wave trip_tempPy
|
|
wave limit_pressure
|
|
wave trip_pressure
|
|
|
|
Save /T /M="\r\n" /I minutes,target_watts,target_tempPy,target_tempB,target_tempA,limit_pressure,trip_tempPy,trip_tempB,trip_tempA,trip_pressure as "anneal-ramp.itx"
|
|
|
|
SetDataFolder saveDF
|
|
end
|
|
|
|
/// Igor sometimes crashes if the PVs are not disconnected when it quits
|
|
static function IgorQuitHook(app)
|
|
string app
|
|
epics_disconnect()
|
|
end
|
|
|
|
/// connect to all required EPICS devices.
|
|
///
|
|
/// can be called repeatedly. the function exits gracefully if connections are existing.
|
|
///
|
|
/// @return zero if successful, non-zero if an error occurred
|
|
static function epics_connect()
|
|
dfref savedf = getdatafolderdfr()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar psu_connected
|
|
nvar ls_connected
|
|
nvar vac_connected
|
|
nvar pyro_connected
|
|
|
|
if (!psu_connected)
|
|
epics_connect_psu()
|
|
endif
|
|
if (!ls_connected)
|
|
epics_connect_ls()
|
|
endif
|
|
if (!vac_connected)
|
|
epics_connect_vac()
|
|
endif
|
|
if (!pyro_connected)
|
|
epics_connect_pyro()
|
|
endif
|
|
|
|
setdatafolder saveDF
|
|
return !(psu_connected && ls_connected && vac_connected && pyro_connected)
|
|
end
|
|
|
|
/// connect to the power supply unit
|
|
///
|
|
/// if the EPICS XOP is not loaded, the function does nothing.
|
|
/// if channels are not available, the function exits with an error code.
|
|
/// the run-time error status is reset.
|
|
///
|
|
/// @return zero if successful, non-zero if an error occurred
|
|
///
|
|
/// @todo the X03DA channel names are hard-coded.
|
|
static function epics_connect_psu()
|
|
dfref savedf = getdatafolderdfr()
|
|
setdatafolder $(package_path)
|
|
|
|
// create variables and waves
|
|
nvar connected = psu_connected
|
|
svar ramp_message
|
|
|
|
// channel ID variables
|
|
nvar chidSetVolts
|
|
nvar chidGetVolts
|
|
nvar chidSetAmps
|
|
nvar chidGetAmps
|
|
nvar chidGetWatts
|
|
nvar chidSetOnOff
|
|
nvar chidGetOnOff
|
|
nvar chidStatCC
|
|
nvar chidStatCV
|
|
nvar chidGetRemote
|
|
|
|
nvar curGetVolts
|
|
nvar curGetAmps
|
|
nvar curGetWatts
|
|
nvar curGetOnOff
|
|
nvar curStatCC
|
|
nvar curStatCV
|
|
|
|
string psu_name = "X03DA-PSU-XP:"
|
|
variable timeout = 5 // seconds
|
|
|
|
#if exists("pvWait")
|
|
// EPICS.XOP version 0.3.0 or later
|
|
pvOpen /Q chidSetVolts, psu_name + "SETVOLTS"
|
|
pvOpen /Q chidGetVolts, psu_name + "GETVOLTS"
|
|
pvOpen /Q chidSetAmps, psu_name + "SETCUR"
|
|
pvOpen /Q chidGetAmps, psu_name + "GETCUR"
|
|
pvOpen /Q chidGetWatts, psu_name + "CALCPWR"
|
|
pvOpen /Q chidSetOnOff, psu_name + "SETONOFF"
|
|
pvOpen /Q chidGetOnOff, psu_name + "GETONOFF"
|
|
pvOpen /Q chidGetRemote, psu_name + "COMGETRMT" // string
|
|
pvOpen /Q chidStatCC, psu_name + "STAT-CC"
|
|
pvOpen /Q chidStatCV, psu_name + "STAT-CV"
|
|
|
|
pvWait timeout
|
|
#endif
|
|
|
|
if (GetRTError(1))
|
|
connected = 0
|
|
ramp_message = "PSU: no connection"
|
|
else
|
|
connected = 1
|
|
endif
|
|
|
|
#if exists("pvMonitor")
|
|
if (connected)
|
|
pvMonitor chidGetVolts, curGetVolts
|
|
pvMonitor chidSetVolts, curSetVolts
|
|
pvMonitor chidGetAmps, curGetAmps
|
|
pvMonitor chidSetAmps, curSetAmps
|
|
pvMonitor chidGetWatts, curGetWatts
|
|
pvMonitor chidGetOnOff, curGetOnOff
|
|
pvMonitor chidStatCC, curStatCC
|
|
pvMonitor chidStatCV, curStatCV
|
|
endif
|
|
#endif
|
|
|
|
setdatafolder saveDF
|
|
return !connected
|
|
end
|
|
|
|
/// connect to the lakeshore temperature controller
|
|
///
|
|
/// if the EPICS XOP is not loaded, the function does nothing.
|
|
/// if channels are not available, the function exits with an error code.
|
|
/// the run-time error status is reset.
|
|
///
|
|
/// @return zero if successful, non-zero if an error occurred
|
|
///
|
|
/// @todo the X03DA channel names are hard-coded.
|
|
static function epics_connect_ls()
|
|
dfref savedf = getdatafolderdfr()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = ls_connected
|
|
svar ramp_message
|
|
|
|
nvar chidGetTempA
|
|
nvar chidGetTempB
|
|
|
|
nvar curGetTempA
|
|
nvar curGetTempB
|
|
|
|
string base_name = "X03DA-PC-LAKESHOREXP:"
|
|
variable timeout = 5 // seconds
|
|
|
|
#if exists("pvWait")
|
|
// EPICS.XOP version 0.3.0 or later
|
|
pvOpen /Q chidGetTempA, base_name + "A-TEMP_RBV"
|
|
pvOpen /Q chidGetTempB, base_name + "B-TEMP_RBV"
|
|
|
|
pvWait timeout
|
|
#endif
|
|
|
|
if (GetRTError(1))
|
|
connected = 0
|
|
ramp_message = "Lakeshore: no connection"
|
|
else
|
|
connected = 1
|
|
endif
|
|
|
|
#if exists("pvMonitor")
|
|
if (connected)
|
|
pvMonitor /F=ann_callback_ls chidGetTempA, curGetTempA
|
|
pvMonitor /F=ann_callback_ls chidGetTempB, curGetTempB
|
|
endif
|
|
#endif
|
|
|
|
setdatafolder saveDF
|
|
return !connected
|
|
end
|
|
|
|
/// connect to the vacuum gauge
|
|
///
|
|
/// if the EPICS XOP is not loaded, the function does nothing.
|
|
/// if channels are not available, the function exits with an error code.
|
|
/// the run-time error status is reset.
|
|
///
|
|
/// @return zero if successful, non-zero if an error occurred
|
|
///
|
|
/// @todo the X03DA channel names are hard-coded.
|
|
static function epics_connect_vac()
|
|
dfref savedf = getdatafolderdfr()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = vac_connected
|
|
svar ramp_message
|
|
|
|
nvar chidGetPressure
|
|
|
|
nvar curGetPressure
|
|
|
|
string base_name = "X03DA-PVC-XP:"
|
|
variable timeout = 5 // seconds
|
|
|
|
#if exists("pvWait")
|
|
// EPICS.XOP version 0.3.0 or later
|
|
pvOpen /Q chidGetPressure, base_name + "IG-PRESSURE"
|
|
|
|
pvWait timeout
|
|
#endif
|
|
|
|
if (GetRTError(1))
|
|
connected = 0
|
|
ramp_message = "vacuum gauge: no connection"
|
|
else
|
|
connected = 1
|
|
endif
|
|
|
|
#if exists("pvMonitor")
|
|
if (connected)
|
|
pvMonitor /F=ann_callback_pvc chidGetPressure, curGetPressure
|
|
endif
|
|
#endif
|
|
|
|
setdatafolder saveDF
|
|
return !connected
|
|
end
|
|
|
|
/// connect to the pyrometer
|
|
///
|
|
/// if the EPICS XOP is not loaded, the function does nothing.
|
|
/// if channels are not available, the function exits with an error code.
|
|
/// the run-time error status is reset.
|
|
///
|
|
/// @return zero if successful, non-zero if an error occurred
|
|
///
|
|
/// @todo the X03DA channel names are hard-coded.
|
|
///
|
|
/// IOC implemented in LabView
|
|
/// X03DA-LV-MAURER:TEMP-1
|
|
/// X03DA-LV-MAURER:TEMP-Q
|
|
static function epics_connect_pyro()
|
|
dfref savedf = getdatafolderdfr()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = pyro_connected
|
|
svar ramp_message
|
|
|
|
nvar chidGetPyro1
|
|
nvar chidGetPyroQ
|
|
|
|
nvar curGetPyro1
|
|
nvar curGetPyroQ
|
|
|
|
string base_name = "X03DA-LV-MAURER:"
|
|
variable timeout = 5 // seconds
|
|
|
|
#if exists("pvWait")
|
|
// EPICS.XOP version 0.3.0 or later
|
|
pvOpen /Q chidGetPyro1, base_name + "TEMP-1"
|
|
pvOpen /Q chidGetPyroQ, base_name + "TEMP-Q"
|
|
|
|
pvWait timeout
|
|
#endif
|
|
|
|
if (GetRTError(1))
|
|
connected = 0
|
|
ramp_message = "pyrometer: no connection"
|
|
else
|
|
connected = 1
|
|
endif
|
|
|
|
#if exists("pvMonitor")
|
|
if (connected)
|
|
pvMonitor /F=ann_callback_ls chidGetPyro1, curGetPyro1
|
|
pvMonitor /F=ann_callback_ls chidGetPyroQ, curGetPyroQ
|
|
endif
|
|
#endif
|
|
|
|
setdatafolder saveDF
|
|
return !connected
|
|
end
|
|
|
|
static function epics_disconnect_chid(chid_var_name)
|
|
string chid_var_name
|
|
|
|
#if exists("pvClose")
|
|
nvar /z chid = $chid_var_name
|
|
if (nvar_exists(chid))
|
|
if (chid != 0)
|
|
pvClose chid
|
|
endif
|
|
chid = 0
|
|
endif
|
|
#endif
|
|
end
|
|
|
|
/// disconnect from all EPICS devices.
|
|
///
|
|
static function epics_disconnect()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
epics_disconnect_psu()
|
|
epics_disconnect_ls()
|
|
epics_disconnect_vac()
|
|
epics_disconnect_pyro()
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// disconnect from the power supply unit
|
|
///
|
|
static function epics_disconnect_psu()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = psu_connected
|
|
if (connected)
|
|
connected = 0
|
|
epics_disconnect_chid("chidSetVolts")
|
|
epics_disconnect_chid("chidGetVolts")
|
|
epics_disconnect_chid("chidSetAmps")
|
|
epics_disconnect_chid("chidGetAmps")
|
|
epics_disconnect_chid("chidGetWatts")
|
|
epics_disconnect_chid("chidSetOnOff")
|
|
epics_disconnect_chid("chidGetOnOff")
|
|
epics_disconnect_chid("chidGetRemote")
|
|
epics_disconnect_chid("chidStatCC")
|
|
epics_disconnect_chid("chidStatCV")
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// disconnect from the lakeshore controller
|
|
///
|
|
static function epics_disconnect_ls()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = ls_connected
|
|
if (connected)
|
|
connected = 0
|
|
|
|
epics_disconnect_chid("chidGetTempA")
|
|
epics_disconnect_chid("chidGetTempB")
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// disconnect from the vacuum gauge
|
|
///
|
|
static function epics_disconnect_vac()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = vac_connected
|
|
if (connected)
|
|
connected = 0
|
|
|
|
epics_disconnect_chid("chidGetPressure")
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// disconnect from the pyrometer
|
|
///
|
|
static function epics_disconnect_pyro()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar connected = pyro_connected
|
|
if (connected)
|
|
connected = 0
|
|
|
|
epics_disconnect_chid("chidGetPyro1")
|
|
epics_disconnect_chid("chidGetPyroQ")
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// create a new ramp table and open it in a table window.
|
|
///
|
|
/// the waves are created in the current data folder.
|
|
/// to be executed, they must be copied into the package folder.
|
|
///
|
|
function ann_new_ramp_table([edit_table])
|
|
variable edit_table
|
|
|
|
if (ParamIsDefault(edit_table))
|
|
edit_table = 1
|
|
endif
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
|
|
make /n=3 /o minutes,cum_minutes,target_watts
|
|
make /n=3 /o target_tempA, target_tempB, target_tempPy
|
|
make /n=3 /o limit_pressure
|
|
make /n=3 /o trip_tempA, trip_tempB, trip_tempPy
|
|
make /n=3 /o trip_pressure
|
|
make /n=3 /o est_temp
|
|
|
|
minutes = 1
|
|
cum_minutes = nan
|
|
target_watts[0] = {0, 5, 0}
|
|
target_tempA = nan
|
|
target_tempB = nan
|
|
target_tempPy = nan
|
|
limit_pressure = 1e-8
|
|
trip_tempA = nan
|
|
trip_tempB = 450
|
|
trip_tempPy = nan
|
|
trip_pressure = 5e-8
|
|
est_temp = nan
|
|
|
|
if (edit_table)
|
|
edit /k=1 minutes, target_watts
|
|
appendtotable target_tempA, trip_tempA
|
|
appendtotable target_tempB, trip_tempB
|
|
appendtotable target_tempPy, trip_tempPy
|
|
appendtotable limit_pressure,trip_pressure
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// initialize the background tasks
|
|
///
|
|
/// can be called repeatedly. the function exits gracefully if tasks are running.
|
|
///
|
|
function ann_init_bg()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
CtrlNamedBackground ann_ramp, period = 60, proc = PearlAnneal#ann_ramp_bg
|
|
CtrlNamedBackground ann_record, period = 600, proc = PearlAnneal#ann_record_bg
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// background task of the recorder
|
|
static function ann_record_bg(s)
|
|
STRUCT WMBackgroundStruct &s
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar curGetVolts
|
|
nvar curGetAmps
|
|
nvar curGetWatts
|
|
nvar curGetOnOff
|
|
nvar curStatCC
|
|
nvar curStatCV
|
|
|
|
nvar curGetTempA
|
|
nvar curGetTempB
|
|
nvar curGetPyro1
|
|
nvar curGetPyroQ
|
|
|
|
nvar curGetPressure
|
|
|
|
nvar recPoint
|
|
nvar recMinutesStart
|
|
|
|
wave recMinutes
|
|
wave recVolts
|
|
wave recAmps
|
|
wave recWatts
|
|
wave recTemp
|
|
wave recPressure
|
|
|
|
variable nshift = 12
|
|
variable plo
|
|
variable phi
|
|
|
|
if (recPoint >= numpnts(recWatts))
|
|
plo = 0
|
|
phi = numpnts(recWatts) - nshift - 1
|
|
recMinutes[plo, phi] = recMinutes[p + nshift]
|
|
recVolts[plo, phi] = recVolts[p + nshift]
|
|
recAmps[plo, phi] = recAmps[p + nshift]
|
|
recWatts[plo, phi] = recWatts[p + nshift]
|
|
recTemp[plo, phi] = recTemp[p + nshift]
|
|
recPressure[plo, phi] = recPressure[p + nshift]
|
|
|
|
plo = numpnts(recWatts) - nshift
|
|
phi = numpnts(recWatts) - 1
|
|
recMinutes[plo, phi] = nan
|
|
recVolts[plo, phi] = nan
|
|
recAmps[plo, phi] = nan
|
|
recWatts[plo, phi] = nan
|
|
recTemp[plo, phi] = nan
|
|
recPressure[plo, phi] = nan
|
|
|
|
recPoint = plo
|
|
endif
|
|
|
|
variable temp = curGetTempA
|
|
if (curGetPyroQ >= 625)
|
|
temp = max(temp, curGetPyroQ)
|
|
elseif (curGetPyro1 >= 625)
|
|
temp = max(temp, curGetPyro1)
|
|
endif
|
|
|
|
recMinutes[recPoint] = datetime / 60 - recMinutesStart
|
|
recVolts[recPoint] = curGetVolts
|
|
recAmps[recPoint] = curGetAmps
|
|
recWatts[recPoint] = curGetWatts
|
|
recTemp[recPoint] = temp
|
|
recPressure[recPoint] = curGetPressure
|
|
|
|
recPoint += 1
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
End
|
|
|
|
/// background task of the ramp
|
|
static function ann_ramp_bg(s)
|
|
STRUCT WMBackgroundStruct &s
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
ann_ramp_step()
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
End
|
|
|
|
/// prepare and execute the next ramp step
|
|
///
|
|
/// check trips and limits before calling ann_ramp_step_exec()
|
|
///
|
|
function ann_ramp_step()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar minutes_start
|
|
nvar minutes_previous
|
|
nvar ramp_phase
|
|
svar ramp_message
|
|
|
|
wave minutes
|
|
wave target_watts
|
|
|
|
variable minutes_now = datetime / 60
|
|
variable minutes_phase = minutes_now - minutes_start
|
|
variable minutes_step = minutes_now - minutes_previous
|
|
|
|
variable trip
|
|
variable hold
|
|
variable phase_complete
|
|
|
|
ann_ramp_update(ramp_phase)
|
|
// check trip conditions
|
|
trip = ann_ramp_trip(ramp_phase)
|
|
if (!trip)
|
|
// check hold conditions
|
|
hold = ann_ramp_hold(ramp_phase)
|
|
if (!hold)
|
|
// check targets
|
|
phase_complete = ann_ramp_target(ramp_phase)
|
|
if (!phase_complete)
|
|
// execute step
|
|
phase_complete = ann_ramp_step_exec(minutes_now)
|
|
ramp_message = ""
|
|
endif
|
|
if (phase_complete)
|
|
ramp_phase += 1
|
|
minutes_start = minutes_now
|
|
// check end of ramp
|
|
if ((ramp_phase >= numpnts(minutes)) || (ramp_phase >= numpnts(target_watts)) || numtype(minutes[ramp_phase]) || numtype(target_watts[ramp_phase]))
|
|
ann_ramp_stop(0)
|
|
endif
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
minutes_previous = minutes_now
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|
|
|
|
/// update control panel variables
|
|
static function ann_ramp_update(phase)
|
|
variable phase
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
wave minutes
|
|
wave target_watts
|
|
wave target_tempA
|
|
wave target_tempB
|
|
wave target_tempPy
|
|
wave trip_tempA
|
|
wave trip_tempB
|
|
wave trip_tempPy
|
|
wave limit_pressure
|
|
wave trip_pressure
|
|
|
|
nvar curTargetWatts
|
|
nvar curTargetTempA
|
|
nvar curTargetTempB
|
|
nvar curTargetTempPy
|
|
nvar curTripTempA
|
|
nvar curTripTempB
|
|
nvar curTripTempPy
|
|
nvar curLimitPressure
|
|
nvar curTripPressure
|
|
nvar curPhaseMinutes
|
|
|
|
curPhaseMinutes = minutes[phase]
|
|
curTargetWatts = target_watts[phase]
|
|
curTargetTempA = target_tempA[phase]
|
|
curTargetTempB = target_tempB[phase]
|
|
curTargetTempPy = target_tempPy[phase]
|
|
curTripTempA = trip_tempA[phase]
|
|
curTripTempB = trip_tempB[phase]
|
|
curTripTempPy = trip_tempPy[phase]
|
|
curLimitPressure = limit_pressure[phase]
|
|
curTripPressure = trip_pressure[phase]
|
|
|
|
setdatafolder savedf
|
|
end
|
|
|
|
/// execute the next ramp step
|
|
///
|
|
/// calculate new setpoints and update the power supply setpoints.
|
|
/// no trips and limits checked in this function.
|
|
///
|
|
/// @return zero during ramp phase, non-zero at end of ramp phase
|
|
static function ann_ramp_step_exec(minutes_now)
|
|
variable minutes_now
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar chidSetVolts
|
|
nvar chidSetAmps
|
|
|
|
nvar curGetVolts
|
|
nvar curGetAmps
|
|
nvar curGetWatts
|
|
nvar curSetVolts
|
|
nvar curSetAmps
|
|
nvar curSetWatts
|
|
|
|
nvar minutes_start
|
|
nvar minutes_previous
|
|
nvar ramp_phase
|
|
nvar ramp_dir
|
|
|
|
variable p2 = ramp_phase
|
|
variable p1 = p2 - 1
|
|
|
|
variable minutes_phase = minutes_now - minutes_start
|
|
variable minutes_step = minutes_now - minutes_previous
|
|
|
|
wave minutes
|
|
wave target_watts
|
|
|
|
variable step_watts
|
|
variable next_volts
|
|
variable next_amps
|
|
variable next_watts
|
|
variable resistance
|
|
|
|
variable max_step_volts = 0.5
|
|
variable max_step_amps = 0.1
|
|
variable max_test_volts = 5.0
|
|
variable max_test_amps = 0.5
|
|
|
|
variable watts_complete
|
|
|
|
// calculate power step
|
|
step_watts = (target_watts[p2] - target_watts[p1]) / minutes[p2] * minutes_step
|
|
next_watts = curSetWatts + step_watts
|
|
|
|
// check end of ramp phase
|
|
if (step_watts > 0.0001)
|
|
watts_complete = next_watts > target_watts[p2]
|
|
elseif (step_watts < -0.0001)
|
|
watts_complete = next_watts < target_watts[p2]
|
|
else
|
|
watts_complete = minutes_phase >= minutes[p2]
|
|
endif
|
|
|
|
// limit power
|
|
if (watts_complete)
|
|
next_watts = curSetWatts
|
|
else
|
|
next_watts = limit(next_watts, 0, max(target_watts[p1], target_watts[p2]))
|
|
endif
|
|
|
|
// calculate voltage and current
|
|
if (next_watts >= 0.1)
|
|
curSetWatts = next_watts
|
|
if ((curGetVolts > 0.1) && (curGetAmps > 0.1))
|
|
resistance = curGetVolts / curGetAmps
|
|
next_volts = limit(sqrt(next_watts * resistance), 0, curGetVolts + max_step_volts)
|
|
next_amps = limit(sqrt(next_watts / resistance), 0, curGetAmps + max_step_amps)
|
|
else
|
|
// apply small voltage to measure the resistance
|
|
next_volts = min(curSetVolts + 0.5, max_test_volts)
|
|
next_amps = min(curSetAmps + 0.1, max_test_amps)
|
|
endif
|
|
else
|
|
curSetWatts = next_watts
|
|
next_volts = 0
|
|
next_amps = 0
|
|
endif
|
|
|
|
// change setpoints
|
|
pvPutNumber /Q chidSetVolts, next_volts
|
|
pvPutNumber /Q chidSetAmps, next_amps
|
|
pvWait 5
|
|
|
|
setdatafolder savedf
|
|
return watts_complete
|
|
end
|
|
|
|
/// check trip conditions
|
|
///
|
|
/// turn of power and stop the ramp if any of the trip conditions is met.
|
|
///
|
|
/// @return non-zero if a trip condition is detected, zero if everything is okay.
|
|
static function ann_ramp_trip(phase)
|
|
variable phase
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
variable trip = 0
|
|
|
|
wave trip_tempA
|
|
wave trip_tempB
|
|
wave trip_tempPy
|
|
wave trip_pressure
|
|
|
|
nvar curGetTempA
|
|
nvar curGetTempB
|
|
nvar curGetTempPyro1
|
|
nvar curGetTempPyroQ
|
|
nvar curGetPressure
|
|
svar ramp_message
|
|
|
|
if ((phase < numpnts(trip_tempA)) && (numtype(trip_tempA[phase]) == 0) && (curGetTempA >= trip_tempA[phase]))
|
|
ramp_message = "temperature A trip"
|
|
trip = 1
|
|
endif
|
|
if ((phase < numpnts(trip_tempB)) && (numtype(trip_tempB[phase]) == 0) && (curGetTempB >= trip_tempB[phase]))
|
|
ramp_message = "temperature B trip"
|
|
trip = 2
|
|
endif
|
|
if ((phase < numpnts(trip_tempPy)) && (numtype(trip_tempPy[phase]) == 0) && (curGetTempPyro1 >= trip_tempPy[phase]))
|
|
ramp_message = "pyrometer trip (1)"
|
|
trip = 3
|
|
endif
|
|
if ((phase < numpnts(trip_tempPy)) && (numtype(trip_tempPy[phase]) == 0) && (curGetTempPyroQ >= trip_tempPy[phase]))
|
|
ramp_message = "pyrometer trip (Q)"
|
|
trip = 4
|
|
endif
|
|
if ((phase < numpnts(trip_pressure)) && (numtype(trip_pressure[phase]) == 0) && (curGetPressure >= trip_pressure[phase]))
|
|
ramp_message = "pressure trip"
|
|
trip = 5
|
|
endif
|
|
|
|
if (trip)
|
|
ann_ramp_stop(1)
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
return trip
|
|
end
|
|
|
|
/// check hold conditions
|
|
///
|
|
/// @return non-zero if a hold condition is detected, zero if everything is okay.
|
|
///
|
|
static function ann_ramp_hold(phase)
|
|
variable phase
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
nvar curGetPressure
|
|
|
|
variable hold = 0
|
|
|
|
wave limit_pressure
|
|
|
|
if ((phase < numpnts(limit_pressure)) && (numtype(limit_pressure[phase]) == 0) && (curGetPressure >= limit_pressure[phase]))
|
|
hold = 5
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
return hold
|
|
end
|
|
|
|
/// check target conditions
|
|
///
|
|
/// @return non-zero if a target reached, zero otherwise.
|
|
static function ann_ramp_target(phase)
|
|
variable phase
|
|
|
|
if (phase < 1)
|
|
return 0
|
|
endif
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
variable target = 0
|
|
|
|
wave target_watts
|
|
wave target_tempA
|
|
wave target_tempB
|
|
wave target_tempPy
|
|
|
|
variable direction_up = target_watts[phase] >= target_watts[phase - 1]
|
|
|
|
nvar curGetTempA
|
|
nvar curGetTempB
|
|
nvar curGetTempPyro1
|
|
nvar curGetTempPyroQ
|
|
svar ramp_message
|
|
|
|
if ((phase < numpnts(target_tempA)) && (numtype(target_tempA[phase]) == 0))
|
|
if (direction_up)
|
|
if (curGetTempA >= target_tempA[phase])
|
|
target = 1
|
|
endif
|
|
else
|
|
if (curGetTempA <= target_tempA[phase])
|
|
target = 1
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
if ((phase < numpnts(target_tempB)) && (numtype(target_tempB[phase]) == 0))
|
|
if (direction_up)
|
|
if (curGetTempB >= target_tempB[phase])
|
|
target = 2
|
|
endif
|
|
else
|
|
if (curGetTempB <= target_tempB[phase])
|
|
target = 2
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
if ((phase < numpnts(target_tempPy)) && (numtype(target_tempPy[phase]) == 0))
|
|
if (direction_up)
|
|
if (curGetTempPyro1 >= target_tempPy[phase])
|
|
target = 3
|
|
endif
|
|
else
|
|
if (curGetTempPyro1 <= target_tempPy[phase])
|
|
target = 3
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
if ((phase < numpnts(target_tempPy)) && (numtype(target_tempPy[phase]) == 0))
|
|
if (direction_up)
|
|
if (curGetTempPyroQ >= target_tempPy[phase])
|
|
target = 4
|
|
endif
|
|
else
|
|
if (curGetTempPyroQ <= target_tempPy[phase])
|
|
target = 4
|
|
endif
|
|
endif
|
|
endif
|
|
|
|
switch(target)
|
|
case 1:
|
|
ramp_message = "temperature A target reached"
|
|
break
|
|
case 2:
|
|
ramp_message = "temperature B target reached"
|
|
break
|
|
case 3:
|
|
ramp_message = "pyrometer 1 target reached"
|
|
break
|
|
case 4:
|
|
ramp_message = "pyrometer Q target reached"
|
|
break
|
|
endswitch
|
|
|
|
setdatafolder savedf
|
|
return target
|
|
end
|
|
|
|
/// start an annealing ramp
|
|
function ann_ramp_start()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
epics_connect()
|
|
|
|
nvar recPoint
|
|
nvar recMinutesStart
|
|
recPoint = 0
|
|
recMinutesStart = datetime / 60
|
|
|
|
wave recMinutes
|
|
wave recVolts
|
|
wave recAmps
|
|
wave recWatts
|
|
wave recTemp
|
|
wave recPressure
|
|
|
|
recMinutes = nan
|
|
recVolts = nan
|
|
recAmps = nan
|
|
recWatts = nan
|
|
recTemp = nan
|
|
recPressure = nan
|
|
|
|
nvar minutes_start
|
|
minutes_start = datetime / 60
|
|
nvar minutes_previous
|
|
minutes_previous = minutes_start
|
|
nvar ramp_phase
|
|
ramp_phase = 1
|
|
nvar ramp_status
|
|
ramp_status = 1
|
|
|
|
nvar chidSetVolts
|
|
nvar chidSetAmps
|
|
nvar chidSetOnOff
|
|
|
|
wave target_watts
|
|
|
|
pvPutNumber /Q chidSetVolts, 0.5
|
|
pvPutNumber /Q chidSetAmps, 0.5
|
|
pvPutNumber /Q chidSetOnOff, 0
|
|
pvWait 5
|
|
|
|
nvar curSetWatts
|
|
curSetWatts = target_watts[0]
|
|
|
|
ann_init_bg()
|
|
CtrlNamedBackground ann_ramp, start
|
|
CtrlNamedBackground ann_record, start
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|
|
|
|
function ann_ramp_pause()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
CtrlNamedBackground ann_ramp, stop
|
|
|
|
nvar ramp_status
|
|
ramp_status = 0.5
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|
|
|
|
function ann_ramp_resume()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
CtrlNamedBackground ann_ramp, start
|
|
|
|
nvar ramp_status
|
|
ramp_status = 1
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|
|
|
|
/// stop a running annealing ramp
|
|
///
|
|
/// @param reset_psu 1 = turn off the power supply, 0 = do not change the power supply
|
|
/// the power supply is also turned off if the current target power is below 1 W.
|
|
function ann_ramp_stop(reset_psu)
|
|
variable reset_psu
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
CtrlNamedBackground ann_ramp, stop
|
|
CtrlNamedBackground ann_record, stop
|
|
|
|
nvar ramp_phase
|
|
ramp_phase = 0
|
|
nvar ramp_status
|
|
ramp_status = 0
|
|
nvar curTargetWatts
|
|
|
|
if (reset_psu || (curTargetWatts < 1))
|
|
nvar chidSetVolts
|
|
nvar chidSetAmps
|
|
nvar chidSetOnOff
|
|
pvPutNumber /Q chidSetVolts, 0
|
|
pvPutNumber /Q chidSetAmps, 0
|
|
pvPutNumber /Q chidSetOnOff, 1
|
|
pvWait 5
|
|
endif
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|
|
|
|
function ann_display_ramp()
|
|
dfref savedf = GetDataFolderDFR()
|
|
setdatafolder $(package_path)
|
|
|
|
wave recMinutes
|
|
wave recVolts
|
|
wave recAmps
|
|
wave recWatts
|
|
wave recTemp
|
|
wave recPressure
|
|
|
|
display recWatts vs recMinutes
|
|
appendtograph /r recVolts vs recMinutes
|
|
appendtograph /r recAmps vs recMinutes
|
|
end
|
|
|
|
Window panel_ramp_gen() : Panel
|
|
PauseUpdate; Silent 1 // building window...
|
|
NewPanel /K=1 /W=(441,64,887,702) as "ramp generator"
|
|
ValDisplay valdisp0,pos={11,178},size={233,42},bodyWidth=200,title="pyro 1"
|
|
ValDisplay valdisp0,limits={0,1500,625},barmisc={10,50}
|
|
ValDisplay valdisp0,value= #"root:packages:pearl_anneal:curGetPyro1"
|
|
ValDisplay valdisp1,pos={11,233},size={233,42},bodyWidth=200,title="pyro q"
|
|
ValDisplay valdisp1,limits={0,1500,625},barmisc={10,50}
|
|
ValDisplay valdisp1,value= #"root:packages:pearl_anneal:curGetPyroQ"
|
|
ValDisplay valdisp2,pos={11,73},size={234,42},bodyWidth=200,title="lake A"
|
|
ValDisplay valdisp2,limits={0,1500,300},barmisc={10,50}
|
|
ValDisplay valdisp2,value= #"root:packages:pearl_anneal:curGetTempA"
|
|
ValDisplay valdisp3,pos={10,128},size={234,42},bodyWidth=200,title="lake B"
|
|
ValDisplay valdisp3,limits={0,1500,300},barmisc={10,50}
|
|
ValDisplay valdisp3,value= #"root:packages:pearl_anneal:curGetTempB"
|
|
ValDisplay valdisp4,pos={16,23},size={229,42},bodyWidth=200,title="watts"
|
|
ValDisplay valdisp4,limits={0,90,0},barmisc={10,50}
|
|
ValDisplay valdisp4,value= #"root:packages:pearl_anneal:curGetWatts"
|
|
ValDisplay valdisp5,pos={6,5},size={60,14},title="phase"
|
|
ValDisplay valdisp5,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp5,value= #"root:packages:pearl_anneal:ramp_phase"
|
|
ValDisplay valdisp6,pos={0,282},size={244,42},bodyWidth=200,title="pressure"
|
|
ValDisplay valdisp6,format="%.1e",limits={1e-09,1e-08,0},barmisc={10,80}
|
|
ValDisplay valdisp6,value= #"root:packages:pearl_anneal:curGetPressure"
|
|
ValDisplay valdisp7,pos={335,90},size={47,14},bodyWidth=14,title="power"
|
|
ValDisplay valdisp7,limits={0,1,0.5},barmisc={0,0},mode= 2,highColor= (60928,60928,60928),lowColor= (0,52224,0),zeroColor= (61440,61440,61440)
|
|
ValDisplay valdisp7,value= #"root:packages:pearl_anneal:curGetOnOff"
|
|
ValDisplay valdisp16,pos={262,168},size={114,14},bodyWidth=34,title="target temp pyro"
|
|
ValDisplay valdisp16,limits={0,0,0},barmisc={0,1000},mode= 2,highColor= (60928,60928,60928),lowColor= (65280,0,0),zeroColor= (0,52224,0)
|
|
ValDisplay valdisp16,value= #"root:packages:pearl_anneal:curTargetTempPy"
|
|
ValDisplay valdisp17,pos={300,4},size={80,14},bodyWidth=14,title="power supply"
|
|
ValDisplay valdisp17,limits={0,1,0.5},barmisc={0,0},mode= 2,highColor= (0,52224,0),lowColor= (65280,0,0),zeroColor= (61440,61440,61440)
|
|
ValDisplay valdisp17,value= #"root:packages:pearl_anneal:psu_connected"
|
|
ValDisplay valdisp18,pos={317,21},size={64,14},bodyWidth=14,title="lakeshore"
|
|
ValDisplay valdisp18,limits={0,1,0.5},barmisc={0,0},mode= 2,highColor= (0,52224,0),lowColor= (65280,0,0),zeroColor= (61440,61440,61440)
|
|
ValDisplay valdisp18,value= #"root:packages:pearl_anneal:ls_connected"
|
|
ValDisplay valdisp19,pos={318,38},size={64,14},bodyWidth=14,title="pyrometer"
|
|
ValDisplay valdisp19,limits={0,1,0.5},barmisc={0,0},mode= 2,highColor= (0,52224,0),lowColor= (65280,0,0),zeroColor= (61440,61440,61440)
|
|
ValDisplay valdisp19,value= #"root:packages:pearl_anneal:pyro_connected"
|
|
ValDisplay valdisp20,pos={293,52},size={91,14},bodyWidth=14,title="vacuum system"
|
|
ValDisplay valdisp20,limits={0,1,0.5},barmisc={0,0},mode= 2,highColor= (0,52224,0),lowColor= (65280,0,0),zeroColor= (61440,61440,61440)
|
|
ValDisplay valdisp20,value= #"root:packages:pearl_anneal:vac_connected"
|
|
ValDisplay valdisp21,pos={341,76},size={41,14},bodyWidth=14,title="ramp"
|
|
ValDisplay valdisp21,limits={0,1,0.5},barmisc={0,0},mode= 2,highColor= (0,52224,0),lowColor= (61440,61440,61440),zeroColor= (0,34816,52224)
|
|
ValDisplay valdisp21,value= #"root:packages:pearl_anneal:ramp_status"
|
|
ValDisplay valdisp8,pos={278,120},size={100,14},title="target watts"
|
|
ValDisplay valdisp8,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp8,value= #"root:packages:pearl_anneal:curTargetWatts"
|
|
ValDisplay valdisp9,pos={278,137},size={100,14},title="target temp A"
|
|
ValDisplay valdisp9,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp9,value= #"root:packages:pearl_anneal:curTargetTempA"
|
|
ValDisplay valdisp10,pos={278,152},size={100,14},title="target temp B"
|
|
ValDisplay valdisp10,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp10,value= #"root:packages:pearl_anneal:curTargetTempB"
|
|
ValDisplay valdisp11,pos={271,266},size={100,14},title="limit pressure"
|
|
ValDisplay valdisp11,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp11,value= #"root:packages:pearl_anneal:curLimitPressure"
|
|
ValDisplay valdisp12,pos={261,205},size={100,14},title="trip temp A"
|
|
ValDisplay valdisp12,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp12,value= #"root:packages:pearl_anneal:curTripTempA"
|
|
ValDisplay valdisp13,pos={262,224},size={100,14},title="trip temp B"
|
|
ValDisplay valdisp13,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp13,value= #"root:packages:pearl_anneal:curTripTempB"
|
|
ValDisplay valdisp14,pos={276,242},size={100,14},title="trip pyro"
|
|
ValDisplay valdisp14,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp14,value= #"root:packages:pearl_anneal:curTripTempPy"
|
|
ValDisplay valdisp15,pos={273,309},size={100,14},title="ramp interval"
|
|
ValDisplay valdisp15,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp15,value= #"root:packages:pearl_anneal:curPhaseMinutes"
|
|
Button b_start,pos={15,362},size={50,20},proc=PearlAnneal#bp_ramp_start,title="start"
|
|
Button b_start,fColor=(0,52224,0)
|
|
Button b_pause,pos={75,362},size={50,20},proc=PearlAnneal#bp_ramp_pause,title="pause"
|
|
Button b_stop,pos={135,362},size={50,20},proc=PearlAnneal#bp_ramp_stop,title="stop"
|
|
Button b_stop,fColor=(52224,0,0)
|
|
Button b_edit,pos={195,362},size={50,20},proc=PearlAnneal#bp_ramp_edit,title="edit"
|
|
ValDisplay valdisp11_1,pos={274,282},size={100,14},title="trip pressure"
|
|
ValDisplay valdisp11_1,limits={0,0,0},barmisc={0,1000}
|
|
ValDisplay valdisp11_1,value= #"root:packages:pearl_anneal:curTripPressure"
|
|
TitleBox title0,pos={16,334},size={400,20}
|
|
TitleBox title0,variable= root:packages:pearl_anneal:ramp_message,fixedSize=1
|
|
DefineGuide UGH0={FT,390}
|
|
String fldrSav0= GetDataFolder(1)
|
|
SetDataFolder root:packages:pearl_anneal:
|
|
Display/W=(82,153,246,462)/FG=(FL,UGH0,FR,FB)/HOST=# recTemp vs recMinutes
|
|
AppendToGraph/R recPressure vs recMinutes
|
|
AppendToGraph/L=power recWatts vs recMinutes
|
|
NewFreeAxis/O/L power
|
|
SetDataFolder fldrSav0
|
|
ModifyGraph margin(left)=80
|
|
ModifyGraph rgb(recPressure)=(0,0,65280),rgb(recWatts)=(0,39168,0)
|
|
ModifyGraph log(right)=1
|
|
ModifyGraph mirror(bottom)=2
|
|
ModifyGraph nticks=3
|
|
ModifyGraph minor=1
|
|
ModifyGraph axThick=0.5
|
|
ModifyGraph axRGB(left)=(65280,0,0),axRGB(right)=(0,0,65280),axRGB(power)=(0,39168,0)
|
|
ModifyGraph tlblRGB(left)=(65280,0,0),tlblRGB(right)=(0,0,65280),tlblRGB(power)=(0,39168,0)
|
|
ModifyGraph alblRGB(left)=(65280,0,0),alblRGB(right)=(0,0,65280),alblRGB(power)=(0,39168,0)
|
|
ModifyGraph lblPos(left)=42,lblPos(power)=35
|
|
ModifyGraph lblLatPos(left)=1
|
|
ModifyGraph btLen=4
|
|
ModifyGraph freePos(power)=48
|
|
Label left "temperature (K)"
|
|
Label bottom "time (minutes)"
|
|
Label right "pressure (mbar)"
|
|
Label power "power (W)"
|
|
SetAxis/E=1 power 0,80
|
|
RenameWindow #,G0
|
|
SetActiveSubwindow ##
|
|
EndMacro
|
|
|
|
static function bp_ramp_start(ba) : ButtonControl
|
|
struct WMButtonAction &ba
|
|
|
|
switch( ba.eventCode )
|
|
case 2: // mouse up
|
|
dfref ann_df = $(package_path)
|
|
nvar /sdfr=ann_df ramp_status
|
|
if (ramp_status < 0.4)
|
|
ann_ramp_start()
|
|
endif
|
|
break
|
|
case -1: // control being killed
|
|
break
|
|
endswitch
|
|
|
|
return 0
|
|
end
|
|
|
|
static function bp_ramp_pause(ba) : ButtonControl
|
|
struct WMButtonAction &ba
|
|
|
|
switch( ba.eventCode )
|
|
case 2: // mouse up
|
|
dfref ann_df = $(package_path)
|
|
nvar /sdfr=ann_df ramp_status
|
|
if (ramp_status > 0.6)
|
|
ann_ramp_pause()
|
|
Button b_pause, win=$(ba.win), title="resume"
|
|
else
|
|
ann_ramp_resume()
|
|
Button b_pause, win=$(ba.win), title="pause"
|
|
endif
|
|
break
|
|
case -1: // control being killed
|
|
break
|
|
endswitch
|
|
|
|
return 0
|
|
end
|
|
|
|
static function bp_ramp_stop(ba) : ButtonControl
|
|
struct WMButtonAction &ba
|
|
|
|
switch( ba.eventCode )
|
|
case 2: // mouse up
|
|
ann_ramp_stop(1)
|
|
break
|
|
case -1: // control being killed
|
|
break
|
|
endswitch
|
|
|
|
return 0
|
|
end
|
|
|
|
static function bp_ramp_edit(ba) : ButtonControl
|
|
struct WMButtonAction &ba
|
|
|
|
dfref savedf = GetDataFolderDFR()
|
|
switch( ba.eventCode )
|
|
case 2: // mouse up
|
|
setdatafolder $(package_path)
|
|
|
|
wave minutes
|
|
wave target_watts
|
|
wave target_tempA
|
|
wave target_tempB
|
|
wave target_tempPy
|
|
wave trip_tempA
|
|
wave trip_tempB
|
|
wave trip_tempPy
|
|
wave limit_pressure
|
|
wave trip_pressure
|
|
|
|
edit /k=1 minutes, target_watts
|
|
appendtotable target_tempA, trip_tempA
|
|
appendtotable target_tempB, trip_tempB
|
|
appendtotable target_tempPy, trip_tempPy
|
|
appendtotable limit_pressure,trip_pressure
|
|
|
|
break
|
|
case -1: // control being killed
|
|
break
|
|
endswitch
|
|
|
|
setdatafolder savedf
|
|
return 0
|
|
end
|