Hey all. I’ve been doing WiFi CSI work on an OpenWrt One and got frustrated with MtkCSIdump stripping out most of the useful metadata. It gives you the I/Q data but throws away source MAC, RSSI, SNR, and packet sequence numbers. Without source MAC you can’t even tell which device a CSI measurement came from. Everything just blends together.
So I reverse-engineered the mt76 netlink vendor interface and wrote a Python library that talks directly to the kernel and keeps everything the driver actually provides. Source MAC means you can separate CSI by device and treat each WiFi link as its own sensor. RSSI and SNR let you weight or reject frames by signal quality. Packet sequence numbers give you exact chain grouping instead of guessing by timestamp.
The library also handles BW80 segment reassembly automatically and includes a traffic stimulator. That last one was a big discovery for me. Idle WiFi is mostly beacons which only use a couple spatial streams. If you send about 100 UDP packets/sec from a client to the router you force data frames and the chain count jumps from around 3-4 to consistently 6. CSI rate roughly doubles too. Costs about 20 KB/s.
On the OpenWrt One (MT7981B, Filogic 820) with BW80 you get 256 subcarriers across up to 6 chains, so 1,536 complex values per measurement. For comparison Intel 5300 gives you 90 and Nexmon on BCM4366c0 gives you 256.
Tested on OpenWrt 24.10 with the mt76 CSI patches from MtkWifiRev. Should work on other mt76 devices with the CSI vendor extension compiled in.
I’m building a WiFi sensing platform on top of this but ekstra-csi is the extraction layer and stands on its own for anyone doing CSI research on mt76 hardware.
Apache-2.0 licensed. Feedback welcome.
2 Likes
100hz target. Mark it.