.. DO NOT EDIT. .. THIS FILE WAS AUTOMATICALLY GENERATED BY SPHINX-GALLERY. .. TO MAKE CHANGES, EDIT THE SOURCE PYTHON FILE: .. "auto_examples/simulation/plot_01_chains.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_simulation_plot_01_chains.py: A coherent receiver as a chain of blocks ======================================== The declarative link ``specs/coherent_link.yaml`` — 16-QAM at 32 GBd over standard fibre, with laser phase noise, a detuned local oscillator, and the standard receiver DSP (dispersion compensation, matched filter, Gardner clock recovery, fourth-power frequency estimation, blind phase search, frame synchronisation) — read as a :class:`comnum.Chain`. **Trace.** ``Chain.trace`` returns the frame after every block: the constellation spins under the frequency offset, is stopped by the frequency estimator (Leven et al. 2007) and its residual phase noise removed by blind phase search (Pfau, Hoffmann & Noé 2009). **Variants.** ``Chain.replace`` changes a block by name. Raising the linewidth of both lasers from 100 kHz to 1 MHz leaves blind phase search with a larger linewidth-symbol duration product, :math:`\Delta\nu T = 3 \cdot 10^{-5}` per laser instead of :math:`3 \cdot 10^{-6}`, and a larger penalty with respect to 16-QAM over AWGN at the same SNR. Both campaigns run on the parallel Rust runner. .. GENERATED FROM PYTHON SOURCE LINES 22-35 .. code-block:: Python import matplotlib.pyplot as plt import numpy as np from _gallery_utils import SPECS import comnum from comnum import blocks as B from comnum.plot import BACKGROUND, BLUE, GREY spec = SPECS / "coherent_link.yaml" link = comnum.Chain.from_spec(spec) print(link) .. rst-class:: sphx-glr-script-out .. code-block:: none Chain( source=Source(constellation='16-QAM', n_symbols=16384, symbol_rate=32000000000.0), pulse_shape=PulseShape(sps=2, rolloff=0.2), tx_laser=PhaseNoise(linewidth_hz=100000.0), fiber=Fiber(length_km=var('length_km')), normalize=Normalize(), awgn=Awgn(snr_db=var('snr_db')), lo_laser=PhaseNoise(linewidth_hz=100000.0), cfo=Cfo(offset_hz=-500000000.0), cdc=Cdc(length_km=var('length_km')), matched_filter=MatchedFilter(rolloff=0.2), gardner=Gardner(kp=0.003, ki=1e-05), decimate=Decimate(), foe=Foe(refined=True), bps=Bps(n=32, b=32), frame_sync=FrameSync(start=2048, length=512, max_delay=64) ) .. GENERATED FROM PYTHON SOURCE LINES 36-37 The constellation after the main stages of the receiver. .. GENERATED FROM PYTHON SOURCE LINES 37-52 .. code-block:: Python frames = link.trace({"length_km": 80, "snr_db": 20}, comnum.Rng(3)) stages = { "decimate": "after clock recovery", "foe": "after frequency estimation", "bps": "after blind phase search", } fig, axes = plt.subplots(1, 3, figsize=(9, 3.2), sharex=True, sharey=True) for ax, (name, title) in zip(axes, stages.items(), strict=True): y = frames[name].samples[2560:-256] ax.plot(y.real, y.imag, ".", markersize=1.0, alpha=0.3, color=BLUE) ax.set(title=title, aspect="equal", xlim=(-1.6, 1.6), ylim=(-1.6, 1.6)) ax.set_xlabel("in phase") axes[0].set_ylabel("quadrature") fig.tight_layout() .. image-sg:: /auto_examples/simulation/images/sphx_glr_plot_01_chains_001.png :alt: after clock recovery, after frequency estimation, after blind phase search :srcset: /auto_examples/simulation/images/sphx_glr_plot_01_chains_001.png :class: sphx-glr-single-img .. GENERATED FROM PYTHON SOURCE LINES 53-54 Bit error rate against the SNR, for two laser linewidths. .. GENERATED FROM PYTHON SOURCE LINES 54-87 .. code-block:: Python snr = np.arange(12.0, 22.1, 2.0) campaign = { "grid": {"length_km": [80], "snr_db": list(snr)}, "stop": {"min_errors": {"ber": 200}, "min_trials": 8, "max_trials": 256}, } variants = { "Δν = 100 kHz": link, "Δν = 1 MHz": link.replace( tx_laser=B.PhaseNoise(linewidth_hz=1e6), lo_laser=B.PhaseNoise(linewidth_hz=1e6) ), } fig, ax = plt.subplots() s = np.linspace(10, 24, 141) ax.semilogy( s, comnum.theory_ber(16, s - comnum.lin2db(4), "qam"), color=GREY, linewidth=1.4, label="16-QAM over AWGN", ) for (name, chain), marker in zip(variants.items(), ["o", "s"], strict=True): res = chain.run(**campaign) _, ber = res.series("snr_db", "ber") keep = ber > 0 ax.semilogy(snr[keep], ber[keep], marker=marker, markeredgecolor=BACKGROUND, label=name) ax.set( xlabel="SNR (dB)", ylabel="bit error rate", ylim=(1e-6, 0.1), title="Coherent 16-QAM receiver, 80 km", ) ax.legend(loc="lower left") fig.tight_layout() .. image-sg:: /auto_examples/simulation/images/sphx_glr_plot_01_chains_002.png :alt: Coherent 16-QAM receiver, 80 km :srcset: /auto_examples/simulation/images/sphx_glr_plot_01_chains_002.png :class: sphx-glr-single-img .. rst-class:: sphx-glr-timing **Total running time of the script:** (0 minutes 4.834 seconds) .. _sphx_glr_download_auto_examples_simulation_plot_01_chains.py: .. only:: html .. container:: sphx-glr-footer sphx-glr-footer-example .. container:: sphx-glr-download sphx-glr-download-jupyter :download:`Download Jupyter notebook: plot_01_chains.ipynb ` .. container:: sphx-glr-download sphx-glr-download-python :download:`Download Python source code: plot_01_chains.py ` .. container:: sphx-glr-download sphx-glr-download-zip :download:`Download zipped: plot_01_chains.zip ` .. only:: html .. rst-class:: sphx-glr-signature `Gallery generated by Sphinx-Gallery `_