MIMO — Capacity path
1. Intro → 2. Channel model → 3. SISO capacity → 4. Ergodic SISO → 5. MIMO capacity
Tools: Shannon calculator
Introduction
We already met ergodic capacity as an expectation. Now treat it as something you compute: how do you estimate it stably, and is there a closed form to check against? Call this a short lab before MIMO.
Motive
Monte Carlo is easy to get slightly wrong—too few samples, the wrong distribution for \(|h|^2\), or \(\log\) where you meant \(\log_2\). A closed form keeps you honest. Once the scalar case matches, you can use the same Monte Carlo pattern on \(\log\det\) for MIMO.
Technical development
\[C_{\mathrm{erg}}(\rho)=\int_0^\infty \log_2(1+\rho u)\,e^{-u}\,du = \frac{e^{1/\rho}}{\ln 2}\,E_1\!\left(\frac{1}{\rho}\right),\]where \(E_1\) is the exponential integral. The integral is exactly the expectation of \(\log_2(1+\rho|h|^2)\) for unit-mean exponential \(|h|^2\).
How this achieves the motive
Agreement between Monte Carlo and the exponential-integral expression tells you your random-number generation and your units are correct. Disagreement usually means someone used \(\log\) instead of \(\log_2\), or drew complex Gaussians without normalising variance.
Sample simulation
import numpy as np
from scipy.special import expi
def erg_mc(rho, n=100000, rng=None):
rng = rng or np.random.default_rng()
return np.mean(np.log2(1 + rho * rng.exponential(1.0, n)))
def erg_ei(rho):
# exp(1/rho) * E_1(1/rho) / ln(2); E_1(x) = -expi(-x)
return np.exp(1 / rho) * (-expi(-1 / rho)) / np.log(2)
for sdb in (0, 10, 20):
rho = 10 ** (sdb / 10)
print("%2d dB MC=%.4f EI=%.4f" % (sdb, erg_mc(rho), erg_ei(rho)))

Sample results
The printed MC and EI columns should match to about two decimal places with \(10^5\) samples. If they disagree, fix the scalar case before touching MIMO. Figure 1 places those numbers on the full SNR axis.
Next topic
Replace the scalar \(|h|^2\) by the eigenvalues of \(\mathbf{HH}^H\) and the same averaging philosophy yields MIMO ergodic capacity.
References
- A. Goldsmith, Wireless Communications, Cambridge University Press, Cambridge, UK, 2005. Chapter 4.
- M. K. Simon and M.-S. Alouini, Digital Communication over Fading Channels, 2nd ed., John Wiley & Sons, Hoboken, NJ, 2005.
- D. Tse and P. Viswanath, Fundamentals of Wireless Communication, Cambridge University Press, Cambridge, UK, 2005. Chapter 5.
Frequently asked questions
What closed-form expression checks a Rayleigh ergodic-capacity Monte Carlo? For unit-mean exponential \(|h|^2\), \(C_{\mathrm{erg}}(\rho)=e^{1/\rho}E_1(1/\rho)/\ln 2\), where \(E_1\) is the exponential integral. Agreement with Monte Carlo to about two decimals at \(10^5\) samples is a good sanity check before moving to MIMO.
What are common numerical mistakes in ergodic-capacity simulations? Too few channel draws, drawing complex Gaussians without unit variance per dimension, and using natural logarithm where capacity is defined with \(\log_2\). Any of these shifts the curve away from the exponential-integral reference.
Why verify the scalar case before simulating MIMO capacity? MIMO capacity replaces \(|h|^2\) by the eigenvalues of \(\mathbf{HH}^H\) inside a log-determinant, but the Monte Carlo pattern is the same. If the scalar loop is wrong, the matrix loop will be wrong in the same way and harder to debug.
Hi this is nice post. i have small doubt Pl clear it.
As ‘h’ defined as
h= sqrt((randn(1,100).^2 + 1i*randn(1,100).^2 ));
Q(1) It shows channel is flat for 100 bits. Is it mean 100 taps?
and
Q(2) If channel is quasi static then what ‘h’ would be ?
Yes. The channel is assumed to be flat
Even for a quasi-static channel, the channel varies slowly over one block that it can be considered constant. Thus the above code is still valid
The Rayleigh channel should be as
h= sqrt(1/2)*((randn(1,1000) + 1i*randn(1,1000) ));
here N=1000 is not the taps as in case of frequency selective channel.
Its slow varying/quasi-static frequency flat channel with
1000 realizations of the single-tap channel over which the monte-carlo simulation has been performed.
Law of large number relates the time average and statistical average for large N.
Thanks for spotting the mistake in the code. Corrected !!!
Hi, is line 17 correct?
Thanks.
I can’t spot any mistake. Please correct if I am wrong.