Ex11: STDP

Spike-timing dependent plasticity — pre/post timing windows

Model: STDP Synapse

Demonstrates STDP where synapse weight changes depend on relative pre/post spike timing. The STDP trace variables follow ODEs:

\[\frac{dA_{pre}}{dt} = -A_{pre}/\tau_{pre}, \quad \frac{dA_{post}}{dt} = -A_{post}/\tau_{post}\]

The network uses HH pre-cells driving IaF post-cells. TVBO models the core IaF cell dynamics.


1. Define IaF Cell in TVBO

from tvbo import SimulationExperiment

exp = SimulationExperiment.from_string("""
label: "NeuroML Ex11: IaF Cell (STDP Network)"
dynamics:
  name: IntegrateAndFire
  parameters:
    leakReversal: { value: -50.0 }
    tau:          { value: 30.0 }
    thresh:       { value: -55.0 }
    reset:        { value: -70.0 }
  state_variables:
    v:
      equation: { rhs: "(leakReversal - v) / tau" }
      initial_value: -50.0
      variable_of_interest: true
  events:
    spike:
      condition: { rhs: "v > thresh" }
      affect:    { rhs: "v = reset" }
network:
  number_of_nodes: 1
integration:
  method: euler
  step_size: 0.005
  duration: 200.0
  time_scale: ms
""")
print(f"Model: {exp.dynamics.name}")
Model: IntegrateAndFire

2. Render LEMS XML

xml = exp.render("lems")
print(xml[:1200])

<Lems>

  <!-- Tell jLEMS/jNeuroML which component is the simulation entry point. -->
  <Target component="sim_NeuroML_Ex11__IaF_Cell__STDP_Network_"/>

  <!-- ════════════════════════════════════════════════════════════════
       Dimensions & Units (inline — no external includes needed)
       ════════════════════════════════════════════════════════════════ -->

  <!-- Dimensions -->
  <Dimension name="none"/>
  <Dimension name="time" t="1"/>
  <Dimension name="voltage" m="1" l="2" t="-3" i="-1"/>
  <Dimension name="per_time" t="-1"/>
  <Dimension name="conductance" m="-1" l="-2" t="3" i="2"/>
  <Dimension name="capacitance" m="-1" l="-2" t="4" i="2"/>
  <Dimension name="current" i="1"/>
  <Dimension name="resistance" m="1" l="2" t="-3" i="-2"/>
  <Dimension name="concentration" l="-3" n="1"/>
  <Dimension name="substance" n="1"/>
  <Dimension name="charge" t="1" i="1"/>
  <Dimension name="temperature" k="1"/>

  <!-- Units -->
  <Unit symbol="s" dimension="time" power="0"/>
  <Unit symbol="ms" dimension="time" power="-3"/>
  <Unit symbol="us" dimension="time" power="-6"/>
  <Unit symbol="V" dimension="voltage" power="0"/>
  <Unit symbol="mV" dimension="voltage" power="-3"/>
  <

3. Run Reference

import sys, os
sys.path.insert(0, os.path.dirname(os.path.abspath(".")))
from _nml_helpers import run_lems_example

ref_outputs = run_lems_example("LEMS_NML2_Ex11_STDP.xml")
for name, arr in ref_outputs.items():
    print(f"  {name}: shape={arr.shape}")
  auto.dat: shape=(30001, 4)

4. Run TVBO

import numpy as np

result = exp.run("neuroml")
da = result.integration.data
tvbo_arr = np.column_stack([da.coords['time'].values, da.values])
print(f"TVBO: shape={tvbo_arr.shape}")
TVBO: shape=(40001, 2)

5. Plot Reference Network

import matplotlib.pyplot as plt
import numpy as np

for name, ref_arr in ref_outputs.items():
    t = ref_arr[:, 0] * 1000
    fig, ax = plt.subplots(figsize=(10, 3))
    for i in range(1, min(ref_arr.shape[1], 5)):
        ax.plot(t, ref_arr[:, i], alpha=0.8, label=f'col {i}')
    ax.set_xlabel("Time (ms)")
    ax.set_title(f"Ex11: STDP — {name}")
    ax.legend(fontsize=7)
    ax.grid(True, alpha=0.3)
    plt.tight_layout()
    plt.show()

STDP Learning Rule

The STDP trace ODEs (\(dA/dt = -A/\tau\)) are expressible as TVBO state variables. The weight update rule on spike events uses the event mechanism. The network topology is NeuroML-native.