Overview of the RFCAP format 📸

Paul Tagliamonte 2020-11-03 format

rfcap is a file format with extremely small ambitions. rfcap files contain a fixed size header, and then a stream of raw IQ data. The rfcap header contains information about the IQ format type, and capture metadata. The header is aligned to a 128 bit boundary, so most iq formats can choose to ignore the header and throw out the first window, meaning existing tools like gqrx can read a subset of rfcap files in the right IQ sample format.

This documentation is of a stable file format. Changes to this spec will result in a non-breaking and careful change, or a major version change. This format is safe to rely on.

The biggest advantage of the rfcap scheme is that IQ data can be piped around without additional sample information such as IQ format, or sample rate, and the metadata remains attached to the stream.

Reference implementation

The hz.tools/rfcap package contains the reference implementation of the rfcap spec, and will be maintained as the spec evolves. Go programmers are strongly advised to use this package as a dependency for reading and writing SDR captures in Go.

Format Description

Each rfcap file is comprised of a single 48 byte header, followed by a stream of IQ data, as described by the header.

Samples

Implementations are advised to store the header, in case samples need to be written to disk, or piped to another application outside of the current process.

The Header is split up into fields containing metadata describing the format and rate of the IQ samples to follow. At minimum, implementations must be able to understand the SampleRate field, the SampleFormat field, and if not only using uint8, the Endianness field.

The header itself is always encoded little endian. This may make things a little confusing when operating over the network, since you may be expecting network order – but it does make it significantly easier to consume on little endian systems (which make up most of the target platforms), and makes things a little easier when the encoded data is also little endian floating point numbers (which is also usually the case on little endian systems).

Field NameTypeDescription
Magic[6]byteCurrently always `RFCAP1` for rfcap v1
Capture Timeint64Number of nanoseconds since the Unix Epoch. Divide by `1e+9` to get a Unix Epoch in seconds, and preform a modulus to get the nanoseconds.
Center Frequencyfloat64Center Frequency of the capture, in Hz, as a floating point 64 bit number.
Sample Rateuint32Number of IQ samples per second this capture was taken at. Each IQ sample is comprised of the real and imaginary sample.
Sample Formatuint8Sample Format defined by the `hz.tools/sdr.SampleFormat` enum.

  • 1: Complex64 (interleaved 32 bit floats)
  • 2: uint8 (interleaved 8 bit uints)
  • 3: int16 (interleaved 16 bit ints)
  • 4: int8 (interleaved 8 bit ints)
Endiannessuint8In order to retain compatability with an earlier rfcap version, Little Endian files are denoted with a 0, rather than a 1.

  • 0: Little Endian
  • 1: Big Endian
Reserved[20]byteCurrently unused. Implementations must not rely on any information in this range, and when writing headers, the data in these bytes must be all zeros.