MIMO Precoding

Precoding: Shaping the Signal Before Transmission

When the transmitter knows the channel (CSI at TX), it can precode the signal to pre-compensate for the channel, simplifying the receiver and improving performance. Precoding moves complexity from RX to TX.

Definition:

SVD-Based Precoding

Using the SVD H=UΞ£VH\mathbf{H} = \mathbf{U}\boldsymbol{\Sigma}\mathbf{V}^H:

TX precoder: W=V\mathbf{W} = \mathbf{V} (right singular vectors) RX combiner: G=UH\mathbf{G} = \mathbf{U}^H (left singular vectors)

The effective channel becomes diagonal: GHW=Ξ£\mathbf{G}\mathbf{H}\mathbf{W} = \boldsymbol{\Sigma}

Each stream sees an independent AWGN channel with gain Οƒk\sigma_k.

def svd_precoding(H):
    U, S, Vh = np.linalg.svd(H, full_matrices=False)
    W = Vh.conj().T  # precoder
    G = U.conj().T   # combiner
    return W, G, S

Definition:

Zero-Forcing Precoding

ZF precoding applies the right pseudoinverse at the transmitter:

WZF=HH(HHH)βˆ’1\mathbf{W}_{\text{ZF}} = \mathbf{H}^H(\mathbf{H}\mathbf{H}^H)^{-1}

with power normalization. The received signal becomes: y=x+n\mathbf{y} = \mathbf{x} + \mathbf{n} (no inter-user interference).

def zf_precoder(H):
    W = H.conj().T @ np.linalg.inv(H @ H.conj().T)
    # Normalize columns to unit power
    W /= np.sqrt(np.sum(np.abs(W)**2, axis=0, keepdims=True))
    return W

ZF precoding requires Ntβ‰₯NrN_t \ge N_r (more TX antennas than streams). It is widely used in multi-user MIMO downlink.

Definition:

Water-Filling Power Allocation

Given SVD channel gains Οƒ1β‰₯Οƒ2β‰₯β‹―\sigma_1 \ge \sigma_2 \ge \cdots, the capacity-maximizing power allocation is:

pk=(ΞΌβˆ’N0Οƒk2)+p_k = \left(\mu - \frac{N_0}{\sigma_k^2}\right)^+

where ΞΌ\mu is chosen so that βˆ‘pk=Ptotal\sum p_k = P_{\text{total}} and (x)+=max⁑(x,0)(x)^+ = \max(x, 0).

def water_filling(channel_gains, total_power, N0):
    gains = np.sort(channel_gains)[::-1]
    N = len(gains)
    for n_active in range(N, 0, -1):
        mu = (total_power + np.sum(N0/gains[:n_active]**2)) / n_active
        powers = mu - N0/gains[:n_active]**2
        if np.all(powers >= 0):
            result = np.zeros(N)
            result[:n_active] = powers
            return result
    return np.zeros(N)

Theorem: SVD Precoding with Water-Filling Achieves MIMO Capacity

The MIMO capacity with perfect CSI at TX and RX is:

C=βˆ‘k=1rlog⁑2 ⁣(1+pkΟƒk2N0)C = \sum_{k=1}^{r} \log_2\!\left(1 + \frac{p_k \sigma_k^2}{N_0}\right)

where r=rank(H)r = \text{rank}(\mathbf{H}), Οƒk\sigma_k are singular values, and pkp_k are water-filling powers. SVD precoding with water-filling achieves this capacity.

SVD decomposes the MIMO channel into rr parallel scalar channels. Water-filling allocates more power to stronger channels, maximizing the total rate.

Theorem: Power Penalty of ZF Precoding

ZF precoding wastes power projecting away from inter-user interference. The effective per-user SNR is:

SNRk=P/NtN0[(HHH)βˆ’1]kk\text{SNR}_k = \frac{P/N_t}{N_0 [(\mathbf{H}\mathbf{H}^H)^{-1}]_{kk}}

This is always less than the no-interference bound PΟƒmax⁑2/(N0Nt)P \sigma_{\max}^2 / (N_0 N_t).

ZF precoding "wastes" some transmit power ensuring zero interference, analogous to ZF detection wasting SNR to suppress noise.

Example: SVD Precoding for 4x4 MIMO

Implement SVD precoding with water-filling for a 4x4 MIMO system and show the resulting parallel channels.

Precoding BER Comparison

Compare BER of SVD precoding, ZF precoding, and no precoding.

Parameters

Common Mistake: Forgetting Power Normalization in Precoding

Mistake:

Using W=V\mathbf{W} = \mathbf{V} without normalizing, so the total transmit power exceeds the power budget.

Correction:

Always normalize: W /= np.sqrt(np.trace(W @ W.conj().T) / Nt). Or use W /= np.linalg.norm(W, 'fro') * sqrt(Nt).

Precoding

Linear transformation applied at the transmitter to shape the signal based on channel knowledge, either diagonalizing the channel (SVD) or nulling inter-user interference (ZF).

Related: Water-Filling

Water-Filling

The optimal power allocation across parallel channels that maximizes total capacity: allocate more power to stronger channels.