Skip to content

Synapses API Reference

Complete reference for synapse types and their usage in Neun Python.

Overview

Neun provides two types of synapses that model different biological coupling mechanisms:

  • Electrical synapses (Gap Junctions): Direct electrical connections through gap junctions. These are passive connections that allow bidirectional current flow proportional to the voltage difference. They don't require numerical integration since they have no internal dynamics.

  • Diffusion synapses (Chemical Synapses): Chemical synaptic connections with neurotransmitter dynamics. These have internal differential equations modeling neurotransmitter release and binding, requiring numerical integration (RungeKutta4 or RungeKutta6).

Electrical Synapse

Electrical synapses model gap junction connections - direct ion channels between neurons that allow instantaneous bidirectional current flow. The synaptic current is simply proportional to the voltage difference: I = g × (V₁ - V₂).

Class Names

Pattern: ESyn{Neuron1}{Neuron2}{Precision}

Note: Electrical synapses don't include an integrator suffix because they have no internal dynamics requiring numerical integration.

Common combinations: - neun_py.ESynHHHHDouble - HH to HH (double precision) - neun_py.ESynHRHRDouble - HR to HR (double precision) - neun_py.ESynHHHRDouble - HH to HR (double precision) - neun_py.ESynHHHHFloat - HH to HH (single precision)

Constructor

synapse = neun_py.ESynHHHHDouble(
    neuron1,           # First neuron
    variable1,         # Variable to couple from neuron1
    neuron2,           # Second neuron
    variable2,         # Variable to couple from neuron2
    conductance1,      # Conductance neuron1 → neuron2
    conductance2       # Conductance neuron2 → neuron1
)

Parameters: - neuron1, neuron2 - Neuron instances to connect - variable1, variable2 - Variable enums (typically .v for voltage) - conductance1, conductance2 - Coupling strengths (negative values typical)

Example

import neun_py

# Create two HH neurons
args = neun_py.HHDoubleConstructorArgs()
n1 = neun_py.HHDoubleRK4(args)
n2 = neun_py.HHDoubleRK4(args)

# Set parameters for both
for n in [n1, n2]:
    n.set_param(neun_py.HHDoubleParameter.cm, 1 * 7.854e-3)
    n.set_param(neun_py.HHDoubleParameter.vna, 50)
    n.set_param(neun_py.HHDoubleParameter.vk, -77)
    n.set_param(neun_py.HHDoubleParameter.vl, -54.387)
    n.set_param(neun_py.HHDoubleParameter.gna, 120 * 7.854e-3)
    n.set_param(neun_py.HHDoubleParameter.gk, 36 * 7.854e-3)
    n.set_param(neun_py.HHDoubleParameter.gl, 0.3 * 7.854e-3)

# Different initial voltages
n1.set(neun_py.HHDoubleVariable.v, -75)
n2.set(neun_py.HHDoubleVariable.v, -65)

# Create electrical synapse (no integrator needed - passive connection)
syn = neun_py.ESynHHHHDouble(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v,
    -0.002,  # Conductance n1 → n2
    -0.002   # Conductance n2 → n1
)

Methods

step(dt)

Advances the synapse by one time step.

syn.step(0.001)

Must be called before stepping the neurons!

get_synaptic_current()

Returns the synaptic current.

current = syn.get_synaptic_current()

Simulation Loop

step = 0.001
duration = 100

time = 0.0
while time < duration:
    # Step synapse FIRST
    syn.step(step)

    # Add external inputs
    n1.add_synaptic_input(0.1)
    n2.add_synaptic_input(0.08)

    # Then step neurons
    n1.step(step)
    n2.step(step)

    time += step

Conductance Values

Typical ranges:

Strength Conductance Effect
Weak -0.0001 Minimal coupling
Moderate -0.001 Noticeable synchronization
Strong -0.01 Strong synchronization
Very Strong -0.1 Nearly identical dynamics

Sign convention: Negative conductances typical for depolarization-driven coupling.

Asymmetric Coupling

# Unidirectional: n1 → n2
syn = neun_py.ESynHHHHDouble(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v,
    -0.002,  # n1 influences n2
    0.0      # n2 does NOT influence n1
)

# Asymmetric bidirectional
syn = neun_py.ESynHHHHDouble(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v,
    -0.003,  # Stronger n1 → n2
    -0.001   # Weaker n2 → n1
)

Diffusion Synapse

Diffusion synapses model chemical synaptic transmission with neurotransmitter dynamics based on the Destexhe et al. (1994) model. They include differential equations for neurotransmitter release (r) and synaptic current, requiring numerical integration.

Class Names

Pattern: DSyn{Neuron1}{Neuron2}{Precision}{Integrator}

Note: Diffusion synapses require an integrator suffix (RK4 or RK6) because they have internal differential equations for neurotransmitter dynamics.

Common combinations: - neun_py.DSynHHHHDoubleRK4 - HH to HH with RungeKutta4 - neun_py.DSynHRHRDoubleRK6 - HR to HR with RungeKutta6 - neun_py.DSynHHHRDoubleRK4 - HH to HR with RungeKutta4 - neun_py.DSynHHHHFloatRK4 - HH to HH (single precision) with RungeKutta4

Constructor

synapse = neun_py.DSynHHHHDoubleRK4(
    neuron1,           # Presynaptic neuron
    variable1,         # Presynaptic variable (typically voltage)
    neuron2,           # Postsynaptic neuron
    variable2          # Postsynaptic variable (typically voltage)
)

Note: Diffusion synapses have internal state variables (neurotransmitter concentration r and synaptic current i) with differential equations requiring numerical integration.

Example

import neun_py

# Create neurons
args = neun_py.HHDoubleConstructorArgs()
n1 = neun_py.HHDoubleRK4(args)
n2 = neun_py.HHDoubleRK4(args)

# ... set parameters ...

# Create diffusion synapse
syn = neun_py.DSynHHHHDoubleRK4(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v
)

Parameters

Diffusion synapses have several biophysical parameters controlling neurotransmitter dynamics:

import neun_py

# Create synapse
syn = neun_py.DSynHHHHDoubleRK4(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v
)

# Set parameters
syn.set_param(neun_py.DSynDoubleParameter.alpha, 5.0)           # Binding rate (ms⁻¹mM⁻¹)
syn.set_param(neun_py.DSynDoubleParameter.beta, 0.18)           # Unbinding rate (ms⁻¹)
syn.set_param(neun_py.DSynDoubleParameter.threshold, -20.0)     # Activation threshold (mV)
syn.set_param(neun_py.DSynDoubleParameter.esyn, -75.0)          # Reversal potential (mV)
syn.set_param(neun_py.DSynDoubleParameter.gsyn, 0.015)          # Max conductance (mS/cm²)
syn.set_param(neun_py.DSynDoubleParameter.T, 1.0)               # Max neurotransmitter (mM)
syn.set_param(neun_py.DSynDoubleParameter.max_release_time, 1.0) # Release duration (ms)

Parameter descriptions: - alpha: Neurotransmitter binding rate - beta: Neurotransmitter unbinding rate - threshold: Presynaptic voltage threshold for release - esyn: Synaptic reversal potential (negative for inhibitory, positive for excitatory) - gsyn: Maximum synaptic conductance - T: Maximum neurotransmitter concentration - max_release_time: Duration of neurotransmitter release after spike

Methods

step(dt)

Advances the synapse dynamics by one time step, integrating the neurotransmitter equations.

syn.step(0.001)  # dt in milliseconds

get_synaptic_current()

Returns the current synaptic current.

current = syn.get_synaptic_current()

get(variable)

Get internal state variables:

r = syn.get(neun_py.DSynDoubleVariable.r)  # Neurotransmitter concentration
i = syn.get(neun_py.DSynDoubleVariable.i)  # Synaptic current

set(variable, value)

Set internal state variables:

syn.set(neun_py.DSynDoubleVariable.r, 0.0)  # Reset neurotransmitter
syn.set(neun_py.DSynDoubleVariable.i, 0.0)  # Reset current

Simulation Loop

Identical to electrical synapse:

step = 0.001
time = 0.0
while time < duration:
    syn.step(step)
    n1.add_synaptic_input(0.1)
    n2.add_synaptic_input(0.08)
    n1.step(step)
    n2.step(step)
    time += step

Multi-Neuron Networks

Chain Topology

import neun_py

def create_hh_neuron(v_init=-65):
    args = neun_py.HHDoubleConstructorArgs()
    n = neun_py.HHDoubleRK4(args)
    # ... set parameters ...
    n.set(neun_py.HHDoubleVariable.v, v_init)
    return n

# Create chain: n1 → n2 → n3
n1 = create_hh_neuron(-70)
n2 = create_hh_neuron(-65)
n3 = create_hh_neuron(-60)

s12 = neun_py.ESynHHHHDouble(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v,
    -0.002, -0.002
)

s23 = neun_py.ESynHHHHDouble(
    n2, neun_py.HHDoubleVariable.v,
    n3, neun_py.HHDoubleVariable.v,
    -0.002, -0.002
)

# Simulation
step = 0.001
time = 0.0
while time < duration:
    # Step all synapses
    s12.step(step)
    s23.step(step)

    # External input to first neuron only
    n1.add_synaptic_input(0.15)

    # Step all neurons
    n1.step(step)
    n2.step(step)
    n3.step(step)

    time += step

Ring Topology

# Create ring: n1 ↔ n2 ↔ n3 ↔ n1
n1 = create_hh_neuron(-70)
n2 = create_hh_neuron(-65)
n3 = create_hh_neuron(-60)

s12 = neun_py.ESynHHHHDouble(
    n1, neun_py.HHDoubleVariable.v,
    n2, neun_py.HHDoubleVariable.v,
    -0.002, -0.002
)

s23 = neun_py.ESynHHHHDouble(
    n2, neun_py.HHDoubleVariable.v,
    n3, neun_py.HHDoubleVariable.v,
    -0.002, -0.002
)

s31 = neun_py.ESynHHHHDouble(
    n3, neun_py.HHDoubleVariable.v,
    n1, neun_py.HHDoubleVariable.v,
    -0.002, -0.002
)

# Simulation
time = 0.0
while time < duration:
    s12.step(step)
    s23.step(step)
    s31.step(step)

    n1.step(step)
    n2.step(step)
    n3.step(step)

    time += step

All-to-All Topology

import neun_py

n_neurons = 4
neurons = [create_hh_neuron(-65 + i*5) for i in range(n_neurons)]

# Create all-to-all synapses
synapses = []
for i in range(n_neurons):
    for j in range(i+1, n_neurons):
        syn = neun_py.ESynHHHHDouble(
            neurons[i], neun_py.HHDoubleVariable.v,
            neurons[j], neun_py.HHDoubleVariable.v,
            -0.001, -0.001
        )
        synapses.append(syn)

# Simulation
step = 0.001
time = 0.0
while time < duration:
    # Step all synapses
    for syn in synapses:
        syn.step(step)

    # Step all neurons
    for neuron in neurons:
        neuron.add_synaptic_input(0.1)
        neuron.step(step)

    time += step

Heterogeneous Networks

Mixing Neuron Types

import neun_py

# Create different neuron types
hh_args = neun_py.HHDoubleConstructorArgs()
hr_args = neun_py.HRDoubleConstructorArgs()

hh_neuron = neun_py.HHDoubleRK4(hh_args)
hr_neuron = neun_py.HRDoubleRK4(hr_args)

# ... set parameters ...

# Connect different types with electrical synapse
syn_elec = neun_py.ESynHHHRDouble(
    hh_neuron, neun_py.HHDoubleVariable.v,
    hr_neuron, neun_py.HRDoubleVariable.x,
    -0.002, -0.002
)

# Or use chemical synapse (requires integrator)
syn_chem = neun_py.DSynHHHRDoubleRK4(
    hh_neuron, neun_py.HHDoubleVariable.v,
    hr_neuron, neun_py.HRDoubleVariable.x
)

Analysis Tools

Synchronization Measurement

import numpy as np

def measure_synchronization(v1_values, v2_values):
    """Measure correlation between two neurons"""
    v1 = np.array(v1_values)
    v2 = np.array(v2_values)
    correlation = np.corrcoef(v1, v2)[0, 1]
    return correlation

# After simulation
sync = measure_synchronization(n1_voltages, n2_voltages)
print(f"Synchronization: {sync:.3f}")

Phase Difference

def phase_difference(v1_values, v2_values):
    """Compute mean phase difference"""
    v1 = np.array(v1_values)
    v2 = np.array(v2_values)
    return np.mean(np.abs(v1 - v2))

# After simulation
phase_diff = phase_difference(n1_voltages, n2_voltages)
print(f"Mean phase difference: {phase_diff:.3f} mV")

Best Practices

Simulation Order

Always follow this order:

  1. Step all synapses
  2. Add external inputs
  3. Step all neurons
# Correct
syn1.step(step)
syn2.step(step)
n1.add_synaptic_input(0.1)
n2.add_synaptic_input(0.1)
n1.step(step)
n2.step(step)

Memory Efficiency

For large networks, use NumPy arrays:

import numpy as np

n_neurons = 100
n_steps = 100000

# Pre-allocate
voltages = np.zeros((n_neurons, n_steps))

for i in range(n_steps):
    # ... step synapses and neurons ...
    for j, neuron in enumerate(neurons):
        voltages[j, i] = neuron.get(neun_py.HHDoubleVariable.v)

Conductance Tuning

Start with weak coupling and increase:

conductances = [0.0001, 0.0005, 0.001, 0.005, 0.01]

for g in conductances:
    syn = neun_py.ESynHHHHDouble(
        n1, neun_py.HHDoubleVariable.v,
        n2, neun_py.HHDoubleVariable.v,
        -g, -g
    )
    # ... simulate and measure synchronization ...

See Also