Skip to content

99 Horus Binary v3 Developmental Notes

Mark Jessop edited this page Oct 11, 2025 · 5 revisions

Some discussion on a proposed Horus Binary v3 mode.

Aims of Horus Binary v3

  • More customisable packet format

    • Use ASN1 for binary packing - lots of great work by xssfox on this.
    • Allow for arbitrary callsigns (Up to some maximum length). No more Payload ID allocation.
    • We will need packet sizes > 32 bytes for this. 48 bytes and bigger will be needed, depending on custom fields.
    • Ideally we want to be able to support a range of packet lengths, e.g. 48 - 128 bytes in 16 byte increments.
  • Don't mess with the underlying modem! It works well. Change how we deal with the bits coming out of the modem.

  • Retain the current Golay(23,12) FEC. We have a known-good implementation on both PCs and microcontrollers. It's performing fine.

Packet Extraction

Current Approach

Screen Shot 2025-10-11 at 10 49 07
  • Bits are clocked through a buffer big enough to hold the largest packet expected

  • Bits are clocked in 'right to left'.

  • A UW search is run https://github.com/projecthorus/horusdemodlib/blob/master/src/horus_api.c#L351

    • It looks like this searches through the left-most 100 bits in the buffer for the UW.
    • So we are essentially doing a UW comparison on every bit as its clocked in.
  • If the UW matches, then the decoder attempts to extract both a Horus v1 and v2 packet from the buffer starting just after the UW location

    • This involves Golay FEC, then CRC16 checks.
  • For Horus binary modes, bits continue to be clocked through the buffer.

    • For RTTY decoding, the buffer is cleared enough to avoid duplicate detections of the expected RTTY preamble (many $$s)

Downside of this approach is the packet has to be clocked through enough to be at the 'left' of the buffer to be decoded. This adds some latency to the decoder, which would get worse if we added longer packet sizes to the same approach.

Proposed Approach

Screen Shot 2025-10-11 at 10 16 14
  • As before, bits are clocked through a buffer, but only big enough to hold the largest packet + UW
  • Clock bits in 2 at a time, not 100 bits at a time.
    • Could do this 1 bit at a time? But packets are always goign to be aligned to a 4FSK symbol, so 2 bits should be OK.
  • On each 2 bits clocked in, check for the UW at specific locations within the buffer.
    • Different UWs used for Horus v1/v2 vs Horus v3 modes.
  • If a UW match is found, attempt packet extraction.
  • If packet extraction is successful, flush the buffer. If not, continue clocking through.

Unique Word

Horus Binary v1/v2 Use the same unique word, defined here: https://github.com/projecthorus/horusdemodlib/blob/master/src/horus_api.c#L80

int8_t uw_horus_binary_v1[] = {
    0,0,1,0,0,1,0,0,
    0,0,1,0,0,1,0,0 
};

This is actually ASCII $$.

For Horus Binary v3, I suggest we use the last row of a 16-bit hadamard matrix as our unique word. This would be:

>>> import scipy.linalg
>>> (scipy.linalg.hadamard(16)[-1]>0).astype(int)
array([1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1])

We could use different rows of the matrix for different packet lengths, this might reduce the need to run multiple packet extractions as the packet is clocked through the buffer.

Coded Packet Sizes

  • Horus Binary v1
    • Uncoded: 22 bytes
    • Coded: 45 bytes, 360 bits.
  • Horus Binary v2
    • Uncoded: 32 bytes
    • Coded: 65 bytes, 520 bits
  • Proposed Horus Binary v3 64 byte
    • Uncoded: 64 bytes
    • Coded: 126 bytes, 1008 bits
Clone this wiki locally