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.

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

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.

  1. 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.
  2. 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.
  3. 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.