File interleaver_core.h¶
FileList > inc > interleaver > interleaver_core.h
Go to the source code of this file
Block interleaving as an object — the geometry, held. More...
#include "dp_interleave.h"#include <stddef.h>#include <stdint.h>
Classes¶
| Type | Name |
|---|---|
| struct | interleaver_state_t A block interleaver's geometry. |
Public Functions¶
| Type | Name |
|---|---|
| interleaver_state_t * | interleaver_create (size_t rows, size_t cols, size_t unit_bits) Build an interleaver over a rows xcols block ofunit_bits units. |
| interleaver_state_t * | interleaver_create_rx (size_t rows, size_t cols, size_t unit_bits) The RECEIVE face of the same interleaver. |
| size_t | interleaver_deinterleave (interleaver_state_t * state, const uint8_t * in, size_t n_in, uint8_t * out, size_t max_out) Undo interleaver_interleave over the same geometry. |
| size_t | interleaver_deinterleave_max_out (const interleaver_state_t * state, size_t n_in) Output bits for n_in input bits — the same number. |
| size_t | interleaver_deinterleave_soft (interleaver_state_t * state, const float * in, size_t n_in, float * out, size_t max_out) Undo an interleave over SOFT values — the receive path that matters. |
| size_t | interleaver_deinterleave_soft_max_out (const interleaver_state_t * state, size_t n_in) Output values for n_in soft input values — the same number. |
| void | interleaver_destroy (interleaver_state_t * state) Release an interleaver. |
| size_t | interleaver_get_block_bits (const interleaver_state_t * state) Bits in one block — rows * cols * unit_bits . |
| size_t | interleaver_get_burst_len (const interleaver_state_t * state) The longest burst this geometry fully spreads — rows . |
| size_t | interleaver_get_separation (const interleaver_state_t * state) Units per codeword — cols . |
| size_t | interleaver_interleave (interleaver_state_t * state, const uint8_t * in, size_t n_in, uint8_t * out, size_t max_out) Interleave a whole number of blocks. |
| size_t | interleaver_interleave_max_out (const interleaver_state_t * state, size_t n_in) Output bits for n_in input bits — the same number. |
| void | interleaver_reset (interleaver_state_t * state) No-op; an interleaver carries nothing between calls. |
Detailed Description¶
The transform itself is dp_interleave.h, header-only and stateless. This is not a second implementation: every method here calls that one. The split is conv/conv_enc's — one owns the arithmetic, the other owns the configured thing a caller holds and reuses.
What holding it buys is that the geometry is DECLARED rather than inferred from whatever length arrives. A block interleaver only works if the transmitter and the receiver agree on the permutation, and deriving cols from the input length means a truncated frame silently produces a DIFFERENT permutation instead of an error.
Stateless, deliberately, and therefore not serializable. Interleaving is per-frame: carrying a partial block across frames would add frame-latency and break per-frame decoding, so a call takes a whole number of blocks or is refused. Nothing survives between calls, so there is nothing to checkpoint — the exemption docs/design/state-serialization.md grants a pure converter.
interleaver_state_t *il = interleaver_create (8, 32, 1);
uint8_t tx[256], rx[256];
interleaver_interleave (il, bits, 256, tx, sizeof tx);
interleaver_deinterleave (il, tx, 256, rx, sizeof rx);
interleaver_destroy (il);
Public Functions Documentation¶
function interleaver_create¶
Build an interleaver over a rows xcols block ofunit_bits units.
Parameters:
rowsInterleaving depth; the longest burst fully spread. Must be non-zero.colsUnits per codeword. Must be non-zero.unit_bitsBits per interleaved unit. 1 interleaves bits; 8 interleaves octets, which is what spreads a burst across the codewords of a symbol-oriented code such as Reed-Solomon over GF(256). Must be non-zero.
Returns:
An interleaver, or NULL if any parameter is zero or the block would overflow.
>>> import numpy as np
>>> from doppler.coding import Interleaver
>>> il = Interleaver(rows=3, cols=4)
>>> il.block_bits, il.burst_len, il.separation
(12, 3, 4)
function interleaver_create_rx¶
The RECEIVE face of the same interleaver.
Identical construction — it delegates to interleaver_create — and it exists because the two ends of a link are written by different people. Someone working the receive side reaches for a Deinterleaver, and a class that is only findable under the transmit name is a class they do not find.
The GEOMETRY is why this is a view over one core rather than a second object: rows, cols and unit_bits are exactly what the two ends must agree on, and a mismatch is not an error but a receiver de-interleaving into a different permutation and handing the decoder plausible garbage. One core means one definition of the geometry to get right.
Parameters:
rowsInterleaving depth, as the transmitter used.colsUnits per codeword, as the transmitter used.unit_bitsBits per interleaved unit, as the transmitter used.
Returns:
An interleaver, or NULL on the same refusals as interleaver_create.
>>> import numpy as np
>>> from doppler.coding import Interleaver, Deinterleaver
>>> tx = Interleaver(rows=3, cols=4)
>>> rx = Deinterleaver(rows=3, cols=4)
>>> bits = np.arange(12, dtype=np.uint8)
>>> wire = np.asarray(tx.interleave(bits))
>>> np.array_equal(np.asarray(rx.deinterleave(wire)), bits)
True
function interleaver_deinterleave¶
Undo interleaver_interleave over the same geometry.
size_t interleaver_deinterleave (
interleaver_state_t * state,
const uint8_t * in,
size_t n_in,
uint8_t * out,
size_t max_out
)
Parameters:
stateThe interleaver.inn_ininterleaved bits, one bit per byte.n_inInput length in bits; a whole number of blocks.outWhere to writen_inbits; must not overlapin.max_outRoom inout, in bits.
Returns:
n_in, or 0 on a refusal.
>>> import numpy as np
>>> from doppler.coding import Interleaver
>>> il = Interleaver(rows=3, cols=4)
>>> x = np.arange(12, dtype=np.uint8)
>>> y = np.asarray(il.interleave(x))
>>> np.array_equal(np.asarray(il.deinterleave(y)), x)
True
function interleaver_deinterleave_max_out¶
Output bits for n_in input bits — the same number.
Identical to interleaver_interleave_max_out, and for the same reason: the inverse of a permutation is a permutation.
Parameters:
stateThe interleaver.n_inInput length in bits.
Returns:
n_in.
>>> from doppler.coding import Interleaver
>>> Interleaver(rows=4, cols=8).deinterleave_max_out(32)
32
function interleaver_deinterleave_soft¶
Undo an interleave over SOFT values — the receive path that matters.
size_t interleaver_deinterleave_soft (
interleaver_state_t * state,
const float * in,
size_t n_in,
float * out,
size_t max_out
)
dsss_burst_receiver's llrs span the whole frame, and an outer decoder wants them de-interleaved BEFORE it runs. Slicing to hard bits first and de-interleaving those throws away the confidence the soft output exists to carry, which is most of what an outer code is for.
There is no interleave_soft: a transmitter has bits, not LLRs.
Parameters:
stateThe interleaver.inn_insoft values, one per interleaved unit-bit.n_inInput length in values; a whole number of blocks.outWhere to writen_invalues; must not overlapin.max_outRoom inout, in values.
Returns:
n_in, or 0 on a refusal.
>>> import numpy as np
>>> from doppler.coding import Interleaver
>>> il = Interleaver(rows=2, cols=3)
>>> llr = np.array([1., 2., 3., 4., 5., 6.], dtype=np.float32)
>>> np.asarray(il.deinterleave_soft(llr)).tolist()
[1.0, 3.0, 5.0, 2.0, 4.0, 6.0]
function interleaver_deinterleave_soft_max_out¶
Output values for n_in soft input values — the same number.
Parameters:
stateThe interleaver.n_inInput length in values.
Returns:
n_in.
>>> from doppler.coding import Interleaver
>>> Interleaver(rows=4, cols=8).deinterleave_soft_max_out(32)
32
function interleaver_destroy¶
Release an interleaver.
A no-op on NULL, like free. The object owns nothing but its three numbers, so this is one free and there is no buffer to drain first.
Parameters:
stateThe interleaver, or NULL.
function interleaver_get_block_bits¶
Bits in one block — rows * cols * unit_bits .
Parameters:
stateThe interleaver.
Returns:
The block size in bits.
>>> from doppler.coding import Interleaver
>>> Interleaver(rows=8, cols=32, unit_bits=8).block_bits
2048
function interleaver_get_burst_len¶
The longest burst this geometry fully spreads — rows .
A burst of up to this many consecutive units on the wire touches each codeword at most once, so an outer code correcting t units per codeword survives a burst of t times this.
>>> from doppler.coding import Interleaver
>>> Interleaver(rows=5, cols=51, unit_bits=8).burst_len
5
function interleaver_get_separation¶
Units per codeword — cols .
The other half of the link budget: what interleaver_get_burst_len spreads a burst ACROSS.
>>> from doppler.coding import Interleaver
>>> Interleaver(rows=5, cols=51, unit_bits=8).separation
51
function interleaver_interleave¶
Interleave a whole number of blocks.
size_t interleaver_interleave (
interleaver_state_t * state,
const uint8_t * in,
size_t n_in,
uint8_t * out,
size_t max_out
)
Parameters:
stateThe interleaver.inn_inbits, one bit per byte.n_inInput length in bits; must be a non-zero multiple ofinterleaver_get_block_bits.outWhere to writen_inbits; must not overlapin.max_outRoom inout, in bits.
Returns:
n_in on success, 0 if the length is not a whole number of blocks or out is too small. A partial block is REFUSED rather than padded: padding changes the length, and a receiver that de-interleaved the padded block would recover different bits.
>>> import numpy as np
>>> from doppler.coding import Interleaver
>>> il = Interleaver(rows=3, cols=4)
>>> x = np.arange(12, dtype=np.uint8)
>>> np.asarray(il.interleave(x)).tolist()
[0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11]
function interleaver_interleave_max_out¶
Output bits for n_in input bits — the same number.
A permutation moves bits and does not add or remove any, so this is the identity. It exists because the binding asks a method how much room its output needs, and answering "the same" is not something a caller should have to know.
Parameters:
stateThe interleaver.n_inInput length in bits.
Returns:
n_in.
>>> from doppler.coding import Interleaver
>>> Interleaver(rows=4, cols=8).interleave_max_out(32)
32
function interleaver_reset¶
No-op; an interleaver carries nothing between calls.
Present because the object surface has it, and honest about why it does nothing: a reset that pretended to clear something would suggest there was something to clear. The geometry is configuration, not state, so it survives — a reset that cleared THAT would leave every later call refusing.
Parameters:
stateThe interleaver.
>>> import numpy as np
>>> from doppler.coding import Interleaver
>>> il = Interleaver(rows=2, cols=3)
>>> il.reset()
>>> il.block_bits
6
The documentation for this class was generated from the following file native/inc/interleaver/interleaver_core.h