Skip to content

How to Apply Signal Processing

This guide shows you how to smooth time series with digital filters, extract rate-of-change features, and use frequency-domain plots to choose filter parameters.

Prerequisites

Try it interactively

  • How to Apply Signal Processing Filters


    Apply NumericalFilter (Butterworth, Chebyshev, Bessel), NumericalDifferentiator, and NumericalIntegrator for signal smoothing and rate-of-change extraction.

    View · Open in marimo

  • How to Visualize Signal Processing


    Butterworth low-pass filtering with frequency spectrum analysis and phase shift inspection on half-hourly electricity demand data using Plotly.

    View · Open in marimo

Smooth High-Frequency Noise

NumericalFilter applies standard digital IIR filters. A lowpass filter removes noise above a chosen cutoff frequency:

from yohou.preprocessing import NumericalFilter

smoother = NumericalFilter(
    design="butterworth",
    mode="lowpass",
    order=4,
    cutoff_frequency=0.2,
)
df_smooth = smoother.fit_transform(df)

The cutoff_frequency is normalized between 0 and 1, where 1 is the Nyquist frequency (half the sampling rate). Use plot_spectrum (below) to identify where noise begins and set the cutoff just below that point.

Start with design="butterworth" and order=4. If the filtered signal still contains unwanted frequencies, increase the order for a sharper rolloff. If you need an even steeper cutoff, switch to "chebyshev1" for passband ripple tolerance (sharper rolloff) or "chebyshev2" for stopband attenuation (cleaner rejection band). Use "elliptic" for the sharpest possible cutoff when both passband and stopband ripple are acceptable. Use "bessel" when preserving waveform shape matters more than a sharp cutoff.

Remove Low-Frequency Drift

Use a highpass filter to remove slow trends or baseline drift while preserving faster dynamics:

detrend = NumericalFilter(
    design="butterworth",
    mode="highpass",
    order=4,
    cutoff_frequency=0.05,
)
df_detrended = detrend.fit_transform(df)

Isolate a Frequency Band

For bandpass or bandstop filtering, pass a 2-tuple as the cutoff_frequency:

# Keep only frequencies between 0.1 and 0.4 of Nyquist
bandpass = NumericalFilter(
    mode="bandpass",
    cutoff_frequency=(0.1, 0.4),
)
df_band = bandpass.fit_transform(df)

Use mode="bandstop" instead to remove a specific frequency band (e.g., a known interference frequency).

Extract Rate of Change

NumericalDifferentiator computes numerical derivatives using central differences:

from yohou.preprocessing import NumericalDifferentiator

diff = NumericalDifferentiator(order=1)
df_rate = diff.fit_transform(df)

The order parameter controls boundary accuracy: 1 uses 2-point differences at boundaries, 2 uses 3-point second-order accurate differences.

To integrate a derivative back, use NumericalIntegrator:

from yohou.preprocessing import NumericalIntegrator

integrator = NumericalIntegrator(method="cumulative_trapezoid")
df_integrated = integrator.fit_transform(df)

The method parameter accepts "cumulative_trapezoid" (faster) or "cumulative_simpson" (more accurate).

Inspect the Frequency Spectrum

Use plot_spectrum to visualize the power spectral density before choosing a cutoff:

from yohou.plotting import plot_spectrum

fig = plot_spectrum(df, columns="value", show_peaks=True, n_peaks=3)
fig.show()

The show_peaks option annotates the dominant frequencies with their corresponding period in sample units, making it easier to identify the boundary between signal and noise.

Check Phase Alignment

Use plot_phase to inspect the phase angle of each frequency component via FFT:

from yohou.plotting import plot_phase

fig = plot_phase(df, columns="value")
fig.show()

Compare the phase plot before and after filtering to verify that the filter does not introduce unacceptable phase distortion at frequencies you care about.

See Also