File size: 4,047 Bytes
e4cdd5f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
"""Simulator vs Chip Comparison Benchmark

==========================================

Demonstrates both backends with the same network, comparing spike counts.



When no FPGA is connected, runs simulator-only and shows expected chip commands.



Features demonstrated: Backend abstraction, deploy/inject/run API, RunResult.

"""

import sys, os, time
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

import neurocore as nc
from neurocore.compiler import Compiler


def build_network():
    """Build a moderately complex E/I network."""
    net = nc.Network()
    exc = net.population(64, params={
        "threshold": 800, "leak": 5, "refrac": 3,
    }, label="excitatory")
    inh = net.population(16, params={
        "threshold": 600, "leak": 2, "refrac": 2,
    }, label="inhibitory")

    net.connect(exc, exc, topology="random_sparse", p=0.1, weight=200, seed=42)
    net.connect(exc, inh, topology="all_to_all", weight=150)
    net.connect(inh, exc, topology="all_to_all", weight=-300, compartment=0)

    return net, exc, inh


def run_simulator(net, exc, inh, timesteps=100):
    """Run on the software simulator."""
    sim = nc.Simulator()
    sim.deploy(net)

    # Inject stimulus to first 8 excitatory neurons
    sim.inject(exc[:8], current=1200)
    result = sim.run(timesteps)
    return result


def main():
    print("=" * 60)
    print("  Simulator vs Chip Comparison Benchmark")
    print("=" * 60)

    net, exc, inh = build_network()
    timesteps = 100

    # Compile and show network summary
    compiled = Compiler().compile(net)
    print(f"\nNetwork: {net.total_neurons()} neurons "
          f"({net.populations[0].size} exc + {net.populations[1].size} inh)")
    print(f"Compiled: {compiled.summary()}")

    # Run simulator
    print(f"\n--- Simulator ({timesteps} timesteps) ---")
    t0 = time.perf_counter()
    result = run_simulator(net, exc, inh, timesteps)
    elapsed = time.perf_counter() - t0

    print(f"Total spikes: {result.total_spikes}")
    print(f"Active neurons: {len(result.spike_trains)}/{net.total_neurons()}")
    print(f"Elapsed: {elapsed * 1000:.1f}ms")

    rates = result.firing_rates()
    if rates:
        max_rate = max(rates.values())
        avg_rate = sum(rates.values()) / len(rates)
        print(f"Max firing rate: {max_rate:.2f} Hz")
        print(f"Avg firing rate: {avg_rate:.2f} Hz (active neurons only)")

    timeseries = result.spike_count_timeseries()
    peak_t = max(range(len(timeseries)), key=lambda i: timeseries[i])
    print(f"Peak activity: timestep {peak_t} ({timeseries[peak_t]} spikes)")

    # Show what would be sent to FPGA
    print(f"\n--- Chip Commands (would be sent via UART) ---")
    print(f"PROG_NEURON commands: {len(compiled.prog_neuron_cmds)}")
    print(f"PROG_INDEX commands:  {len(compiled.prog_index_cmds)}")
    print(f"PROG_POOL commands:   {len(compiled.prog_pool_cmds)}")
    print(f"PROG_ROUTE commands:  {len(compiled.prog_route_cmds)}")
    print(f"PROG_DELAY commands:  {len(compiled.prog_delay_cmds)}")
    total_bytes = (len(compiled.prog_neuron_cmds) * 7
                   + len(compiled.prog_index_cmds) * 10
                   + len(compiled.prog_pool_cmds) * 9
                   + len(compiled.prog_route_cmds) * 10)
    print(f"Total deploy payload: ~{total_bytes} bytes")

    # Try chip backend (will fail without hardware)
    print(f"\n--- Chip Backend ---")
    try:
        chip = nc.Chip(port="COM3")
        chip.deploy(net)
        chip.inject(exc[:8], current=1200)
        chip_result = chip.run(timesteps)
        print(f"Chip spikes: {chip_result.total_spikes}")
        print(f"Match: {'YES' if chip_result.total_spikes == result.total_spikes else 'NO'}")
        chip.close()
    except Exception as e:
        print(f"No FPGA connected ({type(e).__name__})")
        print("  Run with --port <port> when FPGA is attached")

    print("\nDone!")


if __name__ == "__main__":
    main()