Configuring gain_lock_mode for ESP32-C6 in ESPectre: A Complete Guide
ESP32-C6 devices lack hardware AGC lock support, so ESPectre automatically falls back to CV normalization whenever GAIN_LOCK_MODE is set to "auto" or "disabled" in micro-espectre/src/config.py.
The ESPectre firmware provides Wi-Fi sensing capabilities for ESP32 microcontrollers, but configuring gain_lock_mode for ESP32 C6 requires specific handling due to missing automatic gain control (AGC) hardware. When running on ESP32-C6 chips, the system cannot achieve a hardware gain lock and instead relies on coefficient of variation (CV) normalization to compute gain-invariant turbulence metrics. This guide explains the three available gain-lock modes and how the firmware automatically adapts the segmentation pipeline for ESP32-C6 hardware.
Understanding Gain-Lock Modes
The repository defines three configurable gain-lock behaviors in micro-espectre/src/config.py. Because the ESP32-C6 (and original ESP32) do not implement hardware gain locking, the firmware treats these modes as follows:
auto(default): Skips the gain-lock phase if the AGC value falls belowGAIN_LOCK_MIN_SAFE_AGC(30). On ESP32-C6, this effectively forces CV normalization because the hardware cannot achieve a valid lock.enabled: Forces a gain-lock attempt on every boot. On ESP32-C6 this operation always fails, making this mode effectively a no-op that still results in CV normalization.disabled: Explicitly bypasses the gain-lock phase entirely, ensuring CV normalization is always used without attempting hardware calibration.
Configuration Constants in config.py
Central configuration resides in micro-espectre/src/config.py, where you define the mode and safety threshold:
# Gain Lock Configuration
# Modes: "auto" (skip if signal too strong), "enabled" (always lock), "disabled" (never lock)
GAIN_LOCK_MODE = "auto" # Recommended: "auto" - skips gain lock if AGC < 30
GAIN_LOCK_MIN_SAFE_AGC = 30 # Minimum safe AGC value (below this, gain lock is skipped in auto mode)
The constant GAIN_LOCK_MIN_SAFE_AGC determines the threshold below which the firmware considers a signal too weak for reliable locking. When GAIN_LOCK_MODE is "auto" and the AGC reading sits below 30, the system immediately enables CV normalization rather than attempting a doomed lock on ESP32-C6 hardware.
Boot-Time Detection and Pipeline Adaptation
Chip Detection in main.py
During initialization, micro-espectre/src/main.py detects the chip type and sets the normalization flag accordingly:
if chip == 'ESP32-C6':
# No hardware gain lock → must use CV normalization
needs_cv_normalization = True
This logic ensures that needs_cv_normalization is True for all ESP32-C6 deployments, regardless of the configured mode, preventing the firmware from waiting on a hardware lock that will never complete.
Segmentation Context in segmentation.py
The motion-detection pipeline consumes this flag via SegmentationContext in micro-espectre/src/segmentation.py:
# Default False for compatibility with origin/develop (most chips have gain lock)
# Set to True for ESP32 which doesn't have gain lock
self.use_cv_normalization = False
When the calibration code detects a missing lock or the user forces disabled mode, the context flips use_cv_normalization to True, ensuring the turbulence calculations use standard-deviation-over-mean normalization rather than AGC-locked amplitude values.
CSI Packet Indicators and Testing
Each CSI packet carries a gain-locked bit (bit 0) defined in micro-espectre/tools/csi_utils.py. For ESP32-C6, this bit is always 0, and the parsing code annotates the description accordingly:
description = f'HT20 {self.label}, no gain lock (ESP32 lacks AGC lock support)'
The test suite in micro-espectre/tests/test_validation_real_data.py explicitly validates this behavior:
def needs_cv_normalization(chip):
return chip == 'ESP32'
This function ensures that unit tests verify CV normalization is applied whenever the target chip lacks hardware lock capabilities.
Practical Configuration Examples
Changing the Mode in Source Code
To permanently disable gain-lock attempts and force CV normalization, edit micro-espectre/src/config.py:
GAIN_LOCK_MODE = "disabled" # Forces CV normalization on every boot
GAIN_LOCK_MIN_SAFE_AGC = 30 # (kept for compatibility with other chips)
After rebuilding and flashing (pio run), the boot log will display:
⚙️ Gain lock mode: disabled → CV normalization always enabled
Runtime Override via CLI
For testing purposes, you can override the configuration constant without modifying source files. The CLI in micro-espectre/src/main.py accepts:
python -m src.main --gain-lock-mode disabled
This argument takes precedence over config.py for that execution only, useful for debugging across different chip variants.
Verifying Configuration Programmatically
You can confirm the active configuration at runtime using the detection utilities:
from src.config import GAIN_LOCK_MODE
from src.main import detect_chip_type
chip = detect_chip_type() # Returns "ESP32-C6"
print(f"Chip: {chip}, Gain-lock mode: {GAIN_LOCK_MODE}")
# Expected output for ESP32-C6:
# Chip: ESP32-C6, Gain-lock mode: disabled
Summary
- ESP32-C6 lacks hardware AGC lock support, making CV normalization mandatory for accurate turbulence sensing.
- Set
GAIN_LOCK_MODE = "disabled"inmicro-espectre/src/config.pyto explicitly skip the lock phase and speed up boot times. - The firmware automatically detects ESP32-C6 in
main.pyand setsneeds_cv_normalization = Truebefore the segmentation pipeline initializes. - CSI packets indicate the lack of gain lock via bit 0, which
csi_utils.pyparses to annotate packet descriptions. - All testing validates that CV normalization is applied when
needs_cv_normalization(chip)returnsTruefor ESP32 variants.
Frequently Asked Questions
What is gain_lock_mode in ESPectre?
gain_lock_mode is a firmware configuration constant that controls whether the system attempts to lock the automatic gain control (AGC) during boot. It supports three values: "auto" (skip lock if AGC < 30), "enabled" (always attempt lock), and "disabled" (never attempt lock). According to the ESPectre source code in micro-espectre/src/config.py, this setting determines whether the segmentation pipeline uses hardware-locked amplitude values or falls back to CV normalization.
Why does ESP32-C6 require CV normalization instead of gain locking?
The ESP32-C6 hardware does not implement an AGC lock mechanism, unlike the ESP32-S3, C3, or C5. As implemented in micro-espectre/src/main.py, the firmware detects the chip type and sets needs_cv_normalization = True for ESP32-C6 devices. This ensures the motion-detection pipeline uses coefficient of variation (standard deviation divided by mean) rather than absolute amplitude values, providing gain-invariant metrics without hardware support.
How do I verify that gain lock is disabled on my ESP32-C6?
Check the boot logs for the message CV normalization always enabled or inspect the CSI packet descriptions in micro-espectre/tools/csi_utils.py, which will show no gain lock (ESP32 lacks AGC lock support) when parsing packets from an ESP32-C6. Programmatically, you can import detect_chip_type from main.py and verify it returns "ESP32-C6" while GAIN_LOCK_MODE is set to "disabled" or "auto".
Can I force gain lock on ESP32-C6 using "enabled" mode?
Setting GAIN_LOCK_MODE = "enabled" will force the firmware to attempt a gain lock on every boot, but on ESP32-C6 this attempt will always fail because the hardware lacks the necessary AGC lock circuitry. The mode becomes effectively a no-op, and the system still falls back to CV normalization after the failed attempt. For ESP32-C6 deployments, "disabled" or "auto" provide the same final result with faster boot times.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →