FILTFILT

The filtfilt function applies a linear digital filter twice, once forward and once backwards. The combined filter has zero phase distortion and a filter order twice that of the original.

This technique is primarily used when it is important to preserve the timing of features in the signal (i.e., zero phase shift), at the cost of being an offline/non-real-time process.

Excel Usage

=FILTFILT(x, b, a, axis, padtype, padlen, filtfilt_method, irlen)
  • x (list[list], required): The input array of data to be filtered.
  • b (list[list], required): The numerator coefficient vector of the filter (1D array in Excel).
  • a (list[list], required): The denominator coefficient vector of the filter (1D array in Excel).
  • axis (int, optional, default: -1): The axis along which the filter is applied.
  • padtype (str, optional, default: “odd”): Extension mode for padding at edges.
  • padlen (int, optional, default: null): Number of elements to extend x by at both ends.
  • filtfilt_method (str, optional, default: “pad”): Method for handling edges.
  • irlen (int, optional, default: null): Impulse response length for Gustafsson’s method.

Returns (list[list]): The filtered signal as a 2D array.

Example 1: Zero-phase filtering

Inputs:

x b a
1 2 3 4 5 4 3 2 1 0.02008337 0.04016673 0.02008337 1 -1.56101808 0.64135154

Excel formula:

=FILTFILT({1,2,3,4,5,4,3,2,1}, {0.02008337,0.04016673,0.02008337}, {1,-1.56101808,0.64135154})

Expected output:

Result
1.04833 1.45384 1.79308 2.02166 2.1079 2.0395 1.82648 1.49805 1.09582
Example 2: Gustafsson’s method

Inputs:

x b a filtfilt_method
1 2 3 4 5 4 3 2 1 0.02008337 0.04016673 0.02008337 1 -1.56101808 0.64135154 gust

Excel formula:

=FILTFILT({1,2,3,4,5,4,3,2,1}, {0.02008337,0.04016673,0.02008337}, {1,-1.56101808,0.64135154}, "gust")

Expected output:

Result
2.85538 2.9054 2.95971 3.00267 3.01908 3.00267 2.95971 2.9054 2.85538

Python Code

Show Code
import numpy as np
from scipy.signal import filtfilt as scipy_filtfilt

def filtfilt(x, b, a, axis=-1, padtype='odd', padlen=None, filtfilt_method='pad', irlen=None):
    """
    Apply a digital filter forward and backward to a signal for zero phase distortion.

    See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.filtfilt.html

    This example function is provided as-is without any representation of accuracy.

    Args:
        x (list[list]): The input array of data to be filtered.
        b (list[list]): The numerator coefficient vector of the filter (1D array in Excel).
        a (list[list]): The denominator coefficient vector of the filter (1D array in Excel).
        axis (int, optional): The axis along which the filter is applied. Default is -1.
        padtype (str, optional): Extension mode for padding at edges. Valid options: Odd, Even, Constant. Default is 'odd'.
        padlen (int, optional): Number of elements to extend x by at both ends. Default is None.
        filtfilt_method (str, optional): Method for handling edges. Valid options: Pad, Gustafsson. Default is 'pad'.
        irlen (int, optional): Impulse response length for Gustafsson's method. Default is None.

    Returns:
        list[list]: The filtered signal as a 2D array.
    """
    try:
        def to_1d(v):
            if isinstance(v, list):
                return np.array([float(x) for row in v for x in row])
            return np.array([float(v)])

        def to2d(x):
            return [[x]] if not isinstance(x, list) else x

        x_arr = np.array(to2d(x))
        b_arr = to_1d(b)
        a_arr = to_1d(a)

        # SciPy's filtfilt requires len(x) > padlen. If no padlen is provided, it
        # defaults to 3*max(len(a), len(b)), which can be too large for short inputs.
        # In that case, shrink padlen to len(x)-1 so the call succeeds.
        padlen_arg = int(padlen) if padlen is not None else None
        if padlen is None:
            axis_int = int(axis)
            if axis_int < 0:
                axis_int = x_arr.ndim + axis_int
            x_len = x_arr.shape[axis_int]
            default_padlen = 3 * max(b_arr.size, a_arr.size)
            if x_len <= default_padlen:
                padlen_arg = max(0, x_len - 1)

        result = scipy_filtfilt(
            b_arr, 
            a_arr, 
            x_arr, 
            axis=int(axis), 
            padtype=padtype if padtype != "None" else None, 
            padlen=padlen_arg, 
            method=filtfilt_method, 
            irlen=int(irlen) if irlen is not None else None
        )

        return result.tolist()
    except Exception as e:
        return f"Error: {str(e)}"

Online Calculator

The input array of data to be filtered.
The numerator coefficient vector of the filter (1D array in Excel).
The denominator coefficient vector of the filter (1D array in Excel).
The axis along which the filter is applied.
Extension mode for padding at edges.
Number of elements to extend x by at both ends.
Method for handling edges.
Impulse response length for Gustafsson's method.