pdc_project/encoder.py
2025-05-30 02:16:51 +02:00

67 lines
No EOL
1.9 KiB
Python

# PDC Project 2025 - Peters Stefan, Pelletier Antoine, Jeong Jaeyi, Cohen Adam
import numpy as np
import sys
ALPHABET = "abcdefghijklmnopqrstuvwxyz" \
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
"0123456789 ."
G = 10.0
ENERGY_LIMIT = 2000.0
TEXT_LENGTH = 40
ALPHABET_LENGTH = len(ALPHABET)
CHAR_TO_IDX = {c: i for i, c in enumerate(ALPHABET)}
assert ALPHABET_LENGTH == 64
def pair_to_index(a: str, b: str) -> int:
i1 = CHAR_TO_IDX[a]
i2 = CHAR_TO_IDX[b]
return (i1 << 6) + i2
def hadamard(r: int) -> np.ndarray:
if r == 0:
return np.array([[1.]], dtype=np.float32)
H = hadamard(r - 1)
return np.block([[H, H], [H, -H]])
def Br(r: int) -> np.ndarray:
H = hadamard(r)
return np.vstack([H, -H])
def make_codebook(r: int = 11, num_blocks: int = TEXT_LENGTH // 2, Eb: float = ENERGY_LIMIT):
B = Br(r)
C = np.hstack((B, B)).astype(np.float32)
n = C.shape[1]
alpha = Eb / (num_blocks * 2 * n)
C *= np.sqrt(alpha, dtype=C.dtype)
return C, alpha
def encode_message(msg: str, C: np.ndarray) -> np.ndarray:
if len(msg) != TEXT_LENGTH:
raise ValueError("Message must be exactly 40 characters.")
idxs = [CHAR_TO_IDX[c] for c in msg]
pair_idxs = [(idxs[i] << 6) | idxs[i+1] for i in range(0, TEXT_LENGTH, 2)]
signal = np.repeat(C[pair_idxs].ravel(), 2).astype(np.float32)
if not np.isclose(signal.dot(signal), ENERGY_LIMIT, atol=1e-3):
raise RuntimeError("energy check failed")
return signal
if __name__ == "__main__":
if len(sys.argv) > 1:
msg = sys.argv[1]
else:
msg = input(f"Enter a message ({TEXT_LENGTH} characters): ").strip()
if len(msg) != TEXT_LENGTH:
print(f"Message must be exactly {TEXT_LENGTH} characters.")
sys.exit(1)
C, _ = make_codebook()
signal = encode_message(msg, C)
np.savetxt("input.txt", signal)
print("Signal written to input.txt")