import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# ------------------------
# Configuration
# ------------------------
num_nodes = 8
slots_per_node = 4
sample_rate = 1000           # samples per second
lfo_rate = 0.5               # Hz for analog oscillation
amplitude_scale = 0.1
noise_scale = 0.02
num_bands = 3                # multi-band simulation
band_freqs = [100, 200, 300]  # arbitrary carrier frequencies

# ------------------------
# Initialize HDGL lattice
# ------------------------
node_lattices = np.zeros((num_nodes, slots_per_node))
node_phases = np.zeros((num_nodes, slots_per_node))

# ------------------------
# Evolve lattice per time step
# ------------------------
def evolve_lattice(lattice, phases, t):
    """
    Evolve lattice for a single time step t
    """
    composite = 0.0
    for node_idx in range(lattice.shape[0]):
        for slot_idx in range(lattice.shape[1]):
            # Analog LFO + noise
            lfo = np.sin(2 * np.pi * lfo_rate * t + node_idx + slot_idx)
            delta = amplitude_scale*lfo + noise_scale*np.random.randn()
            lattice[node_idx, slot_idx] += delta
            phases[node_idx, slot_idx] += delta
            # Multi-band contribution
            for f in band_freqs:
                composite += lattice[node_idx, slot_idx] * np.sin(2*np.pi*f*t + phases[node_idx, slot_idx])
    # Normalize
    composite /= (lattice.size * len(band_freqs))
    return composite

# ------------------------
# Setup plotting
# ------------------------
plt.style.use('dark_background')
fig, ax = plt.subplots(figsize=(12,4))
ax.set_xlim(0, 5)  # 5 seconds window
ax.set_ylim(-1, 1)
line, = ax.plot([], [], lw=1)

time_data = []
signal_data = []

t_global = 0.0
dt = 1.0 / sample_rate

def update(frame):
    global t_global
    composite = evolve_lattice(node_lattices, node_phases, t_global)
    time_data.append(t_global)
    signal_data.append(composite)
    # Keep last 5 seconds
    while time_data[-1] - time_data[0] > 5:
        time_data.pop(0)
        signal_data.pop(0)
    line.set_data(time_data, signal_data)
    t_global += dt
    return line,

ani = FuncAnimation(fig, update, interval=dt*1000, blit=True)
plt.show()
