import numpy as np
import matplotlib.pyplot as plt

# -----------------------------
# NETWORK & LATTICE SETUP
# -----------------------------
num_nodes = 10
num_strands = 8
slots_per_strand = 4
lattice_size = (num_strands, slots_per_strand)

# Frequency mapping (example bands in Hz)
frequency_bands = np.array([100e6, 300e6, 600e6, 900e6,
                            1.2e9, 1.6e9, 2.0e9, 2.4e9])

# Phyllotaxis positions
def phyllotaxis_positions(n, c=1.0):
    golden_angle = np.pi * (3 - np.sqrt(5))
    positions = []
    for i in range(n):
        r = c * np.sqrt(i)
        theta = i * golden_angle
        x = r * np.cos(theta)
        y = r * np.sin(theta)
        positions.append((x, y))
    return np.array(positions)

node_positions = phyllotaxis_positions(num_nodes)
node_lattices = [np.random.rand(*lattice_size) for _ in range(num_nodes)]

# -----------------------------
# ENVIRONMENT SIGNALS
# -----------------------------
def environment_signal(freq, t):
    """FM or AM style analog field"""
    # Example: simple AM carrier
    am = np.sin(2*np.pi*freq*t) * (1 + 0.3*np.sin(2*np.pi*1e3*t))  # 1kHz modulator
    # Example: simple FM carrier
    fm = np.sin(2*np.pi*freq*t + 0.1*np.sin(2*np.pi*1e3*t))
    return am + fm  # combined agnostic signal

# -----------------------------
# DYNAMIC LATTICE EVOLUTION
# -----------------------------
def evolve_lattice(node_lattices, freqs, t, ticks=50):
    """Simulate dynamic evolution over time with environmental riding"""
    composite = np.zeros_like(t)
    for tick in range(ticks):
        for node_idx, lattice in enumerate(node_lattices):
            # small dynamic perturbation to lattice (simulate evolution)
            lattice += np.random.randn(*lattice.shape) * 0.005
            lattice = np.clip(lattice, 0, 1)
            # ride each band
            for s, freq in enumerate(freqs):
                for slot in range(lattice.shape[1]):
                    weight = np.exp(-np.linalg.norm(node_positions[node_idx]))
                    delta_phase = lattice[s, slot] * 0.05 * weight
                    composite += np.sin(2*np.pi*freq*t + delta_phase)
        # add environmental agnostic signals
        for freq in freqs:
            composite += 0.5 * environment_signal(freq, t)
    return composite

# -----------------------------
# SIMULATION
# -----------------------------
t = np.linspace(0, 1e-5, 10000)  # 10 microsecond sample
composite_signal = evolve_lattice(node_lattices, frequency_bands, t, ticks=20)

# -----------------------------
# VISUALIZATION
# -----------------------------
plt.figure(figsize=(12,4))
plt.plot(t*1e6, composite_signal)
plt.title("Dynamic Multi-Node HDGL Lattice Riding Environmental Signals")
plt.xlabel("Time (µs)")
plt.ylabel("Amplitude")
plt.grid(True)
plt.show()

# Node layout (phyllotaxis)
plt.figure(figsize=(5,5))
plt.scatter(node_positions[:,0], node_positions[:,1], c='cyan', s=100)
plt.title("Phyllotaxis Node Layout")
plt.axis('equal')
plt.grid(True)
plt.show()
