Note

Go to the end to download the full example code.

# Mean-field theory for random balanced network¶

Run this example as a Jupyter notebook:

See our guide for more information and troubleshooting.

This script performs a mean-field analysis of the spiking network of
excitatory and an inhibitory population of leaky-integrate-and-fire neurons
simulated in `brunel_delta_nest.py`

. We refer to this spiking network of LIF
neurons with ‘SLIFN’.

The self-consistent equation for the population-averaged firing rates (eq.27 in [1], [2]) is solved by integrating a pseudo-time dynamics (eq.30 in [1]). The latter constitutes a network of rate neurons, which is simulated here. The asymptotic rates, i.e., the fixed points of the dynamics (eq.30), are the prediction for the population and time-averaged from the spiking simulation.

## References¶

```
import nest
import numpy
nest.ResetKernel()
```

Assigning the simulation parameters to variables.

```
dt = 0.1 # the resolution in ms
simtime = 50.0 # Simulation time in ms
```

Definition of the network parameters in the SLIFN

```
g = 5.0 # ratio inhibitory weight/excitatory weight
eta = 2.0 # external rate relative to threshold rate
epsilon = 0.1 # connection probability
```

Definition of the number of neurons and connections in the SLIFN, needed for the connection strength in the Siegert neuron network

```
order = 2500
NE = 4 * order # number of excitatory neurons
NI = 1 * order # number of inhibitory neurons
CE = int(epsilon * NE) # number of excitatory synapses per neuron
CI = int(epsilon * NI) # number of inhibitory synapses per neuron
C_tot = int(CI + CE) # total number of synapses per neuron
```

Initialization of the parameters of the Siegert neuron and the connection strength. The parameter are equivalent to the LIF-neurons in the SLIFN.

```
tauMem = 20.0 # time constant of membrane potential in ms
theta = 20.0 # membrane threshold potential in mV
neuron_params = {
"tau_m": tauMem,
"t_ref": 2.0,
"theta": theta,
"V_reset": 0.0,
}
J = 0.1 # postsynaptic amplitude in mV in the SLIFN
J_ex = J # amplitude of excitatory postsynaptic potential
J_in = -g * J_ex # amplitude of inhibitory postsynaptic potential
# drift_factor in diffusion connections (see [1], eq. 28) for external
# drive, excitatory and inhibitory neurons
drift_factor_ext = tauMem * 1e-3 * J_ex
drift_factor_ex = tauMem * 1e-3 * CE * J_ex
drift_factor_in = tauMem * 1e-3 * CI * J_in
# diffusion_factor for diffusion connections (see [1], eq. 29)
diffusion_factor_ext = tauMem * 1e-3 * J_ex**2
diffusion_factor_ex = tauMem * 1e-3 * CE * J_ex**2
diffusion_factor_in = tauMem * 1e-3 * CI * J_in**2
```

External drive, this is equivalent to the drive in the SLIFN

```
nu_th = theta / (J * CE * tauMem)
nu_ex = eta * nu_th
p_rate = 1000.0 * nu_ex * CE
```

Configuration of the simulation kernel by the previously defined time
resolution used in the simulation. Setting `print_time`

to True prints the
already processed simulation time as well as its percentage of the total
simulation time.

```
nest.resolution = dt
nest.print_time = True
nest.overwrite_files = True
print("Building network")
```

Creation of the nodes using `Create`

. One rate neuron represents the
excitatory population of LIF-neurons in the SLIFN and one the inhibitory
population assuming homogeneity of the populations.

```
siegert_ex = nest.Create("siegert_neuron", params=neuron_params)
siegert_in = nest.Create("siegert_neuron", params=neuron_params)
```

The Poisson drive in the SLIFN is replaced by a driving rate neuron,
which does not receive input from other neurons. The activity of the rate
neuron is controlled by setting `mean`

to the rate of the corresponding
poisson generator in the SLIFN.

```
siegert_drive = nest.Create("siegert_neuron", params={"mean": p_rate})
```

To record from the rate neurons a multimeter is created and the parameter
`record_from`

is set to rate as well as the recording interval to dt

```
multimeter = nest.Create("multimeter", params={"record_from": ["rate"], "interval": dt})
```

Connections between `Siegert neurons`

are realized with the synapse model
`diffusion_connection`

. These two parameters reflect the prefactors in
front of the rate variable in eq. 27-29 in [1].

Connections originating from the driving neuron

```
syn_dict = {
"drift_factor": drift_factor_ext,
"diffusion_factor": diffusion_factor_ext,
"synapse_model": "diffusion_connection",
}
nest.Connect(siegert_drive, siegert_ex + siegert_in, "all_to_all", syn_dict)
nest.Connect(multimeter, siegert_ex + siegert_in)
```

Connections originating from the excitatory neuron

```
syn_dict = {
"drift_factor": drift_factor_ex,
"diffusion_factor": diffusion_factor_ex,
"synapse_model": "diffusion_connection",
}
nest.Connect(siegert_ex, siegert_ex + siegert_in, "all_to_all", syn_dict)
```

Connections originating from the inhibitory neuron

```
syn_dict = {
"drift_factor": drift_factor_in,
"diffusion_factor": diffusion_factor_in,
"synapse_model": "diffusion_connection",
}
nest.Connect(siegert_in, siegert_ex + siegert_in, "all_to_all", syn_dict)
```

Simulate the network

```
nest.Simulate(simtime)
```

Analyze the activity data. The asymptotic rate of the Siegert neuron
corresponds to the population- and time-averaged activity in the SLIFN.
For the symmetric network setup used here, the excitatory and inhibitory
rates are identical. For comparison execute the example `brunel_delta_nest.py`

.

```
data = multimeter.events
rates_ex = data["rate"][numpy.where(data["senders"] == siegert_ex.global_id)]
rates_in = data["rate"][numpy.where(data["senders"] == siegert_in.global_id)]
times = data["times"][numpy.where(data["senders"] == siegert_in.global_id)]
print(f"Excitatory rate : {rates_ex[-1]:.2f} Hz")
print(f"Inhibitory rate : {rates_in[-1]:.2f} Hz")
```