The goal of this article serie is to extract decoded wifi frames from raw IQ samples. Like you would do with Wireshark but without your wifi card.
But first we will see how to do the "bytes to signal" direction. This is simpler and will set the scene for the opposite.

IQ samples ?
- Computer manipulates digital data. Incoming wave must be sampled and quantized.
- The signal we are interested in is around 5.21 - 5.23GHz. The direct way to digitize it would be to low-pass filter the incoming signal and sample it at 10.46GHz (to avoid aliasing). Problems :
- This would require a very fast ADC, which I guess would not be easy to build. (read ... expensive)
- This would result in a huge amount of data : with 16bits per sample, this would mean 20GB per second of capture. Transfert, storage and processing would be painful.
- When we say a signal has a "narrow" bandwidth around \( F_c=5.22GHz \), this means we can write our signal as \( s(t) = A(t)sin(2\pi f_c t + \phi(t)) \) or, alternatively, \(s(t)=I(t) cos(2\pi f_c t) + Q(t)sin(2\pi f_c t) \). With \(A\), \(\phi\), \(I\) and \(Q\) varying "slowly" compared to the fast moving carrier sin. Actually, if our signal is 20MHz wide, they have only frequency components below 20MHz.
- Then, if we describe the signal by sampling I and Q, instead of s, we may use a far lower sampling rate.
- Software-Defined-Radio is a device doing this. It is a complicated piece of hardware but we will assume it is just a black box doing conversion between IQ samples and real radio waves.

Scope of this work
- WIfi (IEEE 802.11) is an agreement about how data should be transmitted over the air. It was first released in 1997. But it grew up as people found new ways to make the users happier : more throughput, less latency, more users at the same time, more security, backward compatible.You can download it here (start with the 4500p document from 2020 and add the various "amendment" documents : happy reading). After Wifi 6 (802.11ax), Wifi 7 (802.11be) is about to come.
- We will focus on the PHY layer here : we will extract bytes from the signal but we will not dig in the connexion process or the way multiple devices agree on who is allowed to talk next.
- We will focus on 802.11a : this is the OFDM method released in 1999. It is not often used alone these days but service messages are still using this encoding and the more performant methods are "just" improvements : we have to understand the basics before going to the bleeding edge.
The plan
- The project will be done when I have a proof I can decode real-world data : for example, finding my network name in the output.
- Decoding wifi frame is a complex multi-step process. If we rush deadlong, I will probably be quickly stuck with something not working and unable to find why. First thing needed will be a test data : signal samples and corresponsing decoded bytes. Luckily : in the standard, there is a dissected example (Annex I) with the result of each encoding step. With this, I can follow the example and build a program step by step, knowing exactly where the bugs are.
- Once the encoding process in-place, the decoding will be developped with each step being validated : decode(encode("message")) should be "message"
- Then, we will go to real-world decoding
Transmit path
Before looking at reception in a following article, let's follow the encoding process together. We will not eplain the purpose of each step here.
We have some bytes and we want to know the IQ samples to transmit so that a 802.11a compliant receiver is be able understand it.
The transmitter has to choose a bitrate. We will choose 36Mbps. The standard provides slightly different recipes resulting in different data rates. When you are far from your router and signal is just above the ambient noise, you choose the lowest data rate (slow and robust) : it is slow but it works. When you are close to the router, you choose the highest bitrate : it works and it is fast.
This is the recipe. 🍲
Start with your data bits

Padding. Add 16 bits at the beginning, 6 bits at the end and continue adding bits at the end you reach a multiple of 144 bits.

Scrambling. Take your data and XOR it bit by bit with the sequence defined in the standard.

Convolutional encoding.

Puncturing. Group your bits 6 by 6 and forget about 4th and 5th bits.

Interleaving. Group your bits by group of 192 and mix these groups by applying the permutation defined in the standard.

Constellation mapping. Group your input bits 4 by 4 and replace each group with the corresponding point in the QAM16 constellation. first group (0110) is mapped to (-1,3), second (1110) becomes (1,3), ... ()

OFDM encoding. Each group of 48 point will be mapped to 80 iq samples. For each group :
- Prepare a 64 IQ array filled with 0, we will label each position from -32 to 31
- Insert data at the positions from -26 to +26, skipping -21,-7,0,7,21
- Insert pilot at the following positions : -21,-7,7,21. The pilots defined in the standard : they are ((1,0) , (1,0) , (1,0) , (-1,0)) for the first four group.
- Compute the inverse fourier transform of the array. If you don't know what this is, it is a well-defined way to get a new 64 IQ array from our previous one.
- Increase your 64 IQ array by copying last 16 cells at the beginning.

- Prepend with a PHR. PHR is a symbol (sequence of 80 iq points) encoding length and rate information. I will slip over it but it follows the same kind of process : convolutional encoding, interleave, mapping to constellation points, OFDM.
- Prepend with a LTS and STS. These sequences are always the same, no matter the data you want to transmit. Just take them as they are and put them before your other IQ samples.

- Transmit. We have our IQ samples. We can tell our SDR box, to transmit them at 20MHz centered around 5.22GHz