本章中讨论了使用ADURL控制面探测器Lambda的过程:
ADURL的使用请见:
EPICS -- areaDetector URL驱动程序-CSDN博客
需要启动一个ADURL的IOC程序,并且设置相关的插件中参数的值:
# st.cm
< envPaths
< st_base.cmd
dbpf 13URL1:cam1:URL1 "/home/xspadmin/data/data_00000_raw/data_00000_raw_000000.tif"
dbpf 13URL1:image1:EnableCallbacks "1"
dbpf 13URL1:Pva1:EnableCallbacks "1"
dbpf 13URL1:image1:BlockingCallbacks "1"
dbpf 13URL1:Pva1:BlockingCallbacks "1"
dbpf 13URL1:TIFF1:EnableCallbacks "1"
dbpf 13URL1:TIFF1:BlockingCallbacks "1"
dbpf 13URL1:cam1:ImageMode "Single"
以下是这款面探测器的介绍:
Lambda探测器一个55um像素大小并且具有高帧率功能的单光子计数X射线探测器。
其官方网页:Lambda – X-Spectrum
技术信息:一个Si 250K系统的技术规格如下表所示:
模块数目 | 1个模块带有1个连接了4个读出芯片的传感器 |
传感器 | Si二极管阵列 |
量子效率 | 95%@8KeV, 70%@12KeV,10%@25KeV |
读出芯片 | Medipix3RXv2 |
像素尺寸 | 55 X 55 um^2 |
传感器尺寸 | 28.4 X 28.4 mm^2 |
格式 | 512 X 512 pixels(262144) |
动态范围 | 最大24位(取决于读出模式) |
每个像素计数率限制 | 200000个/像素/s(不带计数率校准) 800000个/像素/s(如果计数率校准测量和使用) |
能量范围 | 6keV ~ 20kev |
能量分辨率 | 2keV |
最大帧率 | 2000Hz@12-bit模式 4000Hz@6-bit模式 24000Hz@1-bit模式 |
读出时间 | 12-bit, 6-bit, 1-bit模式,无读出时间 24-bit模式,1ms |
点扩散函数 | 1像素FWHM |
数据格式 | Hdf5(Nexus标准) |
外部触发/门控 | 3.3V |
软件接口 | 基于C++的硬件库,python包 |
冷却 | 气冷,水冷 |
尺寸 | 150.5mm长,85mm宽和40mm长 |
重量 | 1.2kg |
过压类别 | 0 |
污染等级 | II |
对厂家提供探测器操作的Python代码进行封装,编写一个采集保存的py文件:
import sys
import xspcontrol as xc
import pyxsp as px
shutter_time = sys.argv[1]
numfs = sys.argv[2]
s = xc.System('/opt/xsp/config/system.yml')
d = s.open_detector('lambda')
r = s.open_receiver('lambda/1')
d.operation_mode = px.OperationMode(px.BitDepth.DEPTH_24, px.ChargeSumming.OFF, px.CounterMode.SINGLE, px.Pitch.PITCH_55)
d.number_of_frames = int(numfs)
d.shutter_time = float(shutter_time)
d.bit_depth = px.BitDepth.DEPTH_24
w = xc.Writer()
w.save_to_file = True
w.save_mode = xc.SaveMode.OVERWRITE
w.save_directory = '/home/xspadmin/data'
w.save_file_prefix = 'data'
s.set_writer('lambda/1', w)
s.frame_timeout_ms = d.shutter_time+10000
while not r.ready:
time.sleep(1)
s.start_acquisition()
while not s.acquisition_finished:
time.sleep(0.5)
del r
del d
del w
del s
由于探测器的数据文件格式为nexus,而ADURL模块不能读取这个格式的文件,需要进行格式类型的转换,厂家也提供了将nexus格式转为tif格式的python程序ConvertNxsToTIFF.py,转换后的文件格式是ADURL模块可以读取的;编写一个bash脚本execute.sh,将采集和转换放在一个脚本中,并且触发ADURL模块程序进行数据读取:
#!/bin/bash
#echo "$1"
#echo "$2"
if [ "$#" != 2 ]; then
shutter_time=1.0
num_frames=1
else
shutter_time=$1
num_frames=$2
fi
#echo "shutter_time:", $shutter_time, "num_frames:", $num_frames
rm -rf /home/xspadmin/data/data_00000_raw
python /home/xspadmin/command/collect.py $shutter_time $num_frames
python /home/xspadmin/NxsToTiff_Scripts/ConvertNxsToTIFF.py --r /home/xspadmin/data/data_00000.nxs
filename=$(date "+%Y-%m-%d-%H_%M_%S")
mv /home/xspadmin/data/data_00000.nxs /home/xspadmin/data/data_$filename.nxs
caput 13URL1:cam1:Acquire 1
编写一个IOC程序来执行以上的bash脚本,在这个IOC程序中使用了一个sub记录,此记录执行时可以调用系统命令来执行这个程序脚本。
以下是这个C程序:
#include
#include
#include
#include
#include
#include
#include
int mySubDebug = 0;
static char cmdstr[100];
static long mySubInit(struct subRecord *precord)
{
if (mySubDebug)
{
printf("Record %s called mySubInit(%p)\n", precord->name, (void *)precord);
}
printf("subInit was called\n");
return 0;
}
static long mySubProcess(struct subRecord * precord)
{
if(mySubDebug)
{
printf("Record %s called mySubProcess(%p)\n", precord->name,(void *)precord);
}
precord->val++;
sprintf(cmdstr, "%s %.2f %d", precord->desc, precord->a, (int )precord->b);
printf("execute command: %s\n", cmdstr);
system(cmdstr);
return 0;
}
epicsExportAddress(int, mySubDebug);
epicsRegisterFunction(mySubInit);
epicsRegisterFunction(mySubProcess);
对应的db文件如下:
record(bi, "$(P)$(R)ExecuteLambda")
{
field(ONAM, "Start")
field(ZNAM, "Stop")
field(FLNK, "$(P)$(R)ExecuteLambdaCheck")
}
record(calcout, "$(P)$(R)ExecuteLambdaCheck")
{
field(INPA, "$(P)$(R)ExecuteLambda")
field(CALC, "A==1")
field(OOPT, "When Non-zero")
field(OUT, "$(P)$(R)ExecuteOK PP CA")
}
record(bo, "$(P)$(R)ExecuteOK")
{
field(FLNK, "$(P)$(R)ExecuteLambdaStart")
}
record(bi, "$(P)$(R)ExecuteIndicate")
{
field(ONAM, "Running")
field(ZNAM, "Idle")
}
record(sub, "$(P)$(R)ExecuteLambdaStart")
{
field(SCAN, "Passive")
field(INPA, "$(P)$(R)TimeLambda")
field(INPB, "$(P)$(R)FramesLambda")
field(SNAM,"mySubProcess")
field(DESC, "execute.sh")
field(FLNK, "$(P)$(R)ExecuteLambdaFinsh.PROC")
}
record(ai, "$(P)$(R)TimeLambda")
{
field(VAL, "1.0")
}
对应的启动文件为:
#!../../bin/linux-x86_64/lambda
#- You may have to change lambda to something else
#- everywhere it appears in this file
< envPaths
cd "${TOP}"
## Register all support components
dbLoadDatabase "dbd/lambda.dbd"
lambda_registerRecordDeviceDriver pdbbase
## Load record instances
dbLoadRecords("db/lambda.db","P=13URL1:,R=cam1:")
cd "${TOP}/iocBoot/${IOC}"
iocInit
编译以上程序,并且启动以上IOC:
epics> dbl
13URL1:cam1:ExecuteLambda
执行通道访问命令运行一次sub记录:
xspadmin@xspserver:/usr/local/EPICS/lambda/iocBoot/ioclambda$ caput 13URL1:cam1:ExecuteLambda.PROC 1
或者用CSS做成图像界面:
具有设置探测器快门时间以及每次采集中需要采集的帧数的功能,点击Collect开始采集。
如果设置了ImageJ插件中数据的访问通道:
在ADURL读取了数据后,将实时显示这个数据: