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

# -------------------------------
# HDGL Lattice Parameters
# -------------------------------
num_strands = 8
slots_per_strand = 4
total_slots = num_strands * slots_per_strand

phi = 1.6180339887
sqrt_phi = np.sqrt(phi)

# Fibonacci and prime-based Ω scaling per instance
fibonacci = [1,1,2,3,5,8,13,21,34,55,89,144,233,377]
primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43]

# Ω_i = 1 / (φ^n_base)^7
n_base = np.arange(1,num_strands+1)
omega = 1 / (phi**n_base)**7

# Initialize lattice analogs D1-D32
lattice = np.random.uniform(0.5, 1.0, (num_strands, slots_per_strand))

# Phase offsets
phases = np.random.uniform(0, 2*np.pi, (num_strands, slots_per_strand))

# Sampling
fs = 2000
duration = 0.05
t = np.linspace(0, duration, int(fs*duration))

# Prepare plot
fig, ax = plt.subplots(figsize=(12,6))
line_output, = ax.plot([], [], lw=2, color='cyan')
ax.set_xlim(0, duration)
ax.set_ylim(-5, 5)
ax.set_title("Full HDGL Lattice Analog Modulator")
ax.set_xlabel("Time (s)")
ax.set_ylabel("Amplitude")

# -------------------------------
# Update function
# -------------------------------
def update(frame):
    global lattice, phases

    # Step lattice analogs with weighted resonance
    lattice_new = np.copy(lattice)
    for s in range(num_strands):
        for i in range(slots_per_strand):
            # base increment
            lattice_new[s,i] += 0.02 * omega[s] * (1 + 0.05*i)
            
            # weighted resonance from other strands (Ω_i influence)
            resonance = np.sum([omega[j]*lattice[j,i] for j in range(num_strands) if j != s])
            lattice_new[s,i] += 0.01 * resonance
            
            # dynamic thresholding (superposition)
            if lattice_new[s,i] > sqrt_phi:
                lattice_new[s,i] = lattice_new[s,i]  # excitation
            else:
                lattice_new[s,i] *= 0.8  # damping for low-n slots

            # phase drift
            phases[s,i] += 0.05 * lattice[s,i]

    lattice[:] = lattice_new

    # Generate composite waveform
    waveform = np.zeros_like(t)
    for s in range(num_strands):
        for i in range(slots_per_strand):
            freq = 50 + 50*lattice[s,i]       # frequency modulated
            amp  = 0.3 + 0.7*lattice[s,i]/np.max(lattice)
            waveform += amp * np.sin(2*np.pi*freq*t + phases[s,i])

    line_output.set_data(t, waveform)
    return [line_output]

# -------------------------------
# Run animation
# -------------------------------
ani = animation.FuncAnimation(fig, update, frames=1000, blit=True, interval=30)
plt.show()
