Patrick Lidstone
Self-hosted

xRIT — LRIT/HRIT file layer (GOES, Meteosat, GK-2A, Elektro-L)

The file-transfer layer of the geostationary weather birds: images travel as xRIT files — a typed header chain (primary header, image structure, …) followed by the data field — fragmented across CCSDS Space Packets using the 2-bit sequence flags, and reassembled per-APID on receive. Sits directly on the CCSDS core this repo already runs.

Rafe project · app/radio/sat/xrit.py, test_sat_xrit.py · build + parse + fragment + reassemble · uncompressed and JPEG (Pillow) image fields; lossless-wavelet LRIT is a follow-on


Abstract

Geostationary imagery (GOES GRB/HRIT, Meteosat, GK-2A, Elektro-L) reaches the ground as xRIT files — "LRIT" at low rate, "HRIT" at high — each a self-describing container: a chain of typed headers, then the payload. The transport beneath is the familiar CCSDS stack (CADUs → VCDUs → Space Packets); the xRIT layer's job is exactly two things, and this module implements both directions of each:

  1. files ↔︎ packets — fragment a file across Space Packets and reassemble, using the packet header's 2-bit sequence flags;
  2. file ↔︎ image — build and parse the header chain and decode the image data field.

1. The file format

1.1 Header chain

Headers are [type(1) | length(2, BE) | fields…], concatenated; the primary header states where the chain ends and the data begins.

Primary header (type 0, 16 bytes) — must be first:

Offset Field
0 type = 0
1–2 header length = 16
3 file type code (0 = image)
4–7 total header length (BE32) — offset of the data field
8–15 data field length in bits (BE64)

Image structure header (type 1, 9 bytes):

Offset Field
0 type = 1
1–2 header length = 9
3 bits per pixel (8 supported)
4–5 columns (BE16)
6–7 lines (BE16)
8 compression: 0 none · 1 lossless · 2 JPEG

parse_xrit walks the chain by (type, length) until the total header length, collecting what it recognises and skipping unknown types — the forward-compatibility property the format was designed for.

1.2 Data field

  • Compression 0: raw 8-bpp pixels, reshaped to (lines, cols).
  • Compression 2 (JPEG): decoded via Pillow — this is what the real lossy LRIT services do; the round-trip test bounds the loss (mean abs error < 4 at quality 90).
  • Compression 1 (lossless wavelet/Rice): not yet implemented — named follow-on.

2. Packet fragmentation and reassembly

Space Packet header: version/type/APID(2) · flags+seq(2) · length(2), then data. The sequence flags (top 2 bits of byte 2) tell the reassembler how fragments compose:

Flags Meaning
01 first segment of a file
00 continuation
10 last segment
11 unsegmented (whole file in one packet)

fragment_to_packets(file, apid, seg=800) cuts the file into ≤ seg-byte segments and numbers them; reassemble_files(packets) keeps one buffer per APID, so interleaved files on different APIDs (the normal situation — a virtual channel carries several image channels at once) reassemble correctly; the test interleaves two images across two APIDs and recovers both exactly.

3. The full chain

The GOES-shaped end-to-end test drives: image → xRIT file → Space Packet → VCDU/M-PDU (892-byte frame) → 4 × RS(255,223) → CADU → QPSK symbols → CCSDS decode → packet extraction → file reassembly → header parse → pixel-exact image. Everything below the packet layer is the LRPT/CCSDS core, already specified there.

4. Validation

Test Asserts
test_xrit_file_roundtrip header fields + pixel-exact image
test_packet_fragment_reassemble genuinely multi-segment file survives
test_interleaved_apids two files interleaved on two APIDs both recovered
test_full_goes_chain_through_ccsds image → … → CADU → … → image, pixel-exact
test_xrit_jpeg_compressed JPEG field genuinely smaller; loss bounded
test_xrit_jpeg_via_packets JPEG file through fragmentation too

5. Limitations

  • Header types beyond 0/1 (annotation, time stamp, key/encryption, segmentation) are skipped on parse and never emitted on build — enough for image work, not for the full dissemination catalogue (text products, DCS).
  • Lossless compression (flag 1) unimplemented (§1.2).
  • Multi-segment image products (one image split across several files with a segmentation header) are not recombined — one file = one image here.
  • Encrypted HRIT (GK-2A) is out of scope without keys.

Related: LRPT (the CCSDS transport beneath), HRPT/AHRPT (the polar siblings), sat.md (how the decoders wire into live SDR collectors).