utils.signals

Utility classes and functions for artificial signal generation.

class utils.signals.Wave(amplitudes: Tensor, frequencies: Tensor, phase_shifts: Tensor, phase_amplitude_coupling: Tensor = None, baseline_shift: Tensor = None, sampling_rate: float = 1000.0, device: str = 'cpu')

Waves are iterables that produce the next value of a specified combination of sine waves, as needed. This allows for the generation of arbitrary waveforms with no concern for memory usage.

Supports basic phase-amplitude coupling as well as phase shifting frequency components with respect to each other.

Parameters:
  • amplitudes (Tensor) – Amplitudes of each frequency component, in arbitrary units.

  • frequencies (Tensor) – Sine component frequencies, in Hz.

  • phase_shifts (Tensor) – Starting phase of each frequency component, to be multiplied by np.pi.

  • phase_amplitude_coupling (Tensor, optional) – Frequency of variations in amplitude of each component, if such coupling is desired. Defaults to None.

  • baseline_shift (Tensor, optional) – Value by which to shift the entire signal (on the y-axis).

  • sampling_rate (int, optional) – Sampling rate in Hz. Defaults to 1000.0 / DT (simulation time step).

  • device (str, optional) – Specifies a hardware device on which to process tensors, e.g. “cuda:0”. Defaults to “cpu”.

See also

OscillatorNeuron

An analog neuron that uses a Wave iterator to generate its output.

Example

Define a fast oscillation amplitude-coupled to the phase of a slower oscillation, maxing out at its trough:

>>> sampling_rate = 1000
>>> amplitudes = torch.tensor([0.1, 1.0])
>>> frequencies = torch.tensor([50.0, 5.0])
>>> phase_shifts = torch.tensor([torch.pi, 0.0])
>>> phase_amplitude_coupling = torch.tensor([frequencies[1], 0.0])

Prepare a signal based on the above parameters:

>>> signal = Wave(amplitudes=amplitudes, frequencies=frequencies, phase_shifts = phase_shifts,
... phase_amplitude_coupling=phase_amplitude_coupling, sampling_rate=sampling_rate)

Generate and plot two seconds of the signal:

>>> import matplotlib.pyplot as plt
>>> values = [next(signal) for _ in range(sampling_rate * 2)]
>>> fig = plt.plot(torch.tensor(values))
>>> plt.show()
class utils.signals.WaveIterable(wave)

Implicit iterator returned by the Wave iterable.

I.e. when you do iter(wave) or for x in wave:... it implicitly creates an instance of this class and uses it to iterate over.

Parameters:

wave (Wave:) – The wave class that will be iterated over.

utils.signals.extend_input_current(blueprint: Tensor, num_steps: int, num_units: int, device: str = 'cpu', mode: str = 'smear') Tensor

Accepts a tensor of values blueprint and either smears or repeats it, depending on mode.

Convenience function for generating a dummy input current from a blueprint. That is to say, the user provides the desired shape of the current time series and specifies how to extend it.

For instance, if mode is “smear”, [0, 1, 0, 2] will be extended to [0, 0, 1, 1, 0, 0, 2, 2, …] to fit the requested duration in simulation step units, num_steps. If mode is “repeat”, [0, 1, 0, 2] will be extended to [0, 1, 0, 2, 0, 1, 0, 2, …].

Parameters:
  • blueprint (Tensor) – Input current values to be extended (typically given under simulation/current in the configuration YAML).

  • num_steps (int) – Length of current to be generated, equal to the number of simulation steps. This is also the number of columns in the returned tensor.

  • num_units (int) – Number of neurons (tensor elements) in the ensemble that will receive the generated current. This is also the number of rows in the returned tensor.

  • device (str, optional) – Specifies a hardware device on which to register PyTorch buffer fields, e.g. “cuda:0”. Defaults to “cpu”.

  • mode (str, optional) – Whether to “smear” the given blueprint or “repeat” it (as in np.tile).

Returns:

The generated current, given as a tensor whose columns are its values at each time point (ensemble elements correspond to rows).

Return type:

Tensor

Examples

>>> extend_input_current(blueprint=torch.tensor([0, 1, 1, 0]), num_steps=8, num_units=2, mode="smear")
tensor([[0., 0., 1., 1., 1., 1., 0., 0.],
        [0., 0., 1., 1., 1., 1., 0., 0.]])
>>> extend_input_current(blueprint=torch.tensor([0, 1, 1, 0]), num_steps=8, num_units=2, mode="repeat")
tensor([[0., 1., 1., 0., 0., 1., 1., 0.],
        [0., 1., 1., 0., 0., 1., 1., 0.]])

Note

Providing a nonsensical num_steps (shorter than or not divisible by the length of the blueprint) will result in truncating or extending the output to the nearest integer multiple of the blueprint length.

Warning

The present implementation supports duplication of the current time series to accommodate multiple units. SimpleSimulator uses this function to support sending varying dummy currents to different ensemble elements.

Note, however, that these mechanisms are better suited for data.synthesis and will be implemented there in a principled manner. This utility function may be deprecated or moved.