.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/communications/fading/plot_02_diversity_combining.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 or to run this example in your browser via JupyterLite. .. rst-class:: sphx-glr-example-title .. _sphx_glr_api_gallery_communications_fading_plot_02_diversity_combining.py: Kahn and Brennan's diversity combining (1954-1959) ================================================== Two antennas a few wavelengths apart rarely fade at the same moment. Short-wave receivers had long switched to whichever antenna was strongest (*selection*, :func:`~engineeringkit.communications.selection_outage_probability`). Leonard Kahn's 1954 "ratio squarer" instead weighted each branch by its own signal strength before adding them. With complex weights equal to the conjugate channel gains this is *maximal-ratio combining* (:func:`~engineeringkit.communications.maximal_ratio_combine`), whose output SNR is the sum of the branch SNRs. D. G. Brennan's 1959 review compared selection, equal-gain and maximal-ratio combining and showed how close they come to one another. With :math:`L` independent branches the error rate falls as :math:`\bar\gamma^{-L}` (:func:`~engineeringkit.communications.ber_bpsk_mrc_rayleigh`). .. GENERATED FROM PYTHON SOURCE LINES 20-25 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from engineeringkit.communications import ber_bpsk_mrc_rayleigh, bpsk, from_db, maximal_ratio_combine, selection_outage_probability .. GENERATED FROM PYTHON SOURCE LINES 26-28 Maximal-ratio combining by simulation ------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 28-54 .. code-block:: Python rng = np.random.default_rng(1954) ebn0_db = np.arange(0, 25, 3.0) n = 200_000 bits = rng.integers(0, 2, n) fig, axes = plt.subplots(1, 2, figsize=(11, 3.8)) fine = np.linspace(0, 25, 251) for L in (1, 2, 4): measured = [] for g in from_db(ebn0_db): h = (rng.standard_normal((L, n)) + 1j * rng.standard_normal((L, n))) / np.sqrt(2) y = h * bpsk(bits) + (rng.standard_normal((L, n)) + 1j * rng.standard_normal((L, n))) * np.sqrt(1 / (2 * g)) measured.append(np.mean((np.real(maximal_ratio_combine(y, h)) > 0) != bits)) measured = np.array(measured) theory = ber_bpsk_mrc_rayleigh(from_db(ebn0_db), L) reliable = theory > 1e-4 assert np.allclose(measured[reliable], theory[reliable], rtol=0.15) axes[0].semilogy(fine, ber_bpsk_mrc_rayleigh(from_db(fine), L), label=f"L = {L}") axes[0].semilogy(ebn0_db[measured > 0], measured[measured > 0], "k.") slope = np.log10(ber_bpsk_mrc_rayleigh(1e2, L) / ber_bpsk_mrc_rayleigh(1e3, L)) print(f"L = {L}: BER at 10 dB = {ber_bpsk_mrc_rayleigh(10.0, L):.2e}, decades per decade of SNR = {slope:.2f}") assert abs(slope - L) < 0.1 axes[0].set(xlabel=r"mean $E_b/N_0$ per branch [dB]", ylabel="bit-error rate", ylim=(1e-6, 0.5), title="Maximal-ratio combining") axes[0].grid(True, which="both", alpha=0.3) axes[0].legend() .. image-sg:: /api/gallery/communications/fading/images/sphx_glr_plot_02_diversity_combining_001.png :alt: Maximal-ratio combining :srcset: /api/gallery/communications/fading/images/sphx_glr_plot_02_diversity_combining_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none L = 1: BER at 10 dB = 2.33e-02, decades per decade of SNR = 1.00 L = 2: BER at 10 dB = 1.60e-03, decades per decade of SNR = 1.99 L = 4: BER at 10 dB = 9.70e-06, decades per decade of SNR = 3.99 .. GENERATED FROM PYTHON SOURCE LINES 55-57 Selection diversity and outage ------------------------------ .. GENERATED FROM PYTHON SOURCE LINES 57-71 .. code-block:: Python threshold = from_db(np.linspace(-30, 10, 201)) for L in (1, 2, 4): axes[1].semilogy(10 * np.log10(threshold), selection_outage_probability(threshold, 1.0, L), label=f"L = {L}") gains = np.abs((rng.standard_normal((2, n)) + 1j * rng.standard_normal((2, n))) / np.sqrt(2)) ** 2 measured_outage = np.mean(np.max(gains, axis=0) < 0.1) print(f"two-branch selection, 10 dB below the mean: outage {measured_outage:.4f}, theory {selection_outage_probability(0.1, 1.0, 2):.4f}") assert abs(measured_outage - selection_outage_probability(0.1, 1.0, 2)) < 0.002 axes[1].set(xlabel="threshold relative to mean SNR [dB]", ylabel="outage probability", title="Selection combining", ylim=(1e-6, 1)) axes[1].grid(True, which="both", alpha=0.3) axes[1].legend() fig.tight_layout() plt.show() .. rst-class:: sphx-glr-script-out .. code-block:: none two-branch selection, 10 dB below the mean: outage 0.0090, theory 0.0091 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 1.000 seconds) .. _sphx_glr_download_api_gallery_communications_fading_plot_02_diversity_combining.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: lite-badge .. image:: images/jupyterlite_badge_logo.svg :target: ../../../../lite/lab/index.html?path=api/gallery/communications/fading/plot_02_diversity_combining.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_02_diversity_combining.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_diversity_combining.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_diversity_combining.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_