# Interaction of segmentation_threshold and threshold_mode in Micro-ESPectre

> Understand how segmentation_threshold and threshold_mode interact in Micro-ESPectre. Learn about fixed vs adaptive thresholds for motion detection and optimize sensitivity.

- Repository: [Francesco Pace/espectre](https://github.com/francescopace/espectre)
- Tags: deep-dive
- Published: 2026-06-10

---

**In Micro-ESPectre, the `SEG_THRESHOLD` configuration variable controls whether the motion detector uses a fixed numeric threshold or an adaptive threshold computed from baseline noise, with the `auto` mode applying a 95th percentile × 1.1 multiplier and `min` mode using the maximum value (100th percentile) for maximum sensitivity.**

The interaction between `segmentation_threshold` and `threshold_mode` determines how the Micro-ESPectre motion detection pipeline balances sensitivity against false positives. This relationship is governed by the `SEG_THRESHOLD` setting in [`micro-espectre/src/config.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/config.py), which instructs the system to either use a static value or dynamically calculate an adaptive threshold based on calibration statistics. Understanding this interaction is essential for tuning the ESP32-based Wi-Fi sensing implementation in the francescopace/espectre repository.

## How SEG_THRESHOLD Defines the Threshold Mode

Located in [`micro-espectre/src/config.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/config.py) (lines 58-63), the `SEG_THRESHOLD` variable accepts three distinct value types that control the threshold behavior:

```python

# config.py

# SEG_THRESHOLD can be:

#   - "auto" (default): adaptive threshold based on baseline noise

#   - "min": maximum sensitivity (may have false positives)

#   - a number (0.0-10.0): fixed manual threshold

SEG_THRESHOLD = "auto"

```

When set to a string value (`"auto"` or `"min"`), the system enters adaptive mode and computes the threshold from calibration data. When set to a numeric value, the system bypasses adaptive calculation and uses the fixed value directly.

## Mapping Threshold Modes to Statistical Parameters

The [`micro-espectre/src/threshold.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/threshold.py) module translates the threshold mode into specific statistical parameters used during calibration. Two functions determine the behavior:

- `get_threshold_percentile(threshold_mode)` – selects the percentile of baseline noise to use
- `get_threshold_factor(threshold_mode)` – applies a safety multiplier to the calculated value

| Mode | Percentile | Factor |
|------|------------|--------|
| `"auto"` | 95 | 1.1 |
| `"min"` | 100 | 1.0 |

The `"auto"` mode uses the 95th percentile of baseline measurements multiplied by 1.1 to provide margin above typical noise. The `"min"` mode uses the 100th percentile (maximum observed value) with no multiplier, maximizing sensitivity at the risk of false positives.

## Computing the Adaptive Threshold

During calibration (typically via [`3_analyze_moving_variance_segmentation.py`](https://github.com/francescopace/espectre/blob/main/3_analyze_moving_variance_segmentation.py)), the `calculate_adaptive_threshold` function in [`threshold.py`](https://github.com/francescopace/espectre/blob/main/threshold.py) (lines 60-78) computes the final value:

```python
percentile = get_threshold_percentile(threshold_mode)   # 95 or 100

factor = get_threshold_factor(threshold_mode)             # 1.1 or 1.0

adaptive_threshold = calculate_percentile(cal_values, percentile) * factor

```

This calculation ensures that the **segmentation threshold** scales with the actual RF environment noise characteristics captured during the calibration run.

## Applying Thresholds in the Detection Pipeline

The runtime detector uses the `SegmentationContext` class in [`micro-espectre/src/segmentation.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/segmentation.py) to maintain state. The threshold is injected via `set_adaptive_threshold`:

```python
def set_adaptive_threshold(self, threshold):
    # clamp to a sane range (1µ to 10)

    self.threshold = max(1e-6, min(10.0, threshold))

```

The `update_state()` method compares `self.current_moving_variance` against `self.threshold` to determine motion start/stop events. If `SEG_THRESHOLD` was set to a numeric value, the system skips adaptive calculation and initializes `SegmentationContext` with the fixed constant directly.

## Configuration Examples

### Using Auto Mode for Balanced Detection

```python

# config.py

SEG_THRESHOLD = "auto"

```

```python
from micro_espectre.src.threshold import calculate_adaptive_threshold
from micro_espectre.src.segmentation import SegmentationContext

# Run calibration on quiet environment

adaptive_thr, perc = calculate_adaptive_threshold(calibration_values, "auto")
print(f"Threshold set to P{perc}×1.1 = {adaptive_thr:.3f}")

ctx = SegmentationContext(window_size=100, threshold=adaptive_thr)

```

### Using Min Mode for Maximum Sensitivity

```python

# config.py

SEG_THRESHOLD = "min"

```

```python
adaptive_thr, perc = calculate_adaptive_threshold(calibration_values, "min")

# Uses maximum observed value with no multiplier

ctx = SegmentationContext(window_size=100, threshold=adaptive_thr)

```

### Using Fixed Manual Threshold

```python

# config.py

SEG_THRESHOLD = 1.5  # Fixed value 0.0-10.0

```

```python

# No calibration calculation needed

ctx = SegmentationContext(window_size=100, threshold=1.5)

```

### Runtime Recalibration

```python

# Update threshold without restarting

new_thr, _ = calculate_adaptive_threshold(new_cal_values, "auto")
ctx.set_adaptive_threshold(new_thr)  # Automatically clamps to [1e-6, 10.0]

```

## Summary

- **SEG_THRESHOLD** in [`config.py`](https://github.com/francescopace/espectre/blob/main/config.py) controls whether Micro-ESPectre uses fixed or adaptive thresholds via the **threshold mode** (`auto`, `min`, or numeric).
- **Adaptive calculation** occurs in [`threshold.py`](https://github.com/francescopace/espectre/blob/main/threshold.py), where `auto` mode applies a 95th percentile × 1.1 multiplier and `min` mode uses the 100th percentile × 1.0.
- **Runtime application** happens through `SegmentationContext.set_adaptive_threshold()`, which clamps values to the range 1×10⁻⁶ to 10.0 before use in the motion state machine.
- **Fixed thresholds** bypass calibration entirely, using the numeric value directly in the detector initialization.

## Frequently Asked Questions

### What is the difference between "auto" and "min" threshold modes?

The `auto` mode calculates the threshold using the 95th percentile of baseline noise multiplied by 1.1, providing robustness against minor fluctuations while maintaining sensitivity. The `min` mode uses the 100th percentile (maximum observed value) with no multiplier, offering maximum sensitivity but increasing the risk of false positives from noise spikes.

### Can I change the threshold without recalibrating?

Yes, you can update the threshold at runtime using the `set_adaptive_threshold()` method on the `SegmentationContext` instance. This method automatically clamps the value to the valid range between 1×10⁻⁶ and 10.0, allowing dynamic adjustment without restarting the detector or recalibrating the system.

### Why does the threshold get clamped to 1e-6 and 10.0?

The clamping in `SegmentationContext.set_adaptive_threshold()` prevents invalid threshold values that could break the motion detection logic. Values below 1×10⁻⁶ would be numerically unstable, while values above 10.0 exceed the maximum expected moving variance range for Wi-Fi sensing signals, ensuring the detector operates within physically meaningful bounds.

### Where is the threshold actually used in the detection logic?

The threshold is compared against `self.current_moving_variance` in the `update_state()` method of `SegmentationContext` (located in [`micro-espectre/src/segmentation.py`](https://github.com/francescopace/espectre/blob/main/micro-espectre/src/segmentation.py)). When the moving variance exceeds the threshold, the state machine transitions to the motion-detected state; when it falls below, the system returns to the idle state.