counter.py 5.16 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
# -*- coding: utf-8 -*-
#
# This file is part of the bliss project
#
# Copyright (c) 2017 Beamline Control Unit, ESRF
# Distributed under the GNU LGPLv3. See LICENSE for more info.

import numpy
import time
from gevent import event,sleep
from bliss.common.event import dispatcher
12
from ..chain import AcquisitionDevice,AcquisitionChannel
13
from bliss.common.measurement import CounterBase
14
15

class CounterAcqDevice(AcquisitionDevice):
16
17
    SIMPLE_AVERAGE,TIME_AVERAGE,INTEGRATE = range(3)

18
    def __init__(self,counter,
19
20
21
22
23
24
25
26
27
28
29
30
31
                 count_time=None,npoints=1,
                 mode=SIMPLE_AVERAGE,**keys):
        """
        Helper to manage acquisition of a sampling counter.

        count_time -- the master integration time.
        npoints -- number of point for this acquisition
        mode -- three mode are available *SIMPLE_AVERAGE* (the default)
        which sum all the sampling values and divide by the number of read value.
        the *TIME_AVERAGE* which sum all integration  then divide by the sum
        of time spend to measure all values. And *INTEGRATION* which sum all integration
        and then normalize it when the *count_time*.
        """
32
33
34
35
36
37
38
39
40
        prepare_once = keys.pop('prepare_once',npoints > 1 and True or False)
        start_once = keys.pop('start_once',npoints > 1 and True or False)
        npoints = max(1,npoints)
        AcquisitionDevice.__init__(self, counter, counter.name, "zerod",
                                   npoints=npoints,
                                   trigger_type=AcquisitionDevice.SOFTWARE,
                                   prepare_once=prepare_once,
                                   start_once=start_once,
                                   **keys)
41
        self._count_time = count_time
42
43
        if not isinstance(counter,CounterBase.ReadAllHandler):
            self.channels.append(AcquisitionChannel(counter.name,numpy.double, (1,)))
44
45
46
47
48
        self._nb_acq_points = 0
        self._event = event.Event()
        self._stop_flag = False
        self._ready_event = event.Event()
        self._ready_flag = True
49
50
51
52
53
54
55
56
        self.__mode = mode

    @property
    def mode(self):
        return self.__mode
    @mode.setter
    def mode(self,value):
        self.__mode = value
57

58
59
60
    def add_counter_to_read(self,counter):
        self.channels.append(AcquisitionChannel(counter.name,numpy.double, (1,)))

61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
    def prepare(self):
        self._nb_acq_points = 0
        self._stop_flag = False
        self._ready_flag = True
        self._event.clear()

    def start(self):
        pass

    def stop(self):
        self._stop_flag = True
        self._trig_time = None
        self._event.set()

    def trigger(self):
        self._trig_time = time.time()
        self._event.set()

    def wait_ready(self):
        """
        will wait until the last triggered point is read
        """
        while not self._ready_flag:
            self._ready_event.wait()
            self._ready_event.clear()

    def reading(self):
88
89
90
91
92
93
94
95
96
        counter_name = [x.name for x in self.channels]
        if isinstance(self.device,CounterBase.ReadAllHandler):
            def read():
                return numpy.array(self.device.read_all(*counter_name),
                                   dtype=numpy.double)
        else:                   # read_all
            def read():
                return numpy.array(self.device.read(),
                                   dtype=numpy.double)
97
98
99
100
101
102
103
104
105
106
107
        while self._nb_acq_points < self.npoints:
            #trigger wait
            self._event.wait()
            self._event.clear()
            self._ready_flag = False
            trig_time = self._trig_time
            if trig_time is None: continue
            if self._stop_flag: break

            nb_read = 0
            acc_read_time = 0
108
            acc_value = numpy.zeros((len(counter_name),),dtype=numpy.double)
109
            stop_time = trig_time + self._count_time or 0
110
111
112
            #Counter integration loop
            while not self._stop_flag:
                start_read = time.time()
113
                read_value = read()
114
                end_read = time.time()
115
116
117
118
119
120
                read_time = end_read - start_read
                
                if self.__mode != CounterAcqDevice.TIME_AVERAGE:
                    acc_value += read_value
                else:
                    acc_value += read_value * (end_read - start_read)
121
122
123
124
125
126
127
128
                nb_read += 1
                acc_read_time += end_read - start_read

                current_time = time.time()
                if (current_time + (acc_read_time / nb_read)) > stop_time:
                    break
                sleep(0) # Be able to kill the task
            self._nb_acq_points += 1
129
130
131
132
133
134
135
136
137
            if self.__mode == CounterAcqDevice.TIME_AVERAGE:
                data = acc_value / nb_read
            else:
                data = acc_value / acc_read_time
                
            if self.__mode == CounterAcqDevice.INTEGRATE:
                data *= self._count_time
            
            channel_data = {name:data[index] for index,name in enumerate(counter_name)}
138
            dispatcher.send("new_data",self,
139
                            {"channel_data": channel_data})
140
141
            self._ready_flag = True
            self._ready_event.set()
142