import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert

# -------------------------------
# SDR / Carrier Simulation Parameters
# -------------------------------
FS = 2000        # Sampling rate (Hz) - replace with SDR sample rate
T = 2.0          # Duration (s)
t = np.arange(0, T, 1/FS)

CARRIER_FREQ = 50  # Hz, for demo (real SDR freq will be in MHz)
CARRIER_AMP = 1.0

# HDGL lattice parameters
NUM_NODES = 4
NUM_CORES = 2
NUM_STRANDS = 4
SLOTS_PER_STRAND = 4
SIDE_AMPLITUDE = 0.05  # Fraction of carrier amplitude

PHI = 1.6180339887
OMEGA_BASE = 1 / (PHI**np.arange(1, NUM_STRANDS+1))**7

# -------------------------------
# Generate Example Carrier (Replace with SDR read in real deployment)
# -------------------------------
carrier = CARRIER_AMP * np.sin(2 * np.pi * CARRIER_FREQ * t)

# -------------------------------
# Initialize Lattice Nodes
# -------------------------------
def init_lattice():
    cores = []
    for _ in range(NUM_CORES):
        lattice = np.random.uniform(0.5, 1.0, (NUM_STRANDS, SLOTS_PER_STRAND))
        phases = np.random.uniform(0, 2*np.pi, (NUM_STRANDS, SLOTS_PER_STRAND))
        cores.append({'lattice': lattice, 'phases': phases})
    return cores

nodes = [init_lattice() for _ in range(NUM_NODES)]

# -------------------------------
# Continuous Lattice Evolution & Modulation
# -------------------------------
def evolve_lattice(node_cores, carrier_signal):
    """Phase-lock lattice to carrier and generate sideband."""
    sideband = np.zeros_like(carrier_signal)
    # Instantaneous carrier phase via Hilbert transform
    analytic_carrier = np.angle(hilbert(carrier_signal))
    for core in node_cores:
        for s in range(NUM_STRANDS):
            for slot in range(SLOTS_PER_STRAND):
                # Phase offset encodes lattice data
                phase_offset = 0.2 * core['lattice'][s, slot]
                target_phase = analytic_carrier + phase_offset
                core['phases'][s, slot] += 0.1 * (target_phase - core['phases'][s, slot])
                # Sideband contribution
                sideband += np.sin(2*np.pi*CARRIER_FREQ*t + core['phases'][s, slot])
    # Normalize
    sideband /= (NUM_CORES * NUM_STRANDS * SLOTS_PER_STRAND)
    return SIDE_AMPLITUDE * sideband

# -------------------------------
# Aggregate Multi-Node Sideband
# -------------------------------
composite_signal = carrier.copy()
for node_cores in nodes:
    composite_signal += evolve_lattice(node_cores, carrier)

# Preserve carrier amplitude
composite_signal /= (1 + NUM_NODES * SIDE_AMPLITUDE)

# -------------------------------
# Receiver: Extract HDGL Sideband
# -------------------------------
def decode_lattice(signal):
    analytic = hilbert(signal)
    amplitude = np.abs(analytic)
    phase = np.unwrap(np.angle(analytic))
    return amplitude, phase

amplitude, phase = decode_lattice(composite_signal)

# -------------------------------
# Plot Results
# -------------------------------
plt.figure(figsize=(14,6))
plt.plot(t, carrier, label='Original Carrier', alpha=0.6)
plt.plot(t, composite_signal, label='Carrier + HDGL Sideband', alpha=0.9)
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('SDR-Level HDGL Lattice Riding Live Carrier (Analog Sideband)')
plt.legend()
plt.show()
