Asking the fleet what it is doing…
monad-knowledge Wi-Fi sensing lab · FIIT STU
Instrument · one record, from the beginning

One record.

Every few milliseconds a Wi-Fi card writes down how the room changed a frame on its way in: one number per tone per antenna, the way a piano tuner notes how loud and how late each key came back. A capture is that notebook. This page opens one real record from it, on the capture you pick, and turns its numbers back into a picture of the echoes with the project's own code.

In plain words Every few milliseconds a Wi-Fi card writes down how the room changed a frame on its way in: one number per tone per antenna, like a piano tuner noting how loud and how late each key came back. This page opens one such note from a real capture and lets you turn its numbers back into a picture of the echoes.

The argument is WS501 week 2, "From OFDM to CSI" (edu/courses/WS501, sections 1 to 4). The bytes are the committed sample catalogue under web/static/csiq/, decoded on this request by the csiq reader; the delay profile is csi/dsp.py:cir and the ratio is the lake reduction's own. Capture: monad07_exp-chan-36_20260901-010744, 5 GHz ch36 tuned to 5180 MHz, 52 tones at 312.5 kHz, 2 chains, 120 records.

Capture: band-2.4__condition-clean__width-HT20 · band-5__condition-clean__width-HT20 · band-5__condition-quarantined__width-HT20 · band-5__condition-clean__width-HT40+ · band-5__condition-clean__width-80MHz · envelope-csiq · envelope-csiq.zst · writer-modern · writer-legacy · band-6

§1

The table

Every 802.11 frame opens with a training field both ends know. On tone k the receiver expects Xk and sees Yk; dividing the one by the other is the channel on that tone. The card does this for every tone and every antenna pair, and the record is that table: a size and an angle per cell.

Ĥ(k) = Y_k / X_k     one complex number per tone per chain

The sizes below are on the card's own integer grid, in decibels. Two chains share one radio and one oscillator, so they see the same room through two antennas a few centimetres apart. Move the record slider and the whole shape breathes; switch to the angle and it looks like noise, which it is not, and which is the point of the next section.

Fig. 1 · one record, size and angle per tonedrag the record
The first record: size in dB per chain across the tone grid (52 tones, 1 nulled centre tone). Pilot tones marked.
Offset (MHz)chain 0 (dB)chain 0 (rad)chain 1 (dB)chain 1 (rad)Pilot
-8.12545.29-1.9143.48-2.33
-7.81243.0-2.5232.942.75
-7.50046.431.848.62-3.07
-7.18832.382.9740.96-1.25
-6.87543.21-0.2844.52-0.54
-6.56243.71-0.6344.43-0.96pilot
-6.25044.32-0.9844.34-1.36
-5.93844.73-1.3244.12-1.71
-5.62544.92-1.6243.74-2.04
-5.31244.75-2.1942.03-2.61
-5.00044.37-2.4540.79-2.85
-4.68843.77-2.6939.2-3.08
-4.37542.89-2.9237.323.03
-4.06241.73-3.1134.822.94
-3.75040.263.031.72.98
-3.43837.972.8629.43-2.94
-3.12535.062.8430.53-2.61
-2.81232.073.0732.03-2.59
-2.50031.39-2.6733.68-2.67
-2.18834.49-2.3734.31-2.87pilot
-1.87537.67-2.334.5-3.09
-1.56240.34-2.3533.952.96
-1.25043.85-2.6329.132.21
-0.93844.9-2.8125.91.04
-0.62545.68-2.9829.87-0.1
-0.31246.243.1334.68-0.65
+0.31246.632.9638.43-0.97
+0.62547.522.7541.68-1.34
+0.93829.612.5427.07-1.79
+1.25046.882.3845.74-1.97
+1.56246.812.2546.63-2.2
+1.87546.562.1247.3-2.43
+2.18846.312.0147.74-2.64pilot
+2.50046.151.948.07-2.86
+2.81245.581.6848.223.0
+3.12545.31.5548.012.79
+3.43845.141.4347.782.58
+3.75045.01.2947.462.36
+4.06244.771.1247.072.14
+4.37544.210.9446.611.91
+4.68843.610.7445.871.65
+5.00042.680.5144.971.38
+5.31241.390.2444.041.07
+5.62539.47-0.0543.070.72
+5.93836.87-0.4442.080.31
+6.25033.32-1.041.32-0.16
+6.56230.04-2.0640.95-0.69pilot
+6.87537.012.4241.8-1.83
+7.18839.731.9542.79-2.35
+7.50041.381.5243.8-2.82
+7.81242.351.144.643.01
+8.12543.20.6745.542.52
Record 251 at RSSI -58 / -59 dBm. The gap at zero is the nulled centre tone, present in every 802.11 grid because the radio leaks at its own carrier. The tick marks under the axis are the pilots, the tones every frame carries at a known value.Week 2 §4.1; pilots per csi/model.py:DOT11_PILOTS.
§2

The ratio, in which the radio cancels

The raw angle is dominated by three things that are not the room: the oscillator offset between the two radios, a slope across tones from the sampling clock, and a jump per frame from where the frame was detected. All three are common to both chains, because both chains share one oscillator. Dividing one chain by the other removes them exactly, and removes the per-frame gain with them.

R(k) = H₀(k) / H₁(k)     |R| in dB, ∠R in rad — the observable the lake stores

What survives is the geometry between the two antennas as the room presents it, and that is a stable quantity. The median of |R| in dB over the tones is the one scalar the reduction keeps per frame; the level essay picks it up from here.

Fig. 2 · the two-chain ratiosize or angle
The first record's ratio across the tone grid.
Offset (MHz)|R| (dB)∠R (rad)
-8.1252.29-0.61
-7.81214.051.17
-7.500-0.5-0.35
-7.188-0.41-0.33
-6.8750.17-0.57
-6.5620.6-0.25
-6.2501.16-0.19
-5.9382.3-0.14
-5.6252.990.23
-5.312-3.10.3
-5.000-2.66-0.05
-4.688-1.05-0.17
-4.375-0.55-0.17
-4.062-0.89-0.21
-3.750-17.27-0.16
-3.4380.25-0.12
-3.1250.15-0.11
-2.8120.28-0.12
-2.5000.14-0.14
-2.1880.55-0.18
-1.8750.93-0.23
-1.5621.92-0.29
-1.2503.56-0.56
-0.938-6.97-1.8
-0.625-1.65-0.43
-0.312-0.85-0.43
+0.31210.53-1.2
+0.6257.661.82
+0.9380.09-0.41
+1.2500.22-0.36
+1.5621.71-0.57
+1.8751.59-0.22
+2.1882.49-0.09
+2.5002.270.36
+2.812-1.50.02
+3.125-0.63-0.2
+3.4380.55-0.24
+3.7503.23-1.17
+4.062-4.81-0.56
+4.375-3.24-0.36
+4.688-18.67-0.18
+5.000-0.67-0.22
+5.312-0.32-0.22
+5.6250.2-0.21
+5.9380.32-0.22
+6.2500.46-0.23
+6.5620.9-0.27
+6.8750.97-0.35
+7.1880.77-0.47
+7.500-0.85-1.14
+7.812-1.01-0.47
+8.125-0.9-0.48
The dashed line is the median over tones: the frame's whole-band scalar, the number that becomes one dot in the level essay's first figure. Compare the angle here with the angle in Fig. 1: the ramp is gone.lake/ingest.py:_ratio; csi/dsp.py:csi_ratio; FarSense (zeng2019) for the representation.
§3

Frequency into delay

The row of tones is the channel seen across frequency. The inverse FFT turns it into the same channel seen across time: one tap per echo, at the delay the echo took. Two echoes can be told apart only when their delays differ by more than one over the bandwidth, and the bandwidth is the tones you keep times their spacing.

h[n] = IDFT{Ĥ(k)}     Δτ = 1 / (N · Δf)

Drag the tones down and watch the main lobe widen. Fifty-two tones at 312.5 kHz is 16 MHz and about 62 ns, eighteen metres of path; thirteen tones is a quarter of that bandwidth and four times the blur. This is what a card that averages tones into groups does to every echo, and why a 20 MHz record cannot place a wall.

Fig. 3 · the delay profile with the tones you keepdrag tones kept

Record 1, chain 0, all 52 tones: resolution 62 ns, rms delay spread 67 ns, strongest tap at 56 ns.

The delay profile, dB below the strongest tap, every eighth bin.
Delay (ns)dB
-400-23.91
-350-23.96
-300-23.13
-250-24.75
-200-26.52
-150-25.96
-100-30.62
-50-15.07
0-3.74
50-0.05
100-1.84
150-4.79
200-7.11
250-12.85
300-14.47
350-24.8
Hann-windowed before the inverse FFT, so a rectangular band edge does not manufacture echoes. The amber bracket is the honest resolution 1/B; bins narrower than that are interpolation. The strongest tap is not at zero delay because the card's own detection offset moves it, frame by frame.csi/dsp.py:cir; week 2 §3; xie2015_0389 for the resolution.
§4

What the hardware adds

Average the sizes over every record and the room's ripple averages towards flat; what does not average away is the card. Four features remain. The nulled centre is a gap, never a weak tone. The outer tones roll off, the analogue filter's soft edge, measured on this fleet at three to four decibels on the outermost three. The two chains sit at different levels, the two front-ends' gains. And the pilots are where they always are.

Fig. 4 · the mean shape over every recordthe card, not the room
Mean size per tone over 120 records, dB from each chain's own median.
Offset (MHz)chain 0chain 1
-8.1251.130.45
-7.812-0.5-6.92
-7.5003.173.87
-7.188-3.950.01
-6.8750.44-1.02
-6.5620.74-1.28
-6.2501.02-1.26
-5.9381.08-0.67
-5.6251.02-0.01
-5.3120.540.16
-5.0000.1-0.15
-4.688-0.37-0.68
-4.375-0.91-1.54
-4.062-1.45-2.73
-3.750-2.07-4.22
-3.438-2.85-5.66
-3.125-3.96-6.03
-2.812-5.11-5.22
-2.500-5.21-4.59
-2.188-3.85-4.4
-1.875-2.52-4.74
-1.562-1.52-5.64
-1.250-0.63-10.67
-0.938-0.54-10.36
-0.625-0.1-6.51
-0.3120.72-3.93
+0.3121.43-2.05
+0.6252.38-0.38
+0.938-11.31-12.43
+1.2502.642.16
+1.5622.672.64
+1.8752.672.99
+2.1882.73.28
+2.5002.733.46
+2.8122.83.59
+3.1252.793.53
+3.4382.753.43
+3.7502.673.28
+4.0622.533.13
+4.3752.32.91
+4.6881.992.65
+5.0001.542.31
+5.3120.881.9
+5.625-0.11.36
+5.938-1.390.81
+6.250-3.230.29
+6.562-4.89-0.06
+6.875-2.30.28
+7.188-1.350.78
+7.500-0.991.23
+7.812-1.131.69
+8.125-1.752.27
The per-record gain is the fourth colouring and it is invisible here by construction: each chain's median is subtracted per record. It shows in Fig. 1 as the whole curve moving up and down with the record slider while its shape stays. Features built from ratios within a record survive it; features that track level across records do not.Week 2 §4.2; band-edge measurement in csi/bandplan.py.

Next: how one minute of these frames becomes a level · the same capture byte by byte · the three bands · JSON: records · delay profile