コード例 #1
0
ファイル: muonlab_ii.py プロジェクト: HiSPARC/pysparc
 def __init__(self):
     self._device = FtdiChip(DESCRIPTION)
コード例 #2
0
 def __init__(self):
     self._device = FtdiChip(DESCRIPTION)
コード例 #3
0
ファイル: muonlab_ii.py プロジェクト: HiSPARC/pysparc
class MuonlabII(object):

    """Access Muonlab II hardware.

    Instantiate this class to get access to connected Muonlab II hardware.
    The hardware device is opened during instantiation.

    """

    _device = None

    # Yes, really, HV1 and 2 are reversed
    _address = {'HV_1': 2,
                'HV_2': 1,
                'THR_1': 3,
                'THR_2': 4,
                'MEAS': 5}

    def __init__(self):
        self._device = FtdiChip(DESCRIPTION)

    def __del__(self):
        """Cleanly shut down muonlab hardware."""

        if self._device and not self._device.closed:
            self.set_pmt1_voltage(0)
            self.set_pmt2_voltage(0)
            self._device.close()

    def _write_setting(self, setting, data):
        """Write setting to device.

        :param setting: string specifying the setting to write.  Must be
            one of HV_1 (for PMT 1 high voltage), HV_2 (for PMT 2 high
            voltage), THR_1 (for PMT 1 threshold), THR_2 (for PMT 2
            threshold) or MEAS (for type of measurement).
        :param data: the raw data byte to write to the device.

        For a high voltage setting, the data byte values (in the range of
        0x00 - 0xff) are mapped linearly to 300 - 1500 V.  For a threshold
        setting, the data byte values (0x00 - 0xff) are linearly mapped to
        0 mV - 1200 mV.

        The type of measurement can be set using only 4 bits.  They must
        be 0b1111 for a muon lifetime measurement.  Any other value will
        select a coincidence time difference measurement.

        """

        if setting not in self._address:
            raise TypeError("Unkown setting: %s" % setting)
        else:
            address_bits = self._address[setting]

        high_byte = (1 << 7) | (address_bits << 4) | ((data & 0xf0) >> 4)
        low_byte = (address_bits << 4) | (data & 0x0f)

        if setting == 'MEAS':
            # Measurement type can be selected using only 1 byte
            command = chr(low_byte)
        else:
            command = array('B', [high_byte, low_byte]).tostring()
        self._device.write(command)

    def set_pmt1_voltage(self, voltage):
        """Set high voltage for PMT 1.

        :param voltage: integer.  Values are clipped to a 300 - 1500 V
            range.

        """
        voltage_byte = map_setting(voltage, 300, 1500, 0x00, 0xff)
        self._write_setting('HV_1', voltage_byte)

    def set_pmt2_voltage(self, voltage):
        """Set high voltage for PMT 2.

        :param voltage: integer.  Values are clipped to a 300 - 1500 V
            range.

        """
        voltage_byte = map_setting(voltage, 300, 1500, 0x00, 0xff)
        self._write_setting('HV_2', voltage_byte)

    def set_pmt1_threshold(self, threshold):
        """Set threshold for PMT 1.

        Events with a signal strength below the specified threshold will
        be ignored as noise.

        :param threshold: integer.  Values are clipped to a 0 - 1200 mV
            range.

        """
        threshold_byte = map_setting(threshold, 0, 1200, 0x00, 0xff)
        self._write_setting('THR_1', threshold_byte)

    def set_pmt2_threshold(self, threshold):
        """Set threshold for PMT 2.

        Events with a signal strength below the specified threshold will
        be ignored as noise.

        :param threshold: integer.  Values are clipped to a 0 - 1200 mV
            range.

        """
        threshold_byte = map_setting(threshold, 0, 1200, 0x00, 0xff)
        self._write_setting('THR_2', threshold_byte)

    def select_lifetime_measurement(self):
        """Select lifetime measurement mode."""

        self._write_setting('MEAS', 0xff)

    def select_coincidence_measurement(self):
        """Select coincidence time difference measurement mode."""

        self._write_setting('MEAS', 0x00)

    def flush_device(self):
        """Flush device output buffers.

        To completely clear out outdated measurements when changing
        parameters, call this method.  All data received after this method
        was called is really newly measured.

        """
        self._device.flush()

    def read_lifetime_data(self):
        """Read lifetime data from detector.

        Raises ValueError when corrupt data is received.

        :returns: list of lifetime measurements

        """
        data = self._device.read()

        if data:
            lifetimes = []
            #for word_value in data[::2]:
            for i in range(0, len(data), 2):
                high_byte, low_byte = ord(data[i]), ord(data[i + 1])

                # sanity checks
                if not (high_byte & 0x80):
                    raise ValueError(
                        "Corrupt lifetime data (high byte bit flag not set)")
                if (low_byte & 0x80):
                    raise ValueError(
                        "Corrupt lifetime data (low byte bit flag set)")

                adc_value = ((high_byte & 0x3f) << 6) | (low_byte & 0x3f)
                lifetime = LIFETIME_SCALE * adc_value
                lifetimes.append(lifetime)
            return lifetimes
        else:
            return []

    def read_coincidence_data(self):
        """Read coincidence data from detector.

        Raises ValueError when corrupt data is received.

        :returns: list of coincidence time difference measurements

        """
        data = self._device.read()
        if data:
            deltatimes = []
            #for word_value in data[::2]:
            for i in range(0, len(data), 2):
                high_byte, low_byte = ord(data[i]), ord(data[i + 1])

                det1_isfirsthit = bool(high_byte & 0x40)
                det2_isfirsthit = bool(low_byte & 0x40)

                # sanity checks
                if not (high_byte & 0x80):
                    raise ValueError("Corrupt coincidence data "
                                     "(high byte bit flag not set)")
                if (low_byte & 0x80):
                    raise ValueError(
                        "Corrupt coincidence data (low byte bit flag set)")
                if not det1_isfirsthit and not det2_isfirsthit:
                    raise ValueError(
                        "Corrupt coincidence data (no hit first flag set)")

                adc_value = ((high_byte & 0x3f) << 6) | (low_byte & 0x3f)
                deltatime = COINCIDENCE_TIMEDELTA_SCALE * adc_value
                if det2_isfirsthit and not det1_isfirsthit:
                    deltatime *= -1
                deltatimes.append((deltatime, det1_isfirsthit,
                                   det2_isfirsthit))
            return deltatimes
        else:
            return []
コード例 #4
0
class MuonlabII(object):
    """Access Muonlab II hardware.

    Instantiate this class to get access to connected Muonlab II hardware.
    The hardware device is opened during instantiation.

    """

    _device = None

    # Yes, really, HV1 and 2 are reversed
    _address = {'HV_1': 2, 'HV_2': 1, 'THR_1': 3, 'THR_2': 4, 'MEAS': 5}

    def __init__(self):
        self._device = FtdiChip(DESCRIPTION)

    def __del__(self):
        """Cleanly shut down muonlab hardware."""

        if self._device and not self._device.closed:
            self.set_pmt1_voltage(0)
            self.set_pmt2_voltage(0)
            self._device.close()

    def _write_setting(self, setting, data):
        """Write setting to device.

        :param setting: string specifying the setting to write.  Must be
            one of HV_1 (for PMT 1 high voltage), HV_2 (for PMT 2 high
            voltage), THR_1 (for PMT 1 threshold), THR_2 (for PMT 2
            threshold) or MEAS (for type of measurement).
        :param data: the raw data byte to write to the device.

        For a high voltage setting, the data byte values (in the range of
        0x00 - 0xff) are mapped linearly to 300 - 1500 V.  For a threshold
        setting, the data byte values (0x00 - 0xff) are linearly mapped to
        0 mV - 1200 mV.

        The type of measurement can be set using only 4 bits.  They must
        be 0b1111 for a muon lifetime measurement.  Any other value will
        select a coincidence time difference measurement.

        """

        if setting not in self._address:
            raise TypeError("Unkown setting: %s" % setting)
        else:
            address_bits = self._address[setting]

        high_byte = (1 << 7) | (address_bits << 4) | ((data & 0xf0) >> 4)
        low_byte = (address_bits << 4) | (data & 0x0f)

        if setting == 'MEAS':
            # Measurement type can be selected using only 1 byte
            command = chr(low_byte)
        else:
            command = array('B', [high_byte, low_byte]).tostring()
        self._device.write(command)

    def set_pmt1_voltage(self, voltage):
        """Set high voltage for PMT 1.

        :param voltage: integer.  Values are clipped to a 300 - 1500 V
            range.

        """
        voltage_byte = map_setting(voltage, 300, 1500, 0x00, 0xff)
        self._write_setting('HV_1', voltage_byte)

    def set_pmt2_voltage(self, voltage):
        """Set high voltage for PMT 2.

        :param voltage: integer.  Values are clipped to a 300 - 1500 V
            range.

        """
        voltage_byte = map_setting(voltage, 300, 1500, 0x00, 0xff)
        self._write_setting('HV_2', voltage_byte)

    def set_pmt1_threshold(self, threshold):
        """Set threshold for PMT 1.

        Events with a signal strength below the specified threshold will
        be ignored as noise.

        :param threshold: integer.  Values are clipped to a 0 - 1200 mV
            range.

        """
        threshold_byte = map_setting(threshold, 0, 1200, 0x00, 0xff)
        self._write_setting('THR_1', threshold_byte)

    def set_pmt2_threshold(self, threshold):
        """Set threshold for PMT 2.

        Events with a signal strength below the specified threshold will
        be ignored as noise.

        :param threshold: integer.  Values are clipped to a 0 - 1200 mV
            range.

        """
        threshold_byte = map_setting(threshold, 0, 1200, 0x00, 0xff)
        self._write_setting('THR_2', threshold_byte)

    def select_lifetime_measurement(self):
        """Select lifetime measurement mode."""

        self._write_setting('MEAS', 0xff)

    def select_coincidence_measurement(self):
        """Select coincidence time difference measurement mode."""

        self._write_setting('MEAS', 0x00)

    def flush_device(self):
        """Flush device output buffers.

        To completely clear out outdated measurements when changing
        parameters, call this method.  All data received after this method
        was called is really newly measured.

        """
        self._device.flush()

    def read_lifetime_data(self):
        """Read lifetime data from detector.

        Raises ValueError when corrupt data is received.

        :returns: list of lifetime measurements

        """
        data = self._device.read()

        if data:
            lifetimes = []
            #for word_value in data[::2]:
            for i in range(0, len(data), 2):
                high_byte, low_byte = ord(data[i]), ord(data[i + 1])

                # sanity checks
                if not (high_byte & 0x80):
                    raise ValueError(
                        "Corrupt lifetime data (high byte bit flag not set)")
                if (low_byte & 0x80):
                    raise ValueError(
                        "Corrupt lifetime data (low byte bit flag set)")

                adc_value = ((high_byte & 0x3f) << 6) | (low_byte & 0x3f)
                lifetime = LIFETIME_SCALE * adc_value
                lifetimes.append(lifetime)
            return lifetimes
        else:
            return []

    def read_coincidence_data(self):
        """Read coincidence data from detector.

        Raises ValueError when corrupt data is received.

        :returns: list of coincidence time difference measurements

        """
        data = self._device.read()
        if data:
            deltatimes = []
            #for word_value in data[::2]:
            for i in range(0, len(data), 2):
                high_byte, low_byte = ord(data[i]), ord(data[i + 1])

                det1_isfirsthit = bool(high_byte & 0x40)
                det2_isfirsthit = bool(low_byte & 0x40)

                # sanity checks
                if not (high_byte & 0x80):
                    raise ValueError("Corrupt coincidence data "
                                     "(high byte bit flag not set)")
                if (low_byte & 0x80):
                    raise ValueError(
                        "Corrupt coincidence data (low byte bit flag set)")
                if not det1_isfirsthit and not det2_isfirsthit:
                    raise ValueError(
                        "Corrupt coincidence data (no hit first flag set)")

                adc_value = ((high_byte & 0x3f) << 6) | (low_byte & 0x3f)
                deltatime = COINCIDENCE_TIMEDELTA_SCALE * adc_value
                if det2_isfirsthit and not det1_isfirsthit:
                    deltatime *= -1
                deltatimes.append(
                    (deltatime, det1_isfirsthit, det2_isfirsthit))
            return deltatimes
        else:
            return []