56 lines
No EOL
1.4 KiB
Python
56 lines
No EOL
1.4 KiB
Python
# 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) |