Restructure package: descriptive study documentation and clean layout

This commit is contained in:
Ki-Ho Lee
2026-08-25 20:25:46 +09:00
parent 7e831474af
commit 1fc9cad834
38 changed files with 397 additions and 2262 deletions
+94
View File
@@ -0,0 +1,94 @@
"""E4 — Symbol-timing offsets with block-wise receiver realignment.
The BS knows the per-user timing estimates (pilot-based) and realigns each
user's block region individually inside the single received frame:
y_al[b_w + t] = y[b_w + t + delta_w], t = 0..d/U-1
Energy that crossed block boundaries is lost or appears as residual
interference, exactly as in a real system with per-user timing advance error.
"""
import numpy as np
import torch
import torch.nn.functional as F
import lib
from lib import (SCENARIOS, UWCA, DEVICE, block_masks, channel, gen_embeddings,
mean_cos, ofdma_decode, save_json, ser, set_seed)
rng = set_seed(42)
d, U, H = 64, 4, 4
dpu = d // U
masks = block_masks(U, d)
scen = SCENARIOS["HIGH"]
off_rng = np.random.default_rng(5)
def gen(n):
return gen_embeddings(n, d, U, rng, scen).to(DEVICE)
model = UWCA(d, U, H).to(DEVICE)
model.load_state_dict(torch.load(lib.DATA / "e1_uwca_HIGH.pt",
map_location=DEVICE))
model.eval()
def realign(y, offs_hat):
"""Block-wise realignment: shift each user's block back by its offset."""
n, dd = y.shape
out = torch.zeros_like(y)
for u in range(U):
b0 = u * dpu
for o in offs_hat[:, u].unique():
o = int(o.item())
idx = offs_hat[:, u] == o
src_end = min(b0 + dpu + o, dd)
ln = src_end - (b0 + o)
if ln > 0:
out[idx, b0:b0 + ln] = y[idx, b0 + o:src_end]
return out
@torch.no_grad()
def evaluate(mode, dmax, snr, err_p=0.0, n_mc=200):
s_acc = c_acc = 0.0
for _ in range(n_mc):
E = gen(64)
offs = None
if dmax > 0:
offs = torch.from_numpy(
off_rng.integers(0, dmax + 1, size=(64, U))).to(DEVICE)
ch = channel(E, snr_db=snr, offsets=offs)
y = ch["yI"]
if dmax > 0 and mode.endswith("cor"):
offs_hat = offs.clone()
if err_p > 0:
flip = torch.from_numpy(
off_rng.random((64, U)) < err_p).to(DEVICE)
pm = torch.from_numpy(
off_rng.choice([-1, 1], size=(64, U))).to(DEVICE)
offs_hat = (offs_hat + flip.long() * pm).clamp(min=0)
y = realign(y, offs_hat)
if mode.startswith("uwca"):
Eh = model(y, ch["yQ"])
else:
Eh = ofdma_decode(y, masks)
s_acc += ser(Eh, E)
c_acc += mean_cos(Eh, E)
return s_acc / n_mc, c_acc / n_mc
dgrid = [0, 1, 2, 4, 8]
out = {"dmax": dgrid, "snr_eval": [10.0, 20.0], "curves": {}}
for label, mode, ep in [("uwca_uncorrected", "uwca_unc", 0.0),
("ofdma_uncorrected", "ofdma_unc", 0.0),
("uwca_corrected", "uwca_cor", 0.0),
("ofdma_corrected", "ofdma_cor", 0.0),
("uwca_corrected_err20", "uwca_cor", 0.2)]:
cur = {}
for snr in out["snr_eval"]:
cur[str(snr)] = [evaluate(mode, dm, snr, ep) for dm in dgrid]
out["curves"][label] = cur
print(f"[E4] {label} 10dB SER: "
f"{[round(a[0],3) for a in cur['10.0']]}", flush=True)
save_json("e4_async.json", out)