# 3.7. Specific Populations¶

ANNarchy provides a set of predefined Population objects to ease the definition of standard networks.

## 3.7.1. Class PoissonPopulation¶

class ANNarchy.PoissonPopulation(geometry, name=None, rates=None, target=None, parameters=None, refractory=None, copied=False)[source]

Population of spiking neurons following a Poisson distribution.

Case 1: Input population

Each neuron of the population will randomly emit spikes, with a mean firing rate defined by the rates argument.

The mean firing rate in Hz can be a fixed value for all neurons:

pop = PoissonPopulation(geometry=100, rates=100.0)


but it can be modified later as a normal parameter:

pop.rates = np.linspace(10, 150, 100)


It is also possible to define a temporal equation for the rates, by passing a string to the argument:

pop = PoissonPopulation(geometry=100, rates="100.0 * (1.0 + sin(2*pi*t/1000.0) )/2.0")


The syntax of this equation follows the same structure as neural variables.

It is also possible to add parameters to the population which can be used in the equation of rates:

pop = PoissonPopulation(
geometry=100,
parameters = '''
amp = 100.0
frequency = 1.0
''',
rates="amp * (1.0 + sin(2*pi*frequency*t/1000.0) )/2.0"
)


Note

The preceding definition is fully equivalent to the definition of this neuron:

poisson = Neuron(
parameters = '''
amp = 100.0
frequency = 1.0
''',
equations = '''
rates = amp * (1.0 + sin(2*pi*frequency*t/1000.0) )/2.0
p = Uniform(0.0, 1.0) * 1000.0 / dt
''',
spike = '''
p < rates
'''
)


The refractory period can also be set, so that a neuron can not emit two spikes too close from each other.

Case 2: Hybrid population

If the rates argument is not set, the population can be used as an interface from a rate-coded population.

The target argument specifies which incoming projections will be summed to determine the instantaneous firing rate of each neuron.

See the example in examples/hybrid/Hybrid.py for a usage.

Parameters: geometry – population geometry as tuple. name – unique name of the population (optional). rates – mean firing rate of each neuron. It can be a single value (e.g. 10.0) or an equation (as string). target – the mean firing rate will be the weighted sum of inputs having this target name (e.g. “exc”). parameters – additional parameters which can be used in the rates equation. refractory – refractory period in ms.

## 3.7.2. Class SpikeSourceArray¶

class ANNarchy.SpikeSourceArray(spike_times, name=None, copied=False)[source]

Spike source generating spikes at the times given in the spike_times array.

Depending on the initial array provided, the population will have one or several neurons, but the geometry can only be one-dimensional.

Parameters: spike_times – a list of times at which a spike should be emitted if the population should have only 1 neuron, a list of lists otherwise. Times are defined in milliseconds, and will be rounded to the closest multiple of the discretization time step dt. name – optional name for the population.

You can later modify the spike_times attribute of the population, but it must have the same number of neurons as the initial one.

The spike times are by default relative to the start of a simulation (ANNarchy.get_time() is 0.0). If you call the reset() method of a SpikeSourceArray, this will set the spike times relative to the current time. You can then repeat a stimulation many times.

# 2 neurons firing at 100Hz with a 1 ms delay
times = [
[ 10, 20, 30, 40],
[ 11, 21, 31, 41]
]
inp = SpikeSourceArray(spike_times=times)

compile()

# Spikes at 10/11, 20/21, etc
simulate(50)

# Reset the internal time of the SpikeSourceArray
inp.reset()

# Spikes at 60/61, 70/71, etc
simulate(50)


## 3.7.3. Class TimedArray¶

class ANNarchy.TimedArray(rates, schedule=0.0, period=-1.0, name=None, copied=False)[source]

Data structure holding sequential inputs for a rate-coded network.

Parameters: rates – array of firing rates. The first axis corresponds to time, the others to the desired dimensions of the population. schedule – either a single value or a list of time points where inputs should be set. Default: every timestep. period – time when the timed array will be reset and start again, allowing cycling over the inputs. Default: no cycling (-1.).

The input values are stored in the (recordable) attribute r, without any further processing. You will need to connect this population to another one using the connect_one_to_one() method.

By default, the firing rate of this population will iterate over the different values step by step:

inputs = np.array(
[
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 1, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 1]
]
)

inp = TimedArray(rates=inputs)

pop = Population(10, ...)

proj = Projection(inp, pop, 'exc')
proj.connect_one_to_one(1.0)

compile()

simulate(10.)


This creates a population of 10 neurons whose activity will change during the first 10*dt milliseconds of the simulation. After that delay, the last input will be kept (i.e. 1 for the last neuron).

If you want the TimedArray to “loop” over the different input vectors, you can specify a period for the inputs:

inp = TimedArray(rates=inputs, period=10.)


If the period is smaller than the length of the rates, the last inputs will not be set.

If you do not want the inputs to be set at every step, but every 10 ms for example, youcan use the schedule argument:

inp = TimedArray(rates=inputs, schedule=10.)


The input [1, 0, 0,…] will stay for 10 ms, then[0, 1, 0, …] for the next 10 ms, etc…

If you need a less regular schedule, you can specify it as a list of times:

inp = TimedArray(rates=inputs, schedule=[10., 20., 50., 60., 100., 110.])


The first input is set at t = 10 ms (r = 0.0 in the first 10 ms), the second at t = 20 ms, the third at t = 50 ms, etc.

If you specify less times than in the array of rates, the last ones will be ignored.

Scheduling can be combined with periodic cycling. Note that you can use the reset() method to manually reinitialize the TimedArray, times becoming relative to that call:

simulate(100.) # ten inputs are shown with a schedule of 10 ms
inp.reset()
simulate(100.) # the same ten inputs are presented again.


## 3.7.4. Class HomogeneousCorrelatedSpikeTrains¶

class ANNarchy.HomogeneousCorrelatedSpikeTrains(geometry, rates, corr, tau, name=None, refractory=None, copied=False)[source]

Population of spiking neurons following a homogeneous distribution with correlated spike trains.

The method describing the generation of homogeneous correlated spike trains is described in:

Brette, R. (2009). Generation of correlated spike trains. <http://audition.ens.fr/brette/papers/Brette2008NC.html>

The implementation is based on the one provided by Brian.

To generate correlated spike trains, the population rate of the group of Poisson-like spiking neurons varies following a stochastic differential equation:

$dx/dt = (mu - x)/tau + sigma * Xi / sqrt(tau)$

where Xi is a random variable. Basically, x will randomly vary around mu over time, with an amplitude determined by sigma and a speed determined by tau.

This doubly stochastic process is called a Cox process or Ornstein-Uhlenbeck process.

To avoid that x becomes negative, the values of mu and sigma are computed from a rectified Gaussian distribution, parameterized by the desired population rate rates, the desired correlation strength corr and the time constant tau. See Brette’s paper for details.

In short, you should only define the parameters rates, corr and tau, and let the class compute mu and sigma for you. Changing rates, corr or tau after initialization automatically recomputes mu and sigma.

Example:

from ANNarchy import *
setup(dt=0.1)

pop_poisson = PoissonPopulation(200, rates=10.)
pop_corr    = HomogeneousCorrelatedSpikeTrains(200, rates=10., corr=0.3, tau=10.)

compile()

simulate(1000.)

pop_poisson.rates=30.
pop_corr.rates=30.

simulate(1000.)

Parameters: geometry – population geometry as tuple. rates – rate in Hz of the population (must be a positive float) corr – total correlation strength (float in [0, 1]) tau – correlation time constant in ms. name – unique name of the population (optional). refractory – refractory period in ms (careful: may break the correlation)

## 3.7.5. Class ImagePopulation¶

class ANNarchy.extensions.image.ImagePopulation(geometry, name=None, copied=False)[source]

Specific rate-coded Population allowing to represent images (png, jpg…) as the firing rate of a population (each neuron represents one pixel).

This extension requires the Python Image Library (pip install Pillow).

Usage:

from ANNarchy import *
from ANNarchy.extensions.image import ImagePopulation

pop = ImagePopulation(geometry=(480, 640))
pop.set_image('image.jpg')

Parameters: geometry – population geometry as tuple. It must correspond to the image size and be fixed through the whole simulation. name – unique name of the population (optional).

• If the geometry is 2D, it corresponds to the (height, width) of the image. Only the luminance of the pixels will be represented (grayscale image).
• If the geometry is 3D, the third dimension can be either 1 (grayscale) or 3 (color).

If the third dimension is 3, each will correspond to the RGB values of the pixels.

Warning

Due to the indexing system of Numpy, a 640*480 image should be fed into a (480, 640) or (480, 640, 3) population.

set_image(image_name)[source]

Sets an image (.png, .jpg or whatever is supported by PIL) into the firing rate of the population.

If the image has a different size from the population, it will be resized.

## 3.7.6. Class VideoPopulation¶

class ANNarchy.extensions.image.VideoPopulation(geometry, opencv_version='4', name=None, copied=False)[source]

Specific rate-coded Population allowing to feed a webcam input into the firing rate of a population (each neuron represents one pixel).

This extension requires the C++ library OpenCV >= 4.0 (apt-get/yum install opencv). pkg-config opencv4 --cflags --libs should not return an error. vtk might additionally have to be installed.

Usage:

from ANNarchy import *
from ANNarchy.extensions.image import VideoPopulation

pop = VideoPopulation(geometry=(480, 640))

compile()

pop.start_camera(0)

while(True):
pop.grab_image()
simulate(10.0)

Parameters: geometry – population geometry as tuple. It must be fixed through the whole simulation. If the camera provides images of a different size, it will be resized. opencv_version – OpenCV version (default: 4). name – unique name of the population (optional).

• If the geometry is 2D, it corresponds to the (height, width) of the image. Only the luminance of the pixels will be represented (grayscale image).
• If the geometry is 3D, the third dimension can be either 1 (grayscale) or 3 (color).

If the third dimension is 3, each will correspond to the RGB values of the pixels.

Warning

Due to the indexing system of Numpy, a 640*480 image should be fed into a (480, 640) or (480, 640, 3) population.

grab_image()[source]

Grabs one image from the camera and feeds it into the population.

The camera must be first started with:

>>> pop.start_camera(0)

release()[source]

Releases the camera

>>> pop.release

start_camera(camera_port=0)[source]

Starts the webcam with the corresponding device (default = 0).

On linux, the camera port corresponds to the number in /dev/video0, /dev/video1, etc.