.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_tutorials/plot_06_signals.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_tutorials_plot_06_signals.py: Looking at the signals along a chain ==================================== Three ways to see what a block does to the signal. :meth:`comnum.Chain.trace` runs one trial and keeps the frame after every block, for plots and NumPy; ``probe`` blocks measure metrics at a point of the link during a whole campaign; the ``dump`` block saves the samples at a point of the link for the first trials of every condition, as SigMF recordings that any tool reads. A Python block can also keep whatever it wants. The chain is the coherent receiver of ``specs/coherent_link.yaml``. .. GENERATED FROM PYTHON SOURCE LINES 12-27 .. code-block:: Python import tempfile from pathlib import Path import matplotlib.pyplot as plt import numpy as np from _gallery_utils import SPECS import comnum from comnum import blocks as B spec = SPECS / "coherent_link.yaml" link = comnum.Chain.from_spec(spec) condition = {"length_km": 1000, "snr_db": 18} .. GENERATED FROM PYTHON SOURCE LINES 28-32 **Trace.** The frame after every block of one trial: its samples, samples per symbol, and what the source recorded (bits, symbols, constellation). ``Trace.plot`` draws one panel per stage with a function of :mod:`comnum.plot`; the functions take a frame directly and read its sampling rate and constellation. .. GENERATED FROM PYTHON SOURCE LINES 32-39 .. code-block:: Python frames = link.trace(condition, comnum.Rng(1)) for name, f in frames.items(): print(f"{name:>16}: {f.samples.size:>6} samples at {f.sps:g} per symbol") fig = frames.plot("constellation", stages=["cdc", "foe", "bps"], skip=2560, max_points=4000) fig.set_size_inches(10, 3.4) fig.tight_layout() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_06_signals_001.png :alt: cdc, foe, bps :srcset: /auto_tutorials/images/sphx_glr_plot_06_signals_001.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-script-out .. code-block:: none source: 16384 samples at 1 per symbol pulse_shape: 32768 samples at 2 per symbol tx_laser: 32768 samples at 2 per symbol fiber: 32768 samples at 2 per symbol normalize: 32768 samples at 2 per symbol awgn: 32768 samples at 2 per symbol lo_laser: 32768 samples at 2 per symbol cfo: 32768 samples at 2 per symbol cdc: 32768 samples at 2 per symbol matched_filter: 32768 samples at 2 per symbol gardner: 32750 samples at 2 per symbol decimate: 16375 samples at 1 per symbol foe: 16375 samples at 1 per symbol bps: 16375 samples at 1 per symbol frame_sync: 16384 samples at 1 per symbol .. GENERATED FROM PYTHON SOURCE LINES 40-42 The spectrum before and after dispersion compensation, and the eye after the matched filter. .. GENERATED FROM PYTHON SOURCE LINES 42-51 .. code-block:: Python fig, axes = plt.subplots(1, 3, figsize=(11, 3.4)) comnum.plot.psd(frames["awgn"], ax=axes[0]) axes[0].set_title("on the channel") comnum.plot.psd(frames["cdc"], ax=axes[1]) axes[1].set_title("after dispersion compensation") comnum.plot.eye(frames["matched_filter"], ax=axes[2], traces=150, skip=4096) axes[2].set_title("after the matched filter") fig.tight_layout() .. image-sg:: /auto_tutorials/images/sphx_glr_plot_06_signals_002.png :alt: on the channel, after dispersion compensation, after the matched filter :srcset: /auto_tutorials/images/sphx_glr_plot_06_signals_002.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 52-57 **Probes.** During a campaign, a ``probe`` after a block measures metrics there, on every trial, reported as ``.`` with their intervals. The power and the PAPR are measured anywhere; the metrics on decisions (SNR, EVM, error rates) need the samples aligned on the transmitted symbols, here after frame synchronisation. .. GENERATED FROM PYTHON SOURCE LINES 57-74 .. code-block:: Python probed = link.probes( {"awgn": ["power_dbm", "papr_db"], "cdc": ["papr_db"], "frame_sync": ["snr_db", "evm"]}, skip_start=2560, skip_end=256, ) res = probed.run( grid={"length_km": [1000], "snr_db": [14, 18]}, metrics=["ber"], stop={"max_trials": 8} ) for r in res: m = r["metrics"] print( f"SNR {r['condition']['snr_db']} dB: {m['awgn.power_dbm']['value']:.1f} dBm on the channel, " f"PAPR {m['awgn.papr_db']['value']:.1f} dB on the channel and {m['cdc.papr_db']['value']:.1f} dB " f"after dispersion compensation; {m['frame_sync.snr_db']['value']:.1f} dB and " f"EVM {100 * np.sqrt(m['frame_sync.evm']['value']):.1f} % at the decisions" ) .. rst-class:: sphx-glr-script-out .. code-block:: none SNR 14 dB: 30.3 dBm on the channel, PAPR 10.5 dB on the channel and 7.4 dB after dispersion compensation; 13.8 dB and EVM 20.5 % at the decisions SNR 18 dB: 30.1 dBm on the channel, PAPR 10.3 dB on the channel and 6.9 dB after dispersion compensation; 17.3 dB and EVM 13.6 % at the decisions .. GENERATED FROM PYTHON SOURCE LINES 75-80 **Dumps.** A ``dump`` block saves the samples at its position for the first trials of every condition (``trials`` of them), as SigMF recordings ``///