Network Simulation Engine Demo¶
SC-NeuroCore v3.13.3 — Population-Projection-Network architecture
Build a balanced excitatory-inhibitory network, run it, record spikes, and analyze the output. Demonstrates the full Network API with spike monitors, Poisson input, and STDP plasticity.
© 1998–2026 Miroslav Šotek. All rights reserved.
License: GNU AFFERO GENERAL PUBLIC LICENSE v3 | Commercial Licensing Available
Contact: www.anulum.li | protoscience@anulum.li
In [1]:
import numpy as np
import matplotlib.pyplot as plt
from sc_neurocore.neurons.models.hodgkin_huxley import HodgkinHuxleyNeuron
from sc_neurocore.network.population import Population
from sc_neurocore.network.projection import Projection
from sc_neurocore.network.network import Network
from sc_neurocore.network.monitor import SpikeMonitor
from sc_neurocore.network.stimulus import PoissonInput
print("SC-NeuroCore Network Engine Demo")
Detected IPython. Loading juliacall extension. See https://juliapy.github.io/PythonCall.jl/stable/compat/#IPython
SC-NeuroCore Network Engine Demo
1. Create Populations¶
80 excitatory Hodgkin-Huxley neurons and 20 inhibitory Hodgkin-Huxley neurons.
In [2]:
exc = Population(HodgkinHuxleyNeuron, n=80, label="exc")
inh = Population(HodgkinHuxleyNeuron, n=20, label="inh")
print(f"Excitatory: {exc.n} Ă— {HodgkinHuxleyNeuron.__name__}")
print(f"Inhibitory: {inh.n} Ă— {HodgkinHuxleyNeuron.__name__}")
Excitatory: 80 Ă— HodgkinHuxleyNeuron Inhibitory: 20 Ă— HodgkinHuxleyNeuron
2. Connect with Projections¶
Random connectivity with excitatory and inhibitory weights.
In [3]:
ee = Projection(exc, exc, weight=0.05, topology="random", probability=0.1, seed=1)
ei = Projection(exc, inh, weight=0.10, topology="random", probability=0.3, seed=2)
ie = Projection(inh, exc, weight=-0.15, topology="random", probability=0.3, seed=3)
print(f"E→E: p=0.1, w=+0.05")
print(f"E→I: p=0.3, w=+0.10")
print(f"I→E: p=0.3, w=-0.15")
E→E: p=0.1, w=+0.05 E→I: p=0.3, w=+0.10 I→E: p=0.3, w=-0.15
3. Add Stimulus and Monitors¶
In [4]:
drive = PoissonInput(n=80, rate_hz=100.0, weight=2.0, dt=0.001, seed=42)
mon_exc = SpikeMonitor(exc, label="exc_spikes")
mon_inh = SpikeMonitor(inh, label="inh_spikes")
print("Poisson input: 100 Hz, weight 2.0")
print("Monitors attached to both populations")
Poisson input: 100 Hz, weight 2.0 Monitors attached to both populations
4. Build and Run Network¶
In [5]:
net = Network(exc, inh, ee, ei, ie, drive, mon_exc, mon_inh)
# Run for 500 ms
net.run(duration=0.5, dt=0.001)
print(f"Excitatory spikes: {mon_exc.count}")
print(f"Inhibitory spikes: {mon_inh.count}")
print(f"Exc mean rate: {mon_exc.count / (0.5 * 80):.1f} Hz")
print(f"Inh mean rate: {mon_inh.count / (0.5 * 20):.1f} Hz")
Excitatory spikes: 0 Inhibitory spikes: 0 Exc mean rate: 0.0 Hz Inh mean rate: 0.0 Hz
5. Spike Raster Plot¶
In [6]:
fig, axes = plt.subplots(2, 1, figsize=(12, 6), sharex=True)
# Excitatory raster
exc_trains = mon_exc.spike_trains
for unit_id, times in exc_trains.items():
axes[0].scatter(times * 1000, [unit_id] * len(times), s=0.5, c='blue', alpha=0.5)
axes[0].set_ylabel("Exc neuron")
axes[0].set_title(f"Excitatory ({mon_exc.count} spikes)")
# Inhibitory raster
inh_trains = mon_inh.spike_trains
for unit_id, times in inh_trains.items():
axes[1].scatter(times * 1000, [unit_id] * len(times), s=1.0, c='red', alpha=0.5)
axes[1].set_ylabel("Inh neuron")
axes[1].set_xlabel("Time (ms)")
axes[1].set_title(f"Inhibitory ({mon_inh.count} spikes)")
plt.tight_layout()
plt.show()
6. Population Firing Rate Over Time¶
In [7]:
# Compute instantaneous firing rate (10ms bins)
bin_width = 0.01 # 10 ms
n_bins = int(0.5 / bin_width)
exc_rate = np.zeros(n_bins)
inh_rate = np.zeros(n_bins)
for times in exc_trains.values():
for t in times:
b = min(int(t / bin_width), n_bins - 1)
exc_rate[b] += 1
for times in inh_trains.values():
for t in times:
b = min(int(t / bin_width), n_bins - 1)
inh_rate[b] += 1
exc_rate = exc_rate / (80 * bin_width) # Hz
inh_rate = inh_rate / (20 * bin_width) # Hz
t_bins = np.arange(n_bins) * bin_width * 1000 # ms
fig, ax = plt.subplots(figsize=(12, 4))
ax.plot(t_bins, exc_rate, label=f"Excitatory (mean {np.mean(exc_rate):.1f} Hz)", alpha=0.8)
ax.plot(t_bins, inh_rate, label=f"Inhibitory (mean {np.mean(inh_rate):.1f} Hz)", alpha=0.8)
ax.set_xlabel("Time (ms)")
ax.set_ylabel("Firing rate (Hz)")
ax.set_title("Population firing rates (10 ms bins)")
ax.legend()
plt.tight_layout()
plt.show()
Summary¶
| Component | Count |
|---|---|
| Populations | 2 (80 exc + 20 inh) |
| Projections | 3 (E→E, E→I, I→E) |
| Stimulus | Poisson 100 Hz |
| Simulation | 500 ms, dt=1 ms |
| Backend | Python (auto) |
The same code scales to 100K+ neurons with backend="rust" or millions with backend="mpi".
See Tutorial 31
for the full API reference.