Convolutional codes#
Convolutional coding: encoder and Viterbi decoder (decision D4).
Batch-vectorized implementations: the only Python loop is over time (the trellis recursion is irreducible); everything across batch and states is numpy. Branch metrics are computed inside the time loop, so memory stays bounded (architecture document, section 8).
- class ConvolutionalEncoder(g: tuple[int, ...] = (91, 121), *, terminated: bool = True, name: str = 'conv_encoder')[source]#
Rate \(1/n\) convolutional encoder.
Signal Model#
With input bits \(x[m]\) and generator polynomials \(g_0, \dots, g_{n-1}\) of constraint length \(K\), the coded stream interleaves the \(n\) parity outputs:
\[y[nm + i] = \bigoplus_{l=0}^{K-1} g_{i}[l] \, x[m - l], \qquad i = 0, \dots, n-1\]The default generators \((133, 171)_8\) with \(K = 7\) are the standard NASA/Voyager code (free distance 10). When
terminatedis True, \(K - 1\) zero tail bits flush the register so the decoder can end in the all-zero state.Axes: axis -1 – bits on the last axis, broadcast over the rest;
(..., N)maps to(..., n (N + K - 1))when terminated.- param g:
Generator polynomials \(g_i\) in octal (MSB = current input tap). Default
(0o133, 0o171).- type g:
tuple of int
- param terminated:
Append \(K - 1\) zero tail bits. Default True.
- type terminated:
bool, keyword-only
- param name:
Name of the processor. Default
"conv_encoder".- type name:
str, keyword-only
References
J. G. Proakis, M. Salehi, Digital Communications, 5th ed., McGraw-Hill, 2008, Section 8.2.
Examples
>>> encoder = ConvolutionalEncoder((0o5, 0o7)) # K=3, rate 1/2 >>> bits = np.array([1, 0, 1, 1]) >>> print(encoder(bits)) [1 1 0 1 0 0 1 0 1 0 1 1]
- property rate: float#
Code rate \(1/n\) (tail bits not counted).
- class ViterbiDecoder(g: tuple[int, ...] = (91, 121), *, soft: bool = False, terminated: bool = True, name: str = 'viterbi')[source]#
Maximum-likelihood decoder for a rate \(1/n\) convolutional code.
Signal Model#
The decoder finds the information sequence \(\hat{x}\) whose coded sequence \(c(\hat{x})\) minimizes the path metric
\[\hat{x} = \arg\min_{x} \sum_{m, i} d\big(r[nm+i],\, c_i[m]\big)\]where \(d\) is the Hamming distance for hard decisions (
soft=False, input bits in \(\{0, 1\}\)) and the max-log metric \(d(r, c) = r \, c\) for soft decisions (soft=True, input log-likelihood ratios \(r = \log P(0)/P(1)\), as produced bySymbolDemapper(..., soft=True)).Axes: axis -1 – coded samples on the last axis, batch-vectorized Viterbi recursion with a Python loop over time only (decision D4);
(..., n (N + K - 1))maps back to(..., N)when terminated.- param g:
Generator polynomials \(g_i\) in octal; must match the encoder. Default
(0o133, 0o171).- type g:
tuple of int
- param soft:
Interpret the input as LLRs instead of hard bits. Default False.
- type soft:
bool, keyword-only
- param terminated:
Assume \(K - 1\) zero tail bits (decoding ends in state 0). Default True.
- type terminated:
bool, keyword-only
- param name:
Name of the processor. Default
"viterbi".- type name:
str, keyword-only
- raises ShapeError:
If the coded length is not a multiple of \(n\), or shorter than the tail.
References
A. J. Viterbi, “Error bounds for convolutional codes and an asymptotically optimum decoding algorithm,” IEEE Trans. Inf. Theory 13(2), 1967; Proakis & Salehi, 5th ed., Section 8.2.
Examples
>>> encoder = ConvolutionalEncoder((0o5, 0o7)) >>> decoder = ViterbiDecoder((0o5, 0o7)) >>> coded = encoder(np.array([1, 0, 1, 1])) >>> coded[2] ^= 1 # one channel error >>> print(decoder(coded)) [1 0 1 1]