Field Guide · term

Also known as: CS8, CS16, CF32, SC16, complex int8, complex int16, complex float32

A sample format is the numeric type used to store each component of an IQ sample: most commonly signed 8-bit integers (CS8), signed 16-bit integers (CS16), or 32-bit IEEE floats (CF32), where the leading C denotes complex (an I and a Q value per sample).1 The format an SDR emits fixes both the dynamic range available to the signal and the number of bytes each sample costs, and it dictates the scaling a program must perform before the DSP can treat the stream as ordinary numbers.

CS82 B/sample · −128…127 CS164 B/sample · −32768…32767 CF328 B/sample · float all normalize to float −1.0 … +1.0 for DSP
Wider formats cost more bytes per sample but carry more dynamic range; whatever the wire format, DSP typically works on floats scaled to about −1…+1.

How it works

The ADC in an SDR produces integers of some native width — 8 bits for an RTL-SDR, 12–16 bits for higher-end radios. The sample format is how those integers are packed for transport:

  • CS8 — one signed byte for I and one for Q, range −128…127. Half the bytes of CS16, so it halves USB and disk bandwidth, at the cost of coarse quantization. Some 8-bit radios also use unsigned bytes centred at 127, which the host must re-centre.
  • CS16 — 16-bit signed integers, the workhorse for radios with 12–16-bit ADCs. Often only the low 12 bits are meaningful, the value left- or right-justified within the 16-bit field.
  • CF32 — 32-bit float per component. It wastes bandwidth on a native-integer source but is the natural currency of DSP: no re-scaling needed, no overflow to police, and it is the standard format for IQ files (the .cfile).

Converting between them is mechanical but must be done right. Integer-to-float means dividing by the full-scale value (e.g. 32768.0 for CS16) so the signal lands in roughly −1.0…+1.0; the reverse means multiplying and then clamping so a hot sample cannot wrap around the integer range into a spurious value. Getting the scale factor or the signed/unsigned convention wrong shows up immediately as a squashed constellation, a DC bias, or clipping.

Relevance to SDR

Sample format is one of the first decisions a receive pipeline confronts, because it trades three things at once: bandwidth (CS8 is half of CS16 over USB and on disk), dynamic range (more bits push the noise floor of the quantizer down, widening the gap between the weakest recoverable signal and a strong nearby one), and numerical precision downstream. High-throughput or storage-bound applications favour the narrowest integer format that still meets the link’s dynamic-range budget, then convert to float only inside the DSP.

GopherTrunk meets this head-on as a pure-Go application spanning several radios. Its RTL-SDR path takes native 8-bit samples, its airspy path unpacks 12-bit ADC data delivered as 16-bit words, and its offline replay reads and writes complex float32 .cfile captures. In every case GT converts the wire format to floats scaled near −1…+1 at the front of the chain, so the rest of the demodulator is written once against a single representation regardless of which format the hardware produced. This normalization is also why a capture recorded in one format can be replayed through the same decode path as a live stream in another.

In practice

Beware endianness and justification: two radios may both claim “16-bit IQ” yet differ in byte order or in whether the 12 valid bits sit in the high or low end of the word. And a persistent DC offset baked into the samples is a property of the capture, not the format — no amount of re-scaling removes it, which is why front-end effects must be reproduced from the raw interleaved IQ rather than blamed on the conversion.

Sources

  1. IQ files and SigMF — PySDR, on storing IQ as int8/int16/float32, scaling, and the complex-file convention. 

See also