Coherence/Phase Analysisv1.5.0

Multi-subcarrier phase coherence

Computes per-subcarrier phase coherence from CSI input and emits coherence_score + quality_report events. Foundation for environment quality assessment and signal gating.

Docs v1.5.0 14 KB medium ESP32-S3 input: CSI phase
CSI capture online · analyzer running at 1 Hz uptime 00:00
Coherence score
mean across active subcarriers
Quality grade
5s rolling window
Active subcarriers
— / 52
OFDM data subcarriers
Gate state
threshold 0.60
Events / sec
rolling 5s

Live signal

Aggregate score
mean coherence · 0..1
Live →
coherence
Score · last 60s
dashed line = gate threshold
min mean max
Recent events
last 5 emitted
All →

Subcarrier health

CSI coherence waterfall
52 OFDM data subcarriers × last 60 samples · pilot tones marked · DC null at index 0
— / 52 active
mean worst best pilots peak hold
1.0 0.75 0.50 0.25 0.0
gate 0.60
coherence peak hold pilot tone gate threshold

Library manifest

cogs.coherence
module metadata · source-of-truth
API reference →
fieldvaluenotes
namecoherencemodule · cogs.coherence
version1.5.0semver · released 2026-04-22
size14 KBcompiled footprint
difficultymediuminstall complexity
hardwareESP32-S3required radio
inputfloat32[52]CSI phase (radians)
eventscoherence_score, quality_reportcog event bus
sourcecogs/src/cogs/coherencerelative to repo root

Live signal

Aggregate score gauge, polar phase distribution, score trend and per-subcarrier coherence — all driven by the live CSI stream.

gate · grade · usable seq 0

Real-time analysis

Aggregate score
mean of active subcarriers
coherence
Phase distribution
per-subcarrier vectors · length = coherence
0 π/2 π -π/2
Score · trend
120 samples · 1 Hz
min mean max

Per-subcarrier coherence

CSI coherence waterfall
52 OFDM data subcarriers × last 60 samples · pilot tones marked · DC null at center
— / 52 active
mean worst best pilots peak hold
1.0 0.75 0.50 0.25 0.0
gate 0.60
coherence peak hold pilot tone gate threshold

Events

Streaming feed of coherence_score, quality_report and gate_change. Capped at 200 entries; older events drop off.

Events / sec
rolling 5s
coherence_score
0
since session start
quality_report
0
aggregated grades
gate_change
0
edge-triggered

Event stream

Configuration

Tunable parameters. Edits update the running analyzer in this preview but do not persist.

Thresholds & cadence

Parameters
drive grading + gate state
Emit rate how often coherence_score publishes
1000 ms
Gate threshold below this, gate closes
0.60
Warn threshold below this, grade is MARGINAL
0.80
Quality window samples per quality_report
5 samples
Live preview
current config applied to the active stream
current_score
grade (local)
gate (local)
usable_subcarriers
emit_rate_ms1000

Subcarrier mask

52 OFDM subcarriers · click to toggle
Edge bands and DC null are commonly masked
active masked — / 52 active

Resolved configuration

cogs.coherence.toml
JSON payload sent to the on-device library

Documentation

Coherence consumes per-subcarrier CSI phase from an ESP32-S3 and emits a scalar coherence score plus a categorical quality report. Downstream cogs use the score (or the derived gate signal) to drop frames captured during interference or motion-induced phase chaos.

Reference

Quick reference
cogs.coherence · v1.5.0
modulecogs.coherence
hardwareESP32-S3
inputfloat32[52] phase (rad)
outputfloat32 score · grade
eventscoherence_score, quality_report, gate_change
sourcecogs/src/cogs/coherence
licenseMIT
Score derivation
how the scalar score is computed

For each tick the analyzer computes the per-subcarrier phase residual against the running mean phase, then maps each residual through exp(-|Δφ|) to produce a per-subcarrier coherence in [0, 1]. The reported score is the mean across active subcarriers (see Config for masking):

score = mean(exp(-|phase_i - phase_mean|))
        for i in active_subcarriers

A perfectly phase-locked signal yields 1.0; uniform phase noise drifts the score toward 0.

Event schema

coherence_score 1 Hz

Scalar coherence score plus per-subcarrier breakdown. Used by downstream cogs for gating.

{
  "type": "coherence_score",
  "ts":   1762345678.421,
  "score": 0.872,
  "raw_score": 0.891,
  "usable_subcarriers": 46,
  "total_subcarriers": 52,
  "gate_open": true,
  "subcarrier_coherence": [0.92, 0.88, ..., 0.74]
}

quality_report every N ticks

Categorical quality grade aggregated over a configurable window. Grades: STABLE, MARGINAL, DEGRADED.

{
  "type": "quality_report",
  "ts":   1762345683.421,
  "grade": "STABLE",
  "window_s": 5,
  "mean_score": 0.871,
  "min_score": 0.812,
  "usable": 46,
  "total": 52
}

gate_change on transition

Edge-triggered notification when the gate transitions between open and closed.

{
  "type": "gate_change",
  "ts":   1762345684.123,
  "state": "closed",
  "reason": "interference",
  "score": 0.412
}

Integration

Subscribe to scores

from cogs.coherence import Coherence
from cogs.bus import bus

coh = Coherence(emit_rate_ms=1000, gate_threshold=0.60)
coh.start()

@bus.on("coherence_score")
def on_score(evt):
    if not evt["gate_open"]:
        return  # phase coherence collapsed — drop this tick
    process_frame(evt["score"])

Configure subcarrier mask

Edge subcarriers (indices 0–5 and 46–51) carry pilot tones or guard bands and are typically masked. The library accepts a list of indices to exclude:

coh = Coherence(
    emit_rate_ms=1000,
    gate_threshold=0.60,
    warn_threshold=0.80,
    quality_window=5,
    subcarrier_mask=[0,1,2,3,4,5, 46,47,48,49,50,51],
)

Gate signal contract

  • gate_open=true iff score >= gate_threshold.
  • gate_change emits only on transitions, not every tick.
  • The gate is advisory — coherence never drops frames itself.