108 lines
4.2 KiB
Python
108 lines
4.2 KiB
Python
"""E1: receiver theory verification (synthetic isotropic contents).
|
|
|
|
Outputs: data/e1_beta.csv, data/e1_snr.csv, data/e1_endpoints.txt
|
|
(figures come from replot_all.py only)
|
|
"""
|
|
import math
|
|
import os
|
|
import numpy as np
|
|
from semantic_mac import (affinity_matrix, matched_filter, demux_sr, demux_sc,
|
|
demux_lmmse, demux_dr, lmmse_matrices,
|
|
sample_latents_isotropic, metrics,
|
|
oma_observe, demux_noma_genie)
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
FIG = os.path.join(HERE, "..", "fig")
|
|
DATA = os.path.join(HERE, "..", "data")
|
|
os.makedirs(FIG, exist_ok=True)
|
|
os.makedirs(DATA, exist_ok=True)
|
|
|
|
U, D, DC = 4, 64, 16
|
|
BATCH = 4000
|
|
NAMES = ["OMA", "NOMA", "SR", "SC", "LMMSE", "DR"]
|
|
|
|
|
|
def run_point(beta, rho, rng, conv_seed=0):
|
|
a = math.sqrt(beta) * np.ones(U)
|
|
B = affinity_matrix(a)
|
|
z = sample_latents_isotropic(BATCH, U, D, DC, a, rng)
|
|
tilde, h = matched_filter(z, B, rho, rng)
|
|
Vc = np.eye(D)[:, :DC]
|
|
res = {}
|
|
res["SR"] = metrics(demux_sr(tilde, B, h), z)
|
|
res["SC"] = metrics(demux_sc(tilde, h), z)
|
|
lm, cf = demux_lmmse(tilde, B, h, rho)
|
|
res["LMMSE"] = metrics(lm, z)
|
|
res["LMMSE_cf"] = float(cf.mean())
|
|
# SR closed form: d sigma^2 [B^-1]_uu / h^2 averaged
|
|
Binv = np.diag(np.linalg.inv(B))
|
|
res["SR_cf"] = float((D / rho) * (Binv[None, :] / h ** 2).mean())
|
|
res["DR"] = metrics(demux_dr(tilde, B, h, rho, a, Vc), z)
|
|
# conventional baselines on a dedicated stream (keeps main draws intact)
|
|
rng_c = np.random.default_rng(90000 + conv_seed)
|
|
res["OMA"] = metrics(oma_observe(z, h, rho, rng_c), z)
|
|
res["NOMA"] = metrics(demux_noma_genie(z, h, rho, rng_c), z)
|
|
return res
|
|
|
|
|
|
def main():
|
|
rng = np.random.default_rng(0)
|
|
rho_db = 10
|
|
rho = 10 ** (rho_db / 10)
|
|
betas = [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 0.95, 0.99]
|
|
rows = []
|
|
for b in betas:
|
|
r = run_point(b, rho, rng, conv_seed=int(b * 100))
|
|
rows.append(r)
|
|
print(f"beta={b:4.2f} " + " ".join(
|
|
f"{n}:cos={r[n][0]:.3f},nmse={r[n][1]:.3f},ser={r[n][2]:.3f}"
|
|
for n in NAMES))
|
|
with open(os.path.join(DATA, "e1_beta.csv"), "w") as f:
|
|
f.write("beta," + ",".join(f"{n}_cos,{n}_nmse,{n}_ser" for n in NAMES)
|
|
+ ",LMMSE_cf,SR_cf\n")
|
|
for b, r in zip(betas, rows):
|
|
f.write(f"{b}," + ",".join(
|
|
f"{r[n][0]},{r[n][1]},{r[n][2]}" for n in NAMES)
|
|
+ f",{r['LMMSE_cf']},{r['SR_cf']}\n")
|
|
|
|
beta_mid = 0.4
|
|
snrs = list(range(0, 21, 4))
|
|
rows_s = []
|
|
for s in snrs:
|
|
r = run_point(beta_mid, 10 ** (s / 10), rng, conv_seed=1000 + s)
|
|
rows_s.append(r)
|
|
print(f"snr={s} " + " ".join(f"{n}:ser={r[n][2]:.3f}" for n in NAMES))
|
|
with open(os.path.join(DATA, "e1_snr.csv"), "w") as f:
|
|
f.write("snr," + ",".join(f"{n}_cos,{n}_nmse,{n}_ser" for n in NAMES) + "\n")
|
|
for s, r in zip(snrs, rows_s):
|
|
f.write(f"{s}," + ",".join(
|
|
f"{r[n][0]},{r[n][1]},{r[n][2]}" for n in NAMES) + "\n")
|
|
|
|
# endpoint checks
|
|
lines = []
|
|
a = math.sqrt(0.4) * np.ones(U)
|
|
B = affinity_matrix(a)
|
|
h = np.clip(np.abs((rng.standard_normal(U) + 1j * rng.standard_normal(U))
|
|
/ math.sqrt(2)), 0.2, None)
|
|
for rdb in (10, 40, 80):
|
|
W, _ = lmmse_matrices(B, h, 10 ** (-rdb / 10), D)
|
|
Ginv = np.linalg.inv(np.diag(1 / h) @ B @ np.diag(h))
|
|
rel = np.linalg.norm(W - Ginv) / np.linalg.norm(Ginv)
|
|
lines.append(f"(i) rho={rdb}dB rel_diff_W_vs_Gammainv={rel:.3e}")
|
|
W0, _ = lmmse_matrices(np.eye(U), h, 0.1, D)
|
|
off = np.abs(W0 - np.diag(np.diag(W0))).max()
|
|
wiener = h ** 2 / (h ** 2 + D * 0.1)
|
|
lines.append(f"(ii) beta=0 max_offdiag={off:.3e} "
|
|
f"max_diag_minus_wiener={np.abs(np.diag(W0)-wiener).max():.3e}")
|
|
with open(os.path.join(DATA, "e1_endpoints.txt"), "w") as f:
|
|
f.write("\n".join(lines) + "\n")
|
|
print("\n".join(lines))
|
|
|
|
# figures are produced only by the canonical replot_all.py (uniform
|
|
# geometry); experiment scripts write CSVs exclusively.
|
|
print("E1 done. Run replot_all.py to regenerate the figures.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|