From eb7eb69c8bc539e8eacf52b290adfcbbe60d36f3 Mon Sep 17 00:00:00 2001 From: KiHoLee Date: Mon, 17 Aug 2026 14:00:48 +0900 Subject: [PATCH] E10: zero-padded WH (768->1024) vs native Haar, wh_padding.csv --- code/revision_sims_gpu.py | 67 ++++++++++++++++++++++++++++++++++++++- data/wh_padding.csv | 10 ++++++ 2 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 data/wh_padding.csv diff --git a/code/revision_sims_gpu.py b/code/revision_sims_gpu.py index 53bf255..4592b35 100644 --- a/code/revision_sims_gpu.py +++ b/code/revision_sims_gpu.py @@ -405,11 +405,76 @@ def E9_ceiling(d=512, snr=60.0, ntr=200): 'blind_mc', 'blind_pred'], rows) +# ------------------------------------------------------------------ +def E10_whpad(beta=0.311, d=768, dpad=1024, ntr=200): + """Zero-padded WH at d=768 (padded to 1024) vs dense Haar at 768. + + The embedding (768) is zero-padded to 1024, masked by H_1024 D_u, + and the exact per-coordinate Wiener uses the true prior (signal + variance 1/768 on the active support, zero on the padding, so the + padded coordinates are discarded). Reference: Haar masks at the + native d=768 with the standard aware demultiplexer. Same per-block + energy E_b = 1 and the same noise PSD; the padded block occupies + dpad channel uses, a bandwidth cost of dpad/d.""" + print(chr(10) + '=== E10: zero-padded WH (768->1024) vs native Haar 768 ===') + snr_db = np.arange(0, 41, 5) + sigs = torch.tensor(10 ** (-snr_db / 20.0), dtype=torch.float32, + device=DEV) + nb = len(snr_db) + H = np.array([[1.0]]) + while H.shape[0] < dpad: + H = np.block([[H, H], [H, -H]]) + Ht = torch.tensor(H / math.sqrt(dpad), dtype=torch.float32, device=DEV) + g = 1.0 - beta**2 + res = {'haar': np.zeros(nb), 'whpad': np.zeros(nb)} + for _ in range(ntr): + e1, e2 = embed_pair(d, beta) + # ---- native Haar at 768 ---- + M1, M2 = haar_g(d), haar_g(d) + Q = M1.T @ M2 + n = cnoise_g(d) + r = (M1 @ e1 + M2 @ e2).to(torch.complex64).unsqueeze(0) \ + + sigs.view(-1, 1) * n.unsqueeze(0) + t1 = (M1.T.to(torch.complex64) @ r.unsqueeze(-1)).squeeze(-1) + g1 = aware_g(t1, Q, beta, 1.0, sigs**2) + res['haar'] += abscos(g1, e1) + # ---- zero-padded WH at 1024 ---- + z = torch.zeros(dpad - d, device=DEV) + e1p = torch.cat([e1, z]); e2p = torch.cat([e2, z]) + D1 = torch.tensor(np.sign(rng.standard_normal(dpad)), + dtype=torch.float32, device=DEV) + D2 = torch.tensor(np.sign(rng.standard_normal(dpad)), + dtype=torch.float32, device=DEV) + W1, W2 = Ht * D1.unsqueeze(0), Ht * D2.unsqueeze(0) + npad = cnoise_g(dpad) + rp = (W1 @ e1p + W2 @ e2p).to(torch.complex64).unsqueeze(0) \ + + sigs.view(-1, 1) * npad.unsqueeze(0) + tw = (W1.T.to(torch.complex64) @ rp.unsqueeze(-1)).squeeze(-1) + q = (D1 * D2)[:d] # active coordinates only + a = 1.0 + beta * q # (d,) + s_var = 1.0 / d # true signal variance + v = g / d + (sigs**2).view(-1, 1) # interference + noise + gains = (s_var * a.unsqueeze(0)) / (a.unsqueeze(0)**2 * s_var + v) + w1 = gains.to(torch.complex64) * tw[:, :d] + res['whpad'] += abscos(w1, e1) + for k in res: + res[k] /= ntr + rows = [[s, res['haar'][i], res['whpad'][i]] + for i, s in enumerate(snr_db)] + write_csv('wh_padding', ['snr_db', 'haar768', 'whpad1024'], rows) + dev = res['haar'] - res['whpad'] + print(f' cosine delta (haar - whpad): max {dev.max():.4f}, ' + f'at 20 dB {dev[list(snr_db).index(20)]:.4f}, ' + f'at 40 dB {dev[-1]:.4f}') + print(f' bandwidth cost: {dpad}/{d} = {dpad/d:.3f}x uses ' + f'(per-use rate factor {d/dpad:.3f})') + + if __name__ == "__main__": todo = set(sys.argv[1:]) ALL = {"E2": E2_sic, "E3": E3_unconditional, "E4": E4_csi, "E5": E5_maskfam, "E7c": E7_multiuser, "E8": E8_mismatch, - "E9": E9_ceiling} + "E9": E9_ceiling, "E10": E10_whpad} for name, fn in ALL.items(): if not todo or name in todo: fn() diff --git a/data/wh_padding.csv b/data/wh_padding.csv new file mode 100644 index 0000000..a2e1b58 --- /dev/null +++ b/data/wh_padding.csv @@ -0,0 +1,10 @@ +snr_db,haar768,whpad1024 +0,0.04595265286625363,0.047847944343229754 +5,0.07112330510281026,0.07224809597013518 +10,0.1199369035474956,0.12063940849155187 +15,0.20449634090065957,0.20457616232335568 +20,0.33400419175624846,0.3319106823205948 +25,0.48966493368148806,0.48235686495900154 +30,0.6161512869596482,0.6032128128409385 +35,0.6835479807853698,0.6678868445754051 +40,0.7102783480286599,0.6937726792693139