def setup_filter(self, respath, run, **kwargs):
        """
        Load the callibration runs and convert voltage signal to yaw angles
        """

        # specify the window of the staircase
        #start, end = 30100, -30001
        start = kwargs.get('start', None)
        end = kwargs.get('end', None)
        figpath = kwargs.get('figpath', None)
#        figfile = kwargs.get('figfile', None)
        dt_treshold = kwargs.get('dt_treshold', None)
#        plot_data = kwargs.get('plot_data', False)
#        respath = kwargs.get('respath', None)
#        run = kwargs.get('run', None)

        # load the dspace mat file
        dspace = ojfresult.DspaceMatFile(respath + run)
        # the yaw channel
        ch = 6
        # or a more robust way of determining the channel number
        ch = dspace.labels_ch['Yaw Laser']

        # sample rate of the signal
        sample_rate = calc_sample_rate(dspace.time)

        # file name based on the run file
        figfile = dspace.matfile.split('/')[-1] + '_ch' + str(ch)

        # prepare the data
        time = dspace.time[start:end]
        # the actual yaw signal
        data = dspace.data[start:end,ch]

        # -------------------------------------------------
        # smoothen the signal with some splines
        # -------------------------------------------------
        # NOTE: the smoothing will make the transitions also smoother. This
        # is not good. The edges of the stair need to be steep!
#        smoothen = UnivariateSpline(dspace.time, dspace.data[:,ch], s=2)
#        data_s_full = smoothen(dspace.time)
#        # first the derivatices
#        data_s_dt = data_s_full[start+1:end+1]-data_s_full[start:end]
#        # than cut it off
#        data_s = data_s_full[start:end]

        # -------------------------------------------------
        # local derivatives of the yaw signal and filtering
        # -------------------------------------------------
        data_dt = dspace.data[start+1:end+1,ch]-dspace.data[start:end,ch]
        # filter the local derivatives
        filt = Filters()
        data_filt, N, delay = filt.fir(time, data, ripple_db=20,
                        freq_trans_width=0.5, cutoff_hz=0.3, plot=False,
                        figpath=figpath, figfile=figfile + 'filter_design',
                        sample_rate=sample_rate)

        data_filt_dt = np.ndarray(data_filt.shape)
        data_filt_dt[1:] = data_filt[1:] - data_filt[0:-1]
        data_filt_dt[0] = np.nan

        # -------------------------------------------------
        # smoothen the signal with some splines
        # -------------------------------------------------
#        smoothen = UnivariateSpline(time, data_filt, s=2)
#        data_s = smoothen(time)
#        # first the derivatices
#        data_s_dt = np.ndarray(data_s.shape)
#        data_s_dt[1:] = data_s[1:]-data_s[:-1]
#        data_s_dt[0] = np.nan

        # -------------------------------------------------
        # filter values above certain treshold
        # ------------------------------------------------
        # only keep values which are steady, meaning dt signal is low!

        # based upon the filtering, only select data points for which the
        # filtered derivative is between a certain treshold
        staircase_i = np.abs(data_filt_dt).__ge__(dt_treshold)
        # make a copy of the original signal and fill in Nans on the selected
        # values
        data_reduced = data.copy()
        data_reduced[staircase_i] = np.nan
        data_reduced_dt = np.ndarray(data_reduced.shape)
        data_reduced_dt[1:] = np.abs(data_reduced[1:] - data_reduced[:-1])
        data_reduced_dt[0] = np.nan

        nonnan_i = np.isnan(data_reduced_dt).__invert__()
        dt_noise_treshold = data_reduced_dt[nonnan_i].max()
        print ' dt_noise_treshold ', dt_noise_treshold

        # remove all the nan values
        data_trim = data_reduced[np.isnan(data_reduced).__invert__()]
        time_trim = time[np.isnan(data_reduced).__invert__()]
#        # figure out which dt's are above the treshold
#        data_trim2 = data_trim.copy()
#        data_trim2.sort()
#        data_trim2.
#        # where the dt of the reduced format is above the noise treshold,
#        # we have a stair
#        data_trim_dt = np.abs(data_trim[1:] - data_trim[:-1])
#        argstairs = data_trim_dt.__gt__(dt_noise_treshold)
#        data_trim2 = data_trim_dt.copy()
#        data_trim_dt.sort()
#        data_trim_dt.__gt__(dt_noise_treshold)

        # -------------------------------------------------
        # read the average value over each stair (time and data)
        # ------------------------------------------------
        data_ordered, time_stair, data_stair = self.order_staircase(time_trim,
                                        data_trim, dt_noise_treshold*4.)

        # -------------------------------------------------
        # setup plot
        # -------------------------------------------------
        labels = np.ndarray(3, dtype='<U100')
        labels[0] = dspace.labels[ch]
        labels[1] = 'yawchan derivative'
        labels[2] = 'psd'

        plot = plotting.A4Tuned()
        title = figfile.replace('_', ' ')
        plot.setup(figpath+figfile+'_filter', nr_plots=2, grandtitle=title,
                   figsize_y=20, wsleft_cm=2., wsright_cm=2.5)

        # -------------------------------------------------
        # plotting of signal
        # -------------------------------------------------
        ax1 = plot.fig.add_subplot(plot.nr_rows, plot.nr_cols, 1)
        ax1.plot(time, data, label='data')
        # add the results of the filtering technique
        time_stair, data_stair
        ax1.plot(time[N-1:], data_reduced[N-1:], 'r', label='data red')
#        ax1.plot(time[N-1:], data_filt[N-1:], 'g', label='data_filt')
        # also include the selected chair data
        label = '%i stairs' % data_stair.shape[0]
        ax1.plot(time_stair, data_stair, 'ko', label=label, alpha=0.2)
        ax1.grid(True)
        ax1.legend(loc='lower left')
        # -------------------------------------------------
        # plotting derivatives on right axis
        # -------------------------------------------------
        ax1b = ax1.twinx()
#        ax1b.plot(time[N:]-delay,data_s_dt[N:],alpha=0.2,label='data_s_dt')
        ax1b.plot(time[N:], data_filt_dt[N:], 'r', alpha=0.2,
                  label='data filt dt')
#        ax1b.plot(time[N:], data_reduced_dt[N:], 'b', alpha=0.2,
#                  label='data_reduced_dt')
#        ax1b.plot(time[N-1:]-delay, filtered_x_dt[N-1:], alpha=0.2)
        ax1b.legend()
        ax1b.grid(True)

        # -------------------------------------------------
        # the power spectral density
        # -------------------------------------------------
        ax3 = plot.fig.add_subplot(plot.nr_rows, plot.nr_cols, 2)
        Pxx, freqs = ax3.psd(data, Fs=sample_rate, label='data')
        Pxx, freqs = ax3.psd(data_dt, Fs=sample_rate, label='data dt')
#        Pxx, freqs = ax3.psd(data_s_dt, Fs=sample_rate, label='data_s_dt')
        Pxx, freqs = ax3.psd(data_filt_dt[N-1:], Fs=sample_rate,
                             label='data filt dt')
        ax3.legend()
#        print Pxx.shape, freqs.shape
        plot.save_fig()

        # -------------------------------------------------
        # get amplitudes of the stair edges
        # -------------------------------------------------

#        # max step
#        data_trim_dt_sort = data_trim_dt.sort()[0]
#        # estimate at what kind of a delta we are looking for when changing
#        # stairs
#        data_dt_std = data_trim_dt.std()
#        data_dt_mean = (np.abs(data_trim_dt)).mean()
#
#        time_data_dt = np.transpose(np.array([time, data_filt_dt]))
#        data_filt_dt_amps = HawcPy.dynprop().amplitudes(time_data_dt, h=1e-3)
#
#        print '=== nr amplitudes'
#        print len(data_filt_dt_amps)
#        print data_filt_dt_amps

        return time_stair, data_stair
    def setup_filter(self, time, data, **kwargs):
        """
        Load the callibration runs and convert voltage signal to yaw angles

        Parameters
        ----------

        time : ndarray(k)

        data : ndarray(k)

        Returns
        -------

        time_stair : ndarray(n)
            Average time stamp over the stair step

        data_stair : ndarray(n)
            Average value of the selected stair step


        """
        # time and data should both be 1D and have the same shape!
        assert time.shape == data.shape

        runid = kwargs.get('runid', self.runid)

        # smoothen method: spline or moving average
        smoothen = kwargs.get('smoothen', 'spline')
        # what is the window of the moving average in seconds
        smooth_window = kwargs.get('smooth_window', 2)

        # specify the window of the staircase
        #start, end = 30100, -30001
        start = kwargs.get('start', 0)
        end = kwargs.get('end', len(time))
        dt = kwargs.get('dt', 1)
        cutoff_hz = kwargs.get('cutoff_hz', None)
        self.points_per_stair = kwargs.get('points_per_stair', 20)
        # at what is the minimum required value on dt or dt2 for a new stair
        self.stair_step_tresh = kwargs.get('stair_step_tresh', 1)

#        plot_data = kwargs.get('plot_data', False)
#        respath = kwargs.get('respath', None)
#        run = kwargs.get('run', None)

        # sample rate of the signal
        sample_rate = calc_sample_rate(time)

        # prepare the data
        time = time[start:end]
        # the actual raw signal
        data = data[start:end]

        # -------------------------------------------------
        # Progress plotting
        # ----------------------------------------------
        if self.plt_progress:
            plt.figure()
            Pxx, freqs = plt.psd(data, Fs=sample_rate, label='data')
            plt.show()

            plt.figure()
            plt.plot(time, data, label='raw data')

        # -------------------------------------------------
        # setup plot
        # -------------------------------------------------
#        labels = np.ndarray(3, dtype='<U100')
#        labels[0] = label
#        labels[1] = 'yawchan derivative'
#        labels[2] = 'psd'

        # remove any underscores for latex printing
        grandtitle = self.figfile.replace('_', '\_')
        plot = plotting.A4Tuned(scale=1.5)
        plot.setup(self.figpath+self.figfile+'_filter', nr_plots=3,
                   grandtitle=grandtitle, wsleft_cm=1.5, wsright_cm=1.8,
                   hspace_cm=1.2, size_x_perfig=10, size_y_perfig=5,
                   wsbottom_cm=1.0, wstop_cm=1.5)

        # -------------------------------------------------
        # plotting original and smoothend signal
        # -------------------------------------------------
        ax1 = plot.fig.add_subplot(plot.nr_rows, plot.nr_cols, 1)
        ax1.plot(time, data, 'b', label='raw data', alpha=0.6)
        data_raw = data.copy()

        # -------------------------------------------------
        # signal frequency filtering, if applicable
        # -------------------------------------------------
        # filter the local derivatives if applicable
        if cutoff_hz:
            filt = Filters()
            data_filt, N, delay = filt.fir(time, data, ripple_db=20,
                            freq_trans_width=0.5, cutoff_hz=cutoff_hz,
                            figpath=self.figpath,
                            figfile=self.figfile + 'filter_design',
                            sample_rate=sample_rate, plot=False,)

            if self.plt_progress:
                # add the results of the filtering technique
                plt.plot(time[N-1:], data_filt[N-1:], 'r', label='freq filt')

            data = data_filt
            time = time[N-1:]#-delay

        else:
            N = 1

        # -------------------------------------------------------
        # smoothen the signal with some splines or moving average
        # -------------------------------------------------------
        # NOTE: the smoothing will make the transitions also smoother. This
        # is not good. The edges of the stair need to be steep!
        # for the binary data this is actually a good thing, since the dt's
        # are almost always the same between time steps. We would otherwise
        # need a dt based on several time steps
        if smoothen == 'splines':
            print 'start applying spline ...',
            uni_spline = UnivariateSpline(time, data)
            data = uni_spline(time)
            print 'done!'
            NN = 0 # no time shift due to filtering?
            if self.plt_progress:
                plt.plot(time, data, label='spline data')

        elif smoothen == 'moving':
            print 'start calculating movering average ...',
            filt = Filters()
            # take av2s window, calculate the number of samples per window
            ws = int(smooth_window*sample_rate)
            data = filt.smooth(data, window_len=ws, window='hanning')
            NN = len(data) - len(time)
            data = data[NN:]
            print 'done!'

            if self.plt_progress:
                plt.plot(time, data, label='moving average')

        else:
            raise ValueError, 'smoothen method should be moving or splines'

        # -------------------------------------------------
        # additional smoothening: downsampling
        # -------------------------------------------------
        # and up again in order not to brake the plotting further down
        time_down = np.arange(time[0], time[-1], 0.1)
        data_down = sp.interpolate.griddata(time, data, time_down)
        # and upsampling again
        data = sp.interpolate.griddata(time_down, data_down, time)

        # -------------------------------------------------
        # plotting original and smoothend signal
        # -------------------------------------------------
        ax1.plot(time, data, 'r', label='data smooth')
        ax1.grid(True)
        leg1 = ax1.legend(loc='best')
        leg1.get_frame().set_alpha(0.5)
        ax1.set_title('smoothing method: ' + smoothen)

        # -------------------------------------------------
        # local derivatives of the signal and filtering
        # -------------------------------------------------
        data_dt = np.ndarray(data.shape)
        data_dt[1:] = data[1:] - data[0:-1]
        data_dt[0] = np.nan
        data_dt = np.abs(data_dt)

        # frequency filter was applied here originally
        data_filt_dt = data_dt

        # if no threshold is given, just take the 20% of the max value
        dt_max = np.nanmax(np.abs(data_filt_dt))*0.2
        dt_treshold = kwargs.get('dt_treshold', dt_max)

        # -------------------------------------------------
        # filter dt or dt2 above certain treshold?
        # -----------------------------------------------
        # only keep values which are steady, meaning dt signal is low!

        if dt == 2:
            tmp = np.ndarray(data_filt_dt.shape)
            tmp[1:] = data_filt_dt[1:] - data_filt_dt[0:-1]
            tmp[0] = np.nan
            data_filt_dt = tmp
        # based upon the filtering, only select data points for which the
        # filtered derivative is between a certain treshold
        staircase_i = np.abs(data_filt_dt).__ge__(dt_treshold)
        # reduce to 1D
        staircase_arg=np.argwhere(np.abs(data_filt_dt)<=dt_treshold).flatten()

        # -------------------------------------------------
        # replace values for too high dt with Nan
        # ------------------------------------------------

        # ---------------------------------
        # METHOD version2, slower because of staircase_arg computation above
        data_masked = data.copy()
        data_masked[staircase_i] = np.nan

        data_masked_dt = data_filt_dt.copy()
        data_masked_dt[staircase_i] = np.nan

        data_trim = data[staircase_arg]
        time_trim = time[staircase_arg]

        print 'max in data_masked_dt:', np.nanmax(data_masked_dt)
        # ---------------------------------
        # METHOD version2, faster if staircase_arg is not required!
        ## make a copy of the original signal and fill in Nans on the selected
        ## values
        #data_masked = data.copy()
        #data_masked[staircase_i] = np.nan
        #
        #data_masked_dt = data_filt_dt.copy()
        #data_masked_dt[staircase_i] = np.nan
        #
        ## remove all the nan values
        #data_trim = data_masked[np.isnan(data_masked).__invert__()]
        #time_trim = time[np.isnan(data_masked).__invert__()]
        #
        #dt_noise_treshold = np.nanmax(data_masked_dt)
        #print 'max in data_masked_dt', dt_noise_treshold
        # ---------------------------------

#        # figure out which dt's are above the treshold
#        data_trim2 = data_trim.copy()
#        data_trim2.sort()
#        data_trim2.
#        # where the dt of the masked format is above the noise treshold,
#        # we have a stair
#        data_trim_dt = np.abs(data_trim[1:] - data_trim[:-1])
#        argstairs = data_trim_dt.__gt__(dt_noise_treshold)
#        data_trim2 = data_trim_dt.copy()
#        data_trim_dt.sort()
#        data_trim_dt.__gt__(dt_noise_treshold)

        # -------------------------------------------------
        # intermediate checking of the signal
        # -------------------------------------------------
        if self.plt_progress:
            # add the results of the filtering technique
            plt.plot(time[N-1:], data_masked[N-1:], 'rs', label='data red')
            plt.legend(loc='best')
            plt.grid(True)
            plt.twinx()
#            plt.plot(time, data_filt_dt, label='data_filt_dt')
            plt.plot(time, data_masked_dt, 'm', label='data\_masked\_dt',
                     alpha=0.4)
            plt.legend(loc='best')
            plt.show()
            print 'saving plt_progress:',
            print self.figpath+'filter_design_progress.png'
            plt.savefig(self.figpath+'filter_design_progress.png')

        # -------------------------------------------------
        # check if we have had sane filtering
        # -------------------------------------------------

        print 'data      :', data.shape
        print 'data_trim :', data_trim.shape
        print 'trim ratio:', len(data)/len(data_trim)

        # there should be at least one True value
        assert staircase_i.any()
        # they can't all be True, than filtering is too heavy
        if len(data_trim) < len(data)*0.01:
            msg = 'dt_treshold is too low, not enough data left'
            raise ValueError, msg
        # if no data is filtered at all, filtering is too conservative
        elif len(data_trim) > len(data)*0.95:
            msg = 'dt_treshold is too high, too much data left'
            raise ValueError, msg
        # if the data array is too big, abort on memory concerns
        if len(data_trim) > 200000:
            msg = 'too much data points for stair case analysis (cfr memory)'
            raise ValueError, msg

        # -------------------------------------------------
        # read the average value over each stair (time and data)
        # ------------------------------------------------
        #try:
            ##np.save('time_trim', time_trim)
            ##np.save('data_trim', data_trim)
            ##np.save('staircase_arg', staircase_arg)
            ##tmp = np.array([self.points_per_stair, self.stair_step_tresh])
            ##np.save('tmp', tmp)
            #data_ordered, time_stair, data_stair, arg_stair \
                #= cython_func.order_staircase(time_trim, data_trim,
                #staircase_arg, self.points_per_stair, self.stair_step_tresh)
        #except ImportError:
        data_ordered, time_stair, data_stair, arg_stair \
            = self.order_staircase(time_trim, data_trim, staircase_arg)

        # convert the arg_stair to a flat set and replace start/stop pairs
        # with all indices in between. Now we can select all stair values
        # in the raw dataset
        arg_st_fl = np.empty(data_raw.shape, dtype=np.int)
        i = 0
        for k in range(arg_stair.shape[1]):
            #print '%6i %6i' % (arg_stair[0,k],arg_stair[1,k])
            tmp = np.arange(arg_stair[0,k], arg_stair[1,k]+1, 1, dtype=np.int)
            #print tmp, '->', i, ':', i+len(tmp)
            arg_st_fl[i:i+len(tmp)] = tmp
            i += len(tmp)
        # remove the unused elements from the array
        arg_st_fl = arg_st_fl[:i]

        # -------------------------------------------------
        # plotting of smoothen signal and stairs
        # -------------------------------------------------
        ax1 = plot.fig.add_subplot(plot.nr_rows, plot.nr_cols, 2)
        ax1.plot(time, data, label='data smooth', alpha=0.6)
        # add the results of the filtering technique

        ax1.plot(time[N-1:], data_masked[N-1:], 'r', label='data masked')
#        ax1.plot(time[N-1:], data_filt[N-1:], 'g', label='data_filt')
        # also include the selected chair data
        figlabel = '%i stairs' % data_stair.shape[0]
        ax1.plot(time_stair, data_stair, 'ko', label=figlabel, alpha=0.4)
        ax1.grid(True)
        # the legend, on or off?
        #leg1 = ax1.legend(loc='upper left')
        #leg1.get_frame().set_alpha(0.5)
        # -------------------------------------------------
        # plotting derivatives on right axis
        # -------------------------------------------------
        ax1b = ax1.twinx()
#        ax1b.plot(time[N:]-delay,data_s_dt[N:],alpha=0.2,label='data_s_dt')
        ax1b.plot(time[N:], data_filt_dt[N:], 'r', alpha=0.35,
                  label='data\_filt\_dt')
        majorFormatter = FormatStrFormatter('%8.1e')
        ax1b.yaxis.set_major_formatter(majorFormatter)
#        ax1b.plot(time[N:], data_masked_dt[N:], 'b', alpha=0.2,
#                  label='data_masked_dt')
#        ax1b.plot(time[N-1:]-delay, filtered_x_dt[N-1:], alpha=0.2)
#        leg1b = ax1b.legend(loc='best')
#        leg1b.get_frame().set_alpha(0.5)
#        ax1b.grid(True)

        # -------------------------------------------------
        # 3th plot to check if the raw chair signal is ok
        # -------------------------------------------------

        ax1 = plot.fig.add_subplot(plot.nr_rows, plot.nr_cols, 3)
        ax1.plot(time[arg_st_fl], data_raw[arg_st_fl], 'k+', label='rawstair',
                 alpha=0.1)
        ax1.plot(time[N-1:], data_masked[N-1:], 'r', label='data masked')
        ax1.set_xlabel('time [s]')

        # -------------------------------------------------
        # the power spectral density
        # -------------------------------------------------
#        ax3 = plot.fig.add_subplot(plot.nr_rows, plot.nr_cols, 3)
#        Pxx, freqs = ax3.psd(data, Fs=sample_rate, label='data smooth')
##        Pxx, freqs = ax3.psd(data_dt, Fs=sample_rate, label='data_dt')
##        Pxx, freqs = ax3.psd(data_filt_dt[N-1:], Fs=sample_rate,
##                             label='data_filt_dt')
#        ax3.legend()
##        print Pxx.shape, freqs.shape

        plot.save_fig()

        # -------------------------------------------------
        # get amplitudes of the stair edges
        # -------------------------------------------------

#        # max step
#        data_trim_dt_sort = data_trim_dt.sort()[0]
#        # estimate at what kind of a delta we are looking for when changing
#        # stairs
#        data_dt_std = data_trim_dt.std()
#        data_dt_mean = (np.abs(data_trim_dt)).mean()
#
#        time_data_dt = np.transpose(np.array([time, data_filt_dt]))
#        data_filt_dt_amps = HawcPy.dynprop().amplitudes(time_data_dt, h=1e-3)
#
#        print '=== nr amplitudes'
#        print len(data_filt_dt_amps)
#        print data_filt_dt_amps

        # -------------------------------------------------
        # save the data
        # -------------------------------------------------

        filename = runid + '-time_stair'
        np.savetxt(self.pprpath + filename, time_stair)
        filename = runid + '-data_stair'
        np.savetxt(self.pprpath + filename, data_stair)

        # in order to maintain backwards compatibility, save the arguments
        # of the stair to self
        self.arg_st_fl = arg_st_fl # flat, contains all indices on the stairs
        # start/stop indeces for stair k = arg_stair[0,k], arg_stair[1,k]
        self.arg_stair = arg_stair


        return time_stair, data_stair