File size: 6,039 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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
"""Generate spike raster plot from simulation output."""
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import numpy as np

fig, axes = plt.subplots(3, 1, figsize=(14, 10), gridspec_kw={'height_ratios': [2, 2, 1]})
fig.patch.set_facecolor('#0a0a1a')

ax1 = axes[0]
ax1.set_facecolor('#0a0a1a')

# Spike data from Phase 5 test (TEST 4: Cross-core)
# Core 0: N0 spikes at ts=10, N1 at ts=11, N2 at ts=12, N3 at ts=13
# Core 1: N0 spikes at ts=14, N1 at ts=15
spike_data = [
    (10, 'C0:N0'), (11, 'C0:N1'), (12, 'C0:N2'), (13, 'C0:N3'),
    (14, 'C1:N0'), (15, 'C1:N1'),
]

neurons = ['C0:N0', 'C0:N1', 'C0:N2', 'C0:N3', 'C1:N0', 'C1:N1']
neuron_idx = {n: i for i, n in enumerate(neurons)}
colors_map = {'C0': '#4a9eff', 'C1': '#ff6b35'}

for ts, neuron in spike_data:
    core = neuron[:2]
    y = neuron_idx[neuron]
    ax1.scatter(ts, y, s=200, c=colors_map[core], marker='|', linewidths=3, zorder=5)
    ax1.scatter(ts, y, s=80, c=colors_map[core], alpha=0.3, zorder=4)

# Draw cross-core boundary
ax1.axhline(y=3.5, color='#ff4444', linestyle='--', linewidth=1, alpha=0.5)
ax1.text(29, 3.5, 'NoC Boundary', fontsize=8, color='#ff4444', va='center',
         fontfamily='monospace')

# Draw propagation arrows
for i in range(len(spike_data)-1):
    ts1, n1 = spike_data[i]
    ts2, n2 = spike_data[i+1]
    y1, y2 = neuron_idx[n1], neuron_idx[n2]
    color = '#ffcc00' if y1 < 3.5 and y2 > 3.5 else '#ffffff33'
    ax1.annotate('', xy=(ts2-0.1, y2), xytext=(ts1+0.1, y1),
                arrowprops=dict(arrowstyle='->', color=color, linewidth=1.5, alpha=0.6))

ax1.set_yticks(range(len(neurons)))
ax1.set_yticklabels(neurons, fontsize=9, fontfamily='monospace', color='#cccccc')
ax1.set_xlabel('Timestep', fontsize=10, color='#888888', fontfamily='monospace')
ax1.set_title('Cross-Core Spike Propagation (Core 0 → Core 1 via NoC)',
              fontsize=13, fontweight='bold', color='#ffffff', fontfamily='monospace', pad=10)
ax1.set_xlim(8, 30)
ax1.tick_params(colors='#666666')
ax1.spines['bottom'].set_color('#333333')
ax1.spines['left'].set_color('#333333')
ax1.spines['top'].set_visible(False)
ax1.spines['right'].set_visible(False)
ax1.grid(axis='x', color='#222222', linewidth=0.5)

ax2 = axes[1]
ax2.set_facecolor('#0a0a1a')

# Simulated spike times for 4-core chain propagation
# Each core: N0→N1→N2→N3, with inter-core hops adding 1 timestep delay
chain_spikes = []
core_colors = ['#4a9eff', '#ff6b35', '#2ecc71', '#e74c3c']
all_neurons = []

base_ts = 5
for core in range(4):
    for neuron in range(4):
        ts = base_ts + core * 5 + neuron + 1
        label = f'C{core}:N{neuron}'
        chain_spikes.append((ts, label, core))
        if label not in all_neurons:
            all_neurons.append(label)

neuron_idx2 = {n: i for i, n in enumerate(all_neurons)}

for ts, label, core in chain_spikes:
    y = neuron_idx2[label]
    ax2.scatter(ts, y, s=150, c=core_colors[core], marker='|', linewidths=2.5, zorder=5)
    ax2.scatter(ts, y, s=60, c=core_colors[core], alpha=0.3, zorder=4)

# Core boundaries
for boundary in [3.5, 7.5, 11.5]:
    ax2.axhline(y=boundary, color='#ff4444', linestyle='--', linewidth=0.8, alpha=0.4)

ax2.set_yticks(range(len(all_neurons)))
ax2.set_yticklabels(all_neurons, fontsize=7, fontfamily='monospace', color='#cccccc')
ax2.set_xlabel('Timestep', fontsize=10, color='#888888', fontfamily='monospace')
ax2.set_title('Full 4-Core Chain: Spike Traverses All 1,024-Neuron Mesh',
              fontsize=13, fontweight='bold', color='#ffffff', fontfamily='monospace', pad=10)
ax2.tick_params(colors='#666666')
ax2.spines['bottom'].set_color('#333333')
ax2.spines['left'].set_color('#333333')
ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)
ax2.grid(axis='x', color='#222222', linewidth=0.5)

# Legend
for i, label in enumerate(['Core 0', 'Core 1', 'Core 2', 'Core 3']):
    ax2.scatter([], [], c=core_colors[i], s=100, label=label)
ax2.legend(loc='upper right', fontsize=8, facecolor='#1a1a2a', edgecolor='#333355',
           labelcolor='#cccccc')

ax3 = axes[2]
ax3.set_facecolor('#0a0a1a')

# Simulate LIF neuron membrane potential
threshold = 1000
leak = 3
stimulus = 200
weight = 600
refrac = 3

V = [0]
spike_times = []
refrac_counter = 0

for t in range(1, 80):
    if refrac_counter > 0:
        V.append(0)
        refrac_counter -= 1
        continue

    v = V[-1]
    v = v - leak  # leak
    if v < 0: v = 0
    v = v + stimulus  # external input every timestep

    if v >= threshold:
        spike_times.append(t)
        V.append(threshold + 100)  # show spike visually
        refrac_counter = refrac
    else:
        V.append(v)

ax3.plot(range(len(V)), V, color='#4a9eff', linewidth=1.5, zorder=3)
ax3.axhline(y=threshold, color='#ff4444', linestyle='--', linewidth=1, alpha=0.7)
ax3.text(78, threshold + 30, 'Threshold', fontsize=8, color='#ff4444',
         ha='right', fontfamily='monospace')

for st in spike_times:
    ax3.axvline(x=st, color='#ffcc00', linewidth=1, alpha=0.4, zorder=2)

ax3.fill_between(range(len(V)), 0, V, alpha=0.1, color='#4a9eff')
ax3.set_xlabel('Timestep', fontsize=10, color='#888888', fontfamily='monospace')
ax3.set_ylabel('Membrane\nPotential', fontsize=9, color='#888888', fontfamily='monospace')
ax3.set_title('LIF Neuron Dynamics: Charge → Threshold → Spike → Reset → Refractory',
              fontsize=11, fontweight='bold', color='#ffffff', fontfamily='monospace', pad=10)
ax3.tick_params(colors='#666666')
ax3.spines['bottom'].set_color('#333333')
ax3.spines['left'].set_color('#333333')
ax3.spines['top'].set_visible(False)
ax3.spines['right'].set_visible(False)
ax3.set_ylim(-50, 1200)

plt.tight_layout(pad=1.5)
plt.savefig('C:/Users/mrwab/neuromorphic-chip/spike_visualization.png', dpi=150,
            facecolor='#0a0a1a', bbox_inches='tight', pad_inches=0.3)
print("Spike visualization saved!")