LMMSEInterpolator#

class sionna.phy.ofdm.LMMSEInterpolator(pilot_pattern, cov_mat_time: torch.Tensor, cov_mat_freq: torch.Tensor, cov_mat_space: torch.Tensor | None = None, order: str = 't-f')[source]#

Bases: sionna.phy.ofdm.channel_estimation.BaseChannelInterpolator

LMMSE interpolation on a resource grid with optional spatial smoothing.

This class computes for each element of an OFDM resource grid a channel estimate and error variance through linear minimum mean square error (LMMSE) interpolation/smoothing. It is assumed that the measurements were taken at the nonzero positions of a PilotPattern.

Depending on the value of order, the interpolation is carried out across time (t), i.e., OFDM symbols, frequency (f), i.e., subcarriers, and optionally space (s), i.e., receive antennas, in any desired order.

For simplicity, we describe the underlying algorithm assuming that interpolation across the sub-carriers is performed first, followed by interpolation across OFDM symbols, and finally by spatial smoothing across receive antennas. The algorithm is similar if interpolation and/or smoothing are performed in a different order. For clarity, antenna indices are omitted when describing frequency and time interpolation, as the same process is applied to all the antennas.

The input h_hat is first reshaped to a resource grid \(\hat{\mathbf{H}} \in \mathbb{C}^{N \times M}\), by scattering the channel estimates at pilot locations according to the pilot_pattern. \(N\) denotes the number of OFDM symbols and \(M\) the number of sub-carriers.

The first pass consists in interpolating across the sub-carriers:

\[\hat{\mathbf{h}}_n^{(1)} = \mathbf{A}_n \hat{\mathbf{h}}_n\]

where \(1 \leq n \leq N\) is the OFDM symbol index and \(\hat{\mathbf{h}}_n\) is the \(n^{\text{th}}\) (transposed) row of \(\hat{\mathbf{H}}\). \(\mathbf{A}_n\) is the \(M \times M\) matrix such that:

\[\mathbf{A}_n = \bar{\mathbf{A}}_n \mathbf{\Pi}_n^\intercal\]

where

\[\bar{\mathbf{A}}_n = \underset{\mathbf{Z} \in \mathbb{C}^{M \times K_n}}{\text{argmin}} \left\lVert \mathbf{Z}\left( \mathbf{\Pi}_n^\intercal \mathbf{R^{(f)}} \mathbf{\Pi}_n + \mathbf{\Sigma}_n \right) - \mathbf{R^{(f)}} \mathbf{\Pi}_n \right\rVert_{\text{F}}^2\]

and \(\mathbf{R^{(f)}}\) is the \(M \times M\) channel frequency covariance matrix, \(\mathbf{\Pi}_n\) the \(M \times K_n\) matrix that spreads \(K_n\) values to a vector of size \(M\) according to the pilot_pattern for the \(n^{\text{th}}\) OFDM symbol, and \(\mathbf{\Sigma}_n \in \mathbb{R}^{K_n \times K_n}\) is the channel estimation error covariance built from err_var and assumed to be diagonal. Computation of \(\bar{\mathbf{A}}_n\) is done using an algorithm based on complete orthogonal decomposition. This is done to avoid matrix inversion for badly conditioned covariance matrices.

The channel estimation error variances after the first interpolation pass are computed as

\[\mathbf{\Sigma}^{(1)}_n = \text{diag} \left( \mathbf{R^{(f)}} - \mathbf{A}_n \mathbf{\Xi}_n \mathbf{R^{(f)}} \right)\]

where \(\mathbf{\Xi}_n\) is the diagonal matrix of size \(M \times M\) that zeros the columns corresponding to sub-carriers not carrying any pilots. Note that interpolation is not performed for OFDM symbols which do not carry pilots.

Remark: The interpolation matrix differs across OFDM symbols as different OFDM symbols may carry pilots on different sub-carriers and/or have different estimation error variances.

Scaling of the estimates is then performed to ensure that their variances match the ones expected by the next interpolation step, and the error variances are updated accordingly:

\[\begin{split}\begin{aligned} \left[\hat{\mathbf{h}}_n^{(2)}\right]_m &= s_{n,m} \left[\hat{\mathbf{h}}_n^{(1)}\right]_m\\ \left[\mathbf{\Sigma}^{(2)}_n\right]_{m,m} &= s_{n,m}\left( s_{n,m}-1 \right) \left[\hat{\mathbf{\Sigma}}^{(1)}_n\right]_{m,m} + \left( 1 - s_{n,m} \right) \left[\mathbf{R^{(f)}}\right]_{m,m} + s_{n,m} \left[\mathbf{\Sigma}^{(1)}_n\right]_{m,m} \end{aligned}\end{split}\]

where the scaling factor \(s_{n,m}\) is such that:

\[\mathbb{E} \left\{ \left\lvert s_{n,m} \left[\hat{\mathbf{h}}_n^{(1)}\right]_m \right\rvert^2 \right\} = \left[\mathbf{R^{(f)}}\right]_{m,m} + \mathbb{E} \left\{ \left\lvert s_{n,m} \left[\hat{\mathbf{h}}^{(1)}_n\right]_m - \left[\mathbf{h}_n\right]_m \right\rvert^2 \right\}\]

which leads to:

\[\begin{split}\begin{aligned} s_{n,m} &= \frac{2 \left[\mathbf{R^{(f)}}\right]_{m,m}}{\left[\mathbf{R^{(f)}}\right]_{m,m} - \left[\mathbf{\Sigma}^{(1)}_n\right]_{m,m} + \left[\hat{\mathbf{\Sigma}}^{(1)}_n\right]_{m,m}}\\ \hat{\mathbf{\Sigma}}^{(1)}_n &= \mathbf{A}_n \mathbf{R^{(f)}} \mathbf{A}_n^{\mathrm{H}}. \end{aligned}\end{split}\]

The second pass consists in interpolating across the OFDM symbols:

\[\hat{\mathbf{h}}_m^{(3)} = \mathbf{B}_m \tilde{\mathbf{h}}^{(2)}_m\]

where \(1 \leq m \leq M\) is the sub-carrier index and \(\tilde{\mathbf{h}}^{(2)}_m\) is the \(m^{\text{th}}\) column of

\[\begin{split}\hat{\mathbf{H}}^{(2)} = \begin{bmatrix} {\hat{\mathbf{h}}_1^{(2)}}^\intercal\\ \vdots\\ {\hat{\mathbf{h}}_N^{(2)}}^\intercal \end{bmatrix}\end{split}\]

and \(\mathbf{B}_m\) is the \(N \times N\) interpolation LMMSE matrix:

\[\mathbf{B}_m = \bar{\mathbf{B}}_m \tilde{\mathbf{\Pi}}_m^\intercal\]

where

\[\bar{\mathbf{B}}_m = \underset{\mathbf{Z} \in \mathbb{C}^{N \times L_m}}{\text{argmin}} \left\lVert \mathbf{Z} \left( \tilde{\mathbf{\Pi}}_m^\intercal \mathbf{R^{(t)}}\tilde{\mathbf{\Pi}}_m + \tilde{\mathbf{\Sigma}}^{(2)}_m \right) - \mathbf{R^{(t)}}\tilde{\mathbf{\Pi}}_m \right\rVert_{\text{F}}^2\]

where \(\mathbf{R^{(t)}}\) is the \(N \times N\) channel time covariance matrix, \(\tilde{\mathbf{\Pi}}_m\) the \(N \times L_m\) matrix that spreads \(L_m\) values to a vector of size \(N\) according to the pilot_pattern for the \(m^{\text{th}}\) sub-carrier, and \(\tilde{\mathbf{\Sigma}}^{(2)}_m \in \mathbb{R}^{L_m \times L_m}\) is the diagonal matrix of channel estimation error variances built by gathering the error variances from (\(\mathbf{\Sigma}^{(2)}_1,\dots,\mathbf{\Sigma}^{(2)}_N\)) corresponding to resource elements carried by the \(m^{\text{th}}\) sub-carrier. Computation of \(\bar{\mathbf{B}}_m\) is done using an algorithm based on complete orthogonal decomposition. This is done to avoid matrix inversion for badly conditioned covariance matrices.

The resulting channel estimate for the resource grid is

\[\hat{\mathbf{H}}^{(3)} = \left[ \hat{\mathbf{h}}_1^{(3)} \dots \hat{\mathbf{h}}_M^{(3)} \right]\]

The resulting channel estimation error variances are the diagonal coefficients of the matrices

\[\mathbf{\Sigma}^{(3)}_m = \mathbf{R^{(t)}} - \mathbf{B}_m \tilde{\mathbf{\Xi}}_m \mathbf{R^{(t)}}, 1 \leq m \leq M\]

where \(\tilde{\mathbf{\Xi}}_m\) is the diagonal matrix of size \(N \times N\) that zeros the columns corresponding to OFDM symbols not carrying any pilots.

Remark: The interpolation matrix differs across sub-carriers as different sub-carriers may have different estimation error variances computed by the first pass. However, all sub-carriers carry at least one channel estimate as a result of the first pass, ensuring that a channel estimate is computed for all the resource elements after the second pass.

Remark: LMMSE interpolation requires knowledge of the time and frequency covariance matrices of the channel. The functions tdl_time_cov_mat() and tdl_freq_cov_mat() compute the expected time and frequency covariance matrices, respectively, for the TDL channel models.

Scaling of the estimates is then performed to ensure that their variances match the ones expected by the next smoothing step, and the error variances are updated accordingly:

\[\begin{split}\begin{aligned} \left[\hat{\mathbf{h}}_m^{(4)}\right]_n &= \gamma_{m,n} \left[\hat{\mathbf{h}}_m^{(3)}\right]_n\\ \left[\mathbf{\Sigma}^{(4)}_m\right]_{n,n} &= \gamma_{m,n}\left( \gamma_{m,n}-1 \right) \left[\hat{\mathbf{\Sigma}}^{(3)}_m\right]_{n,n} + \left( 1 - \gamma_{m,n} \right) \left[\mathbf{R^{(t)}}\right]_{n,n} + \gamma_{m,n} \left[\mathbf{\Sigma}^{(3)}_n\right]_{m,m} \end{aligned}\end{split}\]

where:

\[\begin{split}\begin{aligned} \gamma_{m,n} &= \frac{2 \left[\mathbf{R^{(t)}}\right]_{n,n}}{\left[\mathbf{R^{(t)}}\right]_{n,n} - \left[\mathbf{\Sigma}^{(3)}_m\right]_{n,n} + \left[\hat{\mathbf{\Sigma}}^{(3)}_n\right]_{m,m}}\\ \hat{\mathbf{\Sigma}}^{(3)}_m &= \mathbf{B}_m \mathbf{R^{(t)}} \mathbf{B}_m^{\mathrm{H}} \end{aligned}\end{split}\]

Finally, a spatial smoothing step is applied to every resource element carrying a channel estimate. For clarity, we drop the resource element indexing \((n,m)\). We denote by \(L\) the number of receive antennas, and by \(\mathbf{R^{(s)}}\in\mathbb{C}^{L \times L}\) the spatial covariance matrix.

LMMSE spatial smoothing consists in the following computations:

\[\hat{\mathbf{h}}^{(5)} = \mathbf{C} \hat{\mathbf{h}}^{(4)}\]

where

\[\mathbf{C} = \mathbf{R^{(s)}} \left( \mathbf{R^{(s)}} + \mathbf{\Sigma}^{(4)} \right)^{-1}.\]

The estimation error variances are the diagonal coefficients of

\[\mathbf{\Sigma}^{(5)} = \mathbf{R^{(s)}} - \mathbf{C}\mathbf{R^{(s)}}\]

The smoothed channel estimate \(\hat{\mathbf{h}}^{(5)}\) and corresponding error variances \(\text{diag}\left( \mathbf{\Sigma}^{(5)} \right)\) are returned for every resource element \((m,n)\).

Remark: No scaling is performed after the last interpolation or smoothing step.

Remark: All passes assume that the estimation error covariance matrix (\(\mathbf{\Sigma}\), \(\tilde{\mathbf{\Sigma}}^{(2)}\), or \(\tilde{\mathbf{\Sigma}}^{(4)}\)) is diagonal, which may not be accurate. When this assumption does not hold, this interpolator is only an approximation of LMMSE interpolation.

Remark: The order in which frequency interpolation, temporal interpolation, and, optionally, spatial smoothing are applied, is controlled using the order parameter.

Parameters:
  • pilot_pattern – Used pilot pattern

  • cov_mat_time (torch.Tensor) – Time covariance matrix of the channel

  • cov_mat_freq (torch.Tensor) – Frequency covariance matrix of the channel

  • cov_mat_space (torch.Tensor | None) – Spatial covariance matrix of the channel. Only required if spatial smoothing is requested (see order).

  • order (str) – Order in which to perform interpolation and optional smoothing. For example, "t-f-s" means that interpolation across the OFDM symbols is performed first ("t": time), followed by interpolation across the sub-carriers ("f": frequency), and finally smoothing across the receive antennas ("s": space). Similarly, "f-t" means interpolation across the sub-carriers followed by interpolation across the OFDM symbols and no spatial smoothing. The spatial covariance matrix (cov_mat_space) is only required when spatial smoothing is requested. Time and frequency interpolation are not optional to ensure that a channel estimate is computed for all resource elements.

Inputs:
  • h_hat – [batch_size, num_rx, num_rx_ant, num_tx, num_streams_per_tx, num_pilot_symbols], torch.complex. Channel estimates for the pilot-carrying resource elements.

  • err_var – [batch_size, num_rx, num_rx_ant, num_tx, num_streams_per_tx, num_pilot_symbols], torch.float. Channel estimation error variances for the pilot-carrying resource elements.

Outputs:
  • h_hat – [batch_size, num_rx, num_rx_ant, num_tx, num_streams_per_tx, num_ofdm_symbols, fft_size], torch.complex. Channel estimates across the entire resource grid for all transmitters and streams.

  • err_var – Same shape as h_hat, torch.float. Channel estimation error variances across the entire resource grid for all transmitters and streams.

Examples

import torch
from sionna.phy.ofdm import (
    ResourceGrid, LSChannelEstimator, LMMSEInterpolator,
    tdl_freq_cov_mat, tdl_time_cov_mat
)

rg = ResourceGrid(num_ofdm_symbols=14,
                  fft_size=64,
                  subcarrier_spacing=30e3,
                  num_tx=1,
                  num_streams_per_tx=1,
                  pilot_pattern="kronecker",
                  pilot_ofdm_symbol_indices=[2, 11])

# Compute covariance matrices
cov_mat_freq = tdl_freq_cov_mat("A", 30e3, 64, 100e-9)
cov_mat_time = tdl_time_cov_mat("A", 3.0, 3.5e9, 35.7e-6, 14)

# Create LMMSE interpolator
interpolator = LMMSEInterpolator(
    rg.pilot_pattern, cov_mat_time, cov_mat_freq, order="f-t"
)

# Use with LS estimator
estimator = LSChannelEstimator(rg, interpolator=interpolator)