# -*- coding: utf-8 -*- """Where does the legitimate advantage over OMA go? An ideal M-ary receiver at the main configuration should reach 0.199 at 10 dB against the 0.275 of resource-matched OMA, a factor of 1.38, while the system measures 0.257, a factor of 1.07. This script splits the shortfall into its two causes: residual multi-user interference, which orthogonal keys do not remove because masking is elementwise, and the distance the trained unit codebook falls short of an orthogonal set. """ import math import sys from pathlib import Path import torch sys.path.insert(0, str(Path(__file__).resolve().parent)) import sse_lib as L from sse_lib import DEVICE, snr_to_sigma2, rayleigh_gain from exp_full import main_model SNR_DB = 10.0 FRAMES = 400_000 CH = 40_000 def ser(m, snr_db, frames, solo=False): """SER of user 0. With solo=True the other users transmit nothing, while the power normalizer c is left at its four-user value so that user 0 keeps exactly the energy it has in the real system.""" tot = wrong = 0 with torch.no_grad(): while tot < frames: n = min(CH, frames - tot) dig = torch.randint(m.vu, (n, m.users, m.P), device=DEVICE) Bn = m.unit_codebook() e = Bn[dig] / math.sqrt(m.P) mk = m.masks() x = e * mk[None, :, None, :] if solo: x = x[:, :1] y = x.sum(dim=1) / m.c h = rayleigh_gain((n, 1), device=DEVICE) sig = snr_to_sigma2(torch.full((n,), snr_db), m.d).to(DEVICE).sqrt() rx = h[:, :, None, None] * y[:, None] \ + sig[:, None, None, None] * torch.randn(n, 1, m.P, m.L, device=DEVICE) r = rx / h[:, :, None, None].clamp_min(1e-6) cand = Bn[None, :, :] * mk[:1, None, :] sc = torch.einsum("nupl,uvl->nupv", r, cand) bad = (sc.argmax(-1)[:, 0] != dig[:, 0]).any(dim=-1) wrong += int(bad.sum()) tot += n return wrong / tot def main(): m = main_model() with torch.no_grad(): Bn = m.unit_codebook() G = Bn @ Bn.T off = G - torch.diag(torch.diag(G)) mk = m.masks() Gm = mk @ mk.T / m.L offm = Gm - torch.diag(torch.diag(Gm)) print("main configuration: d=%d P=%d L=%d Vu=%d U=%d" % (m.d, m.P, m.L, m.vu, m.users)) print("key cross-correlation, max |off-diagonal| : %.2e" % offm.abs().max()) print("codebook Gram, max |off-diagonal| : %.4f" % off.abs().max()) print("codebook Gram, rms off-diagonal : %.4f" % off.pow(2).sum().div(m.vu * (m.vu - 1)).sqrt()) print("(an orthogonal set of %d codewords in %d dims would read 0)" % (m.vu, m.L)) print() four = ser(m, SNR_DB, FRAMES, solo=False) solo = ser(m, SNR_DB, FRAMES, solo=True) print("user-0 SER, all four users transmitting : %.4f" % four) print("user-0 SER, other users silent : %.4f" % solo) print("OMA, resource matched (closed form) : %.4f" % L.oma_ser([SNR_DB])[0]) print("ideal 16-ary orthogonal (separate MC) : 0.1986") if __name__ == "__main__": main()