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.
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: monad05_exp-chan-36_20260901-012425, 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
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.
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.
| Offset (MHz) | chain 0 (dB) | chain 0 (rad) | chain 1 (dB) | chain 1 (rad) | Pilot |
|---|---|---|---|---|---|
| -8.125 | 30.18 | -2.86 | 42.4 | -2.11 | |
| -7.812 | 43.46 | 1.41 | 39.43 | 2.83 | |
| -7.500 | 45.75 | 0.54 | 47.22 | -1.72 | |
| -7.188 | 47.29 | 0.95 | 44.66 | -0.87 | |
| -6.875 | 30.51 | 1.75 | 31.49 | 0.73 | |
| -6.562 | 35.35 | 1.28 | 35.66 | 0.15 | pilot |
| -6.250 | 37.13 | 0.61 | 38.4 | -0.45 | |
| -5.938 | 36.58 | -0.12 | 40.28 | -1.02 | |
| -5.625 | 35.0 | -0.9 | 41.8 | -1.58 | |
| -5.312 | 27.73 | 2.81 | 41.16 | -2.78 | |
| -5.000 | 30.91 | 1.22 | 39.54 | 2.9 | |
| -4.688 | 34.32 | 0.39 | 36.64 | 2.38 | |
| -4.375 | 36.36 | -0.23 | 31.95 | 1.93 | |
| -4.062 | 36.91 | -0.84 | 28.69 | 1.87 | |
| -3.750 | 37.83 | -1.35 | 27.79 | 1.78 | |
| -3.438 | 39.94 | -1.93 | 29.59 | 1.67 | |
| -3.125 | 42.05 | -2.51 | 32.21 | 0.94 | |
| -2.812 | 43.33 | -2.99 | 34.18 | 0.22 | |
| -2.500 | 43.9 | 2.87 | 34.93 | -0.57 | |
| -2.188 | 44.21 | 2.43 | 35.8 | -1.27 | pilot |
| -1.875 | 44.38 | 2.06 | 36.53 | -2.03 | |
| -1.562 | 44.07 | 1.66 | 36.53 | -2.68 | |
| -1.250 | 43.98 | 0.85 | 37.36 | 2.65 | |
| -0.938 | 44.42 | 0.45 | 37.03 | 2.26 | |
| -0.625 | 44.78 | -0.06 | 36.11 | 1.92 | |
| -0.312 | 44.58 | -0.53 | 35.12 | 1.57 | |
| +0.312 | 44.08 | -0.98 | 34.51 | 1.23 | |
| +0.625 | 43.09 | -1.42 | 34.63 | 0.86 | |
| +0.938 | 28.23 | -2.19 | 25.62 | 0.75 | |
| +1.250 | 45.47 | -2.74 | 44.65 | 0.36 | |
| +1.562 | 44.98 | 3.01 | 45.76 | 0.02 | |
| +1.875 | 44.75 | 2.5 | 46.41 | -0.37 | |
| +2.188 | 44.87 | 1.91 | 46.73 | -0.78 | pilot |
| +2.500 | 45.29 | 1.28 | 47.02 | -1.19 | |
| +2.812 | 46.75 | 0.12 | 47.36 | -1.99 | |
| +3.125 | 46.99 | -0.45 | 47.64 | -2.35 | |
| +3.438 | 47.06 | -0.98 | 47.55 | -2.69 | |
| +3.750 | 46.88 | -1.48 | 47.39 | -3.01 | |
| +4.062 | 46.45 | -1.97 | 47.49 | 2.98 | |
| +4.375 | 46.04 | -2.42 | 47.74 | 2.65 | |
| +4.688 | 45.38 | -2.78 | 47.91 | 2.31 | |
| +5.000 | 44.56 | -3.12 | 48.12 | 1.89 | |
| +5.312 | 44.44 | 2.88 | 48.07 | 1.44 | |
| +5.625 | 44.96 | 2.56 | 47.66 | 0.98 | |
| +5.938 | 45.47 | 2.17 | 47.06 | 0.53 | |
| +6.250 | 45.93 | 1.74 | 46.37 | 0.05 | |
| +6.562 | 46.2 | 1.3 | 45.44 | -0.42 | pilot |
| +6.875 | 45.69 | 0.28 | 43.29 | -1.45 | |
| +7.188 | 45.13 | -0.25 | 41.8 | -2.02 | |
| +7.500 | 44.15 | -0.78 | 39.06 | -2.6 | |
| +7.812 | 43.33 | -1.27 | 33.72 | 3.0 | |
| +8.125 | 42.1 | -1.8 | 24.59 | 0.79 |
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.
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.
| Offset (MHz) | |R| (dB) | ∠R (rad) |
|---|---|---|
| -8.125 | -13.28 | -2.02 |
| -7.812 | -1.54 | 0.41 |
| -7.500 | -4.84 | -0.47 |
| -7.188 | 0.55 | -0.73 |
| -6.875 | 7.27 | -2.58 |
| -6.562 | -3.41 | -0.83 |
| -6.250 | -0.56 | -0.61 |
| -5.938 | -2.12 | -0.58 |
| -5.625 | -1.28 | -0.48 |
| -5.312 | -0.31 | -0.44 |
| -5.000 | 0.31 | -0.4 |
| -4.688 | -0.45 | -0.41 |
| -4.375 | 0.19 | -0.47 |
| -4.062 | 1.0 | -0.43 |
| -3.750 | -17.24 | -0.55 |
| -3.438 | 0.23 | -0.52 |
| -3.125 | -0.42 | -0.64 |
| -2.812 | -0.24 | -0.57 |
| -2.500 | 0.18 | -0.5 |
| -2.188 | 0.41 | -0.46 |
| -1.875 | 0.82 | -0.33 |
| -1.562 | -0.52 | -0.32 |
| -1.250 | -0.46 | -0.43 |
| -0.938 | 0.52 | -1.02 |
| -0.625 | 0.98 | -0.53 |
| -0.312 | 1.23 | -0.53 |
| +0.312 | 2.98 | -1.34 |
| +0.625 | 2.56 | 0.85 |
| +0.938 | -4.17 | -0.58 |
| +1.250 | -1.88 | -0.57 |
| +1.562 | 0.64 | -1.2 |
| +1.875 | 2.9 | -0.52 |
| +2.188 | 3.25 | -0.06 |
| +2.500 | -1.8 | -0.11 |
| +2.812 | -1.97 | -0.73 |
| +3.125 | -0.88 | -0.71 |
| +3.438 | 0.0 | -0.64 |
| +3.750 | 0.33 | -0.39 |
| +4.062 | 0.99 | -0.35 |
| +4.375 | -0.12 | -0.36 |
| +4.688 | -19.03 | -0.39 |
| +5.000 | -0.66 | -0.39 |
| +5.312 | -0.28 | -0.4 |
| +5.625 | -0.29 | -0.36 |
| +5.938 | 0.16 | -0.31 |
| +6.250 | -0.25 | -0.33 |
| +6.562 | -0.21 | -0.42 |
| +6.875 | 0.41 | -0.46 |
| +7.188 | 0.68 | -0.47 |
| +7.500 | 2.16 | -1.04 |
| +7.812 | 2.74 | -0.59 |
| +8.125 | 9.12 | -2.21 |
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.
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.
Record 1, chain 0, all 52 tones: resolution 62 ns, rms delay spread 74 ns, strongest tap at 275 ns.
| Delay (ns) | dB |
|---|---|
| -400 | -25.63 |
| -350 | -22.96 |
| -300 | -20.28 |
| -250 | -18.85 |
| -200 | -20.19 |
| -150 | -24.34 |
| -100 | -32.36 |
| -50 | -24.11 |
| 0 | -29.73 |
| 50 | -20.79 |
| 100 | -11.67 |
| 150 | -13.25 |
| 200 | -7.9 |
| 250 | -0.79 |
| 300 | -0.51 |
| 350 | -5.39 |
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.
| Offset (MHz) | chain 0 | chain 1 |
|---|---|---|
| -8.125 | -2.85 | 1.4 |
| -7.812 | 2.21 | -1.36 |
| -7.500 | 0.75 | -1.07 |
| -7.188 | 0.69 | 8.84 |
| -6.875 | -3.54 | -0.4 |
| -6.562 | -3.27 | 0.01 |
| -6.250 | -3.14 | 0.41 |
| -5.938 | -3.17 | 0.76 |
| -5.625 | -3.08 | 1.05 |
| -5.312 | -2.49 | 1.16 |
| -5.000 | -2.04 | 0.8 |
| -4.688 | -1.58 | 0.25 |
| -4.375 | -0.8 | -0.46 |
| -4.062 | 0.31 | -0.8 |
| -3.750 | 1.31 | -0.81 |
| -3.438 | 2.11 | -0.76 |
| -3.125 | 2.66 | -0.71 |
| -2.812 | 2.93 | -0.75 |
| -2.500 | 2.98 | -0.84 |
| -2.188 | 2.91 | -0.94 |
| -1.875 | 2.73 | -1.14 |
| -1.562 | 2.47 | -1.35 |
| -1.250 | 1.77 | -1.67 |
| -0.938 | 1.4 | -1.86 |
| -0.625 | 1.14 | -2.06 |
| -0.312 | 0.99 | -2.17 |
| +0.312 | 0.97 | -2.09 |
| +0.625 | 1.09 | -1.95 |
| +0.938 | -15.76 | -18.99 |
| +1.250 | 1.76 | -1.53 |
| +1.562 | 1.87 | -1.65 |
| +1.875 | 1.83 | -1.73 |
| +2.188 | 1.61 | -1.84 |
| +2.500 | 1.26 | -1.7 |
| +2.812 | -0.08 | -0.01 |
| +3.125 | -1.17 | 1.26 |
| +3.438 | -2.52 | 2.44 |
| +3.750 | -3.95 | 3.48 |
| +4.062 | -5.21 | 4.39 |
| +4.375 | -5.81 | 5.15 |
| +4.688 | -5.39 | 5.83 |
| +5.000 | -4.39 | 6.46 |
| +5.312 | -3.15 | 7.07 |
| +5.625 | -1.95 | 7.62 |
| +5.938 | -0.91 | 8.14 |
| +6.250 | -0.13 | 8.52 |
| +6.562 | 0.39 | 8.76 |
| +6.875 | 0.49 | 8.68 |
| +7.188 | 0.08 | 8.34 |
| +7.500 | -0.64 | 7.78 |
| +7.812 | -1.65 | 6.95 |
| +8.125 | -2.84 | 6.26 |
Next: how one minute of these frames becomes a level · the same capture byte by byte · the three bands · JSON: records · delay profile