16-QAM constellation diagram with AWGN noise
Digital Comms
Example from the compendium of canonical charts
Python Code
"""Digital Comms — 16-QAM constellation diagram with AWGN noise."""
import numpy as np
import plotly.graph_objects as go
def generate():
RNG = np.random.default_rng(42)
# ── 16-QAM ideal constellation points ────────────────────────────────────────
# Gray-coded 16-QAM: I,Q ∈ {-3,-1,+1,+3}/sqrt(10)
levels = np.array([-3, -1, 1, 3]) / np.sqrt(10)
I_ideal, Q_ideal = np.meshgrid(levels, levels)
I_ideal = I_ideal.ravel()
Q_ideal = Q_ideal.ravel()
# ── Generate ~2000 random symbols with AWGN ───────────────────────────────────
N = 2000
idx = RNG.integers(0, 16, size=N)
I_tx = I_ideal[idx]
Q_tx = Q_ideal[idx]
# AWGN: Es=1, SNR_dB=15
SNR_dB = 15
Es = 1.0
sigma = np.sqrt(Es / (2 * 10 ** (SNR_dB / 10))) # per-dimension std
I_noisy = I_tx + RNG.normal(0, sigma, N)
Q_noisy = Q_tx + RNG.normal(0, sigma, N)
# ── Build figure ──────────────────────────────────────────────────────────────
fig = go.Figure()
fig.add_trace(go.Scattergl(
x=I_noisy,
y=Q_noisy,
mode="markers",
marker=dict(size=4, opacity=0.45, color=VIOLET),
name="Received symbols",
))
fig.add_trace(go.Scatter(
x=I_ideal,
y=Q_ideal,
mode="markers",
marker=dict(size=12, symbol="x", color="#e03030", line=dict(width=2)),
name="Ideal points",
))
fig.update_layout(
xaxis=dict(
title="In-phase (I)",
scaleanchor="y",
scaleratio=1,
constrain="domain",
zeroline=True,
zerolinecolor="#cccccc",
range=[-1.1, 1.1],
),
yaxis=dict(
title="Quadrature (Q)",
zeroline=True,
zerolinecolor="#cccccc",
range=[-1.1, 1.1],
),
legend=dict(x=0.01, y=0.99),
)
return fig
if __name__ == "__main__":
generate()
Made with Plotly