Measure voltage across load of each of the following control board
        feedback circuits:

         - Reference _(i.e., attenuated high-voltage amplifier output)_.
         - Load _(i.e., voltage across DMF device)_.

        For each channel in the channel mask. The measured voltage _(i.e.,
        ``V2``)_ can be used to compute the impedance of the measured load, the
        input voltage _(i.e., ``V1``)_, etc.

        Parameters
        ----------
        sampling_window_ms : float
            Length of sampling window (in milleseconds) for each
            RMS/peak-to-peak voltage measurement.
        n_sampling_windows_per_channel : int
            Number of RMS/peak-to-peak voltage measurements to take.
        delay_between_windows_ms : float
            Delay (in milleseconds) between RMS/peak-to-peak voltage
            measurements.
        interleave_samples : bool
            If ``True``, interleave RMS/peak-to-peak measurements for analog
            channels.

            For example, ``[<i_0>, <j_0>, <i_1>, <j_1>, ..., <i_n>, <j_n>]``
            where ``i`` and ``j`` correspond to two different analog channels.

            If ``False``, all measurements for each analog channel are taken
            together.  For example, ``[<i_0>, ..., <i_n>, <j_0>, ..., <j_n>]``
            where ``i`` and ``j`` correspond to two different analog channels.
        rms : bool
            If ``True``, a RMS voltage measurement is collected for each
            sampling window.

            Otherwise, peak-to-peak measurements are collected.
        channel_mask : array-like
            State of device channels.  Length should be equal to the number of
            device channels.

        Returns
        -------
        pandas.DataFrame
            Table containing one actuation RMS measurement and one device load
            impedance measurement per row and the columns ``frequency``,
            ``voltage``, ``channel_i``, ``V_actuation``, ``capacitance``, and
            ``impedance``.

            Rows are indexed by time since first measurement in frame.

def sweep_channels(self,
                       sampling_window_ms,
                       n_sampling_windows_per_channel,
                       delay_between_windows_ms,
                       interleave_samples,
                       rms,
                       channel_mask):
        '''
        Measure voltage across load of each of the following control board
        feedback circuits:

         - Reference _(i.e., attenuated high-voltage amplifier output)_.
         - Load _(i.e., voltage across DMF device)_.

        For each channel in the channel mask. The measured voltage _(i.e.,
        ``V2``)_ can be used to compute the impedance of the measured load, the
        input voltage _(i.e., ``V1``)_, etc.

        Parameters
        ----------
        sampling_window_ms : float
            Length of sampling window (in milleseconds) for each
            RMS/peak-to-peak voltage measurement.
        n_sampling_windows_per_channel : int
            Number of RMS/peak-to-peak voltage measurements to take.
        delay_between_windows_ms : float
            Delay (in milleseconds) between RMS/peak-to-peak voltage
            measurements.
        interleave_samples : bool
            If ``True``, interleave RMS/peak-to-peak measurements for analog
            channels.

            For example, ``[<i_0>, <j_0>, <i_1>, <j_1>, ..., <i_n>, <j_n>]``
            where ``i`` and ``j`` correspond to two different analog channels.

            If ``False``, all measurements for each analog channel are taken
            together.  For example, ``[<i_0>, ..., <i_n>, <j_0>, ..., <j_n>]``
            where ``i`` and ``j`` correspond to two different analog channels.
        rms : bool
            If ``True``, a RMS voltage measurement is collected for each
            sampling window.

            Otherwise, peak-to-peak measurements are collected.
        channel_mask : array-like
            State of device channels.  Length should be equal to the number of
            device channels.

        Returns
        -------
        pandas.DataFrame
            Table containing one actuation RMS measurement and one device load
            impedance measurement per row and the columns ``frequency``,
            ``voltage``, ``channel_i``, ``V_actuation``, ``capacitance``, and
            ``impedance``.

            Rows are indexed by time since first measurement in frame.
        '''

        channel_cumsum = np.cumsum(channel_mask)

        # figure out how many channels are in the mask, and how many we can scan
        # per request
        n_channels_in_mask = channel_cumsum[-1]
        max_channels_per_call = (self.MAX_PAYLOAD_LENGTH - 4*4) / \
                                 (3*2) / n_sampling_windows_per_channel

        # cache the channel mask
        self._channel_mask_cache = np.array(channel_mask)

        buffer = np.zeros(4)
        for i in range(int(math.ceil(n_channels_in_mask / max_channels_per_call))):
            # figure out which channels to include in this call
            ind = np.logical_and(channel_cumsum >= i * max_channels_per_call,
                                 channel_cumsum < (i + 1) * max_channels_per_call)

            # copy those channels from the cached mask
            channel_mask_ = np.zeros(len(self._channel_mask_cache), dtype=int)
            channel_mask_[ind] = self._channel_mask_cache[ind]

            # convert it to a uint8_tVector
            channel_mask_uint8 = uint8_tVector()
            channel_mask_uint8.extend(channel_mask_)

            buffer = buffer[:-4]
            buffer = np.concatenate((buffer, np.array(Base.sweep_channels(self,
                                                     sampling_window_ms,
                                                     n_sampling_windows_per_channel,
                                                     delay_between_windows_ms,
                                                     interleave_samples,
                                                     rms,
                                                     channel_mask_uint8))))
        return self.sweep_channels_buffer_to_feedback_result(buffer)