# encoder.py import numpy as np # System parameters G = 10.0 # power gain for even samples ENERGY_LIMIT = 2000.0 # total energy per block ALPHABET = ( [chr(i) for i in range(ord('a'), ord('z')+1)] + [chr(i) for i in range(ord('A'), ord('Z')+1)] + [str(i) for i in range(10)] + [' ', '.'] ) assert len(ALPHABET) == 64, "Alphabet must be size 64" def hadamard(r: int) -> np.ndarray: if r == 0: return np.array([[1]], dtype=float) M = hadamard(r-1) return np.block([[M, M], [M, -M]]) def Br(r: int) -> np.ndarray: M = hadamard(r) return np.vstack([M, -M]) def make_codebook(r: int, num_blocks: int) -> np.ndarray: """ Build 64x64 codebook and scale blocks so energy per block ≤ ENERGY_LIMIT/num_blocks """ B = Br(r) C = np.hstack([B, B]).astype(float) raw_norm = np.sum(C[0]**2) margin = 0.95 alpha = margin * (ENERGY_LIMIT / num_blocks) / raw_norm return np.sqrt(alpha) * C def interleave(c: np.ndarray) -> np.ndarray: half = c.size // 2 x = np.empty(c.size) x[0::2] = c[:half] x[1::2] = c[half:] return x def encode_message(msg: str, C: np.ndarray) -> np.ndarray: """ Encode 40-character message into interleaved code symbols """ if len(msg) != 40: raise ValueError("Message must be exactly 40 characters.") idx = [ALPHABET.index(ch) for ch in msg] blocks = [interleave(C[i]) for i in idx] return np.concatenate(blocks)