Gets channel samples. The raw data group samples are not loaded to
        memory so it is advised to use ``filter`` or ``select`` instead of
        performing several ``get`` calls.

        Channel can be specified in two ways:

        * using the first positional argument *name*

            * if *source* is given this will be first used to validate the
              channel selection
            * if there are multiple occurances for this channel then the
              *group* and *index* arguments can be used to select a specific
              group.
            * if there are multiple occurances for this channel and either the
              *group* or *index* arguments is None then a warning is issued

        * using the group number (keyword argument *group*) and the channel
          number (keyword argument *index*). Use *info* method for group and
          channel numbers

        If the *raster* keyword argument is not *None* the output is
        interpolated accordingly

        Parameters
        ----------
        name : string
            name of channel
        group : int
            0-based group index
        index : int
            0-based channel index
        raster : float
            time raster in seconds
        samples_only : bool
            if *True* return only the channel samples as numpy array; if
                *False* return a *Signal* object
        data : bytes
            prevent redundant data read by providing the raw data group samples
        raw : bool
            return channel samples without appling the conversion rule; default
            `False`
        ignore_invalidation_bits : bool
            option to ignore invalidation bits
        source : str
            source name used to select the channel
        record_offset : int
            if *data=None* use this to select the record offset from which the
            group data should be loaded
        record_count : int
            number of records to read; default *None* and in this case all
            available records are used
        copy_master : bool
            make a copy of the timebase for this channel

        Returns
        -------
        res : (numpy.array, numpy.array) | Signal
            returns *Signal* if *samples_only*=*False* (default option),
            otherwise returns a (numpy.array, numpy.array) tuple of samples and
            invalidation bits. If invalidation bits are not used or if
            *ignore_invalidation_bits* if False, then the second item will be
            None.

            The *Signal* samples are:

                * numpy recarray for channels that have composition/channel
                  array address or for channel of type
                  CANOPENDATE, CANOPENTIME
                * numpy array for all the rest

        Raises
        ------
        MdfException :

        * if the channel name is not found
        * if the group index is out of range
        * if the channel index is out of range

        Examples
        --------
        >>> from asammdf import MDF, Signal
        >>> import numpy as np
        >>> t = np.arange(5)
        >>> s = np.ones(5)
        >>> mdf = MDF(version='4.10')
        >>> for i in range(4):
        ...     sigs = [Signal(s*(i*10+j), t, name='Sig') for j in range(1, 4)]
        ...     mdf.append(sigs)
        ...
        >>> # first group and channel index of the specified channel name
        ...
        >>> mdf.get('Sig')
        UserWarning: Multiple occurances for channel "Sig". Using first occurance from data group 4. Provide both "group" and "index" arguments to select another data group
        <Signal Sig:
                samples=[ 1.  1.  1.  1.  1.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # first channel index in the specified group
        ...
        >>> mdf.get('Sig', 1)
        <Signal Sig:
                samples=[ 11.  11.  11.  11.  11.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # channel named Sig from group 1 channel index 2
        ...
        >>> mdf.get('Sig', 1, 2)
        <Signal Sig:
                samples=[ 12.  12.  12.  12.  12.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # channel index 1 or group 2
        ...
        >>> mdf.get(None, 2, 1)
        <Signal Sig:
                samples=[ 21.  21.  21.  21.  21.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> mdf.get(group=2, index=1)
        <Signal Sig:
                samples=[ 21.  21.  21.  21.  21.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # validation using source name
        ...
        >>> mdf.get('Sig', source='VN7060')
        <Signal Sig:
                samples=[ 12.  12.  12.  12.  12.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">

def get(
        self,
        name=None,
        group=None,
        index=None,
        raster=None,
        samples_only=False,
        data=None,
        raw=False,
        ignore_invalidation_bits=False,
        source=None,
        record_offset=0,
        record_count=None,
        copy_master=True,
    ):
        """Gets channel samples. The raw data group samples are not loaded to
        memory so it is advised to use ``filter`` or ``select`` instead of
        performing several ``get`` calls.

        Channel can be specified in two ways:

        * using the first positional argument *name*

            * if *source* is given this will be first used to validate the
              channel selection
            * if there are multiple occurances for this channel then the
              *group* and *index* arguments can be used to select a specific
              group.
            * if there are multiple occurances for this channel and either the
              *group* or *index* arguments is None then a warning is issued

        * using the group number (keyword argument *group*) and the channel
          number (keyword argument *index*). Use *info* method for group and
          channel numbers

        If the *raster* keyword argument is not *None* the output is
        interpolated accordingly

        Parameters
        ----------
        name : string
            name of channel
        group : int
            0-based group index
        index : int
            0-based channel index
        raster : float
            time raster in seconds
        samples_only : bool
            if *True* return only the channel samples as numpy array; if
                *False* return a *Signal* object
        data : bytes
            prevent redundant data read by providing the raw data group samples
        raw : bool
            return channel samples without appling the conversion rule; default
            `False`
        ignore_invalidation_bits : bool
            option to ignore invalidation bits
        source : str
            source name used to select the channel
        record_offset : int
            if *data=None* use this to select the record offset from which the
            group data should be loaded
        record_count : int
            number of records to read; default *None* and in this case all
            available records are used
        copy_master : bool
            make a copy of the timebase for this channel

        Returns
        -------
        res : (numpy.array, numpy.array) | Signal
            returns *Signal* if *samples_only*=*False* (default option),
            otherwise returns a (numpy.array, numpy.array) tuple of samples and
            invalidation bits. If invalidation bits are not used or if
            *ignore_invalidation_bits* if False, then the second item will be
            None.

            The *Signal* samples are:

                * numpy recarray for channels that have composition/channel
                  array address or for channel of type
                  CANOPENDATE, CANOPENTIME
                * numpy array for all the rest

        Raises
        ------
        MdfException :

        * if the channel name is not found
        * if the group index is out of range
        * if the channel index is out of range

        Examples
        --------
        >>> from asammdf import MDF, Signal
        >>> import numpy as np
        >>> t = np.arange(5)
        >>> s = np.ones(5)
        >>> mdf = MDF(version='4.10')
        >>> for i in range(4):
        ...     sigs = [Signal(s*(i*10+j), t, name='Sig') for j in range(1, 4)]
        ...     mdf.append(sigs)
        ...
        >>> # first group and channel index of the specified channel name
        ...
        >>> mdf.get('Sig')
        UserWarning: Multiple occurances for channel "Sig". Using first occurance from data group 4. Provide both "group" and "index" arguments to select another data group
        <Signal Sig:
                samples=[ 1.  1.  1.  1.  1.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # first channel index in the specified group
        ...
        >>> mdf.get('Sig', 1)
        <Signal Sig:
                samples=[ 11.  11.  11.  11.  11.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # channel named Sig from group 1 channel index 2
        ...
        >>> mdf.get('Sig', 1, 2)
        <Signal Sig:
                samples=[ 12.  12.  12.  12.  12.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # channel index 1 or group 2
        ...
        >>> mdf.get(None, 2, 1)
        <Signal Sig:
                samples=[ 21.  21.  21.  21.  21.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> mdf.get(group=2, index=1)
        <Signal Sig:
                samples=[ 21.  21.  21.  21.  21.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        >>> # validation using source name
        ...
        >>> mdf.get('Sig', source='VN7060')
        <Signal Sig:
                samples=[ 12.  12.  12.  12.  12.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">

        """

        gp_nr, ch_nr = self._validate_channel_selection(
            name, group, index, source=source
        )

        grp = self.groups[gp_nr]

        interp_mode = self._integer_interpolation

        original_data = data

        if ch_nr >= 0:

            # get the channel object
            channel = grp.channels[ch_nr]

            dependency_list = grp.channel_dependencies[ch_nr]

            # get data group record
            parents, dtypes = grp.parents, grp.types
            if parents is None:
                parents, dtypes = self._prepare_record(grp)

            # get group data
            if data is None:
                data = self._load_data(
                    grp, record_offset=record_offset, record_count=record_count
                )
            else:
                data = (data,)

            channel_invalidation_present = (
                channel.flags
                & (v4c.FLAG_INVALIDATION_BIT_VALID | v4c.FLAG_ALL_SAMPLES_VALID)
                == v4c.FLAG_INVALIDATION_BIT_VALID
            )

            bit_count = channel.bit_count
        else:
            # get data group record
            parents, dtypes = self._prepare_record(grp)

            parent, bit_offset = parents[ch_nr]

            channel_invalidation_present = False
            dependency_list = None

            channel = grp.logging_channels[-ch_nr - 1]

            # get group data
            if data is None:
                data = self._load_data(
                    grp, record_offset=record_offset, record_count=record_count
                )
            else:
                data = (data,)

            bit_count = channel.bit_count

        data_type = channel.data_type
        channel_type = channel.channel_type
        stream_sync = channel_type == v4c.CHANNEL_TYPE_SYNC

        encoding = None

        master_is_required = not samples_only or raster

        # check if this is a channel array
        if dependency_list:
            if not isinstance(dependency_list[0], ChannelArrayBlock):
                # structure channel composition

                _dtype = dtype(channel.dtype_fmt)
                if _dtype.itemsize == bit_count // 8:
                    fast_path = True
                    channel_values = []
                    timestamps = []
                    invalidation_bits = []

                    byte_offset = channel.byte_offset
                    record_size = (
                        grp.channel_group.samples_byte_nr
                        + grp.channel_group.invalidation_bytes_nr
                    )

                    count = 0
                    for fragment in data:

                        bts = fragment[0]
                        types = [
                            ("", f"V{byte_offset}"),
                            ("vals", _dtype),
                            ("", f"V{record_size - _dtype.itemsize - byte_offset}"),
                        ]

                        channel_values.append(fromstring(bts, types)["vals"].copy())

                        if master_is_required:
                            timestamps.append(
                                self.get_master(
                                    gp_nr, fragment, copy_master=copy_master
                                )
                            )
                        if channel_invalidation_present:
                            invalidation_bits.append(
                                self.get_invalidation_bits(gp_nr, channel, fragment)
                            )

                        count += 1
                else:
                    fast_path = False
                    names = [grp.channels[ch_nr].name for _, ch_nr in dependency_list]

                    channel_values = [[] for _ in dependency_list]
                    timestamps = []
                    invalidation_bits = []

                    count = 0
                    for fragment in data:
                        for i, (dg_nr, ch_nr) in enumerate(dependency_list):
                            vals = self.get(
                                group=dg_nr,
                                index=ch_nr,
                                samples_only=True,
                                data=fragment,
                                ignore_invalidation_bits=ignore_invalidation_bits,
                                record_offset=record_offset,
                                record_count=record_count,
                            )[0]
                            channel_values[i].append(vals)
                        if master_is_required:
                            timestamps.append(
                                self.get_master(
                                    gp_nr, fragment, copy_master=copy_master
                                )
                            )
                        if channel_invalidation_present:
                            invalidation_bits.append(
                                self.get_invalidation_bits(gp_nr, channel, fragment)
                            )

                        count += 1

                if fast_path:
                    if count > 1:
                        vals = concatenate(channel_values)
                    else:
                        vals = channel_values[0]
                else:
                    if count > 1:
                        arrays = [concatenate(lst) for lst in channel_values]
                    else:
                        arrays = [lst[0] for lst in channel_values]
                    types = [
                        (name_, arr.dtype, arr.shape[1:])
                        for name_, arr in zip(names, arrays)
                    ]
                    types = dtype(types)

                    vals = fromarrays(arrays, dtype=types)

                if master_is_required:
                    if count > 1:
                        timestamps = concatenate(timestamps)
                    else:
                        timestamps = timestamps[0]

                if channel_invalidation_present:
                    if count > 1:
                        invalidation_bits = concatenate(invalidation_bits)
                    else:
                        invalidation_bits = invalidation_bits[0]
                    if not ignore_invalidation_bits:
                        vals = vals[nonzero(~invalidation_bits)[0]]
                        if master_is_required:
                            timestamps = timestamps[nonzero(~invalidation_bits)[0]]

                if raster and len(timestamps) > 1:
                    t = arange(timestamps[0], timestamps[-1], raster)

                    vals = (
                        Signal(vals, timestamps, name="_")
                        .interp(t, interpolation_mode=interp_mode)
                    )

                    vals, timestamps, invalidation_bits = (
                        vals.samples,
                        vals.timestamps,
                        vals.invalidation_bits,
                    )

            else:
                # channel arrays
                channel_group = grp.channel_group
                samples_size = (
                    channel_group.samples_byte_nr + channel_group.invalidation_bytes_nr
                )

                channel_values = []
                timestamps = []
                invalidation_bits = []
                count = 0
                for fragment in data:

                    data_bytes, offset, _count = fragment

                    cycles = len(data_bytes) // samples_size

                    arrays = []
                    types = []
                    try:
                        parent, bit_offset = parents[ch_nr]
                    except KeyError:
                        parent, bit_offset = None, None

                    if parent is not None:
                        if grp.record is None:
                            dtypes = grp.types
                            if dtypes.itemsize:
                                record = fromstring(data_bytes, dtype=dtypes)
                            else:
                                record = None

                        else:
                            record = grp.record

                        vals = record[parent]
                    else:
                        vals = self._get_not_byte_aligned_data(data_bytes, grp, ch_nr)

                    vals = vals.copy()

                    dep = dependency_list[0]
                    if dep.flags & v4c.FLAG_CA_INVERSE_LAYOUT:
                        shape = vals.shape
                        shape = (shape[0],) + shape[1:][::-1]
                        vals = vals.reshape(shape)

                        axes = (0,) + tuple(range(len(shape) - 1, 0, -1))
                        vals = transpose(vals, axes=axes)

                    cycles_nr = len(vals)

                    for ca_block in dependency_list[:1]:
                        dims_nr = ca_block.dims

                        if ca_block.ca_type == v4c.CA_TYPE_SCALE_AXIS:
                            shape = (ca_block.dim_size_0,)
                            arrays.append(vals)
                            dtype_pair = channel.name, vals.dtype, shape
                            types.append(dtype_pair)

                        elif ca_block.ca_type == v4c.CA_TYPE_LOOKUP:
                            shape = vals.shape[1:]
                            arrays.append(vals)
                            dtype_pair = channel.name, vals.dtype, shape
                            types.append(dtype_pair)

                            if ca_block.flags & v4c.FLAG_CA_FIXED_AXIS:
                                for i in range(dims_nr):
                                    shape = (ca_block[f"dim_size_{i}"],)
                                    axis = []
                                    for j in range(shape[0]):
                                        key = f"axis_{i}_value_{j}"
                                        axis.append(ca_block[key])
                                    axis = array([axis for _ in range(cycles_nr)])
                                    arrays.append(axis)
                                    dtype_pair = (f"axis_{i}", axis.dtype, shape)
                                    types.append(dtype_pair)
                            else:
                                for i in range(dims_nr):
                                    try:
                                        ref_dg_nr, ref_ch_nr = ca_block.referenced_channels[
                                            i
                                        ]
                                    except:
                                        debug_channel(
                                            self, grp, channel, dependency_list
                                        )
                                        raise

                                    axisname = (
                                        self.groups[ref_dg_nr].channels[ref_ch_nr].name
                                    )

                                    shape = (ca_block[f"dim_size_{i}"],)
                                    if ref_dg_nr == gp_nr:
                                        axis_values = self.get(
                                            group=ref_dg_nr,
                                            index=ref_ch_nr,
                                            samples_only=True,
                                            data=fragment,
                                            ignore_invalidation_bits=ignore_invalidation_bits,
                                            record_offset=record_offset,
                                            record_count=cycles,
                                        )[0]
                                    else:
                                        channel_group = grp.channel_group
                                        record_size = channel_group.samples_byte_nr
                                        record_size += (
                                            channel_group.invalidation_bytes_nr
                                        )
                                        start = offset // record_size
                                        end = start + len(data_bytes) // record_size + 1
                                        ref = self.get(
                                            group=ref_dg_nr,
                                            index=ref_ch_nr,
                                            samples_only=True,
                                            ignore_invalidation_bits=ignore_invalidation_bits,
                                            record_offset=record_offset,
                                            record_count=cycles,
                                        )[0]
                                        axis_values = ref[start:end].copy()
                                    axis_values = axis_values[axisname]

                                    arrays.append(axis_values)
                                    dtype_pair = (axisname, axis_values.dtype, shape)
                                    types.append(dtype_pair)

                        elif ca_block.ca_type == v4c.CA_TYPE_ARRAY:
                            shape = vals.shape[1:]
                            arrays.append(vals)
                            dtype_pair = channel.name, vals.dtype, shape
                            types.append(dtype_pair)

                    for ca_block in dependency_list[1:]:
                        dims_nr = ca_block.dims

                        if ca_block.flags & v4c.FLAG_CA_FIXED_AXIS:
                            for i in range(dims_nr):
                                shape = (ca_block[f"dim_size_{i}"],)
                                axis = []
                                for j in range(shape[0]):
                                    key = f"axis_{i}_value_{j}"
                                    axis.append(ca_block[key])
                                axis = array([axis for _ in range(cycles_nr)])
                                arrays.append(axis)
                                types.append((f"axis_{i}", axis.dtype, shape))
                        else:
                            for i in range(dims_nr):
                                ref_dg_nr, ref_ch_nr = ca_block.referenced_channels[i]

                                axisname = (
                                    self.groups[ref_dg_nr].channels[ref_ch_nr].name
                                )

                                shape = (ca_block[f"dim_size_{i}"],)
                                if ref_dg_nr == gp_nr:
                                    axis_values = self.get(
                                        group=ref_dg_nr,
                                        index=ref_ch_nr,
                                        samples_only=True,
                                        data=fragment,
                                        ignore_invalidation_bits=ignore_invalidation_bits,
                                        record_offset=record_offset,
                                        record_count=cycles,
                                    )[0]
                                else:
                                    channel_group = grp.channel_group
                                    record_size = channel_group.samples_byte_nr
                                    record_size += channel_group.invalidation_bytes_nr
                                    start = offset // record_size
                                    end = start + len(data_bytes) // record_size + 1
                                    ref = self.get(
                                        group=ref_dg_nr,
                                        index=ref_ch_nr,
                                        samples_only=True,
                                        ignore_invalidation_bits=ignore_invalidation_bits,
                                        record_offset=record_offset,
                                        record_count=cycles,
                                    )[0]
                                    axis_values = ref[start:end].copy()
                                axis_values = axis_values[axisname]

                                arrays.append(axis_values)
                                dtype_pair = axisname, axis_values.dtype, shape
                                types.append(dtype_pair)

                    vals = fromarrays(arrays, dtype(types))

                    if master_is_required:
                        timestamps.append(
                            self.get_master(gp_nr, fragment, copy_master=copy_master)
                        )
                    if channel_invalidation_present:
                        invalidation_bits.append(
                            self.get_invalidation_bits(gp_nr, channel, fragment)
                        )

                    channel_values.append(vals)
                    count += 1

                if count > 1:
                    vals = concatenate(channel_values)
                elif count == 1:
                    vals = channel_values[0]
                else:
                    vals = []

                if master_is_required:
                    if count > 1:
                        timestamps = concatenate(timestamps)
                    else:
                        timestamps = timestamps[0]

                if channel_invalidation_present:
                    if count > 1:
                        invalidation_bits = concatenate(invalidation_bits)
                    else:
                        invalidation_bits = invalidation_bits[0]
                    if not ignore_invalidation_bits:
                        vals = vals[nonzero(~invalidation_bits)[0]]
                        if master_is_required:
                            timestamps = timestamps[nonzero(~invalidation_bits)[0]]

                if raster and len(timestamps) > 1:
                    t = arange(timestamps[0], timestamps[-1], raster)

                    vals = (
                        Signal(vals, timestamps, name="_")
                        .interp(t, interpolation_mode=interp_mode)
                    )

                    vals, timestamps, invalidation_bits = (
                        vals.samples,
                        vals.timestamps,
                        vals.invalidation_bits,
                    )

            conversion = channel.conversion

        else:
            # get channel values
            if channel_type in {
                v4c.CHANNEL_TYPE_VIRTUAL,
                v4c.CHANNEL_TYPE_VIRTUAL_MASTER,
            }:
                if not channel.dtype_fmt:
                    channel.dtype_fmt = get_fmt_v4(data_type, 64)
                ch_dtype = dtype(channel.dtype_fmt)

                channel_values = []
                timestamps = []
                invalidation_bits = []

                channel_group = grp.channel_group
                record_size = channel_group.samples_byte_nr
                record_size += channel_group.invalidation_bytes_nr

                count = 0
                for fragment in data:
                    data_bytes, offset, _count = fragment
                    offset = offset // record_size

                    vals = arange(len(data_bytes) // record_size, dtype=ch_dtype)
                    vals += offset

                    if master_is_required:
                        timestamps.append(
                            self.get_master(gp_nr, fragment, copy_master=copy_master)
                        )
                    if channel_invalidation_present:
                        invalidation_bits.append(
                            self.get_invalidation_bits(gp_nr, channel, fragment)
                        )

                    channel_values.append(vals)
                    count += 1

                if count > 1:
                    vals = concatenate(channel_values)
                elif count == 1:
                    vals = channel_values[0]
                else:
                    vals = []

                if master_is_required:
                    if count > 1:
                        timestamps = concatenate(timestamps)
                    else:
                        timestamps = timestamps[0]

                if channel_invalidation_present:
                    if count > 1:
                        invalidation_bits = concatenate(invalidation_bits)
                    else:
                        invalidation_bits = invalidation_bits[0]
                    if not ignore_invalidation_bits:
                        vals = vals[nonzero(~invalidation_bits)[0]]
                        if master_is_required:
                            timestamps = timestamps[nonzero(~invalidation_bits)[0]]

                if raster and len(timestamps) > 1:
                    num = float(float32((timestamps[-1] - timestamps[0]) / raster))
                    if num.is_integer():
                        t = linspace(timestamps[0], timestamps[-1], int(num))
                    else:
                        t = arange(timestamps[0], timestamps[-1], raster)

                    vals = (
                        Signal(vals, timestamps, name="_")
                        .interp(t, interpolation_mode=interp_mode)
                    )

                    vals, timestamps, invalidation_bits = (
                        vals.samples,
                        vals.timestamps,
                        vals.invalidation_bits,
                    )

            else:
                channel_values = []
                timestamps = []
                invalidation_bits = []

                count = 0
                for fragment in data:

                    data_bytes, offset, _count = fragment
                    try:
                        parent, bit_offset = parents[ch_nr]
                    except KeyError:
                        parent, bit_offset = None, None

                    if parent is not None:
                        if grp.record is None:
                            record = fromstring(data_bytes, dtype=dtypes)

                        else:
                            record = grp.record

                        vals = record[parent]

                        dtype_ = vals.dtype
                        shape_ = vals.shape
                        size = vals.dtype.itemsize
                        for dim in shape_[1:]:
                            size *= dim

                        kind_ = dtype_.kind

                        if kind_ == "b":
                            pass
                        elif len(shape_) > 1 and data_type != v4c.DATA_TYPE_BYTEARRAY:
                            vals = self._get_not_byte_aligned_data(
                                data_bytes, grp, ch_nr
                            )
                        elif kind_ not in "ui":
                            if bit_offset:
                                vals = self._get_not_byte_aligned_data(
                                    data_bytes, grp, ch_nr
                                )
                            else:
                                if bit_count != size * 8:
                                    if (
                                        bit_count % 8 == 0
                                        and size in (2, 4, 8)
                                        and data_type <= 3
                                    ):  # integer types
                                        vals = vals.view(f"<u{size}")
                                        if data_type in v4c.SIGNED_INT:
                                            vals = as_non_byte_sized_signed_int(
                                                vals, bit_count
                                            )
                                        else:
                                            mask = (1 << bit_count) - 1
                                            if vals.flags.writeable:
                                                vals &= mask
                                            else:
                                                vals = vals & mask
                                    else:
                                        vals = self._get_not_byte_aligned_data(
                                            data_bytes, grp, ch_nr
                                        )
                                else:
                                    if data_type <= 3:
                                        if not channel.dtype_fmt:
                                            channel.dtype_fmt = get_fmt_v4(data_type, bit_count, channel_type)
                                        channel_dtype = dtype(channel.dtype_fmt.split(')')[-1])
                                        vals = vals.view(channel_dtype)

                        else:
                            if data_type <= 3:
                                if dtype_.byteorder == ">":
                                    if bit_offset or bit_count != size << 3:
                                        vals = self._get_not_byte_aligned_data(
                                            data_bytes, grp, ch_nr
                                        )
                                else:
                                    if bit_offset:
                                        if kind_ == "i":
                                            vals = vals.astype(
                                                dtype(f"{dtype_.byteorder}u{size}")
                                            )
                                            vals >>= bit_offset
                                        else:
                                            vals = vals >> bit_offset

                                    if bit_count != size << 3:
                                        if data_type in v4c.SIGNED_INT:
                                            vals = as_non_byte_sized_signed_int(
                                                vals, bit_count
                                            )
                                        else:
                                            mask = (1 << bit_count) - 1
                                            if vals.flags.writeable:
                                                vals &= mask
                                            else:
                                                vals = vals & mask
                            else:
                                if bit_count != size * 8:
                                    vals = self._get_not_byte_aligned_data(
                                        data_bytes, grp, ch_nr
                                    )
                                else:
                                    if not channel.dtype_fmt:
                                        channel.dtype_fmt = get_fmt_v4(data_type, bit_count, channel_type)
                                    channel_dtype = dtype(channel.dtype_fmt.split(')')[-1])
                                    vals = vals.view(channel_dtype)

                    else:
                        vals = self._get_not_byte_aligned_data(data_bytes, grp, ch_nr)

                    if bit_count == 1 and self._single_bit_uint_as_bool:
                        vals = array(vals, dtype=bool)
                    else:
                        if not channel.dtype_fmt:
                            channel.dtype_fmt = get_fmt_v4(
                                data_type, bit_count, channel_type,
                            )
                        channel_dtype = dtype(channel.dtype_fmt.split(")")[-1])
                        if vals.dtype != channel_dtype:
                            vals = vals.astype(channel_dtype)

                    if master_is_required:
                        timestamps.append(
                            self.get_master(gp_nr, fragment, copy_master=copy_master)
                        )
                    if channel_invalidation_present:
                        invalidation_bits.append(
                            self.get_invalidation_bits(gp_nr, channel, fragment)
                        )

                    if vals.flags.writeable:
                        channel_values.append(vals)
                    else:
                        channel_values.append(vals.copy())
                    count += 1

                if count > 1:
                    vals = concatenate(channel_values)
                elif count == 1:
                    vals = channel_values[0]
                else:
                    vals = []

                if master_is_required:
                    if count > 1:
                        timestamps = concatenate(timestamps)
                    elif count == 1:
                        timestamps = timestamps[0]
                    else:
                        timestamps = []

                if channel_invalidation_present:
                    if count > 1:
                        invalidation_bits = concatenate(invalidation_bits)
                    elif count == 1:
                        invalidation_bits = invalidation_bits[0]
                    else:
                        invalidation_bits = []
                    if not ignore_invalidation_bits:
                        vals = vals[nonzero(~invalidation_bits)[0]]
                        if master_is_required:
                            timestamps = timestamps[nonzero(~invalidation_bits)[0]]

                if raster and len(timestamps) > 1:

                    num = float(float32((timestamps[-1] - timestamps[0]) / raster))
                    if num.is_integer():
                        t = linspace(timestamps[0], timestamps[-1], int(num))
                    else:
                        t = arange(timestamps[0], timestamps[-1], raster)

                    vals = (
                        Signal(vals, timestamps, name="_")
                        .interp(t, interpolation_mode=interp_mode)
                    )

                    vals, timestamps, invalidation_bits = (
                        vals.samples,
                        vals.timestamps,
                        vals.invalidation_bits,
                    )

            # get the channel conversion
            conversion = channel.conversion

            if channel_type == v4c.CHANNEL_TYPE_VLSD:
                signal_data = self._load_signal_data(group=grp, index=ch_nr)
                if signal_data:
                    values = []

                    vals = vals.tolist()

                    for offset in vals:
                        (str_size,) = UINT32_uf(signal_data, offset)
                        offset += 4
                        values.append(signal_data[offset : offset + str_size])

                    if data_type == v4c.DATA_TYPE_BYTEARRAY:

                        vals = array(values)
                        vals = vals.view(dtype=f"({vals.itemsize},)u1")

                    else:

                        vals = array(values)

                        if data_type == v4c.DATA_TYPE_STRING_UTF_16_BE:
                            encoding = "utf-16-be"

                        elif data_type == v4c.DATA_TYPE_STRING_UTF_16_LE:
                            encoding = "utf-16-le"

                        elif data_type == v4c.DATA_TYPE_STRING_UTF_8:
                            encoding = "utf-8"

                        elif data_type == v4c.DATA_TYPE_STRING_LATIN_1:
                            encoding = "latin-1"

                        else:
                            raise MdfException(
                                f'wrong data type "{data_type}" for vlsd channel'
                            )

                else:
                    # no VLSD signal data samples
                    if data_type != v4c.DATA_TYPE_BYTEARRAY:
                        vals = array([], dtype="S")

                        if data_type == v4c.DATA_TYPE_STRING_UTF_16_BE:
                            encoding = "utf-16-be"

                        elif data_type == v4c.DATA_TYPE_STRING_UTF_16_LE:
                            encoding = "utf-16-le"

                        elif data_type == v4c.DATA_TYPE_STRING_UTF_8:
                            encoding = "utf-8"

                        elif data_type == v4c.DATA_TYPE_STRING_LATIN_1:
                            encoding = "latin-1"

                        else:
                            raise MdfException(
                                f'wrong data type "{data_type}" for vlsd channel'
                            )
                    else:
                        vals = array([], dtype=get_fmt_v4(data_type, bit_count, v4c.CHANNEL_TYPE_VALUE))

            elif channel_type in {
                v4c.CHANNEL_TYPE_VALUE,
                v4c.CHANNEL_TYPE_MLSD,
            } and (
                v4c.DATA_TYPE_STRING_LATIN_1
                <= data_type
                <= v4c.DATA_TYPE_STRING_UTF_16_BE
            ):

                if data_type == v4c.DATA_TYPE_STRING_UTF_16_BE:
                    encoding = "utf-16-be"

                elif data_type == v4c.DATA_TYPE_STRING_UTF_16_LE:
                    encoding = "utf-16-le"

                elif data_type == v4c.DATA_TYPE_STRING_UTF_8:
                    encoding = "utf-8"

                elif data_type == v4c.DATA_TYPE_STRING_LATIN_1:
                    encoding = "latin-1"

                else:
                    raise MdfException(
                        f'wrong data type "{data_type}" for string channel'
                    )

            # CANopen date
            if data_type == v4c.DATA_TYPE_CANOPEN_DATE:

                vals = vals.tostring()

                types = dtype(
                    [
                        ("ms", "<u2"),
                        ("min", "<u1"),
                        ("hour", "<u1"),
                        ("day", "<u1"),
                        ("month", "<u1"),
                        ("year", "<u1"),
                    ]
                )
                vals = vals.view(types)

                arrays = []
                arrays.append(vals["ms"])
                # bit 6 and 7 of minutes are reserved
                arrays.append(vals["min"] & 0x3F)
                # only firt 4 bits of hour are used
                arrays.append(vals["hour"] & 0xF)
                # the first 4 bits are the day number
                arrays.append(vals["day"] & 0xF)
                # bit 6 and 7 of month are reserved
                arrays.append(vals["month"] & 0x3F)
                # bit 7 of year is reserved
                arrays.append(vals["year"] & 0x7F)
                # add summer or standard time information for hour
                arrays.append((vals["hour"] & 0x80) >> 7)
                # add day of week information
                arrays.append((vals["day"] & 0xF0) >> 4)

                names = [
                    "ms",
                    "min",
                    "hour",
                    "day",
                    "month",
                    "year",
                    "summer_time",
                    "day_of_week",
                ]
                vals = fromarrays(arrays, names=names)

                del arrays
                conversion = None

            # CANopen time
            elif data_type == v4c.DATA_TYPE_CANOPEN_TIME:

                types = dtype([("ms", "<u4"), ("days", "<u2")])
                vals = vals.view(types)

                arrays = []
                # bits 28 to 31 are reserverd for ms
                arrays.append(vals["ms"] & 0xFFFFFFF)
                arrays.append(vals["days"] & 0x3F)

                names = ["ms", "days"]
                vals = fromarrays(arrays, names=names)

                del arrays

            if not raw:
                if conversion:
                    vals = conversion.convert(vals)
                    conversion = None

        if samples_only:
            if not channel_invalidation_present or not ignore_invalidation_bits:
                invalidation_bits = None
            res = vals, invalidation_bits
        else:
            # search for unit in conversion texts

            if name is None:
                name = channel.name

            unit = conversion and conversion.unit or channel.unit

            comment = channel.comment

            source = channel.source
            cg_source = grp.channel_group.acq_source
            if source:
                source = SignalSource(
                    source.name,
                    source.path,
                    source.comment,
                    source.source_type,
                    source.bus_type,
                )
            elif cg_source:
                source = SignalSource(
                    cg_source.name,
                    cg_source.path,
                    cg_source.comment,
                    cg_source.source_type,
                    cg_source.bus_type,
                )
            else:
                source = None

            if hasattr(channel, "attachment_addr"):
                index = self._attachments_map[channel.attachment_addr]
                attachment = self.extract_attachment(index=index)
            elif channel_type == v4c.CHANNEL_TYPE_SYNC:
                index = self._attachments_map[channel.data_block_addr]
                attachment = self.extract_attachment(index=index)
            else:
                attachment = ()

            master_metadata = self._master_channel_metadata.get(gp_nr, None)

            if not channel_invalidation_present or not ignore_invalidation_bits:
                invalidation_bits = None

            try:
                res = Signal(
                    samples=vals,
                    timestamps=timestamps,
                    unit=unit,
                    name=name,
                    comment=comment,
                    conversion=conversion,
                    raw=raw,
                    master_metadata=master_metadata,
                    attachment=attachment,
                    source=source,
                    display_name=channel.display_name,
                    bit_count=bit_count,
                    stream_sync=stream_sync,
                    invalidation_bits=invalidation_bits,
                    encoding=encoding,
                )
            except:
                debug_channel(self, grp, channel, dependency_list)
                raise

        return res