.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "api/gallery/communications/information/plot_05_nyquist_raised_cosine.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_information_plot_05_nyquist_raised_cosine.py: Nyquist's ISI criterion: raised-cosine pulses (1928) ==================================================== The same 1928 paper that set the limit of :math:`2B` pulses per second also said which pulse shapes reach it without intersymbol interference: those whose spectrum, copied at every multiple of the symbol rate, adds up to a constant. The ideal sinc pulse meets the criterion with the least bandwidth but decays as :math:`1/t`, so any timing error lets many neighbours leak in. The raised-cosine family (:func:`~engineeringkit.communications.raised_cosine_pulse`, :func:`~engineeringkit.communications.raised_cosine_spectrum`) spends an excess bandwidth :math:`\alpha/2T` on a cosine roll-off that keeps the criterion and makes the tails fall as :math:`1/t^3`. Split into two root-raised-cosine filters (:func:`~engineeringkit.communications.root_raised_cosine_pulse`), one at each end of the link, it also gives the receiver a matched filter. .. GENERATED FROM PYTHON SOURCE LINES 19-31 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from engineeringkit.communications import ( bpsk, raised_cosine_bandwidth, raised_cosine_pulse, raised_cosine_spectrum, root_raised_cosine_pulse, ) from engineeringkit.communications.visualizers import plot_eye_diagram .. GENERATED FROM PYTHON SOURCE LINES 32-34 Zero crossings at every other symbol, and the folded spectrum -------------------------------------------------------------- .. GENERATED FROM PYTHON SOURCE LINES 34-52 .. code-block:: Python T = 1.0 t = np.linspace(-6, 6, 2401) f = np.linspace(-1.2, 1.2, 1201) fig, axes = plt.subplots(1, 3, figsize=(13, 3.8)) for a in (0.0, 0.35, 1.0): axes[0].plot(t, raised_cosine_pulse(t, T, a), label=rf"$\alpha$ = {a}") axes[1].plot(f, raised_cosine_spectrum(f, T, a)) k = np.arange(-6, 7) assert np.allclose(raised_cosine_pulse(k * T, T, a), k == 0, atol=1e-12) folded = sum(raised_cosine_spectrum(f + n / T, T, a) for n in range(-3, 4)) assert np.allclose(folded[np.abs(np.abs(f) - 0.5) > 1e-9], T) print(f"alpha = {a}: bandwidth at 2400 baud = {float(raised_cosine_bandwidth(2400, a)):.0f} Hz") axes[0].plot(np.arange(-6, 7), np.zeros(13), "k.", ms=4) axes[0].set(xlabel="t / T", ylabel="p(t)", title="Raised-cosine pulses") axes[0].legend() axes[1].set(xlabel="f T", ylabel="P(f) / T", title="Spectra") .. image-sg:: /api/gallery/communications/information/images/sphx_glr_plot_05_nyquist_raised_cosine_001.png :alt: Raised-cosine pulses, Spectra :srcset: /api/gallery/communications/information/images/sphx_glr_plot_05_nyquist_raised_cosine_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none alpha = 0.0: bandwidth at 2400 baud = 1200 Hz alpha = 0.35: bandwidth at 2400 baud = 1620 Hz alpha = 1.0: bandwidth at 2400 baud = 2400 Hz [Text(0.5, 12.633333333333331, 'f T'), Text(480.8104575163399, 0.5, 'P(f) / T'), Text(0.5, 1.0, 'Spectra')] .. GENERATED FROM PYTHON SOURCE LINES 53-60 Eye diagrams through a root-raised-cosine pair ---------------------------------------------- Transmit and receive filters are root raised cosines, so the end-to-end pulse is a raised cosine and the eye closes to two points at the sampling instant, however small the roll-off. The small residue left is the cost of truncating each filter to eight symbols either side. .. GENERATED FROM PYTHON SOURCE LINES 60-78 .. code-block:: Python rng = np.random.default_rng(1928) sps, span = 16, 8 taps = root_raised_cosine_pulse(np.arange(-span * sps, span * sps + 1) / sps, T, 0.35) / np.sqrt(sps) symbols = bpsk(rng.integers(0, 2, 400)) upsampled = np.zeros(symbols.size * sps) upsampled[::sps] = symbols received = np.convolve(np.convolve(upsampled, taps), taps) delay = 2 * span * sps plot_eye_diagram(received, sps, ax=axes[2], offset=delay + sps // 2 + sps * 10) samples = received[delay : delay + symbols.size * sps : sps] isi = np.max(np.abs(samples[10:-10] - symbols[10:-10])) print(f"worst intersymbol interference at the sampling instants: {isi:.1e}") assert isi < 1e-2 axes[2].set(title=r"Eye after RRC $\times$ RRC, $\alpha$ = 0.35") fig.tight_layout() plt.show() .. rst-class:: sphx-glr-script-out .. code-block:: none worst intersymbol interference at the sampling instants: 7.1e-03 .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 0.197 seconds) .. _sphx_glr_download_api_gallery_communications_information_plot_05_nyquist_raised_cosine.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/information/plot_05_nyquist_raised_cosine.ipynb :alt: Launch JupyterLite :width: 150 px .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_05_nyquist_raised_cosine.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_05_nyquist_raised_cosine.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_05_nyquist_raised_cosine.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_