Ejemplo n.º 1
0
    def init_ctr(self, bin_n, bin_w):

        bin_w = int(bin_w / 1e-12)

        # Close existing counter, if it was initialized before
        self.close_ctr()

        # Instantiate counter measurement
        try:
            self._ctr = TT.TimeDifferences(tagger=self._tagger,
                                           click_channel=self._click_ch,
                                           start_channel=self._start_ch,
                                           n_bins=bin_n,
                                           binwidth=bin_w)

            # save bin_number in internal variable
            self._bin_n = bin_n

        # handle NotImplementedError (typical error, produced by TT functions)
        except NotImplementedError:
            # remove reference to the counter measurement
            self._ctr = None

            msg_str = 'init_ctr(): instantiation of TimeDifferences measurement failed'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)

        # Prepare counter to be started by start_counting()
        # (TimeDifferences measurement starts running immediately after instantiation,
        # so it is necessary to stop it and erase all counts collected between instantiation and stop() call)
        self._ctr.stop()
        self._ctr.clear()

        return 0
Ejemplo n.º 2
0
    def start_counting(self):

        # Try stopping and restarting counter measurement
        try:
            self._ctr.stop(
            )  # does not fail even if the measurement is not running
            self._ctr.clear()
            self._ctr.start()

            # Wait until the counter is actually ready to count
            time.sleep(0.1)

            return 0

        # handle exception in TT function calls [NotImplementedError]
        except NotImplementedError:
            # Since stop() and clear() methods are very robust,
            # this part is only executed if counter is totally broken.
            # In this case it makes sense to close counter.
            self.close_ctr()

            msg_str = 'start_counting(): call failed. Counter was closed. \n'\
                      'Re-initialize counter by calling init_ctr() again'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)
Ejemplo n.º 3
0
    def get_all_chs(self):
        """Returns list of all channels available on the device,
        including edge type sign.

        Positive/negative numbers correspond to detection of rising/falling edges.
        For example:
            1 means 'rising edge on connector 1'
            -1 means 'falling edge on connector 1


        :return: (list of int) list of channel numbers including edge sign.
                Example: [-8, -7, -6, -5, -4, -3, -2, -1, 1, 2, 3, 4, 5, 6, 7, 8]
                Empty list is returned in the case of error.
        """

        # Sanity check: check that connection to the device was established
        if self._tagger is None:
            msg_str = 'get_all_chs(): not connected to the device yet'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)

        channel_list = list(
            self._tagger.getChannelList(
                TT.TT_CHANNEL_RISING_AND_FALLING_EDGES))
        return channel_list
Ejemplo n.º 4
0
    def terminate_counting(self):

        # Action of this method is non-trivial for "in_progress" state only
        if self.get_status() != 1:
            return 0

        # Try stopping and clearing counter measurement
        try:
            # stop counter, clear count array
            self._ctr.stop()
            self._ctr.clear()

            # set status to "idle"
            self._set_status(0)
            return 0

        # handle exception in TT.stop()/TT.clear()
        except NotImplementedError:
            # Since stop() and clear() methods are very robust,
            # this part is only executed if counter is totally broken.
            # In this case it makes sense to close counter.
            self.close_ctr()

            msg_str = 'terminate_counting(): call failed. Counter was closed. \n' \
                      'Re-initialize it by calling init_ctr()'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)
Ejemplo n.º 5
0
    def start_counting(self):

        current_status = self.get_status()

        # Sanity check: ensure that counter is not "void"
        if current_status == -1:
            msg_str = 'start_counting(): ' \
                      'counter is in "void" state - it ether was not initialized or was closed. \n' \
                      'Initialize it by calling init_ctr()'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)

        # Terminate counting if it is already running
        if current_status == 1:
            self.terminate_counting()

        # Try stopping and restarting counter measurement
        try:
            self._ctr.stop(
            )  # does not fail even if the measurement is not running
            self._ctr.clear()
            self._ctr.start()

            # set status to "in_progress"
            self._set_status(1)

            # Wait until the counter is actually ready to count
            time.sleep(0.1)

            return 0

        # handle exception in TT function calls [NotImplementedError]
        except NotImplementedError:
            # Since stop() and clear() methods are very robust,
            # this part is only executed if counter is totally broken.
            # In this case it makes sense to close counter.
            self.close_ctr()

            msg_str = 'start_counting(): call failed. Counter was closed. \n'\
                      'Re-initialize counter by calling init_ctr() again'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)
Ejemplo n.º 6
0
    def get_count_ar(self, timeout=-1):

        # If current status is "in_progress",
        # wait for transition to some other state:
        #   "finished" if measurement completes successfully,
        #   "idle" if measurement is terminated,
        #   "void" if counter breaks
        start_time = time.time()
        sleep_time = abs(timeout) / 100

        while self.get_status() == 1:
            # stop waiting if timeout elapses
            if time.time() - start_time > timeout >= 0:
                break
            time.sleep(sleep_time)

        # Analyze current status and return correspondingly
        status = self.get_status()

        # return data only in the case of "finished" state
        if status == 2:
            count_array = np.array(self._ctr.getData(), dtype=np.uint32)

            # Fix of the issue with an additional gate pulse needed to complete
            # measurement (see comment in init_ctr() for explanation):
            #   the last element of returned array is just a copy
            #   of the last physically measured bin
            count_array = np.append(count_array, count_array[-1])

            return count_array

        # return empty list for all other states ("in_progress", "idle", and "void")
        else:
            if status == 1:
                self.log.warn(
                    'get_count_ar(): operation timed out, but counter is still running. \n'
                    'Try calling get_count_ar() later or terminate process by terminate_counting().'
                )
            elif status == 0:
                self.log.warn(
                    'get_count_ar(): counter is "idle" - nothing to read')
            else:
                msg_str = 'get_count_ar(): counter broke and was deleted \n' \
                          'Re-initialize it by calling init_ctr()'
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)

            return []
Ejemplo n.º 7
0
    def stop_counting(self):

        # Try stopping counter measurement
        try:
            # stop counter
            self._ctr.stop()

            return 0

        # handle exception in TT.stop()/TT.clear()
        except NotImplementedError:
            # Since stop() and clear() methods are very robust,
            # this part is only executed if counter is totally broken.
            # In this case it makes sense to close counter.
            self.close_ctr()

            msg_str = 'terminate_counting(): call failed. Counter was closed. \n' \
                      'Re-initialize it by calling init_ctr()'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)
Ejemplo n.º 8
0
    def set_ch_assignment(self, click_ch=None, start_ch=None):
        """Sets click channel and and gate channel.

        This method only changes internal variables
        self._click_ch and self._gate_ch.
        To apply the channel update, call  init_ctr() again.


        :param click_ch: (int|list of int) click channel number
                              positive/negative values - rising/falling edge detection
                              if list is given, clicks on all specified channels
                              will be merged into one logic channel

        :param start_ch: (int) channel number
                             positive/negative - count during high/low gate level

        :return: (dict) actually channel assignment:
                        {
                            'click_channel': (int) click_chnl_num,
                            'gate_channel': (int) gate_chnl_num
                        }
        """

        if click_ch is not None:
            # for convenience bring int type of input to list of int
            if isinstance(click_ch, list):
                click_ch_list = click_ch
            elif isinstance(click_ch, int):
                click_ch_list = [click_ch]
            else:
                # unknown input type
                msg_str = 'set_ch_assignment(click_ch={0}): invalid argument type'\
                          ''.format(click_ch)
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)

            # sanity check: all requested channels are available on the device
            all_chs = self.get_all_chs()
            for channel in click_ch_list:
                if channel not in all_chs:
                    msg_str = 'set_ch_assignment(): '\
                              'click_ch={0} - this channel is not available on the device'\
                              ''.format(click_ch)
                    self.log.error(msg_str=msg_str)
                    raise CtrError(msg_str)

            # If several channel numbers were passed, create virtual Combiner channel
            if len(click_ch_list) > 1:
                self._combiner = TT.Combiner(tagger=self._tagger,
                                             channels=click_ch_list)
                # Obtain int channel number for the virtual channel
                click_ch_list = [self._combiner.getChannel()]

            # Set new value for click channel
            self._click_ch = int(click_ch_list[0])

        if start_ch is not None:

            # sanity check: channel is available on the device
            if start_ch not in self.get_all_chs():
                msg_str = 'set_ch_assignment(): '\
                          'start_ch={0} - this channel is not available on the device'\
                          ''.format(start_ch)
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)

            # Set new value for gate channel
            self._start_ch = int(start_ch)

        return self.get_ch_assignment()
Ejemplo n.º 9
0
    def init_ctr(self, bin_number, gate_type):

        # Device-specific fix explanation:
        #
        #   CountBetweenMarkers measurement configured for n_value bins
        #   indeed fills-up buffer after n_value gate pules, but call of
        #   self._ctr.ready() still gives False. Only after one additional
        #   gate pulse it gives True, such that self.get_status()
        #   gives 2 and self.get_count_ar() returns:
        #
        #       device always needs an additional pulse to complete
        #       (even for n_values = 1 it needs 2 gate pulses).
        #
        #   Since this is very counter-intuitive and confuses
        #   above-lying logic, a fix is made here:
        #
        #       For given bin_number, CountBetweenMarkers measurement
        #       is instantiated with n_values = (bin_number - 1) such
        #       that it completes after receiving bin_number physical
        #       gate pulses as expected.
        #
        #       As a result, in the returned count_ar
        #       (still of length bin_number, as logic expects), the last
        #       value is just a copy of (bin_number - 1)-st element.
        #
        #   The last physical bin is not actually measured, what can lead
        #   to confusions when bin_number is on the order of one.
        #   The warning below reminds about it:
        if bin_number <= 5:
            self.log.warn(
                'init_ctr(): due to strange behaviour of TT.CountBetweenMarkers '
                'measurement, this driver makes a hack: counter is configured to '
                'measure bin_number-1 pulses and the last element of the returned '
                'count_ar is just a copy of the preceding one. \n'
                'With bin_number={}, only the first {} gate windows will actually be '
                'measured.'
                ''.format(bin_number, bin_number - 1))

        # Close existing counter, if it was initialized before
        if self.get_status() != -1:
            self.close_ctr()

        # Instantiate counter measurement
        try:
            if gate_type == 'RF':
                self._ctr = TT.CountBetweenMarkers(
                    tagger=self._tagger,
                    click_channel=self._click_ch,
                    begin_channel=self._gate_ch,
                    end_channel=-self._gate_ch,
                    n_values=bin_number - 1)
            elif gate_type == 'RR':
                self._ctr = TT.CountBetweenMarkers(
                    tagger=self._tagger,
                    click_channel=self._click_ch,
                    begin_channel=self._gate_ch,
                    n_values=bin_number - 1)
            else:
                msg_str = 'init_ctr(): unknown gate type "{}" \n' \
                          'Valid types are: \v' \
                          '     "RR" - Raising-Raising \n' \
                          '     "RF" - Raising-Falling'
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)

            # set status to "idle"
            self._set_status(0)

            # save bin_number in internal variable
            self._bin_number = bin_number

        # handle NotImplementedError (typical error, produced by TT functions)
        except NotImplementedError:
            # remove reference to the counter measurement
            self._ctr = None
            # set status to "void"
            self._set_status(-1)

            msg_str = 'init_ctr(): instantiation of CountBetweenMarkers measurement failed'
            self.log.error(msg_str=msg_str)
            raise CtrError(msg_str)

        # Prepare counter to be started by start_counting()
        # (CountBetweenMarkers measurement starts running immediately after instantiation,
        # so it is necessary to stop it and erase all counts collected between instantiation and stop() call)
        self._ctr.stop()
        self._ctr.clear()

        return 0
Ejemplo n.º 10
0
    def _set_status(self, new_status):
        """Method to set new status in a clean way.

        This method compares the requested new_status with current status
        and checks if this transition is possible. If transition is possible,
        the change is applied to self._status. Otherwise, no status change
        is applied, -1 is returned, and error message is logged.


        :param new_status: (int) new status value
                            -1 - "void"
                             0 - "idle"
                             1 - "in_progress"
                             2 - "finished"

        :return: (int) operation status code:
                 0 - OK, change was accepted and applied
                -1 - Error, impossible transition was requested,
                     no state change was applied
        """

        # Transition to "void" is always possible
        # by calling close_ctr()
        if new_status == -1:
            self._status = -1
            return 0

        # Transition to "idle" is possible from
        #   "void" by calling init_ctr()
        #   "in_progress" by calling terminate_counting()
        if new_status == 0:
            if self._status == -1 or self._status == 1:
                self._status = 0
                return 0
            else:
                msg_str = '_set_status(): transition to new_status={0} from self._status={1} is impossible. \n'\
                          'Counter status was not changed.'\
                          ''.format(new_status, self._status)
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)

        # Transition to "in_progress" is possible from
        #   "idle" by calling start_counting()
        #   "finished" by calling start_counting()
        if new_status == 1:
            if self._status == 0 or self._status == 2:
                self._status = 1
                return 0
            else:
                msg_str = '_set_status(): transition to new_status={0} from self._status={1} is impossible. \n'\
                          'Counter status was not changed.'\
                          ''.format(new_status, self._status)
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)

        # Transition to "finished" is only possible from "in_progress"
        # by successful completion of count_array accumulation
        if new_status == 2:
            if self._status == 1:
                self._status = 2
                return 0
            else:
                msg_str = '_set_status(): transition to new_status={0} from self._status={1} is impossible. \n'\
                          'Counter status was not changed.'\
                          ''.format(new_status, self._status)
                self.log.error(msg_str=msg_str)
                raise CtrError(msg_str)