Compress the signal.
Bit by bit.
The U-plane is your fronthaul bandwidth — raw IQ samples matched to their C-plane command by sectionId. Here we decode a real U-plane packet, read the udCompHdr (udIqWidth + udCompMeth), and run block floating point by hand on one PRB — one shared exponent, twelve shortened mantissas. Then the whole codec family (block scaling, μ-law, beamspace, modulation compression) and the efficiency levers. Verbatim from O-RAN WG4 CUS.0 v21 §8 + Annex A/D.
The U-plane — IQ, block floating point & the codecs
The player screen is a live animation stage — the U-plane header assembles, the udCompHdr splits into udIqWidth and udCompMeth, a PRB of twelve IQ samples collapses to one shared exponent plus short mantissas, and the bit-count bar shrinks, exactly as the narration reaches each idea. Karaoke subtitles EN + Persian, fullscreen.
Compress one PRB with block floating point
One PRB = 12 subcarriers = 12 complex samples = 24 I/Q values. Uncompressed at 16-bit = 384 bits. BFP stores one shared exponent (4 bits) + 24 shortened mantissas. Set the mantissa width and watch it shrink.
① find the largest |sample| in the block → ② that sets one shared exponent → ③ store every sample as a short mantissa → ④ decompress = shift back.
A U-plane packet, field by field
The header answers when and which PRBs; the udCompHdr tells you how to read the samples before you read a single one.
| Part | Field | Bits | Meaning |
|---|---|---|---|
| Radio header | dataDirection | 1 | gNB Tx (DL) or Rx (UL) |
| payloadVersion | 3 | payload format version | |
| filterIndex | 4 | which filter (e.g. PRACH) | |
| frameId · subframeId · slotId · symbolId | 8·4·6·6 | exact symbol in time | |
| Section | sectionId | 12 | matches the C-plane command |
| startPrbu / numPrbu | 10 / 8 | first PRB / how many PRBs | |
| udCompHdr | 8 | udIqWidth(4) + udCompMeth(4) — not always present | |
| Payload | udCompParam + IQ | 0/8/16 + … | compression param, then the samples |
The udCompHdr is 8 bits: the top nibble is udIqWidth (bits per I and per Q), the bottom nibble is udCompMeth (the codec). A 9-bit sample does not align to a byte, so IQ is packed tightly (Annex D). Decode the udCompHdr first — read it wrong and every sample after it is garbage.
The compression method — 4 bits, one family
The udCompMeth nibble selects the codec. Base methods 0–4; higher values combine a codec with selective RE sending.
| udCompMeth | Codec | Idea | Annex |
|---|---|---|---|
| 0000 | No compression | raw IQ at udIqWidth bits | — |
| 0001 | Block floating point (BFP) | one shared exponent + short mantissas per PRB | A.1 |
| 0010 | Block scaling | scale by a factor, not a power of two | A.2 |
| 0011 | μ-law | non-linear companding (audio-style) | A.3 |
| 0100 | Modulation compression | DL-only — uses the known constellation | A.5 |
| 0101–1000 | + selective RE sending | codec combined with RE masks | A.6 |
Beamspace compression (types I & II, Annex A.4) works in the beam domain for massive MIMO. Modulation compression is downlink only: only the O-DU knows exactly which constellation point it transmitted, so it can encode a sample in very few bits. On the uplink the O-RU has no such certainty — so it cannot apply it.
Beyond compression — three more levers
| Lever | What it does | Clause |
|---|---|---|
| Selective RE sending | a mask marks active REs; only those samples are transmitted | Annex A.6 |
| Data blanking | whole muted regions are simply not sent | §8.4.2 |
| Digital power scaling | keeps signal levels in the useful range (gain/power scaling) | §8.1.3 |
Real radios stack these: BFP (≈16→9 bit) × selective RE sending (skip empty REs) × blanking (skip muted regions). That is how a 100 MHz carrier that would need ~12 Gb/s of raw IQ (Chapter 2) is squeezed onto a 25 GbE link. Compression chooses your codec; these levers reclaim what compression cannot.
🛠 Engineer detail block — what you'll actually meet in the field
- Decode the udCompHdr first. udIqWidth tells your dissector how many bits per I and per Q. Guess it wrong and every downstream sample is noise — the #1 U-plane capture mistake.
- BFP is the default you will see. udCompMeth 0001, one 4-bit exponent per PRB in udCompParam, then packed mantissas. If a vendor claims "no compression," expect ~double the fronthaul.
- Modulation compression is DL-only. If someone proposes it for uplink, that is a red flag — the O-RU cannot know the constellation point. Great DL savings, impossible UL.
- Compression trades bandwidth for EVM. Fewer mantissa bits = smaller fronthaul = higher error vector magnitude. 9-bit BFP is the usual sweet spot; drop to 6-bit only if the link forces you.
- sectionId still rules. Even here in the U-plane, the section is matched to its C-plane command by sectionId — the thread from Chapter 3 never lets go.