# Space turbo code: exact 3200/6400 transport profile

Source: local [CCSDS 131.0-B-5 PDF](space_turbo_coding_ccds.pdf), September 2023,
section 6, printed pages 6-1 through 6-8, and section 10. This implementation
uses Python and NumPy only. It does not replace the older ETSI codec.

## Constituents and interleaver

Two 16-state recursive systematic convolutional constituents, figure 6-2,
connection vectors G0=10011 and G1=11011. The left-to-right register stages are
d1,d2,d3,d4 (successive delays of the feedback input w). Explicit equations:

    w[t] = u[t] XOR d3 XOR d4
    p[t] = w[t] XOR d1 XOR d3 XOR d4
    (d1,d2,d3,d4) <- (w[t],d1,d2,d3)

Both begin in state zero. Encoder b receives u[pi]. Using zero-based s=0..k-1,
k1=8, k2=k/8, the section 6.3g permutation is:

    m = s mod 2; i = floor(s/(2*k2)); j = floor(s/2)-i*k2
    t = (19*i+1) mod (k1/2); q = t mod 8
    primes = [31,37,43,47,53,59,61,67]
    c = (primes[q]*j+21*m) mod k2
    pi[s] = 2*(t+c*(k1/2)+1)-m-1

The last minus one converts the document's read addresses to zero-based indexing.
The original allowed k values are 1784,3568,7136,8920. The application extends
this formula to k=3200, k2=400; it is explicitly checked to be a permutation.
Its first addresses are [3,170,299,466,595,762,891,1058,1187,1354].

## Rate 1/2 and exact framing

At each clock t transmit the systematic bit of a, followed by parity a for even
t and parity b for odd t. Thus the ordering is (u0,pa0,u1,pb1,u2,pa2,...).
This matches section 6.3j and figure 6-3.

The standard terminates both constituents using four feedback-selected input
bits, making their register states zero. Its transmitted length is 2*(k+4),
so the actual rate is slightly less than its nominal 1/2. The implementation
supports this reference with `TurboCode(k, terminated=True, transport=False)`.

The application requires EXACTLY 3200 information bits -> 6400 channel bits.
It transmits only the first k clocks: the eight encoded tail symbols are omitted.
The decoder therefore uses a known zero initial state and an unconstrained final
state. This is equivalent to marginalizing four unobserved termination clocks;
it does not pretend the state is zero immediately after the information bits.
There are no payload filler bits, hidden CRC bits, or dropped Codec2 bits.
This custom punctured-tail profile is CCSDS-derived, not a standard CCSDS link.

## Public transport mapping

For each one-second block, XOR the 6400 encoded bits with the section 10 degree-17
pseudo-randomizer, h(x)=x^17+x^14+1, register seed `11000111000111000`, reset per
block. Its first 40 output bits match the PDF:
`0001110001110001101110010001101110101001`.

The implementation shifts toward the rightmost output stage; feedback is the
XOR of old register positions 16 and 2 (zero-based, left to right). This precise
shift convention avoids ambiguity in polynomial notation.

Then apply the custom physical permutation:
`physical[j]=(173*j+29) mod 6400`, with `transmitted[j]=randomized[physical[j]]`.
This disperses position-dependent neural errors and is independent of pi.
No ASM is inserted: an imported WAV must retain exact sample/block alignment.
The fixed randomizer and permutations are public channel formatting.

The waveform generator receives the transmitted block reshaped `(10,10,64)`:
ten 100ms calls per second, each containing 640 bits. Output is 16000 signed
samples at 16kHz. Serialize mono PCM16 with the same flooring used in training.
The analyzer receives only saved signed PCM samples, in 1600-sample blocks,
and returns 640 logits per block. No old autoencoder unit scaling is applied.

## Soft decoding and statistics

The analyzer logit is log(P(1)/P(0)); turbo input LLR is its negative.
Undo physical permutation, then negate LLRs at PN-one positions. Depuncture
missing alternating parities with zero LLRs, not known-zero bits. Iterate two
log-MAP BCJR constituent passes, exchanging extrinsic information through pi.
The implementation also permits max-log-MAP for comparison. Default maximum
12 iterations, with decision-stability early exit after at least four iterations
and two unchanged iterations. Stability is not a CRC or proof of correctness.

Report raw transmitted-bit errors and post-turbo information-bit errors separately,
with total bit counts, per-block failures, iterations and actual saved-WAV path.
True source bits are read ONLY after inference/decoding to compute statistics.
With an independently uploaded carrier the receiver reports decoded audio and
convergence diagnostics, without asserting a measured BER it cannot know.

## Codec2 payload

Codec2 mode 3200 uses 160 samples at 8kHz -> 64 bits / 20ms (8 bytes).
Fifty packets give 3200 information bits each second. Every such second occupies
one 6400-bit turbo word and one second of neural carrier. Preserve Codec2 state
over the recording, with a fresh native process for each encode/decode operation.
Final partial input seconds are padded for transport; local source-backed playback
can be trimmed to the original duration. A standalone imported carrier contains
whole seconds and has no embedded original-length field.
