Browser-local CSI capture quality checker (GL-MT6000 / mt76)
By Wu Jun · Updated 2026-11-02 · 6 min read
Establish whether a capture is analysable before spending time on cleaning, spectral analysis or machine learning.
This checker parses only this project's public container:
double timestamp + uint16 length + mt76 CSI payload. All CSI processing happens in the current browser tab;
the selected capture is not uploaded [1] [2].
Parsed locally; no CSI upload. Transmitter MAC addresses are counted but omitted from reports.
Choose a capture file to start the local check.
Capture quality result
Detailed counts and consistency
What it checks
| Layer | Result | Purpose |
|---|---|---|
| Framing | 10-byte outer record header, payload length, truncated tail | Detect wrong format or an unfinished file |
| Closed groups | chain_info bit 15 |
Count complete groups, an unclosed tail and records per group |
| Chain consistency | Tx/Rx pairs and their mode | Separate complete 2×4 groups from missing-chain groups |
| Subcarriers | data_num distribution |
Detect 256-subcarrier groups and unexpected switching |
| Timing | Group-start intervals: p50, p95 and maximum | Find >1 s or >5 s gaps and out-of-order timestamps |
| I/Q | Payload byte count and all-zero blocks | Detect length mismatches and records with no usable samples |
Verdict rules
- Pass: at least 10 closed groups, chain and subcarrier coverage at or above 98%, non-zero I/Q, and no out-of-order groups;
- Review: the file parses, but has a truncated tail, missing chains, mixed subcarriers, out-of-order groups or a maximum gap over five seconds;
- Fail: no closed groups, a malformed payload header, no non-zero I/Q, or a file that is not this capture format.
These are fast screening thresholds, not an IEEE conformance test or a guarantee of algorithm accuracy. A formal experiment should still record firmware, driver, channel, bandwidth, exact command, free disk space and daemon memory. For the full offline statistics, run the Python quality audit.
What to do with the result
Do not delete a file simply because it says “review”, and do not send a “pass” straight into model training. Trace the result back through the capture chain:
| Result | Check first | Avoid |
|---|---|---|
| Outer framing fails | whether the file came from this project's csi_capture scripts; the 10-byte outer header, length field, transfer truncation and generator version |
editing lengths manually or parsing another format as this container |
| No closed groups | chain_info bit 15, frame-type/MAC filters, continuous client traffic, interface name and daemon logs |
blaming a broken antenna or unsupported firmware without evidence |
| Incomplete chain groups | the actual Tx×Rx pairs per group, chain_info, firmware and antenna configuration; whether missing chains are fixed |
silently zero-filling, copying another chain or treating array indexes as physical-antenna proof |
| Mixed subcarrier counts | whether 20/40/80 MHz width, RU, client width or channel configuration changed during capture; whether incompatible records were concatenated | reshaping 64, 256 or other record lengths into one matrix |
| A timestamp gap exceeds the line | daemon logs, AP/client counters, receiver loss and disk stalls in the same window; whether no CSI report was triggered | calling the gap UDP loss from the file alone, or inventing a uniform time axis |
| Empty I/Q or length mismatch | data_num in the payload header, actual byte count, byte order, writer completion and whether traffic matched the filter |
padding all-zero or short payloads and continuing an algorithm comparison |
| Everything passes | firmware, driver, channel, bandwidth, command, file SHA-256 and report; then repeat in an independent session | interpreting container validity as human-detection, localisation or model accuracy |
This table only answers whether the file and capture chain are safe to use in the next analysis step. It does not validate a classifier or a sensing task. When reporting an issue, include the exported JSON/Markdown report, relevant logs and a minimal reproduction. Raw captures can still contain unredacted MAC addresses and absolute time, so apply the privacy workflow before sharing them.
Important boundary: a gap is not automatically packet loss
The capture file proves only that no closed measurement group was written during that interval. The cause could be packet loss, a receiver falling behind on disk, no CSI trigger, a frame-filter mismatch, or a stopped capture daemon. Without daemon logs, interface counters and receiver-side drop counters, a single timestamp gap cannot be assigned to one cause.
An unterminated tail group is also commonly just the point where capture stopped. It should be quarantined, not silently zero-filled. This is the same treatment used by the published Python audit, so the browser quick check and offline recomputation can be compared directly.
Data format and reproduction
The page reads the analyser-side container:
repeated:
float64 host_timestamp
uint16 payload_length
payload_length bytes:
24-byte little-endian mt76 CSI header
int16 I/Q pairs
The container is produced by csi_capture.py and csi_capture_linux.sh; the payload header follows the mt76 CSI
reporting layout. The toolkit publishes the scripts, data-format contract and a real loopback test
[1] [3]. To validate this page first, select “Load the public 60-second sample”.
The expected result is 2,777 records, 347 closed groups, 256 subcarriers, 8 chains per group and one tail record.
You can also reproduce the same result in Python:
Privacy
The current page reads the raw CSI file, but the file is not submitted through a form, fetch or analysis API.
The page still loads the site's normal JavaScript, styles, fonts and advertising scripts; those routine requests
should not contain the selected capture. Exported reports omit transmitter MAC addresses and retain only the
transmitter count. A browser extension, malicious script or compromised device can defeat any local-processing
claim, so handle unredacted captures only on a trusted machine.
References and data sources
Every external claim carries a source and an evidence grade (grading scheme). Grade E marks first-party, reproducible measurements from this project.
- Grade E · first-party measurement
Router CSI Toolkit — capture/analysis/watchdog scripts (MIT, public repository)
Router CSI Lab · 2026
github.com/jjjwu/router-csi-toolkit · verified: GitHub API verified the public repository, capture-quality preflight, successful CI and the v0.1.3 release on 2026-11-02; the archive SHA-256 is 59f144c0…adea7 · The public repository includes a dependency-free capture preflight; the browser checker uses the same container definition and evidence boundaries. - Grade E · first-party measurement
Router CSI Lab — GL-MT6000 (MT7986) Wi-Fi CSI dataset, 10 s sample + 10 min capture
Router CSI Lab · 2026
doi:10.5281/zenodo.23434789 · verified: CC BY 4.0; SHA-256 published; Zenodo DOI 10.5281/zenodo.23434789 · The dataset has a Zenodo DOI (10.5281/zenodo.23434789) and can be cited directly. - Grade C · official docs
openwrt/mt76 — mac80211 driver for MediaTek Wi-Fi chipsets
OpenWrt project / MediaTek
github.com/openwrt/mt76 · verified: GitHub API 2026-10-11 (stars 890, last push 2026-10-08) · Upstream of the open-source mt76 driver used here; the CSI patch is applied on top of this codebase.