filter out data about a central frequency with some bandwidth using an IIR filter.
    
        Parameters
        ----------
        freq : float
            The frequency of the peak of interest in the PSD
        FractionOfSampleFreq : integer, optional
            The fraction of the sample frequency to sub-sample the data by.
            This sometimes needs to be done because a filter with the appropriate
            frequency response may not be generated using the sample rate at which
            the data was taken. Increasing this number means the x, y and z signals
            produced by this function will be sampled at a lower rate but a higher
            number means a higher chance that the filter produced will have a nice
            frequency response.
        PeakWidth : float, optional
            The width of the pass-band of the IIR filter to be generated to
            filter the peak. Defaults to 10KHz
        filterImplementation : string, optional
            filtfilt or lfilter - use scipy.filtfilt or lfilter
            ifft - uses built in IFFT_filter
            default: filtfilt
        timeStart : float, optional
            Starting time for filtering. Defaults to start of time data.
        timeEnd : float, optional
            Ending time for filtering. Defaults to end of time data.
        NPerSegmentPSD : int, optional
            NPerSegment to pass to scipy.signal.welch to calculate the PSD
        PyCUDA : bool, optional
            Only important for the 'ifft'-method
            If True, uses PyCUDA to accelerate the FFT and IFFT
            via using your NVIDIA-GPU
            If False, performs FFT and IFFT with conventional
            scipy.fftpack
        MakeFig : bool, optional
            If True - generate figure showing filtered and unfiltered PSD
            Defaults to True.
        show_fig : bool, optional
            If True - plot unfiltered and filtered PSD
            Defaults to True.
    
        Returns
        -------
        timedata : ndarray
            Array containing the time data
        FiletedData : ndarray
            Array containing the filtered signal in volts with time.
        fig : matplotlib.figure.Figure object
            The figure object created showing the PSD of the filtered 
            and unfiltered signal
        ax : matplotlib.axes.Axes object
            The axes object created showing the PSD of the filtered 
            and unfiltered signal

def filter_data(self, freq, FractionOfSampleFreq=1, PeakWidth=10000,
                    filterImplementation="filtfilt",
                    timeStart=None, timeEnd=None,
                    NPerSegmentPSD=1000000,
                    PyCUDA=False, MakeFig=True, show_fig=True):
        """
        filter out data about a central frequency with some bandwidth using an IIR filter.
    
        Parameters
        ----------
        freq : float
            The frequency of the peak of interest in the PSD
        FractionOfSampleFreq : integer, optional
            The fraction of the sample frequency to sub-sample the data by.
            This sometimes needs to be done because a filter with the appropriate
            frequency response may not be generated using the sample rate at which
            the data was taken. Increasing this number means the x, y and z signals
            produced by this function will be sampled at a lower rate but a higher
            number means a higher chance that the filter produced will have a nice
            frequency response.
        PeakWidth : float, optional
            The width of the pass-band of the IIR filter to be generated to
            filter the peak. Defaults to 10KHz
        filterImplementation : string, optional
            filtfilt or lfilter - use scipy.filtfilt or lfilter
            ifft - uses built in IFFT_filter
            default: filtfilt
        timeStart : float, optional
            Starting time for filtering. Defaults to start of time data.
        timeEnd : float, optional
            Ending time for filtering. Defaults to end of time data.
        NPerSegmentPSD : int, optional
            NPerSegment to pass to scipy.signal.welch to calculate the PSD
        PyCUDA : bool, optional
            Only important for the 'ifft'-method
            If True, uses PyCUDA to accelerate the FFT and IFFT
            via using your NVIDIA-GPU
            If False, performs FFT and IFFT with conventional
            scipy.fftpack
        MakeFig : bool, optional
            If True - generate figure showing filtered and unfiltered PSD
            Defaults to True.
        show_fig : bool, optional
            If True - plot unfiltered and filtered PSD
            Defaults to True.
    
        Returns
        -------
        timedata : ndarray
            Array containing the time data
        FiletedData : ndarray
            Array containing the filtered signal in volts with time.
        fig : matplotlib.figure.Figure object
            The figure object created showing the PSD of the filtered 
            and unfiltered signal
        ax : matplotlib.axes.Axes object
            The axes object created showing the PSD of the filtered 
            and unfiltered signal
        """
        if timeStart == None:
            timeStart = self.timeStart
        if timeEnd == None:
            timeEnd = self.timeEnd

        time = self.time.get_array()

        StartIndex = _np.where(time == take_closest(time, timeStart))[0][0]
        EndIndex = _np.where(time == take_closest(time, timeEnd))[0][0]

        
        input_signal = self.voltage[StartIndex: EndIndex][0::FractionOfSampleFreq]
        SAMPLEFREQ = self.SampleFreq / FractionOfSampleFreq
        if filterImplementation == "filtfilt" or filterImplementation == "lfilter":
            if filterImplementation == "filtfilt":
                ApplyFilter = scipy.signal.filtfilt
            elif filterImplementation == "lfilter":
                ApplyFilter = scipy.signal.lfilter
                
    
            b, a = make_butterworth_bandpass_b_a(freq, PeakWidth, SAMPLEFREQ)
            print("filtering data")
            filteredData = ApplyFilter(b, a, input_signal)
    
            if(_np.isnan(filteredData).any()):
                raise ValueError(
                    "Value Error: FractionOfSampleFreq must be higher, a sufficiently small sample frequency should be used to produce a working IIR filter.")
        elif filterImplementation == "ifft":
            filteredData = IFFT_filter(input_signal, SAMPLEFREQ, freq-PeakWidth/2, freq+PeakWidth/2, PyCUDA = PyCUDA)
        else:
            raise ValueError("filterImplementation must be one of [filtfilt, lfilter, ifft] you entered: {}".format(filterImplementation))
    
        if MakeFig == True:
            f, PSD = scipy.signal.welch(
                input_signal, SAMPLEFREQ, nperseg=NPerSegmentPSD)
            f_filtdata, PSD_filtdata = scipy.signal.welch(filteredData, SAMPLEFREQ, nperseg=NPerSegmentPSD)
            fig, ax = _plt.subplots(figsize=properties["default_fig_size"])
            ax.plot(f, PSD)
            ax.plot(f_filtdata, PSD_filtdata, label="filtered data")
            ax.legend(loc="best")
            ax.semilogy()
            ax.set_xlim([freq - PeakWidth, freq + PeakWidth])
        else:
            fig = None
            ax = None
        if show_fig == True:
            _plt.show()
        timedata = time[StartIndex: EndIndex][0::FractionOfSampleFreq]
        return timedata, filteredData, fig, ax