KBestDetector#

class sionna.phy.mimo.KBestDetector(output: str, num_streams: int, k: int, constellation_type: str | None = None, num_bits_per_symbol: int | None = None, constellation: sionna.phy.mapping.Constellation | None = None, hard_out: bool = False, use_real_rep: bool = False, list2llr: sionna.phy.mimo.utils.List2LLR | None = None, precision: Literal['single', 'double'] | None = None, device: str | None = None, **kwargs)[source]#

Bases: sionna.phy.block.Block

MIMO K-Best detector.

This block implements K-Best MIMO detection as described in (Eq. 4-5) [FT2015]. It can either generate hard decisions (for symbols or bits) or compute LLRs.

The algorithm operates in either the complex or real-valued domain. Although both options produce identical results, the former has the advantage that it can be applied to arbitrary non-QAM constellations. It also reduces the number of streams (or depth) by a factor of two.

The way soft-outputs (i.e., LLRs) are computed is determined by the list2llr function. The default solution List2LLRSimple assigns a predetermined value to all LLRs without counter-hypothesis.

This block assumes the following channel model:

\[\mathbf{y} = \mathbf{H}\mathbf{x} + \mathbf{n}\]

where \(\mathbf{y}\in\mathbb{C}^M\) is the received signal vector, \(\mathbf{x}\in\mathcal{C}^S\) is the vector of transmitted symbols which are uniformly and independently drawn from the constellation \(\mathcal{C}\), \(\mathbf{H}\in\mathbb{C}^{M\times S}\) is the known channel matrix, and \(\mathbf{n}\in\mathbb{C}^M\) is a complex Gaussian noise vector. It is assumed that \(\mathbb{E}\left[\mathbf{n}\right]=\mathbf{0}\) and \(\mathbb{E}\left[\mathbf{n}\mathbf{n}^{\mathsf{H}}\right]=\mathbf{S}\), where \(\mathbf{S}\) has full rank.

In a first optional step, the channel model is converted to its real-valued equivalent, see complex2real_channel(). We assume in the sequel the complex-valued representation. Then, the channel is whitened using whiten_channel():

\[\begin{split}\tilde{\mathbf{y}} &= \mathbf{S}^{-\frac{1}{2}}\mathbf{y}\\ &= \mathbf{S}^{-\frac{1}{2}}\mathbf{H}\mathbf{x} + \mathbf{S}^{-\frac{1}{2}}\mathbf{n}\\ &= \tilde{\mathbf{H}}\mathbf{x} + \tilde{\mathbf{n}}.\end{split}\]

Next, the columns of \(\tilde{\mathbf{H}}\) are sorted according to their norm in descending order. Then, the QR decomposition of the resulting channel matrix is computed:

\[\tilde{\mathbf{H}} = \mathbf{Q}\mathbf{R}\]

where \(\mathbf{Q}\in\mathbb{C}^{M\times S}\) is unitary and \(\mathbf{R}\in\mathbb{C}^{S\times S}\) is upper-triangular. The channel outputs are then pre-multiplied by \(\mathbf{Q}^{\mathsf{H}}\). This leads to the final channel model on which the K-Best detection algorithm operates:

\[\bar{\mathbf{y}} = \mathbf{R}\bar{\mathbf{x}} + \bar{\mathbf{n}}\]

where \(\bar{\mathbf{y}}\in\mathbb{C}^S\), \(\bar{\mathbf{x}}\in\mathbb{C}^S\), and \(\bar{\mathbf{n}}\in\mathbb{C}^S\) with \(\mathbb{E}\left[\bar{\mathbf{n}}\right]=\mathbf{0}\) and \(\mathbb{E}\left[\bar{\mathbf{n}}\bar{\mathbf{n}}^{\mathsf{H}}\right]=\mathbf{I}\).

LLR Computation

The K-Best algorithm produces \(K\) candidate solutions \(\bar{\mathbf{x}}_k\in\mathcal{C}^S\) and their associated distance metrics \(d_k=\lVert \bar{\mathbf{y}} - \mathbf{R}\bar{\mathbf{x}}_k \rVert^2\) for \(k=1,\dots,K\). If the real-valued channel representation is used, the distance metrics are scaled by 0.5 to account for the reduced noise power in each complex dimension. A hard-decision is simply the candidate with the shortest distance. Various ways to compute LLRs from this list (and possibly additional side-information) are possible. The (sub-optimal) default solution is List2LLRSimple. Custom solutions can be provided.

Parameters:
  • output (str) – Type of output, either "bit" for LLRs on bits or "symbol" for logits on constellation symbols

  • num_streams (int) – Number of transmitted streams

  • k (int) – Number of paths to keep. Cannot be larger than the number of constellation points to the power of the number of streams.

  • constellation_type (str | None) – Constellation type, one of "qam", "pam", or "custom". For "custom", an instance of Constellation must be provided.

  • num_bits_per_symbol (int | None) – Number of bits per constellation symbol, e.g., 4 for QAM16. Only required for constellation_type in ["qam", "pam"].

  • constellation (sionna.phy.mapping.Constellation | None) – An instance of Constellation or None. If None, constellation_type and num_bits_per_symbol must be provided.

  • hard_out (bool) – If True, the detector computes hard-decided bit values or constellation point indices instead of soft-values. Defaults to False.

  • use_real_rep (bool) – If True, the detector uses the real-valued equivalent representation of the channel. Note that this only works with a QAM constellation. Defaults to False.

  • list2llr (sionna.phy.mimo.utils.List2LLR | None) – The function to be used to compute LLRs from a list of candidate solutions. If None, the default solution List2LLRSimple is used.

  • precision (Literal['single', 'double'] | None) – Precision used for internal calculations and outputs. If set to None, precision is used.

  • device (str | None) – Device for computations

Inputs:
  • y – […,M], torch.complex. Received signals.

  • h – […,M,num_streams], torch.complex. Channel matrices.

  • s – […,M,M], torch.complex. Noise covariance matrices.

One of:

Outputs:
  • llr – […, num_streams, num_bits_per_symbol], torch.float. LLRs or hard-decisions for every bit of every stream, if output equals "bit".

  • logits – […, num_streams, num_points], torch.float or […, num_streams], torch.int32. Logits or hard-decisions for constellation symbols for every stream, if output equals "symbol". Hard-decisions correspond to the symbol indices.

Parameters:

Examples

detector = KBestDetector(
    output="bit",
    num_streams=2,
    k=16,
    constellation_type="qam",
    num_bits_per_symbol=4
)
llr = detector(y, h, s)

Attributes

property list2llr: sionna.phy.mimo.utils.List2LLR#

Set/get the function to compute LLRs from candidate solutions.

Methods

build(*input_shapes)[source]#

Initialize the block based on the inputs’ shapes.

Subclasses can override this method to create tensors or sub-blocks whose sizes depend on the input shapes.

Parameters:
  • *arg_shapes – Shapes of the positional arguments. Can be tuples (for tensors) or nested structures thereof (for lists/dicts of tensors).

  • **kwarg_shapes – Shapes of the keyword arguments. Can be tuples (for tensors) or nested structures thereof (for lists/dicts of tensors).