Choosing the Cutoff Frequency for ESPectre’s Low‑Pass Filter: A Practical Guide

Set the lowpass_cutoff parameter between 5 Hz and 20 Hz depending on your noise environment and motion speed requirements, starting with the default 11 Hz for balanced detection performance.

ESPectre is an open-source Wi‑Fi sensing framework that converts Channel State Information (CSI) into motion detection signals. When high-frequency RF noise causes false-positive motion events, the optional low-pass filter implemented in micro-espectre/src/filters.py attenuates frequencies above the configured cutoff while preserving the slower variations generated by human movement. Selecting the optimal cutoff frequency requires balancing noise suppression against the risk of filtering out rapid gestures.

What the ESPectre Low‑Pass Filter Does

Filter Architecture and Purpose

The LowPassFilter class implements a first-order IIR Butterworth design that removes fast-varying components from the turbulence signal. According to the source code in micro-espectre/src/filters.py (lines 18–65), the filter preserves the slower motion-related variations typical of human movement (approximately 0.5–10 Hz) while suppressing high-frequency RF bursts caused by Wi-Fi traffic or electrical interference.

The filter calculates its coefficients (b0 and a1) at initialization using the bilinear transform (lines 58–65). During operation, the filter() method applies the difference equation:


y[n] = b0·x[n] + b0·x[n‑1] – a1·y[n‑1]

Default Configuration State

By default, the filter is disabled (lowpass_enabled: false) to minimize processing overhead in quiet environments. When enabled, the default cutoff frequency is 11 Hz, defined as LOWPASS_CUTOFF in micro-espectre/src/config.py (line 73). This value was selected during empirical testing to remove the majority of RF spikes while preserving the 0.5–10 Hz motion band common to most human activities.

How the Cutoff Frequency Affects Motion Detection

The lowpass_cutoff value determines which frequency components reach the motion detection algorithm. The repository documentation identifies three operational ranges:

Cutoff Range Signal Effect Detection Impact
5 – 8 Hz Strong filtering removes most high-frequency noise Fewer false positives, but fast gestures may be smoothed out causing missed detections
11 Hz (default) Balanced filtering preserves human-movement frequencies while reducing RF spikes Optimal compromise with ~92% recall and <3% false-positive rate
15 – 20 Hz Light filtering attenuates only the highest noise components Higher recall for rapid movements but increased false positives in crowded RF environments

Two opposing factors drive the selection:

  • Noise level: Noisy RF environments (multiple Wi-Fi devices, microwaves) benefit from lower cutoffs (5–8 Hz) to suppress spurious high-frequency interference.
  • Motion speed: Rapid gestures (sports, fast hand motions) require higher cutoffs (15–20 Hz) to retain high-frequency motion components.

Selecting the Right Cutoff Frequency

Follow this iterative tuning process to optimize your deployment:

  1. Start with defaults: Begin with lowpass_enabled: false or enabled at lowpass_cutoff: 11 to establish a baseline.
  2. Address false positives: If you observe motion events while the room is empty, enable the filter and reduce the cutoff to 5–8 Hz.
  3. Recover missed movements: If quick gestures go undetected after lowering the cutoff, raise the value gradually (12 Hz → 15 Hz) until detection recovers while monitoring the false-positive rate.
  4. Iterate and test: Re-flash the device after each change, or adjust via Home Assistant for session-only testing, and monitor the motion binary sensor logs.

Why the Default is 11 Hz

The 11 Hz default was selected during extensive empirical testing as documented in the repository’s Tuning Guide. At this frequency, the filter removes the majority of high-frequency RF bursts caused by Wi-Fi traffic while preserving the 0.5–10 Hz band that contains most human motion signatures. This setting achieves approximately 92% recall with a false-positive rate below 3%, making it suitable for general-purpose room occupancy detection.

Interaction with Other Signal Processing Stages

Understanding the filter’s position in the processing chain prevents configuration conflicts. The low-pass filter sits after the optional Hampel outlier filter (which removes impulsive spikes) and before any normalization steps. It operates independently of the gain-lock and CV-normalization mechanisms, which process raw CSI amplitude before turbulence calculation.

Code Examples

Enabling the Filter via ESPHome Configuration

Configure the cutoff frequency in your ESPHome YAML file. The values are passed to micro-espectre/src/config.py, where LOWPASS_CUTOFF is read at line 73:

espectre:
  lowpass_enabled: true          # Enable the IIR Butterworth filter

  lowpass_cutoff: 11.0           # Cut-off frequency in Hz

  segmentation_threshold: auto   # Maintain default adaptive threshold

Direct Python Usage

Instantiate the LowPassFilter class directly for custom processing pipelines:

from micro_espectre.src.filters import LowPassFilter

# Initialize with custom cutoff and 100 Hz sample rate

lp = LowPassFilter(cutoff_hz=8.0, sample_rate_hz=100.0, enabled=True)

# Process turbulence values stream

filtered_values = []
for value in turbulence_stream:
    filtered_values.append(lp.filter(value))

# Reset filter state between measurement sessions

lp.reset()

The constructor calculates coefficients using the bilinear transform, and the filter() method applies the IIR difference equation as implemented in lines 58–65 of micro-espectre/src/filters.py.

Validating Filter Configuration in Unit Tests

Verify filter initialization in your test suite as shown in micro-espectre/tests/test_segmentation.py (lines 65–69):

from micro_espectre.tests.test_segmentation import SegmentationContext

ctx = SegmentationContext(enable_lowpass=True, lowpass_cutoff=11.5)
assert ctx.lowpass_filter is not None
assert ctx.lowpass_filter.cutoff_hz == 11.5

Summary

  • The ESPectre low-pass filter is a first-order IIR Butterworth implementation in micro-espectre/src/filters.py that reduces high-frequency RF noise.
  • The default 11 Hz cutoff balances noise suppression with motion detection accuracy (~92% recall, <3% false positives).
  • Lower cutoffs (5–8 Hz) suit noisy environments but may miss rapid gestures; higher cutoffs (15–20 Hz) capture fast movements but increase false positives.
  • Configure the cutoff via ESPHome YAML (lowpass_cutoff) or programmatically through the LowPassFilter class constructor.
  • The filter processes turbulence signals after Hampel outlier removal and before normalization stages.

Frequently Asked Questions

What is the optimal cutoff frequency for a noisy office environment?

For environments with high RF interference from multiple Wi-Fi devices or microwave ovens, set the cutoff to 5–8 Hz. This aggressive filtering removes the high-frequency noise responsible for false-positive motion alerts while still preserving slower body movements.

Can I disable the low-pass filter entirely?

Yes. Set lowpass_enabled: false in your ESPHome configuration or pass enabled=False to the LowPassFilter constructor. Disabling the filter reduces CPU usage and is appropriate for quiet RF environments where false positives are not problematic.

How does the cutoff frequency interact with the sample rate?

The LowPassFilter class requires both cutoff_hz and sample_rate_hz parameters. The sample rate determines the Nyquist frequency (half the sample rate), which must be higher than your chosen cutoff. The filter coefficients (b0 and a1) are calculated at initialization using the bilinear transform based on these two values, ensuring stable operation across different sampling configurations.

Will lowering the cutoff frequency below 11 Hz introduce detection latency?

A first-order IIR filter introduces minimal phase delay, but very low cutoffs (below 5 Hz) may smooth rapid motion onsets enough to delay the threshold-crossing event by one or two samples (10–20 ms at 100 Hz). For most human motion detection scenarios, this delay is imperceptible compared to the inherent latency of the Wi-Fi sensing pipeline.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →