Raster Strategies

Added in version 0.10.0.

A stimulator may not be able to drive every electrode at the same time. A Raster splits the electrode array into groups that take turns, limiting how much current has to be delivered at any one instant.

A raster is a scheduling constraint, not a stimulus by itself:

image / video -> Encoder -> electrical Stimulus
                     ^
                     |
                   Raster

The raster says which electrodes may pulse together. The Encoder decides when the pulses occur and what their amplitudes or frequencies are.

The usual workflow

Raster strategies are attached to an implant and are picked up automatically by an encoder:

import pulse2percept as p2p
from pulse2percept.units import uA, Hz

implant = p2p.implants.ArgusII()
implant.raster = p2p.implants.CheckerboardRaster(implant, n_groups=5)

encoder = p2p.stimuli.AmplitudeEncoder(
    implant, amp_range=(0, 50 * uA), freq=20 * Hz
)
implant.stim = encoder.encode(p2p.stimuli.BostonTrain())

Here the 60 electrodes are split into five groups. Electrodes within one group may pulse together, while different groups receive different time slots.

You can inspect the grouping directly:

implant.raster.plot(implant)
implant.raster.members(implant.electrode_names, 0)

Built-in strategies

pulse2percept provides three raster strategies:

Raster

Strategy

SequentialRaster

Split electrodes into sequential groups. On a regular grid this can reproduce a row or line raster.

CheckerboardRaster

Spread electrodes in each group as far apart as possible across a regular grid.

CustomRaster

Assign electrodes to groups explicitly.

A sequential raster is the simplest:

implant.raster = p2p.implants.SequentialRaster(n_groups=6)

For Argus II, whose electrodes are ordered row by row, SequentialRaster(6) puts one row in each group. Setting interleave=True instead distributes consecutive electrodes across different groups.

A checkerboard raster is usually more spatially distributed:

implant.raster = p2p.implants.CheckerboardRaster(implant, n_groups=5)

It derives the grouping from the electrode locations, so it works with square, rectangular, rotated, and hexagonal grids. The array must actually lie on a regular grid, and not every number of groups is possible for every geometry.

For complete control, specify the groups yourself:

corners = ['A1', 'A10', 'F1', 'F10']
rest = [e for e in implant.electrode_names if e not in corners]

implant.raster = p2p.implants.CustomRaster([corners, rest])

Every electrode must belong to exactly one group.

How the timing works

Groups take their turns one after another. The spacing between turns is the raster’s group_dur.

By default, group_dur=None. The encoder then spreads the groups evenly across the pulse period. For example, six groups driven at 20 Hz share the 50 ms period, so their slots begin one-sixth of a period apart.

You can instead specify the slot duration explicitly:

from pulse2percept.units import ms

raster = p2p.implants.SequentialRaster(
    n_groups=6, group_dur=1 * ms
)

This gives a 6 ms raster sweep: group 0 starts at 0 ms, group 1 at 1 ms, and so on.

The slot must be long enough to contain a pulse, and the whole sweep must fit within the relevant pulse period.

Amplitude versus frequency encoding

Rastering behaves differently depending on what the encoder modulates.

With AmplitudeEncoder, every electrode has the same pulse period. Their group offsets therefore remain fixed and cannot drift into one another. Rastering does not lower the requested pulse frequency in this case.

With FrequencyEncoder, electrodes can have different pulse periods. Those schedules would eventually drift into one another, so the encoder constrains differing periods to whole raster sweeps. Periods are always rounded up, never down, so rastering may make an electrode pulse more slowly than requested but never faster.

A shorter explicit group_dur produces a shorter sweep and therefore finer frequency resolution when this matters.

Choosing a strategy

For most simulations:

  • use SequentialRaster when you want a simple line, block, or interleaved schedule;

  • use CheckerboardRaster when you want simultaneously active electrodes spread across a regular array;

  • use CustomRaster when the hardware already defines the groups or you need a specific pattern.

If rastering is not part of the question you are studying, you can leave it unset. The encoder will then stimulate all electrodes on the same schedule.

Physical units

group_dur accepts either a bare number in milliseconds or a unitful quantity:

from pulse2percept.units import us

raster = p2p.implants.SequentialRaster(
    n_groups=6, group_dur=1000 * us
)

See Physical Units for the full units convention.