Ejemplo n.º 1
0
def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
    """Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
    Note that broadcasting does not work.
    """
    from scipy.signal import sosfilt_zi
    from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
    x = np.asarray(x)

    if padlen is None:
        edge = 0
    else:
        edge = padlen

    # x's 'axis' dimension must be bigger than edge.
    if x.shape[axis] <= edge:
        raise ValueError("The length of the input vector x must be at least "
                         "padlen, which is %d." % edge)

    if padtype is not None and edge > 0:
        # Make an extension of length `edge` at each
        # end of the input array.
        if padtype == 'even':
            ext = even_ext(x, edge, axis=axis)
        elif padtype == 'odd':
            ext = odd_ext(x, edge, axis=axis)
        else:
            ext = const_ext(x, edge, axis=axis)
    else:
        ext = x

    # Get the steady state of the filter's step response.
    zi = sosfilt_zi(sos)

    # Reshape zi and create x0 so that zi*x0 broadcasts
    # to the correct value for the 'zi' keyword argument
    # to lfilter.
    #zi_shape = [1] * x.ndim
    #zi_shape[axis] = zi.size
    #zi = np.reshape(zi, zi_shape)
    x0 = axis_slice(ext, stop=1, axis=axis)
    # Forward filter.
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

    # Backward filter.
    # Create y0 so zi*y0 broadcasts appropriately.
    y0 = axis_slice(y, start=-1, axis=axis)
    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

    # Reverse y.
    y = axis_reverse(y, axis=axis)

    if edge > 0:
        # Slice the actual signal from the extended signal.
        y = axis_slice(y, start=edge, stop=-edge, axis=axis)

    return y
Ejemplo n.º 2
0
def _sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None, method='pad', irlen=None):
    """Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with SOS.
    Note that broadcasting does not work.
    """
    from scipy.signal import sosfilt_zi
    from scipy.signal._arraytools import odd_ext, axis_slice, axis_reverse
    x = np.asarray(x)
    
    if padlen is None:
        edge = 0
    else:
        edge = padlen

    # x's 'axis' dimension must be bigger than edge.
    if x.shape[axis] <= edge:
        raise ValueError("The length of the input vector x must be at least "
                         "padlen, which is %d." % edge)

    if padtype is not None and edge > 0:
        # Make an extension of length `edge` at each
        # end of the input array.
        if padtype == 'even':
            ext = even_ext(x, edge, axis=axis)
        elif padtype == 'odd':
            ext = odd_ext(x, edge, axis=axis)
        else:
            ext = const_ext(x, edge, axis=axis)
    else:
        ext = x

    # Get the steady state of the filter's step response.
    zi = sosfilt_zi(sos)

    # Reshape zi and create x0 so that zi*x0 broadcasts
    # to the correct value for the 'zi' keyword argument
    # to lfilter.
    #zi_shape = [1] * x.ndim
    #zi_shape[axis] = zi.size
    #zi = np.reshape(zi, zi_shape)
    x0 = axis_slice(ext, stop=1, axis=axis)
    # Forward filter.
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

    # Backward filter.
    # Create y0 so zi*y0 broadcasts appropriately.
    y0 = axis_slice(y, start=-1, axis=axis)
    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

    # Reverse y.
    y = axis_reverse(y, axis=axis)

    if edge > 0:
        # Slice the actual signal from the extended signal.
        y = axis_slice(y, start=edge, stop=-edge, axis=axis)

    return y
Ejemplo n.º 3
0
    def butter_bandpass_sosfiltfilt(self,
                                    lowcut=None,
                                    highcut=None,
                                    accel_axis="z",
                                    order=5,
                                    axis=-1,
                                    padtype="odd",
                                    padlen=None,
                                    method='pad',
                                    irlen=None):
        '''Filtfilt version using Second Order sections. Code is taken from scipy.signal.filtfilt and adapted to make it work with
        sos. Note that broadcasting does not work'''
        data = np.asarray(getattr(self.df, accel_axis[:]))
        sos = self.butter_bandpass(lowcut, highcut, order)

        if padlen is None:
            edge = 0
        else:
            edge = padlen

        if data.shape[axis] <= edge:
            raise ValueError(
                "The length of the input vector x must be at least padlen, which is %d."
                % edge)

        if padtype is not None and edge > 0:
            if padtype == "even":
                ext = even_ext(data, edge, axis=axis)
            elif padtype == "odd":
                ext = odd_ext(data, edge, axis=axis)
            else:
                ext = const_ext(data, edge, axis=axis)
        else:
            ext = data

        # Get the steady state of the filter's first step resopnse
        zi = sosfilt_zi(sos)

        # Reshape zi and create x0 so that zi*x0 broadcasts to the correct value for the zi keyword argument to lfilter
        x0 = axis_slice(ext, stop=1, axis=axis)
        # Forward filter
        (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x0)

        y0 = axis_slice(y, start=-1, axis=axis)
        # Backward filter
        (y, zf) = sosfilt(sos,
                          axis_reverse(y, axis=axis),
                          axis=axis,
                          zi=zi * y0)
        y = axis_reverse(y, axis=axis)

        if edge > 0:
            y = axis_slice(y, start=edge, stop=-edge, axis=axis)

        return y
Ejemplo n.º 4
0
def _fit_edge(x, window_start, window_stop, interp_start, interp_stop, axis,
              polyorder, deriv, delta, y):
    """
    Given an n-d array `x` and the specification of a slice of `x` from
    `window_start` to `window_stop` along `axis`, create an interpolating
    polynomial of each 1-d slice, and evaluate that polynomial in the slice
    from `interp_start` to `interp_stop`.  Put the result into the
    corresponding slice of `y`.
    """

    # Get the edge into a (window_length, -1) array.
    try:
        from scipy.signal._arraytools import axis_slice
    except ImportError:
        raise ImportError('Your scipy installation seems to be outdated, '
                          'cant import scipy.signal._arraytools')
    x_edge = axis_slice(x, start=window_start, stop=window_stop, axis=axis)
    if axis == 0 or axis == -x.ndim:
        xx_edge = x_edge
        swapped = False
    else:
        xx_edge = x_edge.swapaxes(axis, 0)
        swapped = True
    xx_edge = xx_edge.reshape(xx_edge.shape[0], -1)

    # Fit the edges.  poly_coeffs has shape (polyorder + 1, -1),
    # where '-1' is the same as in xx_edge.
    poly_coeffs = np.polyfit(np.arange(0, window_stop - window_start), xx_edge,
                             polyorder)

    if deriv > 0:
        poly_coeffs = _polyder(poly_coeffs, deriv)

    # Compute the interpolated values for the edge.
    i = np.arange(interp_start - window_start, interp_stop - window_start)
    values = np.polyval(poly_coeffs, i.reshape(-1, 1)) / (delta**deriv)

    # Now put the values into the appropriate slice of y.
    # First reshape values to match y.
    shp = list(y.shape)
    shp[0], shp[axis] = shp[axis], shp[0]
    values = values.reshape(interp_stop - interp_start, *shp[1:])
    if swapped:
        values = values.swapaxes(0, axis)
    # Get a view of the data to be replaced by values.
    y_edge = axis_slice(y, start=interp_start, stop=interp_stop, axis=axis)
    y_edge[...] = values
Ejemplo n.º 5
0
def _fit_edge(x, window_start, window_stop, interp_start, interp_stop,
              axis, polyorder, deriv, delta, y):
    """
    Given an n-d array `x` and the specification of a slice of `x` from
    `window_start` to `window_stop` along `axis`, create an interpolating
    polynomial of each 1-d slice, and evaluate that polynomial in the slice
    from `interp_start` to `interp_stop`.  Put the result into the
    corresponding slice of `y`.
    """

    # Get the edge into a (window_length, -1) array.
    try:
        from scipy.signal._arraytools import axis_slice
    except ImportError:
        raise ImportError('Your scipy installation seems to be outdated, '
                          'cant import scipy.signal._arraytools')
    x_edge = axis_slice(x, start=window_start, stop=window_stop, axis=axis)
    if axis == 0 or axis == -x.ndim:
        xx_edge = x_edge
        swapped = False
    else:
        xx_edge = x_edge.swapaxes(axis, 0)
        swapped = True
    xx_edge = xx_edge.reshape(xx_edge.shape[0], -1)

    # Fit the edges.  poly_coeffs has shape (polyorder + 1, -1),
    # where '-1' is the same as in xx_edge.
    poly_coeffs = np.polyfit(np.arange(0, window_stop - window_start),
                             xx_edge, polyorder)

    if deriv > 0:
        poly_coeffs = _polyder(poly_coeffs, deriv)

    # Compute the interpolated values for the edge.
    i = np.arange(interp_start - window_start, interp_stop - window_start)
    values = np.polyval(poly_coeffs, i.reshape(-1, 1)) / (delta ** deriv)

    # Now put the values into the appropriate slice of y.
    # First reshape values to match y.
    shp = list(y.shape)
    shp[0], shp[axis] = shp[axis], shp[0]
    values = values.reshape(interp_stop - interp_start, *shp[1:])
    if swapped:
        values = values.swapaxes(0, axis)
    # Get a view of the data to be replaced by values.
    y_edge = axis_slice(y, start=interp_start, stop=interp_stop, axis=axis)
    y_edge[...] = values
Ejemplo n.º 6
0
    def test_axis_slice(self):
        a = np.arange(12).reshape(3, 4)

        s = axis_slice(a, start=0, stop=1, axis=0)
        assert_array_equal(s, a[0:1, :])

        s = axis_slice(a, start=-1, axis=0)
        assert_array_equal(s, a[-1:, :])

        s = axis_slice(a, start=0, stop=1, axis=1)
        assert_array_equal(s, a[:, 0:1])

        s = axis_slice(a, start=-1, axis=1)
        assert_array_equal(s, a[:, -1:])

        s = axis_slice(a, start=0, step=2, axis=0)
        assert_array_equal(s, a[::2, :])

        s = axis_slice(a, start=0, step=2, axis=1)
        assert_array_equal(s, a[:, ::2])
Ejemplo n.º 7
0
    def test_axis_slice(self):
        a = np.arange(12).reshape(3, 4)

        s = axis_slice(a, start=0, stop=1, axis=0)
        assert_array_equal(s, a[0:1, :])

        s = axis_slice(a, start=-1, axis=0)
        assert_array_equal(s, a[-1:, :])

        s = axis_slice(a, start=0, stop=1, axis=1)
        assert_array_equal(s, a[:, 0:1])

        s = axis_slice(a, start=-1, axis=1)
        assert_array_equal(s, a[:, -1:])

        s = axis_slice(a, start=0, step=2, axis=0)
        assert_array_equal(s, a[::2, :])

        s = axis_slice(a, start=0, step=2, axis=1)
        assert_array_equal(s, a[:, ::2])
Ejemplo n.º 8
0
Archivo: filter.py Proyecto: e-q/gwpy
def sosfiltfilt(sos, x, axis=-1, padtype="odd", padlen=0):
    x = asarray(x)

    # `method` is "pad"
    if padtype not in ["even", "odd", "constant", None]:
        raise ValueError(
            ("Unknown value '%s' given to padtype.  padtype " "must be 'even', 'odd', 'constant', or None.") % padtype
        )

    if padtype is None:
        padlen = 0
    if padlen is None:
        edge = sos.shape[0] * 6
    else:
        edge = padlen

    # x's 'axis' dimension must be bigger than edge.
    if x.shape[axis] <= edge:
        raise ValueError("The length of the input vector x must be at least " "padlen, which is %d." % edge)

    if padtype is not None and edge > 0:
        # Make an extension of length `edge` at each
        # end of the input array.
        if padtype == "even":
            ext = even_ext(x, edge, axis=axis)
        elif padtype == "odd":
            ext = odd_ext(x, edge, axis=axis)
        else:
            ext = const_ext(x, edge, axis=axis)
    else:
        ext = x

    # Get the steady state of the filter's step response.
    zi = sosfilt_zi(sos)

    # Reshape zi and create x0 so that zi*x0 broadcasts
    # to the correct value for the 'zi' keyword argument
    # to lfilter.
    zi_shape = [1] * x.ndim
    zi_shape[axis] = zi.size
    zi = reshape(zi, zi_shape)
    x0 = axis_slice(ext, stop=1, axis=axis)
    zix0 = reshape(zi * x0, (sos.shape[0], 2))

    # Forward filter
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zix0)

    # Backward filter
    # Create y0 so zi*y0 broadcasts appropriately.
    y0 = axis_slice(y, start=-1, axis=axis)
    ziy0 = reshape(zi * y0, (sos.shape[0], 2))

    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=ziy0)

    # Reverse y
    y = axis_reverse(y, axis=axis)

    if edge > 0:
        # Slice the actual signal from the extended signal.
        y = axis_slice(y, start=edge, stop=-edge, axis=axis)

    return y
Ejemplo n.º 9
0
def sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=0):
    x = asarray(x)

    # `method` is "pad"
    if padtype not in ['even', 'odd', 'constant', None]:
        raise ValueError(("Unknown value '%s' given to padtype.  padtype "
                          "must be 'even', 'odd', 'constant', or None.") %
                         padtype)

    if padtype is None:
        padlen = 0
    if padlen is None:
        edge = sos.shape[0] * 6
    else:
        edge = padlen

    # x's 'axis' dimension must be bigger than edge.
    if x.shape[axis] <= edge:
        raise ValueError("The length of the input vector x must be at least "
                         "padlen, which is %d." % edge)

    if padtype is not None and edge > 0:
        # Make an extension of length `edge` at each
        # end of the input array.
        if padtype == 'even':
            ext = even_ext(x, edge, axis=axis)
        elif padtype == 'odd':
            ext = odd_ext(x, edge, axis=axis)
        else:
            ext = const_ext(x, edge, axis=axis)
    else:
        ext = x

    # Get the steady state of the filter's step response.
    zi = sosfilt_zi(sos)

    # Reshape zi and create x0 so that zi*x0 broadcasts
    # to the correct value for the 'zi' keyword argument
    # to lfilter.
    zi_shape = [1] * x.ndim
    zi_shape[axis] = zi.size
    zi = reshape(zi, zi_shape)
    x0 = axis_slice(ext, stop=1, axis=axis)
    zix0 = reshape(zi * x0, (sos.shape[0], 2))

    # Forward filter
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zix0)

    # Backward filter
    # Create y0 so zi*y0 broadcasts appropriately.
    y0 = axis_slice(y, start=-1, axis=axis)
    ziy0 = reshape(zi * y0, (sos.shape[0], 2))

    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=ziy0)

    # Reverse y
    y = axis_reverse(y, axis=axis)

    if edge > 0:
        # Slice the actual signal from the extended signal.
        y = axis_slice(y, start=edge, stop=-edge, axis=axis)

    return y
Ejemplo n.º 10
0
        def filtfilt(b, a, x, axis=-1, padtype='odd', padlen=None):
            """
            A forward-backward filter.

            This function applies a linear filter twice, once forward
            and once backwards.  The combined filter has linear phase.

            Before applying the filter, the function can pad the data along the
            given axis in one of three ways: odd, even or constant.  The odd
            and even extensions have the corresponding symmetry about the end point
            of the data.  The constant extension extends the data with the values
            at end points.  On both the forward and backwards passes, the
            initial condition of the filter is found by using `lfilter_zi` and
            scaling it by the end point of the extended data.

            Parameters
            ----------
            b : (N,) array_like
                The numerator coefficient vector of the filter.
            a : (N,) array_like
                The denominator coefficient vector of the filter.  If a[0]
                is not 1, then both a and b are normalized by a[0].
            x : array_like
                The array of data to be filtered.
            axis : int, optional
                The axis of `x` to which the filter is applied.
                Default is -1.
            padtype : str or None, optional
                Must be 'odd', 'even', 'constant', or None.  This determines the
                type of extension to use for the padded signal to which the filter
                is applied.  If `padtype` is None, no padding is used.  The default
                is 'odd'.
            padlen : int or None, optional
                The number of elements by which to extend `x` at both ends of
                `axis` before applying the filter. This value must be less than
                `x.shape[axis]-1`.  `padlen=0` implies no padding.
                The default value is 3*max(len(a),len(b)).

            Returns
            -------
            y : ndarray
                The filtered output, an array of type numpy.float64 with the same
                shape as `x`.

            See Also
            --------
            lfilter_zi, lfilter

            Examples
            --------
            First we create a one second signal that is the sum of two pure sine
            waves, with frequencies 5 Hz and 250 Hz, sampled at 2000 Hz.

            >>> t = np.linspace(0, 1.0, 2001)
            >>> xlow = np.sin(2 * np.pi * 5 * t)
            >>> xhigh = np.sin(2 * np.pi * 250 * t)
            >>> x = xlow + xhigh

            Now create a lowpass Butterworth filter with a cutoff of 0.125 times
            the Nyquist rate, or 125 Hz, and apply it to x with filtfilt.  The
            result should be approximately xlow, with no phase shift.

            >>> from scipy import signal
            >>> b, a = signal.butter(8, 0.125)
            >>> y = filtfilt(b, a, x, padlen=150)
            >>> print('%.5g' % np.abs(y - xlow).max())
            9.1086e-06

            We get a fairly clean result for this artificial example because
            the odd extension is exact, and with the moderately long padding,
            the filter's transients have dissipated by the time the actual data
            is reached.  In general, transient effects at the edges are
            unavoidable.

            """

            if padtype not in ['even', 'odd', 'constant', None]:
                raise ValueError(("Unknown value '%s' given to padtype.  padtype must "
                                 "be 'even', 'odd', 'constant', or None.") %
                                    padtype)

            b = np.asarray(b)
            a = np.asarray(a)
            x = np.asarray(x)

            ntaps = max(len(a), len(b))

            if padtype is None:
                padlen = 0

            if padlen is None:
                # Original padding; preserved for backwards compatibility.
                edge = ntaps * 3
            else:
                edge = padlen

            # x's 'axis' dimension must be bigger than edge.
            if x.shape[axis] <= edge:
                raise ValueError("The length of the input vector x must be at least "
                                 "padlen, which is %d." % edge)

            if padtype is not None and edge > 0:
                # Make an extension of length `edge` at each
                # end of the input array.
                if padtype == 'even':
                    ext = even_ext(x, edge, axis=axis)
                elif padtype == 'odd':
                    ext = odd_ext(x, edge, axis=axis)
                else:
                    ext = const_ext(x, edge, axis=axis)
            else:
                ext = x

            # Get the steady state of the filter's step response.
            zi = lfilter_zi(b, a)

            # Reshape zi and create x0 so that zi*x0 broadcasts
            # to the correct value for the 'zi' keyword argument
            # to lfilter.
            zi_shape = [1] * x.ndim
            zi_shape[axis] = zi.size
            zi = np.reshape(zi, zi_shape)
            x0 = axis_slice(ext, stop=1, axis=axis)

            # Forward filter.
            (y, zf) = lfilter(b, a, ext, axis=axis, zi=zi * x0)

            # Backward filter.
            # Create y0 so zi*y0 broadcasts appropriately.
            y0 = axis_slice(y, start=-1, axis=axis)
            (y, zf) = lfilter(b, a, axis_reverse(y, axis=axis), axis=axis, zi=zi * y0)

            # Reverse y.
            y = axis_reverse(y, axis=axis)

            if edge > 0:
                # Slice the actual signal from the extended signal.
                y = axis_slice(y, start=edge, stop=-edge, axis=axis)

            return y
Ejemplo n.º 11
0
        def filtfilt(b, a, x, axis=-1, padtype='odd', padlen=None):
            """
            A forward-backward filter.

            This function applies a linear filter twice, once forward
            and once backwards.  The combined filter has linear phase.

            Before applying the filter, the function can pad the data along the
            given axis in one of three ways: odd, even or constant.  The odd
            and even extensions have the corresponding symmetry about the end point
            of the data.  The constant extension extends the data with the values
            at end points.  On both the forward and backwards passes, the
            initial condition of the filter is found by using `lfilter_zi` and
            scaling it by the end point of the extended data.

            Parameters
            ----------
            b : (N,) array_like
                The numerator coefficient vector of the filter.
            a : (N,) array_like
                The denominator coefficient vector of the filter.  If a[0]
                is not 1, then both a and b are normalized by a[0].
            x : array_like
                The array of data to be filtered.
            axis : int, optional
                The axis of `x` to which the filter is applied.
                Default is -1.
            padtype : str or None, optional
                Must be 'odd', 'even', 'constant', or None.  This determines the
                type of extension to use for the padded signal to which the filter
                is applied.  If `padtype` is None, no padding is used.  The default
                is 'odd'.
            padlen : int or None, optional
                The number of elements by which to extend `x` at both ends of
                `axis` before applying the filter. This value must be less than
                `x.shape[axis]-1`.  `padlen=0` implies no padding.
                The default value is 3*max(len(a),len(b)).

            Returns
            -------
            y : ndarray
                The filtered output, an array of type numpy.float64 with the same
                shape as `x`.

            See Also
            --------
            lfilter_zi, lfilter

            Examples
            --------
            First we create a one second signal that is the sum of two pure sine
            waves, with frequencies 5 Hz and 250 Hz, sampled at 2000 Hz.

            >>> t = np.linspace(0, 1.0, 2001)
            >>> xlow = np.sin(2 * np.pi * 5 * t)
            >>> xhigh = np.sin(2 * np.pi * 250 * t)
            >>> x = xlow + xhigh

            Now create a lowpass Butterworth filter with a cutoff of 0.125 times
            the Nyquist rate, or 125 Hz, and apply it to x with filtfilt.  The
            result should be approximately xlow, with no phase shift.

            >>> from scipy import signal
            >>> b, a = signal.butter(8, 0.125)
            >>> y = filtfilt(b, a, x, padlen=150)
            >>> print('%.5g' % np.abs(y - xlow).max())
            9.1086e-06

            We get a fairly clean result for this artificial example because
            the odd extension is exact, and with the moderately long padding,
            the filter's transients have dissipated by the time the actual data
            is reached.  In general, transient effects at the edges are
            unavoidable.

            """

            if padtype not in ['even', 'odd', 'constant', None]:
                raise ValueError(
                    ("Unknown value '%s' given to padtype.  padtype must "
                     "be 'even', 'odd', 'constant', or None.") % padtype)

            b = np.asarray(b)
            a = np.asarray(a)
            x = np.asarray(x)

            ntaps = max(len(a), len(b))

            if padtype is None:
                padlen = 0

            if padlen is None:
                # Original padding; preserved for backwards compatibility.
                edge = ntaps * 3
            else:
                edge = padlen

            # x's 'axis' dimension must be bigger than edge.
            if x.shape[axis] <= edge:
                raise ValueError(
                    "The length of the input vector x must be at least "
                    "padlen, which is %d." % edge)

            if padtype is not None and edge > 0:
                # Make an extension of length `edge` at each
                # end of the input array.
                if padtype == 'even':
                    ext = even_ext(x, edge, axis=axis)
                elif padtype == 'odd':
                    ext = odd_ext(x, edge, axis=axis)
                else:
                    ext = const_ext(x, edge, axis=axis)
            else:
                ext = x

            # Get the steady state of the filter's step response.
            zi = lfilter_zi(b, a)

            # Reshape zi and create x0 so that zi*x0 broadcasts
            # to the correct value for the 'zi' keyword argument
            # to lfilter.
            zi_shape = [1] * x.ndim
            zi_shape[axis] = zi.size
            zi = np.reshape(zi, zi_shape)
            x0 = axis_slice(ext, stop=1, axis=axis)

            # Forward filter.
            (y, zf) = lfilter(b, a, ext, axis=axis, zi=zi * x0)

            # Backward filter.
            # Create y0 so zi*y0 broadcasts appropriately.
            y0 = axis_slice(y, start=-1, axis=axis)
            (y, zf) = lfilter(b,
                              a,
                              axis_reverse(y, axis=axis),
                              axis=axis,
                              zi=zi * y0)

            # Reverse y.
            y = axis_reverse(y, axis=axis)

            if edge > 0:
                # Slice the actual signal from the extended signal.
                y = axis_slice(y, start=edge, stop=-edge, axis=axis)

            return y
Ejemplo n.º 12
0
def sosfiltfilt(sos, x, axis=-1, padtype='odd', padlen=None):
    """
    A forward-backward filter using cascaded second-order sections.
    See `filtfilt` for more complete information about this method.
    Parameters
    ----------
    sos : array_like
        Array of second-order filter coefficients, must have shape
        ``(n_sections, 6)``. Each row corresponds to a second-order
        section, with the first three columns providing the numerator
        coefficients and the last three providing the denominator
        coefficients.
    x : array_like
        The array of data to be filtered.
    axis : int, optional
        The axis of `x` to which the filter is applied.
        Default is -1.
    padtype : str or None, optional
        Must be 'odd', 'even', 'constant', or None.  This determines the
        type of extension to use for the padded signal to which the filter
        is applied.  If `padtype` is None, no padding is used.  The default
        is 'odd'.
    padlen : int or None, optional
        The number of elements by which to extend `x` at both ends of
        `axis` before applying the filter.  This value must be less than
        ``x.shape[axis] - 1``.  ``padlen=0`` implies no padding.
        The default value is::
            3 * (2 * len(sos) + 1 - min((sos[:, 2] == 0).sum(),
                                        (sos[:, 5] == 0).sum()))
        The extra subtraction at the end attempts to compensate for poles
        and zeros at the origin (e.g. for odd-order filters) to yield
        equivalent estimates of `padlen` to those of `filtfilt` for
        second-order section filters built with `scipy.signal` functions.
    Returns
    -------
    y : ndarray
        The filtered output with the same shape as `x`.
    See Also
    --------
    filtfilt, sosfilt, sosfilt_zi
    Notes
    -----
    .. versionadded:: 0.18.0
    """
    sos, n_sections = _validate_sos(sos)

    # `method` is "pad"...
    ntaps = 2 * n_sections + 1
    ntaps -= min((sos[:, 2] == 0).sum(), (sos[:, 5] == 0).sum())
    edge, ext = _validate_pad(padtype, padlen, x, axis, ntaps=ntaps)

    # These steps follow the same form as filtfilt with modifications
    zi = sosfilt_zi(sos)  # shape (n_sections, 2) --> (n_sections, ..., 2, ...)
    zi_shape = [1] * x.ndim
    zi_shape[axis] = 2
    zi.shape = [n_sections] + zi_shape
    x_0 = axis_slice(ext, stop=1, axis=axis)
    (y, zf) = sosfilt(sos, ext, axis=axis, zi=zi * x_0)
    y_0 = axis_slice(y, start=-1, axis=axis)
    (y, zf) = sosfilt(sos, axis_reverse(y, axis=axis), axis=axis, zi=zi * y_0)
    y = axis_reverse(y, axis=axis)
    if edge > 0:
        y = axis_slice(y, start=edge, stop=-edge, axis=axis)
    return y