.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/foundations/plot_02_ber_qam_awgn.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_foundations_plot_02_ber_qam_awgn.py: Bit error rate of M-QAM over AWGN ================================= The waterfall curves of Gray-mapped 4-, 16- and 64-QAM over the additive white Gaussian noise channel, against the closed form .. math:: P_b \approx \frac{4}{\log_2 M}\left(1 - \frac{1}{\sqrt{M}}\right) Q\left(\sqrt{\frac{3 \log_2 M}{M - 1}\frac{E_b}{N_0}}\right) (Proakis & Salehi, *Digital Communications*, Sec. 4.3). The campaign is a declarative specification run on every core by the Rust runner: each point stops after 200 bit errors, and the sweep of a constellation stops once its BER falls below :math:`10^{-6}`. The error bars are the 95 % Wilson intervals. .. GENERATED FROM PYTHON SOURCE LINES 18-42 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np import comnum from comnum.plot import BACKGROUND, MUTED results = comnum.run_spec( """ name: qam_awgn seed: 2024 grid: m: [4, 16, 64] ebn0_db: {from: 0, to: 20, step: 1} link: - {type: source, constellation: {kind: qam, m: $m}, n_symbols: 8192} - {type: awgn_ebn0, ebn0_db: $ebn0_db} metrics: {report: [ber]} stop: {min_errors: {ber: 200}, min_trials: 8, max_trials: 4000} callbacks: skip_below: {metric: ber, threshold: 1e-6, along: ebn0_db} """ ) .. GENERATED FROM PYTHON SOURCE LINES 43-44 Simulated points with their intervals, and the closed form. .. GENERATED FROM PYTHON SOURCE LINES 44-72 .. code-block:: Python fig, ax = plt.subplots() eb = np.linspace(0, 20, 201) for m in [4, 16, 64]: # the conditions skipped below 1e-6 have no metric: series leaves them out x, ber, lo, hi = results.series("ebn0_db", "ber", interval=True, m=m) keep = ber > 0 (line,) = ax.semilogy(eb, comnum.theory_ber(m, eb, "qam"), linewidth=1.4) ax.errorbar( x[keep], ber[keep], yerr=[ber[keep] - lo[keep], hi[keep] - ber[keep]], fmt="o", color=line.get_color(), markeredgecolor=BACKGROUND, capsize=0, label=f"{m}-QAM", ) ax.plot([], [], color=MUTED, linewidth=1.4, label="theory") ax.set( ylim=(1e-6, 0.5), xlim=(0, 20), xlabel="$E_b/N_0$ (dB)", ylabel="bit error rate", title="Gray-mapped QAM over AWGN", ) ax.legend() fig.tight_layout() .. image-sg:: /auto_examples/foundations/images/sphx_glr_plot_02_ber_qam_awgn_001.png :alt: Gray-mapped QAM over AWGN :srcset: /auto_examples/foundations/images/sphx_glr_plot_02_ber_qam_awgn_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 73-75 The Eb/N0 needed for a BER of 1e-5 grows by 3.8 dB from QPSK to 16-QAM, and by 4.4 dB more to 64-QAM: the price of two more bits per symbol. .. GENERATED FROM PYTHON SOURCE LINES 75-81 .. code-block:: Python for m in [4, 16, 64]: lo, hi = 0.0, 30.0 for _ in range(60): mid = (lo + hi) / 2 lo, hi = (mid, hi) if comnum.theory_ber(m, mid, "qam") > 1e-5 else (lo, mid) print(f"{m:>2}-QAM: Eb/N0 = {lo:.2f} dB at a BER of 1e-5") .. rst-class:: sphx-glr-script-out .. code-block:: none 4-QAM: Eb/N0 = 9.59 dB at a BER of 1e-5 16-QAM: Eb/N0 = 13.43 dB at a BER of 1e-5 64-QAM: Eb/N0 = 17.79 dB at a BER of 1e-5 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 2.871 seconds) .. _sphx_glr_download_auto_examples_foundations_plot_02_ber_qam_awgn.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_ber_qam_awgn.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_02_ber_qam_awgn.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_02_ber_qam_awgn.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_