Ex20: Analog Synapses

Graded (non-spiking) synaptic transmission via continuous projections

Model: Analog Synapses

Three iafCells: one source driven by pulse generators, connected to two targets via graded (analog) synapses — a linearGradedSynapse and a voltage-dependent gradedSynapse. Uses continuousProjection with auto-generated silentSynapse as the pre-component.

Reference: NeuroML2 LEMS_NML2_Ex20_AnalogSynapses.xml


1. Define Network in TVBO

from tvbo import SimulationExperiment

exp = SimulationExperiment.from_string("""
label: "NeuroML Ex20: Analog Synapses"
dynamics:
  name: iafCell
  iri: neuroml:iafCell
network:
  dynamics:
    iaf:
      name: iaf
      iri: neuroml:iafCell
      parameters:
        leakConductance: {value: 0.2, unit: nS}
        leakReversal: {value: -70, unit: mV}
        thresh: {value: -55, unit: mV}
        reset: {value: -70, unit: mV}
        C: {value: 3.2, unit: pF}
    pg1:
      name: pg1
      iri: neuroml:pulseGenerator
      parameters:
        delay: {value: 50, unit: ms}
        duration: {value: 200, unit: ms}
        amplitude: {value: 0.0032, unit: nA}
    pg2:
      name: pg2
      iri: neuroml:pulseGenerator
      parameters:
        delay: {value: 400, unit: ms}
        duration: {value: 200, unit: ms}
        amplitude: {value: 0.0020, unit: nA}
    pg3:
      name: pg3
      iri: neuroml:pulseGenerator
      parameters:
        delay: {value: 700, unit: ms}
        duration: {value: 200, unit: ms}
        amplitude: {value: 0.0010, unit: nA}
  nodes:
    - {id: 0, dynamics: iaf}
    - {id: 1, dynamics: iaf}
    - {id: 2, dynamics: iaf}
    - {id: 10, dynamics: pg1}
    - {id: 11, dynamics: pg2}
    - {id: 12, dynamics: pg3}
  edges:
    # Continuous (graded) synapses: source cell 0 → targets 1 and 2
    - source: 0
      target: 1
      coupling: linearGradedSynapse
      parameters:
        conductance: {value: 5, unit: pS}
    - source: 0
      target: 2
      coupling: gradedSynapse
      parameters:
        conductance: {value: 5, unit: pS}
        delta: {value: 5, unit: mV}
        Vth: {value: -55, unit: mV}
        k: {value: 0.025, unit: per_ms}
        erev: {value: 0, unit: mV}
    # All 3 pulse generators → source cell 0
    - {source: 10, target: 0}
    - {source: 11, target: 0}
    - {source: 12, target: 0}
integration:
  method: euler
  step_size: 0.05
  duration: 1000.0
  time_scale: ms
""")
print(f"Model: {exp.dynamics.name if exp.dynamics else 'network'}")
Model: iafCell

2. Render LEMS XML

xml = exp.render("lems")
print(xml[:2500])
<Lems>
  <Target component="sim_NeuroML_Ex20__Analog_Synapses"/>

  <Include file="Cells.xml"/>
  <Include file="Networks.xml"/>
  <Include file="Inputs.xml"/>
  <Include file="Simulation.xml"/>

    <iafCell id="iaf" C="3.2 pF" leakConductance="0.2 nS" leakReversal="-70 mV" reset="-70 mV" thresh="-55 mV"/>

    <pulseGenerator id="pg1" amplitude="0.0032 nA" delay="50.0 ms" duration="200.0 ms"/>

    <pulseGenerator id="pg2" amplitude="0.002 nA" delay="400.0 ms" duration="200.0 ms"/>

    <pulseGenerator id="pg3" amplitude="0.001 nA" delay="700.0 ms" duration="200.0 ms"/>

    <linearGradedSynapse id="linearGradedSynapse" conductance="5.0 pS"/>

    <gradedSynapse id="gradedSynapse" Vth="-55.0 mV" conductance="5.0 pS" delta="5.0 mV" erev="0.0 mV" k="0.025 per_ms"/>

    <silentSynapse id="silent_linearGradedSynapse"/>

    <silentSynapse id="silent_gradedSynapse"/>

    <network id="net1">
        <population id="iaf_pop" component="iaf" size="3"/>
        <continuousProjection id="contProj_0" presynapticPopulation="iaf_pop" postsynapticPopulation="iaf_pop">
            <continuousConnection id="0" preCell="0" postCell="1" preComponent="silent_linearGradedSynapse" postComponent="linearGradedSynapse"/>
        </continuousProjection>
        <continuousProjection id="contProj_1" presynapticPopulation="iaf_pop" postsynapticPopulation="iaf_pop">
            <continuousConnection id="0" preCell="0" postCell="2" preComponent="silent_gradedSynapse" postComponent="gradedSynapse"/>
        </continuousProjection>
        <explicitInput target="iaf_pop[0]" input="pg1" destination="synapses"/>
        <explicitInput target="iaf_pop[0]" input="pg2" destination="synapses"/>
        <explicitInput target="iaf_pop[0]" input="pg3" destination="synapses"/>
    </network>

    <Simulation id="sim_NeuroML_Ex20__Analog_Synapses" length="1000.0ms" step="0.05ms" target="net1">
        <OutputFile id="of0" fileName="results/iaf.dat">
            <OutputColumn id="iaf_pop_0_v" quantity="iaf_pop[0]/v"/>
            <OutputColumn id="iaf_pop_1_v" quantity="iaf_pop[1]/v"/>
            <OutputColumn id="iaf_pop_2_v" quantity="iaf_pop[2]/v"/>
        </OutputFile>
    </Simulation>

</Lems>

3. Run Reference

from tvbo.adapters.neuroml import run_lems_example

ref_outputs = run_lems_example("LEMS_NML2_Ex20_AnalogSynapses.xml")
for name, arr in ref_outputs.items():
    print(f"  {name}: shape={arr.shape}")
  ex20_v.dat: shape=(20001, 4)

4. Run TVBO

result = exp.run("neuroml")
da = result.integration.data
print(f"TVBO: {da.dims}, shape={da.shape}")
TVBO: ('time', 'quantity'), shape=(20001, 3)

5. Compare & Plot

from tvbo.adapters.neuroml import plot_lems_comparison
plot_lems_comparison("LEMS_NML2_Ex20_AnalogSynapses.xml", ref_outputs, result.integration.data, title_prefix="Ex20")