Commit 27733b06 authored by Matias Guijarro's avatar Matias Guijarro
Browse files

Merge branch '494-counter_mode' into 'master'

Resolve "Setting counter acquisition device acquisition mode (AVERAGE, INTEGRATION, ...)"

Closes #494

See merge request bliss/bliss!1128
parents d88fd87d 77f07ab9
...@@ -237,7 +237,12 @@ class SamplingCounter(Counter): ...@@ -237,7 +237,12 @@ class SamplingCounter(Counter):
] ]
def __init__( def __init__(
self, name, controller, grouped_read_handler=None, conversion_function=None self,
name,
controller,
grouped_read_handler=None,
conversion_function=None,
acquisition_device_mode=None,
): ):
if grouped_read_handler is None and hasattr(controller, "read_all"): if grouped_read_handler is None and hasattr(controller, "read_all"):
grouped_read_handler = DefaultSamplingCounterGroupedReadHandler(controller) grouped_read_handler = DefaultSamplingCounterGroupedReadHandler(controller)
...@@ -249,6 +254,8 @@ class SamplingCounter(Counter): ...@@ -249,6 +254,8 @@ class SamplingCounter(Counter):
if callable(conversion_function): if callable(conversion_function):
add_conversion_function(self, "read", conversion_function) add_conversion_function(self, "read", conversion_function)
self.acquisition_device_mode = acquisition_device_mode
super(SamplingCounter, self).__init__( super(SamplingCounter, self).__init__(
name, grouped_read_handler, conversion_function, controller name, grouped_read_handler, conversion_function, controller
) )
...@@ -319,7 +326,15 @@ class SoftCounter(SamplingCounter): ...@@ -319,7 +326,15 @@ class SoftCounter(SamplingCounter):
def __init__(self, name): def __init__(self, name):
self.name = name self.name = name
def __init__(self, obj=None, value="value", name=None, controller=None, apply=None): def __init__(
self,
obj=None,
value="value",
name=None,
controller=None,
apply=None,
acquisition_device_mode=None,
):
if obj is None and inspect.ismethod(value): if obj is None and inspect.ismethod(value):
obj = value.__self__ obj = value.__self__
self.get_value, value_name = self.get_read_func(obj, value) self.get_value, value_name = self.get_read_func(obj, value)
...@@ -336,7 +351,9 @@ class SoftCounter(SamplingCounter): ...@@ -336,7 +351,9 @@ class SoftCounter(SamplingCounter):
if apply is None: if apply is None:
apply = lambda x: x apply = lambda x: x
self.apply = apply self.apply = apply
super(SoftCounter, self).__init__(name, controller) super(SoftCounter, self).__init__(
name, controller, acquisition_device_mode=acquisition_device_mode
)
@staticmethod @staticmethod
def get_read_func(obj, value): def get_read_func(obj, value):
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
import numpy import numpy
import time import time
import warnings import warnings
import enum
import gevent import gevent
from gevent import event from gevent import event
from bliss.common.event import dispatcher from bliss.common.event import dispatcher
...@@ -84,11 +85,22 @@ class BaseCounterAcquisitionDevice(AcquisitionDevice): ...@@ -84,11 +85,22 @@ class BaseCounterAcquisitionDevice(AcquisitionDevice):
self.channels.update_from_iterable(data) self.channels.update_from_iterable(data)
class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice): @enum.unique
SIMPLE_AVERAGE, TIME_AVERAGE, INTEGRATE = list(range(3)) class SamplingMode(enum.IntEnum):
"""SamplingCounterAcquisitionDevice Mode Class """
SIMPLE_AVERAGE = 0
TIME_AVERAGE = 1
INTEGRATE = 2
class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
def __init__( def __init__(
self, counters_or_groupreadhandler, count_time=None, mode=SIMPLE_AVERAGE, **keys self,
counters_or_groupreadhandler,
count_time=None,
mode=SamplingMode.SIMPLE_AVERAGE,
**keys
): ):
""" """
Helper to manage acquisition of a sampling counter. Helper to manage acquisition of a sampling counter.
...@@ -136,7 +148,13 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice): ...@@ -136,7 +148,13 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
@mode.setter @mode.setter
def mode(self, value): def mode(self, value):
self.__mode = value try:
self.__mode = SamplingMode[value]
except KeyError:
raise ValueError(
"Invalid mode '%s', the mode must be in %s"
% (value, list(SamplingMode.__members__.keys()))
)
def prepare(self): def prepare(self):
self.device.prepare(*self.grouped_read_counters) self.device.prepare(*self.grouped_read_counters)
...@@ -194,7 +212,7 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice): ...@@ -194,7 +212,7 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
end_read = time.time() end_read = time.time()
read_time = end_read - start_read read_time = end_read - start_read
if self.__mode == SamplingCounterAcquisitionDevice.TIME_AVERAGE: if self.__mode == SamplingMode.TIME_AVERAGE:
acc_value += read_value * (end_read - start_read) acc_value += read_value * (end_read - start_read)
else: else:
acc_value += read_value acc_value += read_value
...@@ -207,12 +225,12 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice): ...@@ -207,12 +225,12 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
break break
gevent.sleep(0) # to be able to kill the task gevent.sleep(0) # to be able to kill the task
self._nb_acq_points += 1 self._nb_acq_points += 1
if self.__mode == SamplingCounterAcquisitionDevice.TIME_AVERAGE: if self.__mode == SamplingMode.TIME_AVERAGE:
data = acc_value / acc_read_time data = acc_value / acc_read_time
else: else:
data = acc_value / nb_read data = acc_value / nb_read
if self.__mode == SamplingCounterAcquisitionDevice.INTEGRATE: if self.__mode == SamplingMode.INTEGRATE:
data *= self.count_time data *= self.count_time
self._emit_new_data(data) self._emit_new_data(data)
......
...@@ -12,7 +12,7 @@ from bliss import setup_globals ...@@ -12,7 +12,7 @@ from bliss import setup_globals
from bliss.scanning.chain import AcquisitionChain from bliss.scanning.chain import AcquisitionChain
from bliss.scanning.acquisition.timer import SoftwareTimerMaster from bliss.scanning.acquisition.timer import SoftwareTimerMaster
from bliss.common import measurementgroup from bliss.common import measurementgroup
from bliss.common.measurement import BaseCounter from bliss.common.measurement import BaseCounter, SamplingCounter
def _get_object_from_name(name): def _get_object_from_name(name):
...@@ -139,6 +139,7 @@ def master_to_devices_mapping( ...@@ -139,6 +139,7 @@ def master_to_devices_mapping(
# Existing device # Existing device
if device_controller in device_dict: if device_controller in device_dict:
return device_dict[device_controller] return device_dict[device_controller]
# Create acquisition_device # Create acquisition_device
settings = acquisition_settings.get(device_controller, {}) settings = acquisition_settings.get(device_controller, {})
device_dict[ device_dict[
...@@ -146,6 +147,12 @@ def master_to_devices_mapping( ...@@ -146,6 +147,12 @@ def master_to_devices_mapping(
] = acquisition_device = counter.create_acquisition_device( ] = acquisition_device = counter.create_acquisition_device(
scan_pars, **settings scan_pars, **settings
) )
# Set the AcquisitionDevice mode
if isinstance(counter, SamplingCounter):
if counter.acquisition_device_mode is not None:
acquisition_device.mode = counter.acquisition_device_mode
# Parent handling # Parent handling
if master_controller is None: if master_controller is None:
master_controller = master_settings.get(device_controller) master_controller = master_settings.get(device_controller)
......
...@@ -164,3 +164,25 @@ def test_soft_counter_scan(beacon): ...@@ -164,3 +164,25 @@ def test_soft_counter_scan(beacon):
numpy.testing.assert_array_almost_equal(data["get_pressure"], 10 * [23.45]) numpy.testing.assert_array_almost_equal(data["get_pressure"], 10 * [23.45])
numpy.testing.assert_array_almost_equal(data["temp_f"], 10 * [12.34 * 9.0 / 5 + 32]) numpy.testing.assert_array_almost_equal(data["temp_f"], 10 * [12.34 * 9.0 / 5 + 32])
return data return data
def test_sampling_counter_acquisition_device_mode(beacon):
diode = beacon.get("diode")
# USING DEFAULT MODE
c = SoftCounter(diode, "read")
assert c.acquisition_device_mode is None
s = loopscan(10, 0.01, c, run=False)
assert s.acq_chain.nodes_list[1].mode.name == "SIMPLE_AVERAGE"
# UPDATING THE MODE
c.acquisition_device_mode = "INTEGRATE"
s = loopscan(10, 0.01, c, run=False)
assert s.acq_chain.nodes_list[1].mode.name == "INTEGRATE"
# SPECIFYING THE MODE
c = SoftCounter(diode, "read", acquisition_device_mode="INTEGRATE")
assert c.acquisition_device_mode == "INTEGRATE"
s = loopscan(10, 0.01, c, run=False)
assert s.acq_chain.nodes_list[1].mode.name == "INTEGRATE"
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
import pytest import pytest
import numpy import numpy
from bliss.common.measurement import SamplingCounter, IntegratingCounter from bliss.common.measurement import SamplingCounter, IntegratingCounter
from bliss.common.scans import loopscan
class Diode(SamplingCounter): class Diode(SamplingCounter):
...@@ -84,6 +85,30 @@ def test_diode_with_controller(beacon): ...@@ -84,6 +85,30 @@ def test_diode_with_controller(beacon):
assert diode.raw_value * 2 == diode_value assert diode.raw_value * 2 == diode_value
def test_sampling_counter_acquisition_device_mode(beacon):
diode = beacon.get("diode")
values = []
def f(x):
values.append(x)
return x
test_diode = Diode(diode, f)
# USING DEFAULT MODE
assert test_diode.acquisition_device_mode is None
s = loopscan(1, 0.1, test_diode)
assert s.acq_chain.nodes_list[1].mode.name == "SIMPLE_AVERAGE"
assert s.get_data()["test_diode"] == pytest.approx(sum(values) / len(values))
# UPDATING THE MODE
values = []
test_diode.acquisition_device_mode = "INTEGRATE"
s = loopscan(1, 0.1, test_diode)
assert s.acq_chain.nodes_list[1].mode.name == "INTEGRATE"
assert s.get_data()["test_diode"] == pytest.approx(sum(values) * 0.1 / len(values))
def test_integ_counter(beacon): def test_integ_counter(beacon):
acq_controller = AcquisitionController() acq_controller = AcquisitionController()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment