return new *MDF* object that contains only the channels listed in
        *channels* argument

        Parameters
        ----------
        channels : list
            list of items to be filtered; each item can be :

                * a channel name string
                * (channel name, group index, channel index) list or tuple
                * (channel name, group index) list or tuple
                * (None, group index, channel index) list or tuple

        version : str
            new mdf file version from ('2.00', '2.10', '2.14', '3.00', '3.10',
            '3.20', '3.30', '4.00', '4.10', '4.11'); default *None* and in this
            case the original file version is used

        Returns
        -------
        mdf : MDF
            new *MDF* file

        Examples
        --------
        >>> from asammdf import MDF, Signal
        >>> import numpy as np
        >>> t = np.arange(5)
        >>> s = np.ones(5)
        >>> mdf = MDF()
        >>> for i in range(4):
        ...     sigs = [Signal(s*(i*10+j), t, name='SIG') for j in range(1,4)]
        ...     mdf.append(sigs)
        ...
        >>> filtered = mdf.filter(['SIG', ('SIG', 3, 1), ['SIG', 2], (None, 1, 2)])
        >>> for gp_nr, ch_nr in filtered.channels_db['SIG']:
        ...     print(filtered.get(group=gp_nr, index=ch_nr))
        ...
        <Signal SIG:
                samples=[ 1.  1.  1.  1.  1.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        <Signal SIG:
                samples=[ 31.  31.  31.  31.  31.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        <Signal SIG:
                samples=[ 21.  21.  21.  21.  21.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        <Signal SIG:
                samples=[ 12.  12.  12.  12.  12.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">

def filter(self, channels, version=None):
        """ return new *MDF* object that contains only the channels listed in
        *channels* argument

        Parameters
        ----------
        channels : list
            list of items to be filtered; each item can be :

                * a channel name string
                * (channel name, group index, channel index) list or tuple
                * (channel name, group index) list or tuple
                * (None, group index, channel index) list or tuple

        version : str
            new mdf file version from ('2.00', '2.10', '2.14', '3.00', '3.10',
            '3.20', '3.30', '4.00', '4.10', '4.11'); default *None* and in this
            case the original file version is used

        Returns
        -------
        mdf : MDF
            new *MDF* file

        Examples
        --------
        >>> from asammdf import MDF, Signal
        >>> import numpy as np
        >>> t = np.arange(5)
        >>> s = np.ones(5)
        >>> mdf = MDF()
        >>> for i in range(4):
        ...     sigs = [Signal(s*(i*10+j), t, name='SIG') for j in range(1,4)]
        ...     mdf.append(sigs)
        ...
        >>> filtered = mdf.filter(['SIG', ('SIG', 3, 1), ['SIG', 2], (None, 1, 2)])
        >>> for gp_nr, ch_nr in filtered.channels_db['SIG']:
        ...     print(filtered.get(group=gp_nr, index=ch_nr))
        ...
        <Signal SIG:
                samples=[ 1.  1.  1.  1.  1.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        <Signal SIG:
                samples=[ 31.  31.  31.  31.  31.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        <Signal SIG:
                samples=[ 21.  21.  21.  21.  21.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">
        <Signal SIG:
                samples=[ 12.  12.  12.  12.  12.]
                timestamps=[0 1 2 3 4]
                unit=""
                info=None
                comment="">

        """

        if version is None:
            version = self.version
        else:
            version = validate_version_argument(version)

        # group channels by group index
        gps = {}

        for item in channels:
            if isinstance(item, (list, tuple)):
                if len(item) not in (2, 3):
                    raise MdfException(
                        "The items used for filtering must be strings, "
                        "or they must match the first 3 argumens of the get "
                        "method"
                    )
                else:
                    group, index = self._validate_channel_selection(*item)
                    if group not in gps:
                        gps[group] = {index}
                    else:
                        gps[group].add(index)
            else:
                name = item
                group, index = self._validate_channel_selection(name)
                if group not in gps:
                    gps[group] = {index}
                else:
                    gps[group].add(index)

        # see if there are exluded channels in the filter list
        for group_index, indexes in gps.items():
            grp = self.groups[group_index]
            included_channels = set(indexes)
            master_index = self.masters_db.get(group_index, None)
            if master_index is not None:
                to_exclude = {master_index}
            else:
                to_exclude = set()
            for index in indexes:
                if self.version in MDF2_VERSIONS + MDF3_VERSIONS:
                    dep = grp.channel_dependencies[index]
                    if dep:
                        for gp_nr, ch_nr in dep.referenced_channels:
                            if gp_nr == group:
                                included_channels.remove(ch_nr)
                else:
                    dependencies = grp.channel_dependencies[index]
                    if dependencies is None:
                        continue
                    if all(
                        not isinstance(dep, ChannelArrayBlock) for dep in dependencies
                    ):
                        channels = grp.channels
                        for _, channel in dependencies:
                            to_exclude.add(channel)
                    else:
                        for dep in dependencies:
                            for gp_nr, ch_nr in dep.referenced_channels:
                                if gp_nr == group:
                                    to_exclude.add(ch_nr)

            gps[group_index] = sorted(included_channels - to_exclude)

        mdf = MDF(version=version)

        mdf.header.start_time = self.header.start_time

        if self.name:
            origin = self.name.parent
        else:
            origin = "New MDF"

        groups_nr = len(gps)

        if self._callback:
            self._callback(0, groups_nr)

        # append filtered channels to new MDF
        for new_index, (group_index, indexes) in enumerate(gps.items()):
            if version < "4.00":
                encodings = []

            group = self.groups[group_index]

            data = self._load_data(group)
            _, dtypes = self._prepare_record(group)

            for idx, fragment in enumerate(data):

                if dtypes.itemsize:
                    group.record = np.core.records.fromstring(fragment[0], dtype=dtypes)
                else:
                    group.record = None

                # the first fragment triggers and append that will add the
                # metadata for all channels
                if idx == 0:
                    sigs = []
                    for j in indexes:
                        sig = self.get(
                            group=group_index,
                            index=j,
                            data=fragment,
                            raw=True,
                            ignore_invalidation_bits=True,
                            copy_master=False,
                        )
                        if version < "4.00":
                            if sig.samples.dtype.kind == "S":
                                encodings.append(sig.encoding)
                                strsig = self.get(
                                    group=group_index,
                                    index=j,
                                    samples_only=True,
                                    ignore_invalidation_bits=True,
                                )[0]
                                sig.samples = sig.samples.astype(strsig.dtype)
                                del strsig
                                if sig.encoding != "latin-1":

                                    if sig.encoding == "utf-16-le":
                                        sig.samples = (
                                            sig.samples.view(np.uint16)
                                            .byteswap()
                                            .view(sig.samples.dtype)
                                        )
                                        sig.samples = encode(
                                            decode(sig.samples, "utf-16-be"), "latin-1"
                                        )
                                    else:
                                        sig.samples = encode(
                                            decode(sig.samples, sig.encoding), "latin-1"
                                        )
                            else:
                                encodings.append(None)
                        if not sig.samples.flags.writeable:
                            sig.samples = sig.samples.copy()
                        sigs.append(sig)

                    source_info = f"Signals filtered from <{origin}>"

                    if sigs:
                        mdf.append(sigs, source_info, common_timebase=True)
                        try:
                            if group.channel_group.flags & v4c.FLAG_CG_BUS_EVENT:
                                mdf.groups[-1].channel_group.flags = group.channel_group.flags
                                mdf.groups[-1].channel_group.acq_name = group.channel_group.acq_name
                                mdf.groups[-1].channel_group.acq_source = group.channel_group.acq_source
                                mdf.groups[-1].channel_group.comment = group.channel_group.comment
                        except AttributeError:
                            pass
                    else:
                        break

                # the other fragments will trigger onl the extension of
                # samples records to the data block
                else:
                    sigs = [
                        (
                            self.get_master(
                                group_index,
                                data=fragment,
                                copy_master=False
                            ),
                            None,
                        )
                    ]

                    for k, j in enumerate(indexes):
                        sig = self.get(
                            group=group_index,
                            index=j,
                            data=fragment,
                            samples_only=True,
                            raw=True,
                            ignore_invalidation_bits=True,
                        )
                        if version < "4.00":
                            encoding = encodings[k]
                            samples = sig[0]
                            if encoding:
                                if encoding != "latin-1":

                                    if encoding == "utf-16-le":
                                        samples = (
                                            samples.view(np.uint16)
                                            .byteswap()
                                            .view(samples.dtype)
                                        )
                                        samples = encode(
                                            decode(samples, "utf-16-be"), "latin-1"
                                        )
                                    else:
                                        samples = encode(
                                            decode(samples, encoding), "latin-1"
                                        )
                                    sig.samples = samples

                        sigs.append(sig)

                    if sigs:
                        mdf.extend(new_index, sigs)

                group.record = None

            if self._callback:
                self._callback(new_index + 1, groups_nr)

            if self._terminate:
                return

        mdf._transfer_events(self)
        if self._callback:
            mdf._callback = mdf._mdf._callback = self._callback
        return mdf