Izhikevich Neuron Example
Overview
This example walks through simulating the Izhikevich spiking neuron and visualizing its membrane potential as we step through different input currents, including a burst-inducing preset. It highlights dynlib's ability to resume simulations, toggle presets, and annotate plots so that you can clearly see how changing drive currents alters the firing pattern.
Key Concepts
- Current stepping: run a single simulation while updating the injected current and resuming state, capturing both transients and new attractors.
- Apply presets: call
sim.apply_preset("bursting")to switch the intrinsic parameters (c,d, etc.) that reshape the neuron's excitability. - Snapshot tooling: use
sim.list_snapshots()plussim.param_vector/param_dictwithsource="snapshot"to inspect the stored configuration after running through different regimes. - Annotated time series:
series.plotsupportsvbandsandvlinesso you can label regimes where the injected current changes.
The Izhikevich Model
The builtin model packages the canonical 2D system:
with a hard reset event when v >= v_th (default 30.0), setting v = c and u = u + d. The default parameters (a=0.02, b=0.2, c=-65, d=8, I=10) reproduce regular spiking; the bursting preset reduces c/d to produce fast bursts that emerge as the current ramps up.
Basic Example
from dynlib import setup
from dynlib.plot import series, fig, export
sim = setup("builtin://ode/izhikevich", stepper="rk4", jit=True, dtype="float32")
I0, T0 = 0.0, 300.0
I1, T1 = 5.0, 600.0
I2, T2 = 10.0, 900.0
I3, T3 = 15.0, 1200.0
I4, T4 = 10.0, 1500.0
sim.config(dt=0.01)
sim.assign(I=I0)
sim.run(T=T0, transient=50.0)
sim.assign(I=I1)
sim.run(T=T1, resume=True)
sim.assign(I=I2)
sim.run(T=T2, resume=True)
sim.assign(I=I3)
sim.run(T=T3, resume=True)
sim.apply_preset("bursting")
sim.assign(I=I4)
sim.run(T=T4, resume=True)
res = sim.results()
ax = fig.single(size=(8, 4))
series.plot(
x=res.t,
y=res["v"],
ax=ax,
ylim=(-80, 50),
title="Membrane Potential (v)",
vbands=[(0, T0, "b"), (T0, T1, "m"), (T1, T2, "g"), (T2, T3, "r"), (T3, T4, "c")],
vlines=[(0, "I=0"), (T0, "I=5"), (T1, "I=10"), (T2, "I=15"), (T3, "I=10")],
vlines_color="red",
)
export.show()
print("SNAPSHOTS: ", sim.list_snapshots())
print("Snapshot Parameter Vector: ", sim.param_vector(source="snapshot"))
print("Snapshot Parameter Dictionary: ", sim.param_dict(source="snapshot"))
series.plot overlays vertical bands/lines to flag each current step, while the run/profile calls demonstrate how resume=True keeps the stateful simulation continuous as current changes. After plotting the membrane potential, the snapshot helpers summarize the stored parameter sets for later analysis.
Complete Examples in Repository
1. Izhikevich Neuron
from dynlib import setup
from dynlib.plot import series, export, fig
sim = setup("builtin://ode/izhikevich",
stepper="rk4",
jit=True,
dtype="float32")
I0, T0 = 0.0, 300.0
I1, T1 = 5.0, 600.0
I2, T2 = 10.0, 900.0
I3, T3 = 15.0, 1200.0
I4, T4 = 10.0, 1500.0
sim.config(dt=0.01)
sim.assign(I=I0)
sim.run(T=T0, transient=50.0)
sim.assign(I=I1)
sim.run(T=T1, resume=True)
sim.assign(I=I2)
sim.run(T=T2, resume=True)
sim.assign(I=I3)
sim.run(T=T3, resume=True)
sim.apply_preset("bursting")
sim.assign(I=I4)
sim.run(T=T4, resume=True)
res = sim.results()
ax = fig.single(size=(8, 4))
series.plot(x=res.t, y=res["v"],
ax=ax,
ylim=(-80, 50),
title="Membrane Potential (v)",
vbands=[(0,T0,"b"), (T0,T1,"m"), (T1,T2,"g"), (T2,T3,"r"), (T3,T4,"c")],
vlines=[(0, "I=0"), (T0, "I=5"), (T1, "I=10"), (T2, "I=15"), (T3, "I=10")],
vlines_color="red")
export.show()
print("SNAPSHOTS: ", sim.list_snapshots())
print("Snapshot Parameter Vector: ", sim.param_vector(source="snapshot"))
print("Snapshot Parameter Dictionary: ", sim.param_dict(source="snapshot"))
- Full driving-current sequence with five regimes and the
burstingpreset applied just before the largest steps. - Demonstrates how to configure
vbands/vlineson aseries.plottrace. - Prints the snapshots, parameter vector, and dictionary so you can audit the recorded presets.
2. Izhikevich Benchmark
from dynlib import build, Sim
from dynlib.plot import series, export
from dynlib.utils import Timer
DSL = '''
inline:
[model]
type = "ode"
[states]
v = -65.0
u = -13.0
[params]
a = 0.02
b = 0.2
c = -65.0
d = 8.0
I = 10.0
[equations]
expr = """
dv = 0.04 * v * v + 5.0 * v + 140.0 - u + I
du = a * (b * v - u)
"""
[events.reset]
cond = "v >= 30.0"
phase = "post"
action = """
v = c
u = u + d
"""
'''
T = 1000
with Timer("build model"):
model = build(DSL, stepper="euler", jit=False, dtype="float32")
with Timer("build model jit"):
model_jit = build(DSL, stepper="euler", jit=True, dtype="float32")
sim = Sim(model)
sim_jit = Sim(model_jit)
with Timer("jit False"):
sim.run(T=T, dt=0.01, cap_rec=10000, record=False)
with Timer("jit True"):
sim_jit.run(T=T, dt=0.01, cap_rec=10000, record=False)
- Uses
dynlib.build/Simwith inline DSL to recreate the same ODE and reset event. - Measures runtime differences between JIT and non-JIT builds using
dynlib.utils.Timer. - Runs
sim.runwithcap_rec=10000andrecord=Falseto isolate performance rather than memory usage.