Computes per-subcarrier phase coherence from CSI input and emits
coherence_score + quality_report events.
Foundation for environment quality assessment and signal gating.
| field | value | notes |
|---|---|---|
| name | coherence | module · cogs.coherence |
| version | 1.5.0 | semver · released 2026-04-22 |
| size | 14 KB | compiled footprint |
| difficulty | medium | install complexity |
| hardware | ESP32-S3 | required radio |
| input | float32[52] | CSI phase (radians) |
| events | coherence_score, quality_report | cog event bus |
| source | cogs/src/cogs/coherence | relative to repo root |
Aggregate score gauge, polar phase distribution, score trend and per-subcarrier coherence — all driven by the live CSI stream.
Streaming feed of coherence_score, quality_report and gate_change. Capped at 200 entries; older events drop off.
Tunable parameters. Edits update the running analyzer in this preview but do not persist.
coherence_score publishes
MARGINAL
quality_report
| current_score | — |
| grade (local) | — |
| gate (local) | — |
| usable_subcarriers | — |
| emit_rate_ms | 1000 |
—
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.
| module | cogs.coherence |
| hardware | ESP32-S3 |
| input | float32[52] phase (rad) |
| output | float32 score · grade |
| events | coherence_score, quality_report, gate_change |
| source | cogs/src/cogs/coherence |
| license | MIT |
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.
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]
}
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
}
Edge-triggered notification when the gate transitions between open and closed.
{
"type": "gate_change",
"ts": 1762345684.123,
"state": "closed",
"reason": "interference",
"score": 0.412
}
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"])
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_open=true iff score >= gate_threshold.gate_change emits only on transitions, not every tick.