Files
camserver_sf/configuration/user_scripts/psss_lock.py
2021-05-17 17:13:03 +02:00

168 lines
5.6 KiB
Python

from logging import getLogger
from cam_server.pipeline.data_processing import functions
from cam_server.pipeline.data_processing.functions import chunk_copy
import json
import numpy
import scipy.signal
import scipy.optimize
import numba
numba.set_num_threads(4)
import threading
import epics
_logger = getLogger(__name__)
output_pv, center_pv, fwhm_pv, ymin_pv, ymax_pv, axis_pv = None, None, None, None, None, None
roi = [0, 0]
initialized = False
epics_lock=threading.RLock()
_logger.info("Import: " +str(threading.get_ident()))
@numba.njit(parallel=True)
def get_spectrum (image, background):
y = image.shape[0]
x = image.shape[1]
profile = numpy.zeros(x, dtype=numpy.uint32)
#for i in range(y):
for i in numba.prange(y):
for j in range(x):
v = image[i,j]
b = background[i,j]
if v > b:
v -= b
else:
v = 0
profile[j] += v
return profile
def initialize(parameters):
global ymin_pv, ymax_pv, axis_pv, output_pv, center_pv, fwhm_pv
_logger.info("Initialize: " + str(threading.get_ident()))
epics_pv_name_prefix = parameters["camera_name"]
output_pv_name = epics_pv_name_prefix + ":SPECTRUM_Y"
center_pv_name = epics_pv_name_prefix + ":SPECTRUM_CENTER"
fwhm_pv_name = epics_pv_name_prefix + ":SPECTRUM_FWHM"
ymin_pv_name = epics_pv_name_prefix + ":SPC_ROI_YMIN"
ymax_pv_name = epics_pv_name_prefix + ":SPC_ROI_YMAX"
axis_pv_name = epics_pv_name_prefix + ":SPECTRUM_X"
epics.ca.clear_cache()
output_pv = epics.PV(output_pv_name)
center_pv = epics.PV(center_pv_name)
fwhm_pv = epics.PV(fwhm_pv_name)
ymin_pv = epics.PV(ymin_pv_name)
ymax_pv = epics.PV(ymax_pv_name)
axis_pv = epics.PV(axis_pv_name)
ymin_pv.wait_for_connection()
ymax_pv.wait_for_connection()
axis_pv.wait_for_connection()
def process_image(image, pulse_id, timestamp, x_axis, y_axis, parameters, bsdata=None, background=None):
global roi, initialized, epics_lock
global ymin_pv, ymax_pv, axis_pv, output_pv, center_pv, fwhm_pv
processed_data = dict()
epics_pv_name_prefix = parameters["camera_name"]
with epics_lock:
if not initialized:
initialize(parameters)
initialized = True
if ymin_pv and ymin_pv.connected:
roi[0] = ymin_pv.value
if ymax_pv and ymax_pv.connected:
roi[1] = ymax_pv.value
if axis_pv and axis_pv.connected:
axis = axis_pv.value
else:
axis = None
if axis is None:
_logger.warning("Energy axis not connected");
return None
if len(axis) < image.shape[1]:
_logger.warning("Energy axis length %d < image width %d", len(axis), image.shape[1])
return None
# match the energy axis to image width
axis = axis[:image.shape[1]]
processing_image = image
nrows, ncols = processing_image.shape
# validate background data
background_image = parameters.pop('background_data', None)
if isinstance(background_image, numpy.ndarray):
#background_image = chunk_copy(background_image)
if background_image.shape != processing_image.shape:
_logger.info("Invalid background shape: %s instead of %s" % (str(background_image.shape), str(processing_image.shape)))
background_image = None
else:
background_image = None
processed_data[epics_pv_name_prefix + ":processing_parameters"] = json.dumps(
{"roi": roi, "background": None if (background_image is None) else parameters.get('image_background')})
# crop the image in y direction
ymin, ymax = int(roi[0]), int(roi[1])
if nrows >= ymax > ymin >= 0:
if (nrows != ymax) or (ymin != 0):
processing_image = processing_image[ymin: ymax, :]
if background_image is not None:
background_image = background_image[ymin:ymax, :]
# remove the background and collapse in y direction to get the spectrum
if background_image is not None:
spectrum = get_spectrum(processing_image, background_image)
else:
spectrum = processing_image.sum(0, 'uint32')
# smooth the spectrum with savgol filter with 51 window size and 3rd order polynomial
smoothed_spectrum = scipy.signal.savgol_filter(spectrum, 51, 3)
# check wether spectrum has only noise. the average counts per pixel at the peak
# should be larger than 1.5 to be considered as having real signals.
minimum, maximum = smoothed_spectrum.min(), smoothed_spectrum.max()
amplitude = maximum - minimum
skip = True
if amplitude > nrows * 1.5:
skip = False
# gaussian fitting
offset, amplitude, center, sigma = functions.gauss_fit_psss(smoothed_spectrum[::2], axis[::2],
offset=minimum, amplitude=amplitude, skip=skip)
# outputs
processed_data[epics_pv_name_prefix + ":SPECTRUM_Y"] = spectrum
processed_data[epics_pv_name_prefix + ":SPECTRUM_X"] = axis
processed_data[epics_pv_name_prefix + ":SPECTRUM_CENTER"] = center
processed_data[epics_pv_name_prefix + ":SPECTRUM_FWHM"] = 2.355 * sigma
with epics_lock:
if output_pv and output_pv.connected:
output_pv.put(processed_data[epics_pv_name_prefix + ":SPECTRUM_Y"])
_logger.debug("caput on %s for pulse_id %s", output_pv, pulse_id)
if center_pv and center_pv.connected:
center_pv.put(processed_data[epics_pv_name_prefix + ":SPECTRUM_CENTER"])
if fwhm_pv and fwhm_pv.connected:
fwhm_pv.put(processed_data[epics_pv_name_prefix + ":SPECTRUM_FWHM"])
return processed_data