E10: zero-padded WH (768->1024) vs native Haar, wh_padding.csv

This commit is contained in:
KiHoLee
2026-08-17 14:00:48 +09:00
parent 37114b11d0
commit eb7eb69c8b
2 changed files with 76 additions and 1 deletions
+66 -1
View File
@@ -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()