initial commit

This commit is contained in:
2022-07-07 15:48:22 +02:00
commit f0f04a2118
3 changed files with 340 additions and 0 deletions

103
Readme.md Normal file
View File

@@ -0,0 +1,103 @@
EPICS simulator
---------------
This provides very dummy images and motor(to be done) records
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/EpicsSim/iocBoot/iocSwissMxSim
./st.cmd
simulate camera (with EPICS simulator)
--------------------------------------
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX
EPICS_CA_ADDR_LIST=localhost
./simCam.py
test camera display
-------------------
cd /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX
EPICS_CA_ADDR_LIST=localhost
./camera.py -u -b SwissMxSim
https://git.psi.ch/SwissMX/swissmx_cristallina/-/wikis/Instructions%20on%20how%20to%20use%20software
caQtDM -macro 'P=SAR-EXPMX' /photonics/home/gac-cristall/Documents/swissmx_cristallina/gui/SwissMX_ChipMotion.ui
caQtDM -macro 'P=SAR-EXPMX' ESB_MX_exp.ui
Camera:
caget SARES30-CAMS156-SMX-OAV:CAMERASTATUS
caget SARES30-CAMS156-SMX-OAV:PICTURE
Zoom:
caget SAR-EXPMX-FETURA:POS_RB
wlp2s0: MAC: 80:38:fb:d6:01:78 wlan-corp 129.129.64.249
enx00e04c680519: MAC: 00:e0:4c:68:05:19
import pyqtgraph.examples
pyqtgraph.examples.run()
Benchmark -> VideoSpeedTest
rsync -vai /home/zamofing_t/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/python/SwissMX/ saresc-cons-02:/tmp/zamofing_t/
/opt/gfa/python-3.5/latest/bin/python camera.py --base-pv SARES30-CAMS156-SMX-OAV
BASE=~/Documents/prj/SwissFEL/epics_ioc_modules/LakeShore
cd $BASE/iocBoot/iocLakeShore1
../../bin/UB20-x86_64/LakeShore st.cmd
[saresc-cons-02 ~]$ ioc records 'SARES30-CAMS156-SMX-OAV:.*'
SARES30-CAMS156-SMX-OAV:PICTURE waveform CCD Picure Col SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:FPICTURE waveform CCD Picture SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:RF_FPICTURE waveform Reduced frequency FPICTURE SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:WIDTH ai Nr. of Pixel width SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:HEIGHT ai Nr. of Pixel height SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:EXPOSURE ao Exposure SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:CAMROI_X_START ao ROI X Start SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:CAMROI_X_END ao ROI X End SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:CAMROI_Y_START ao ROI Y Start SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:CAMROI_Y_END ao ROI Y End SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:BINX ao Binning X SARES30-CPCW-CAMS156-SMX-OAV office
SARES30-CAMS156-SMX-OAV:BINY ao Binning Y SARES30-CPCW-CAMS156-SMX-OAV office
waveform:
Native DBF type: DBF_SHORT
Number of elements: 5000
SARES30-CAMS156-SMX-OAV:WIDTH 2448
SARES30-CAMS156-SMX-OAV:HEIGHT 2048
caqtdm camsf
caqtdm -macro 'NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV' /sf/controls/config/qt/Camera/CameraMiniView_RF.ui
caqtdm -macro 'NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV' /sf/controls/config/qt/Camera/CameraExpert_RF.ui
03 last file: /sf/controls/config/qt/Camera/CameraMiniView_RF.ui, macro: NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV
07-07-2022 12:14:03 last file: /sf/controls/config/qt/Camera/CameraMiniView_RF.ui, macro: NAME=SARES30-CAMS156-SMX-OAV,CAMNAME=SARES30-CAMS156-SMX-OAV
mkdir EpicsSim
cd EpicsSim
makeBaseApp.pl -t ioc SwissMxSim
makeBaseApp.pl -a UB20-x86_64 -i -t ioc -p SwissMxSim SwissMxSim
cd ~/Documents/prj/SwissFEL/epics_ioc_modules/ESB_MX/EpicsSim/iocBoot/iocSwissMxSim
./st.cmd
EPICS_CA_ADDR_LIST=localhost
ipython3
import epics
p = epics.PV('SwissMxSim:PICTURE', auto_monitor=False)
print(p.info)
import numpy as np
a=np.arange(10000,dtype=np.uint16)
p.put(a)
print(p.get())
https://pyepics.github.io/pyepics/arrays.html

203
camera.py Executable file
View File

@@ -0,0 +1,203 @@
#!/usr/bin/env python
"""
Hi Zac,
at the moment there is no channel for the min or max values. The reason for this is the binning. With this you change these numbers.
At the end you need 3*2 numbers :
Physical resolution
Max resolution for ROI
Resolution of your image
And the logic how you can change the numbers ;-)
The simples trick for getting the max resolution is to set binning to 1 and write big numbers in the ROI (REGIONX_END / REGIONY_END) channels . They will be corrected to the max resolution.
Sorry for this. When you want all numbers, I can think about the export of the whole "mess". Inside the IOC there is the central checking routine. Sometimes it could be helpful to have this in EPICS.
Best regards
Helge
"""
import enum
import logging
import epics
import numpy as np
logger = logging.getLogger(__name__)
global imv
class camera_server(object):
def __init__(self, basename="ESB-MX-CAM"):
self._pv=pv=dict()
os.environ['EPICS_CA_ADDR_LIST'] = 'localhost'
if basename[-1]!=':': basename+=':'
self._transformations = []
pv['pic']=epics.PV(basename+"FPICTURE", auto_monitor=True, callback=self.new_frame_callback)
for k,v in (('w','WIDTH'),('h','HEIGHT'),):
pv[k]=epics.PV(basename+v)
return
def new_frame_callback(self, **kwargs):
"""kargs contains:
pvname: the name of the pv
value: the latest value
char_value: string representation of value
count: the number of data elements
ftype: the numerical CA type indicating the data type
type: the python type for the data
status: the status of the PV (1 for OK)
precision: number of decimal places of precision for floating point values
units: string for PV units
severity: PV severity
timestamp: timestamp from CA server.
read_access: read access (True/False)
write_access: write access (True/False)
access: string description of read- and write-access
host: host machine and CA port serving PV
enum_strs: the list of enumeration strings
upper_disp_limit: upper display limit
lower_disp_limit: lower display limit
upper_alarm_limit: upper alarm limit
lower_alarm_limit: lower alarm limit
upper_warning_limit: upper warning limit
lower_warning_limit: lower warning limit
upper_ctrl_limit: upper control limit
lower_ctrl_limit: lower control limit
chid: integer channel ID
cb_info: (index, self) tuple containing callback ID
and the PV object"""
print('new_frame_callback')
try:
pv=self._pv
w, h = int(pv['w'].value), int(pv['h'].value)
pic = pv['pic'].get(count=w * h, as_numpy=True).reshape((h, w))
if pic.dtype==np.int16:
pic.dtype=np.uint16
self.pic=pic
print(pic[-1][-1])
imv.setImage(pic)
except:
logger.warning("failed to fetch image")
def get_image(self):
pv=self._pv
try:
pic = self.pic
except:
self.new_frame_callback()
pic = self.pic
for t in self._transformations:
if Transforms.ROTATE_90 == t:
pic = np.rot90(pic, 1)
elif Transforms.ROTATE_180 == t:
pic = np.rot90(pic, 2)
elif Transforms.ROTATE_270 == t:
pic = np.rot90(pic, 3)
elif Transforms.FLIP_LR == t:
pic = np.fliplr(pic)
elif Transforms.FLIP_UD == t:
pic = np.flipud(pic)
elif Transforms.TRANSPOSE == t:
pic = pic.transpose()
return pic
if __name__ == "__main__":
import time, os, PIL
logging.basicConfig(format="%(asctime)s $(levelname)s %(message)s", level=logging.DEBUG)
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--ui", "-u", help="qt test", action="store_true")
parser.add_argument("--base-pv","-b",help="PV prefix for images; default=ESB-MX-CAM",type=str,default="ESB-MX-CAM",)
args = parser.parse_args()
print('STARTING')
os.environ['EPICS_CA_ADDR_LIST']='localhost'
cam = camera_server(basename=args.base_pv)
#pv = cam._pv
#w, h = int(pv['w'].value), int(pv['h'].value)
#a = np.arange(w*h, dtype=np.uint16)
#pv['pic'].put(a)
#print(pv['pic'].get())
if not args.ui:
n = 1
base = time.strftime("/tmp/image_%Y%m%d_%H%M%S_{:05d}.png")
while True:
fname = base.format(n)
img=cam.get_image()
print(type(img))
type(img)
print(img,img.dtype)
PIL.Image.fromarray(img).save(fname)
logging.info("acquired {}".format(fname))
try:
input("<enter> for next image, ctrl-c to abort")
except KeyboardInterrupt:
exit(0)
n += 1
else:
import sys
from pyqtgraph.Qt import QtCore, QtGui
import pyqtgraph as pg
print(pg.__version__)
# Interpret image data as row-major instead of col-major
pg.setConfigOptions(imageAxisOrder='row-major')
app = QtGui.QApplication([])
## Create window with ImageView widget
win = QtGui.QMainWindow()
win.resize(800,800)
imv = pg.ImageView()
win.setCentralWidget(imv)
win.show()
win.setWindowTitle('pyqtgraph example: ImageView')
## Create random 3D data set with noisy signals
img = pg.gaussianFilter(np.random.normal(size=(200, 200)), (5, 5)) * 20 + 100
img = img[np.newaxis,:,:]
decay = np.exp(-np.linspace(0,0.3,100))[:,np.newaxis,np.newaxis]
data = np.random.normal(size=(100, 200, 200))
data += img * decay
data += 2
## Add time-varying signal
sig = np.zeros(data.shape[0])
sig[30:] += np.exp(-np.linspace(1,10, 70))
sig[40:] += np.exp(-np.linspace(1,10, 60))
sig[70:] += np.exp(-np.linspace(1,10, 30))
sig = sig[:,np.newaxis,np.newaxis] * 3
data[:,50:60,30:40] += sig
## Display the data and assign each frame a time value from 1.0 to 3.0
imv.setImage(data, xvals=np.linspace(1., 3., data.shape[0]))
imv.setImage(cam.get_image())
## Set a custom color map
colors = [
(0, 0, 0),
(45, 5, 61),
(84, 42, 55),
(150, 87, 60),
(208, 171, 141),
(255, 255, 255)
]
cmap = pg.ColorMap(pos=np.linspace(0.0, 1.0, 6), color=colors)
imv.setColorMap(cmap)
## Start Qt event loop unless running in interactive mode.
if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
QtGui.QApplication.instance().exec_()

34
simCam.py Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python
# *-----------------------------------------------------------------------*
# | |
# | Copyright (c) 2022 by Paul Scherrer Institute (http://www.psi.ch) |
# | |
# | Author Thierry Zamofing (thierry.zamofing@psi.ch) |
# *-----------------------------------------------------------------------*
import os,epics
import time
import numpy as np
print('STARTING')
os.environ['EPICS_CA_ADDR_LIST'] = 'localhost'
pv=dict()
basename='SwissMxSim:'
#pv['pic'] = epics.PV(basename + "FPICTURE", auto_monitor=True, callback=self.new_frame_callback)
pv['pic'] = epics.PV(basename + "FPICTURE")
for k, v in (('w', 'WIDTH'), ('h', 'HEIGHT'),):
pv[k] = epics.PV(basename + v)
pv['w'].put(300)
pv['h'].put(400)
w, h = int(pv['w'].value), int(pv['h'].value)
for j in range(100):
for i in range(20):
a = np.arange(w * h, dtype=np.uint16)//i
pv['pic'].put(a)
print(pv['pic'].get())
time.sleep(.01)