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

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):
]
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"):
grouped_read_handler = DefaultSamplingCounterGroupedReadHandler(controller)
......@@ -249,6 +254,8 @@ class SamplingCounter(Counter):
if callable(conversion_function):
add_conversion_function(self, "read", conversion_function)
self.acquisition_device_mode = acquisition_device_mode
super(SamplingCounter, self).__init__(
name, grouped_read_handler, conversion_function, controller
)
......@@ -319,7 +326,15 @@ class SoftCounter(SamplingCounter):
def __init__(self, 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):
obj = value.__self__
self.get_value, value_name = self.get_read_func(obj, value)
......@@ -336,7 +351,9 @@ class SoftCounter(SamplingCounter):
if apply is None:
apply = lambda x: x
self.apply = apply
super(SoftCounter, self).__init__(name, controller)
super(SoftCounter, self).__init__(
name, controller, acquisition_device_mode=acquisition_device_mode
)
@staticmethod
def get_read_func(obj, value):
......
......@@ -8,6 +8,7 @@
import numpy
import time
import warnings
import enum
import gevent
from gevent import event
from bliss.common.event import dispatcher
......@@ -84,11 +85,22 @@ class BaseCounterAcquisitionDevice(AcquisitionDevice):
self.channels.update_from_iterable(data)
class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
SIMPLE_AVERAGE, TIME_AVERAGE, INTEGRATE = list(range(3))
@enum.unique
class SamplingMode(enum.IntEnum):
"""SamplingCounterAcquisitionDevice Mode Class """
SIMPLE_AVERAGE = 0
TIME_AVERAGE = 1
INTEGRATE = 2
class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
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.
......@@ -136,7 +148,13 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
@mode.setter
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):
self.device.prepare(*self.grouped_read_counters)
......@@ -194,7 +212,7 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
end_read = time.time()
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)
else:
acc_value += read_value
......@@ -207,12 +225,12 @@ class SamplingCounterAcquisitionDevice(BaseCounterAcquisitionDevice):
break
gevent.sleep(0) # to be able to kill the task
self._nb_acq_points += 1
if self.__mode == SamplingCounterAcquisitionDevice.TIME_AVERAGE:
if self.__mode == SamplingMode.TIME_AVERAGE:
data = acc_value / acc_read_time
else:
data = acc_value / nb_read
if self.__mode == SamplingCounterAcquisitionDevice.INTEGRATE:
if self.__mode == SamplingMode.INTEGRATE:
data *= self.count_time
self._emit_new_data(data)
......
......@@ -12,7 +12,7 @@ from bliss import setup_globals
from bliss.scanning.chain import AcquisitionChain
from bliss.scanning.acquisition.timer import SoftwareTimerMaster
from bliss.common import measurementgroup
from bliss.common.measurement import BaseCounter
from bliss.common.measurement import BaseCounter, SamplingCounter
def _get_object_from_name(name):
......@@ -139,6 +139,7 @@ def master_to_devices_mapping(
# Existing device
if device_controller in device_dict:
return device_dict[device_controller]
# Create acquisition_device
settings = acquisition_settings.get(device_controller, {})
device_dict[
......@@ -146,6 +147,12 @@ def master_to_devices_mapping(
] = acquisition_device = counter.create_acquisition_device(
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
if master_controller is None:
master_controller = master_settings.get(device_controller)
......
......@@ -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["temp_f"], 10 * [12.34 * 9.0 / 5 + 32])
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 @@
import pytest
import numpy
from bliss.common.measurement import SamplingCounter, IntegratingCounter
from bliss.common.scans import loopscan
class Diode(SamplingCounter):
......@@ -84,6 +85,30 @@ def test_diode_with_controller(beacon):
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):
acq_controller = AcquisitionController()
......
Markdown is supported
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