.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/receiver/plot_03_sync_mimo_ofdm.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_03_sync_mimo_ofdm.py: OFDM synchronisation and MIMO-OFDM ================================== **Timing and frequency.** The preamble of Schmidl & Cox (*IEEE Trans. Commun.* 45(12), 1997) has two identical halves: their correlation peaks — on a plateau as long as the cyclic prefix — at the start of the symbol, and its phase gives the carrier frequency offset, here in units of the subcarrier spacing. The error variance of the offset falls as :math:`1/\mathrm{SNR}`. **MIMO-OFDM.** With two transmit and two receive antennas over the EPA profile, every subcarrier carries a flat 2 × 2 MIMO channel; the detectors of the MIMO module run subcarrier by subcarrier (Stüber et al., *Proc. IEEE* 92(2), 2004). ML (here the sphere decoder) collects the receive diversity that the linear detectors lose. .. GENERATED FROM PYTHON SOURCE LINES 16-73 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from _gallery_utils import mimo_ofdm_ser import comnum from comnum.plot import AMBER, BACKGROUND, GREY ofdm = comnum.Ofdm(128, 100, n_cp=16) c = comnum.Constellation("qam", 4).normalized() pre = comnum.ofdm_preamble(ofdm, seed=3) rng = comnum.Rng(1) data = ofdm.modulate(c.symbols(rng.integers(4, 2 * 100))) r = np.concatenate([np.zeros(300), pre, data]) r = r + rng.complex_noise(r.size, 0.1) metric = comnum.schmidl_cox(r, ofdm.fft_len // 2) fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(9.5, 3.8)) ax1.plot(metric, linewidth=1.4) ax1.axvspan(300, 300 + 4 * 16, color=AMBER, alpha=0.25, label="cyclic prefix") ax1.set(xlabel="sample", ylabel="M(d)", title="Schmidl & Cox timing metric, 10 dB", xlim=(0, 1100)) ax1.legend() def cfo_rmse(snr_db, trials=200): s2 = comnum.db2lin(-snr_db) err = [] for t in range(trials): g = comnum.Rng.stream(2, "cfo", int(snr_db + 100), t) eps = g.uniform(1)[0] - 0.5 d = ofdm.modulate(c.symbols(g.integers(4, 100))) x = np.concatenate([np.zeros(150), pre, d]) x = (x + g.complex_noise(x.size, s2)) * np.exp( 2j * np.pi * eps * np.arange(x.size) / ofdm.fft_len ) err.append(comnum.ofdm_synchronize(x, ofdm)["cfo"] - eps) return np.sqrt(np.mean(np.square(err))) snrs = np.arange(-5.0, 26.0, 5.0) ax2.semilogy( snrs, [cfo_rmse(s) for s in snrs], marker="o", markeredgecolor=BACKGROUND, label="simulated" ) ax2.semilogy( snrs, cfo_rmse(10.0) * 10 ** (-(snrs - 10) / 20), color=GREY, linestyle=":", linewidth=1.2, label=r"$\propto 1/\sqrt{\mathrm{SNR}}$", ) ax2.set( xlabel="SNR (dB)", ylabel="RMS error (subcarrier spacings)", title="frequency offset estimate" ) ax2.legend() fig.tight_layout() .. image-sg:: /auto_examples/receiver/images/sphx_glr_plot_03_sync_mimo_ofdm_001.png :alt: Schmidl & Cox timing metric, 10 dB, frequency offset estimate :srcset: /auto_examples/receiver/images/sphx_glr_plot_03_sync_mimo_ofdm_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 74-75 2 × 2 MIMO-OFDM over EPA (1.92 MHz, 96 of 128 subcarriers), perfect CSI. .. GENERATED FROM PYTHON SOURCE LINES 75-102 .. code-block:: Python mofdm = comnum.Ofdm(128, 96, oversampling=1, n_cp=16) ch = comnum.TdlChannel("epa", 1.92e6, n_rx=2, n_tx=2) def ser(snr_db, method, frames=150): """Four OFDM symbols per frame, one channel per frame, per-subcarrier detection (shared with the test that checks these curves).""" return mimo_ofdm_ser(mofdm, ch, c, snr_db, method, frames, seed=3, condition=int(snr_db)) fig, ax = plt.subplots() snr = np.arange(0.0, 31.0, 5.0) for (name, m), marker in zip( {"ZF": "zf", "MMSE": "mmse", "MMSE-SIC": "mmse_sic", "ML (sphere)": "sphere"}.items(), ["o", "s", "D", "^"], strict=True, ): v = np.array([ser(s, m) for s in snr]) keep = v > 0 ax.semilogy(snr[keep], v[keep], marker=marker, markeredgecolor=BACKGROUND, label=name) ax.set( xlabel=r"$E_s/N_0$ per receive antenna (dB)", ylabel="symbol error rate", title="2 × 2 MIMO-OFDM, QPSK, EPA", ) ax.legend() fig.tight_layout() .. image-sg:: /auto_examples/receiver/images/sphx_glr_plot_03_sync_mimo_ofdm_002.png :alt: 2 × 2 MIMO-OFDM, QPSK, EPA :srcset: /auto_examples/receiver/images/sphx_glr_plot_03_sync_mimo_ofdm_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.253 seconds) .. _sphx_glr_download_auto_examples_receiver_plot_03_sync_mimo_ofdm.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_03_sync_mimo_ofdm.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_03_sync_mimo_ofdm.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_03_sync_mimo_ofdm.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_