ACIDCAT . FILE FORMAT REFERENCE

SigMF Anatomy

Signal Metadata Format.sigmf-meta + .sigmf-data
rev 2026.07
meta JSON sidecar
data headerless IQ
datatype c/r i/u/f bits
lineage GNU Radio 2017

SigMF is what you get when you apply the raw-PCM-plus-header idea to radio. A software-defined radio dumps a headerless stream of IQ samples to a .sigmf-data file; a JSON sidecar, .sigmf-meta, describes it — a global object (datatype, sample rate, hardware, checksum), a captures list (frequency-tagged segments of the stream), and optional annotations (labeled sample ranges). It is the exact structure of a raw PCM file next to a detached WAV header, which is why an audio tool reads it: IQ is just complex-valued audio. The tabs open the sidecar and the sample stream. This page is drawn from a spec-conformant example (SigMF v1.0.0), not a captured recording. Hover a field to light its bytes, click a field with a + for its table. Color marks kind (see the key).

A WAV file staples its header to its samples; SigMF detaches them. The samples live raw and headerless in .sigmf-data — nothing but back-to-back IQ values — and everything you need to interpret them lives in a separate JSON file, .sigmf-meta. That sidecar has three parts: global (the geometry: datatype, sample rate, hardware, a sha512 of the data), captures (segments of the stream, each tagged with the radio frequency it was tuned to), and annotations (labeled sample ranges — “a signal is here”). The example below is built to the SigMF v1.0.0 schema.

a SigMF recording, laid out
capture.sigmf-meta — the JSON sidecar ├─ global datatype "ci16_le", sample_rate 2 MHz, sha512 ├─ captures [ sample_start 0, frequency 8.428 GHz ] └─ annotations labeled sample ranges (optional) capture.sigmf-data — headerless IQ: I0 Q0 I1 Q1 ...
the metadata-format idea, dated
2017SigMF — drafted at a DARPA Hackfest and stewarded by the GNU Radio project to end the chaos of undocumented .iq dumps. One open schema for “what is in this pile of samples”.
splitmeta / data. The .sigmf-meta JSON and the .sigmf-data stream are a pair, joined by base name — exactly like a detached WAV header sitting beside raw PCM.
bare IQthe unlabeled cousins. .cu8, .cs16, GQRX .raw, PortaPack .C16 + .TXT — the same headerless stream with geometry inferred from the extension, a sidecar, or the filename.
bridgeaudio meets RF. IQ is complex-valued audio; the SigMF sample_rate is the capture bandwidth. The same statistics used on PCM — DC offset, clipping — apply unchanged, which is why RF and audio tooling overlap.
the header is a sidecar. Because the geometry is in a separate JSON, the .sigmf-data file is pure samples — no magic, no offsets, nothing to sniff. You cannot read it without the meta, the same way raw PCM is meaningless without knowing its rate and width. A reader has to anchor on the meta and treat the data plane as the sample stream it describes.
captures are byte regions. Each capture's sample_start times the datatype's bytes-per-sample is a byte offset into the data file, so a capture (or an annotation) is a real, extractable segment. One tuned segment can be pulled out of a multi-gigabyte capture from offset and length alone.
frequency is the RF twist. The one field with no audio analogue is core:frequency on each capture — the center frequency the radio was tuned to (8.428 GHz here). It is why the stream is split into captures at all: a scan that retunes writes a new capture at each frequency, all in one data file.
formatUTF-8 JSONglobalthe geometrykeyscore: namespacereadas plain text

The sidecar is one JSON object with three top-level keys: global, captures, and annotations. The global object carries the fields that make the raw data readable — the core:datatype (sample geometry), core:sample_rate, core:version, an optional core:sha512 integrity hash, and hardware info. All keys live under a core: namespace. The map is the opening bytes of a SigMF meta file.

meta JSON, opening bytes

Plain ASCII. Hover datatype_key — the field that decides how the data stream is read.

the datatype is the whole ballgame. Without core:datatype, the .sigmf-data bytes are meaningless — it alone says whether a byte pair is a complex int16 or half of a float. It must be parsed into a geometry (complex/real, int/uint/float, bit width, endianness) before touching the data. The Datatype tab breaks the string down.
sha512 makes it verifiable. The global core:sha512 is a hash of the entire data file, so a recording is tamper-evident: recompute it and you know the samples are intact. Verification is opt-in in practice — hashing a multi-gigabyte capture is expensive enough to skip by default.
grammar(c/r)(i/u/f)(bits)(_endian)one stringfull geometryexampleci16_le

The core:datatype is a tiny grammar that packs a full sample description into one token: a required c (complex) or r (real), then i/u/f (signed int, unsigned int, or float), then the bit width, then an endian suffix for anything wider than a byte. The map breaks down ci16_le — complex, signed 16-bit, little-endian, so 4 bytes per sample (two int16 components).

datatype string "ci16_le" (7 bytes)

Hover each letter — every character is one decision in the grammar.

parametric, not a lookup table. WAV enumerates format tags (1 = PCM, 3 = float, ...); SigMF composes the type from parts. cu8 is complex unsigned 8-bit (2 B/sample, no endian needed); rf32_le is real float32; ru8 and ri16_le are the real counterparts; ci16_be is big-endian complex int16. Real and complex both take a leading letter — there is no bare form. The grammar is regular: a type missing its c/r prefix, or a multibyte type without its endian suffix, is invalid.
complex means interleaved. The leading c is why the data stream reads I Q I Q ... — each sample is two components, in-phase then quadrature. That is identical to how a stereo WAV interleaves left and right; here the two channels are the real and imaginary parts of one complex signal.
contentraw IQ sampleslayoutI Q I Q ...noheadergeometryfrom the meta

The .sigmf-data file is nothing but samples — no magic, no length, no framing. Under the ci16_le geometry from the meta, it is a run of complex int16 pairs: an in-phase (I) and a quadrature (Q) component per sample, little-endian, back to back. The map is the first two complex samples, decoded with the meta's datatype.

data stream, first 2 complex samples (8 bytes)

Hover a pair — I then Q, each a little-endian int16. Sample 0 = (−4, 2).

meaningless without the meta. These eight bytes could be four int16s, two float16s, or one part of a wider type — only core:datatype resolves it. That is the whole trade SigMF makes: keep the data plane utterly plain, and put every interpretation decision in the sidecar. Lose the meta and you are back to guessing geometry, exactly the problem headerless PCM has always posed.
the same audio statistics apply. DC offset (a non-zero mean on I or Q) and clipping (components pinned at the type's limit) are the identical health checks used on PCM audio — both are measured per component, I and Q separately. IQ is complex audio, so the audio toolbox transfers wholesale; only core:frequency has no PCM analogue. One wrinkle: an unsigned datatype is offset-binary, so its zero sits at half-scale — cu8 (the RTL-SDR native format) reads silence as 0x80, not 0x00.