Files
uwca-semantic-mac/experiments/make_figures.py
T

159 lines
6.4 KiB
Python
Executable File

"""Regenerate the figure PDFs from data/*.json into ../fig/.
Uniform geometry: 8:6 axes box, shared rcParams, no tight bounding box.
"""
import json
from pathlib import Path
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
HERE = Path(__file__).resolve().parent
DATA = HERE / "data"
FIG = HERE.parent / "fig"
FIG.mkdir(exist_ok=True)
plt.rcParams.update({
"font.size": 9, "axes.labelsize": 10, "axes.titlesize": 10,
"legend.fontsize": 7.5, "xtick.labelsize": 8.5, "ytick.labelsize": 8.5,
"lines.linewidth": 1.4, "lines.markersize": 4.5,
"figure.dpi": 200, "savefig.dpi": 300,
"grid.alpha": 0.35, "axes.grid": True,
})
AXRECT = [0.17, 0.165, 0.79, 0.80] # single panel 8:6-ish
FSIZE = (3.5, 2.75)
def newfig():
f = plt.figure(figsize=FSIZE)
ax = f.add_axes(AXRECT)
return f, ax
def save(f, name, axes=None):
f.canvas.draw()
if axes:
for ax in axes:
for lbl in [ax.xaxis.label, ax.yaxis.label]:
bb = lbl.get_window_extent()
fw, fh = f.canvas.get_width_height()
assert bb.x0 >= -1 and bb.y0 >= -1 and bb.x1 <= fw + 1 \
and bb.y1 <= fh + 1, f"label clipped in {name}"
f.savefig(FIG / name)
plt.close(f)
print("saved", FIG / name)
C = {"ofdma": "#546E7A", "blind": "#8D6E63", "noma": "#E65100",
"uwca": "#1565C0", "genie": "#2E7D32", "extra": "#C62828",
"aux": "#6A1B9A"}
# ---------------------------------------------------------------- fig_fair --
# axes box kept at 2.59 x 2.12 in; panel tags "(a)"/"(b)" BELOW the panels
d = json.load(open(DATA / "e1_fair_baselines.json"))
snr = d["snr"]
FH = 3.10 # taller canvas for below-axis tags
AXH = 2.12 / FH
AXB = 0.86 / FH
f = plt.figure(figsize=(7.1, FH))
axs = [f.add_axes([0.115, AXB, 0.365, AXH]),
f.add_axes([0.615, AXB, 0.365, AXH])]
for ax, sc, ttl in zip(axs, ["HIGH", "MIX"], ["(a) HIGH", "(b) MIX"]):
v = d["scenarios"][sc]
ax.semilogy(snr, v["ofdma"]["ser"], "s--", color=C["ofdma"], label="OFDMA")
ax.semilogy(snr, v["lmmse_blind"]["ser"], "v-", color=C["blind"],
markevery=(1, 2), label="LMMSE-blind")
ax.semilogy(snr, v["noma"]["ser"], "^-.", color=C["noma"], label="NOMA-SIC")
ax.semilogy(snr, v["uwca"]["ser"], "o-", color=C["uwca"], label="UWCA (prop.)")
ax.semilogy(snr, v["lmmse_genie"]["ser"], "d:", color=C["genie"],
label="LMMSE-genie")
ax.set_xlabel("SNR (dB)")
ax.set_ylabel("SER")
ax.set_xlim(0, 20)
ax.text(0.5, -0.31, ttl, transform=ax.transAxes,
ha="center", va="top", fontsize=10)
axs[1].legend(loc="lower left", framealpha=0.9, fontsize=7)
save(f, "fig_fair.pdf", axs)
# -------------------------------------------------------------- fig_resorth --
d = json.load(open(DATA / "e6_residual_orth.json"))
snr = d["snr"]
f, ax = newfig()
ax.plot(snr, d["uwca"]["rho_input"], "k--", label=r"input $\rho(\mathbf{e}_u,\mathbf{e}_v)$")
ax.plot(snr, d["uwca"]["rho_decoded"], "o-", color=C["uwca"],
label=r"UWCA decoded $\rho(\hat{\mathbf{e}}_u,\hat{\mathbf{e}}_v)$")
ax.plot(snr, d["uwca"]["rho_residual"], "s-", color=C["extra"],
label=r"UWCA residual $\rho(\mathbf{r}_u,\mathbf{r}_v)$")
ax.plot(snr, d["ofdma"]["rho_decoded"], "^:", color=C["ofdma"],
label=r"OFDMA decoded")
ax.set_xlabel("SNR (dB)")
ax.set_ylabel("Pearson correlation")
ax.set_xlim(0, 20)
ax.set_ylim(-0.05, 0.62)
ax.legend(loc="upper right", framealpha=0.9, fontsize=6.8)
save(f, "fig_resorth.pdf", [ax])
# --------------------------------------------------------------- fig_phase2 --
d = json.load(open(DATA / "e2_phase_iui.json"))
sg = d["sigma_phi_deg"]
f, ax = newfig()
sty = {"complexI_zerotrain": ("o-", C["uwca"], "mismatch-trained"),
"complexI_augtrain": ("s--", C["genie"], "phase-augmented"),
"complexIQ_iqtrain": ("^:", C["extra"], "two-rail (I/Q)")}
for key, (mk, col, lab) in sty.items():
ax.plot(sg, d["curves"][key]["10.0"]["ser"], mk, color=col, label=lab)
for key, (mk, col, lab) in sty.items():
ax.plot(sg, d["curves"][key]["20.0"]["ser"], mk, color=col, alpha=0.45,
label="_nolegend_")
ax.annotate("10 dB", xy=(1.5, 0.29), fontsize=8)
ax.annotate("20 dB", xy=(1.5, 0.135), fontsize=8)
ax.set_xlabel(r"phase residual $\sigma_\varphi$ (deg)")
ax.set_ylabel("SER")
ax.set_ylim(0.0, 0.45)
ax.legend(loc="upper left", framealpha=0.9, fontsize=7)
save(f, "fig_phase2.pdf", [ax])
# ---------------------------------------------------------------- fig_async --
d = json.load(open(DATA / "e4_async.json"))
dm = d["dmax"]
f, ax = newfig()
cur = d["curves"]
ax.plot(dm, [a[0] for a in cur["uwca_uncorrected"]["10.0"]], "o--",
color=C["uwca"], alpha=0.5, label="UWCA, uncorrected")
ax.plot(dm, [a[0] for a in cur["ofdma_uncorrected"]["10.0"]], "s--",
color=C["ofdma"], alpha=0.5, label="OFDMA, uncorrected")
ax.plot(dm, [a[0] for a in cur["uwca_corrected"]["10.0"]], "o-",
color=C["uwca"], label="UWCA, realigned")
ax.plot(dm, [a[0] for a in cur["ofdma_corrected"]["10.0"]], "s-",
color=C["ofdma"], label="OFDMA, realigned")
ax.plot(dm, [a[0] for a in cur["uwca_corrected_err20"]["10.0"]], "^-.",
color=C["extra"], label="UWCA, realigned (20% est. err.)")
ax.set_xlabel(r"maximum timing offset $\Delta$ (symbols)")
ax.set_ylabel("SER")
ax.set_ylim(0, 1.05)
ax.legend(loc="lower right", ncol=2, framealpha=0.9, fontsize=6.0)
save(f, "fig_async.pdf", [ax])
# ------------------------------------------------------------- fig_dynusers --
d = json.load(open(DATA / "e3_dynamic_users.json"))
ks = d["k"]
f = plt.figure(figsize=FSIZE)
ax = f.add_axes([0.20, 0.165, 0.76, 0.80])
ax.plot(ks, [a[1] for a in d["fixed8"]["10.0"]], "o-", color=C["uwca"],
label="single model, 10 dB")
ax.plot(ks, [a[1] for a in d["fixed8"]["20.0"]], "o--", color=C["uwca"],
alpha=0.5, label="single model, 20 dB")
ok = sorted(int(k) for k in d["oracle"])
ax.plot(ok, [d["oracle"][str(k)]["10.0"][1] for k in ok], "s", ls="none",
color=C["extra"], label="per-count retrained, 10 dB")
ax.plot(ok, [d["oracle"][str(k)]["20.0"][1] for k in ok], "s", ls="none",
mfc="none", color=C["extra"], label="per-count retrained, 20 dB")
ax.set_xlabel(r"number of active users $|\mathcal{A}|$")
ax.set_ylabel(r"mean cosine $\bar{c}$")
ax.set_ylim(0.28, 0.47)
ax.legend(loc="upper left", framealpha=0.9, fontsize=6.8)
save(f, "fig_dynusers.pdf", [ax])
print("ALL FIGURES DONE")