.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/receiver/plot_02_ofdm_channel_estimation.py" .. LINE NUMBERS ARE GIVEN BELOW. .. only:: html .. note:: :class: sphx-glr-download-link-note :ref:`Go to the end ` to download the full example code. .. rst-class:: sphx-glr-example-title .. _sphx_glr_auto_examples_receiver_plot_02_ofdm_channel_estimation.py: OFDM over multipath: channel estimation ======================================= A multipath channel is frequency selective, but OFDM with a cyclic prefix longer than its delay spread sees it as one flat fading coefficient per subcarrier, which a one-tap equaliser removes — provided the receiver knows it. The channel here is the Extended Vehicular A profile of 3GPP TS 36.101 (nine taps, 357 ns RMS delay spread) at a sampling rate of 3.84 MHz, with Clarke/Jakes Doppler (Zheng & Xiao 2003). Pilots on a lattice (one subcarrier in 3, one symbol in 4; Coleri et al. 2002) give least-squares estimates, interpolated across the subcarriers — linearly, or by linear MMSE with the frequency correlation of the channel (van de Beek et al. 1995), the true one or the uniform profile over the cyclic prefix of the robust design (Edfors et al. 1998) — and linearly in time. .. GENERATED FROM PYTHON SOURCE LINES 17-28 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np import comnum from comnum.plot import BACKGROUND, GREY N, K, CP, FS = 256, 200, 16, 3.84e6 ofdm = comnum.Ofdm(N, K, oversampling=1, n_cp=CP) c = comnum.Constellation("qam", 4).normalized() .. GENERATED FROM PYTHON SOURCE LINES 29-31 The channel seen by the grid: the magnitude of H(k, l) for an EVA realisation at a Doppler of 300 Hz over 140 OFDM symbols (about 10 ms). .. GENERATED FROM PYTHON SOURCE LINES 31-56 .. code-block:: Python L = 140 ch = comnum.TdlChannel("eva", FS, doppler_hz=300.0) x = ofdm.modulate(np.ones(K * L)) _, taps = ch.fade(x, comnum.Rng(1)) H = np.stack( [ np.abs(taps.frequency_response(sym * ofdm.block_len, ofdm.bins, N)[:, 0, 0]) for sym in range(L) ] ) fig, ax = plt.subplots(figsize=(7.0, 3.6)) im = ax.imshow( 20 * np.log10(H.T), aspect="auto", origin="lower", cmap="Blues", vmin=-25, vmax=8, extent=(0, L * ofdm.block_len / FS * 1e3, -K / 2 * FS / N / 1e6, K / 2 * FS / N / 1e6), ) ax.set(xlabel="time (ms)", ylabel="frequency (MHz)", title="EVA, 300 Hz Doppler: |H| (dB)") ax.grid(False) fig.colorbar(im, ax=ax) fig.tight_layout() .. image-sg:: /auto_examples/receiver/images/sphx_glr_plot_02_ofdm_channel_estimation_001.png :alt: EVA, 300 Hz Doppler: |H| (dB) :srcset: /auto_examples/receiver/images/sphx_glr_plot_02_ofdm_channel_estimation_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 57-59 Estimation error and bit error rate over static EVA realisations (one per grid of 14 symbols), QPSK. .. GENERATED FROM PYTHON SOURCE LINES 59-125 .. code-block:: Python def link(eb, estimator, frames=150, seed=1): grid = comnum.ResourceGrid(K, 14, pattern="lattice", freq=3, time=4, seed=1) ch = comnum.TdlChannel("eva", FS) err = tot = 0 mse = 0.0 for f in range(frames): rng = comnum.Rng.stream(seed, "ofdm", int(eb * 10), f) bits = comnum.bits(2 * grid.n_data, rng) x = ofdm.modulate(grid.map(c.map_bits(bits))) y, taps = ch.fade(x, rng) s2 = N / (2 * K * comnum.db2lin(eb)) rx = ofdm.demodulate(y + rng.complex_noise(y.size, s2)) h = np.tile(taps.frequency_response(0, ofdm.bins, N)[:, 0, 0], 14) nv = s2 * K / N if estimator == "perfect CSI": hh = h elif estimator == "LMMSE, true profile": hh = comnum.ofdm_estimate( grid, rx, nv, "lmmse", delays=[float(d) for d in taps.delays], powers=ch.powers, n_fft=N, ) elif estimator == "LMMSE, robust": hh = comnum.ofdm_estimate(grid, rx, nv, "lmmse", max_delay=CP, n_fft=N) else: hh = comnum.ofdm_estimate(grid, rx, nv, "linear") mse += np.mean(np.abs(hh - h) ** 2) / frames err += int((c.demap_bits(grid.extract(rx / hh)) != bits).sum()) tot += bits.size return err / tot, mse ebs = np.arange(0.0, 31.0, 5.0) names = ["linear interpolation", "LMMSE, robust", "LMMSE, true profile", "perfect CSI"] res = {n: [link(e, n) for e in ebs] for n in names} fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9.5, 3.9)) for name, marker in zip(names[:3], ["o", "s", "D"], strict=True): ax1.semilogy( ebs, [r[1] for r in res[name]], marker=marker, markeredgecolor=BACKGROUND, label=name ) ax1.set(xlabel="$E_b/N_0$ (dB)", ylabel="MSE of the channel estimate", title="estimation error") ax1.legend() fine = np.linspace(0, 30, 121) ax2.semilogy( fine, comnum.theory_ber_rayleigh_mrc(fine, branches=1), color=GREY, linewidth=1.4, label="Rayleigh, theory", ) for name, marker in zip(names, ["o", "s", "D", "^"], strict=True): ax2.semilogy( ebs, [r[0] for r in res[name]], marker=marker, markeredgecolor=BACKGROUND, label=name ) ax2.set( xlabel="$E_b/N_0$ (dB)", ylabel="bit error rate", title="QPSK OFDM over EVA", ylim=(1e-4, 0.3) ) ax2.legend(fontsize=8) fig.tight_layout() .. image-sg:: /auto_examples/receiver/images/sphx_glr_plot_02_ofdm_channel_estimation_002.png :alt: estimation error, QPSK OFDM over EVA :srcset: /auto_examples/receiver/images/sphx_glr_plot_02_ofdm_channel_estimation_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 126-128 With perfect CSI every subcarrier is a flat Rayleigh channel: the BER is that of BPSK over Rayleigh fading with coherent detection, 0.5 (1 - sqrt(γ/(1 + γ))). .. GENERATED FROM PYTHON SOURCE LINES 128-133 .. code-block:: Python eb = 10.0 print( f"{eb} dB: simulated {res['perfect CSI'][2][0]:.4f}, theory " f"{comnum.theory_ber_rayleigh_mrc(eb, branches=1):.4f}" ) .. rst-class:: sphx-glr-script-out .. code-block:: none 10.0 dB: simulated 0.0209, theory 0.0233 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 7.945 seconds) .. _sphx_glr_download_auto_examples_receiver_plot_02_ofdm_channel_estimation.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_ofdm_channel_estimation.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_ofdm_channel_estimation.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_ofdm_channel_estimation.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_