diff --git a/models/pulsepacket_generator.h b/models/pulsepacket_generator.h
index ddb6af7acb..dd24824324 100644
--- a/models/pulsepacket_generator.h
+++ b/models/pulsepacket_generator.h
@@ -48,14 +48,13 @@ Generate sequence of Gaussian pulse packets
Description
+++++++++++
-The pulsepacket_generator produces a spike train contains Gaussian pulse
-packets centered about given times. A Gaussian pulse packet is
-a given number of spikes with normal distributed random displacements
-from the center time of the pulse.
-It resembles the output of synfire groups of neurons.
+The ``pulsepacket_generator`` produces a spike train contains Gaussian pulse
+packets centered about given times. A Gaussian pulse packet is a given
+number of spikes with normal distributed random displacements from the center
+time of the pulse. It resembles the output of synfire groups of neurons.
- All targets receive identical spike trains.
-- New pulse packets are generated when activity or sdev are changed.
+- New pulse packets are generated when activity or ``sdev`` are changed.
- Gaussian pulse are independently generated for each given
pulse-center time.
- Both standard deviation and number of spikes may be set at any time.
@@ -64,13 +63,13 @@ It resembles the output of synfire groups of neurons.
.. include:: ../models/stimulation_device.rst
pulse_times
- Times of the centers of pulses (ms)
+ List of times of the centers of pulses in ms.
activity
- Number of spikes per pulse
+ Number of spikes per pulse. Default: ``0``.
sdev
- Standard deviation of spike times in each pulse (ms)
+ Standard deviation of spike times in each pulse in ms. Default: ``0.0``.
Setting parameters from a stimulation backend
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
diff --git a/nestkernel/stimulation_device.h b/nestkernel/stimulation_device.h
index ac3b40f6e9..512ebb9cb8 100644
--- a/nestkernel/stimulation_device.h
+++ b/nestkernel/stimulation_device.h
@@ -48,14 +48,15 @@ global offset that shifts the stimulation period. All three values are
set as times in ms.
- For spike-emitting devices, only spikes with times `t` that fulfill
- `start` < `t` <= `stop` are emitted. Spikes that have timestamp of
- `t` = `start` are not emitted.
+ :math:`\mathrm{start} < t \leq \mathrm{stop}` are emitted. Spikes
+ that have timestamp of :math:`t = \mathrm{start}` are not emitted.
- For current-emitting devices, the current is activated and
deactivated such that the current first affects the target dynamics
- during the update step (start, start+h], i.e., an effect can be
- recorded at the earliest at time start+h. The last interval during
- which the current affects the target's dynamics is (stop-h, stop].
+ during the update step :math:`(\mathrm{start}, \mathrm{start}+h]`,
+ that is, an effect can be recorded at the earliest at time
+ :math:`\mathrm{start}+h`. The last interval during which the current
+ affects the target's dynamics is :math:`(\textrm{stop}-h, \textrm{stop}]`.
The property ``stimulus_source`` defaults to an empty string. It can
be set to the name of a stimulation backend, in which case it will
@@ -68,28 +69,28 @@ Parameters
++++++++++
label
- A string (default: `""`) specifying an arbitrary textual label for
- the device. Stimulation backends might use the label to generate
- device specific identifiers like filenames and such.
+ A string specifying an arbitrary textual label for the device.
+ Stimulation backends might use the label to generate device specific
+ identifiers like filenames and such. Default: ``""``.
origin
- A positive floating point number (default : `0.0`) used as the
- reference time in ms for `start` and `stop`.
+ A positive floating point number used as the reference time in ms
+ for ``start`` and ``stop``. Default: ``0.0``.
start
- A positive floating point number (default: `0.0`) specifying the
- activation time in ms, relative to `origin`.
+ A positive floating point number specifying the activation time in ms,
+ relative to ``origin``. Default: ``0.0``.
stimulus_source
- A string (default: `""`) specifying the name of the stimulation
- backend from which to get the data for updating the stimulus
- parameters of the device. By default the device uses its
- internally stored parameters for updating the stimulus.
+ A string specifying the name of the stimulation backend from which to
+ get the data for updating the stimulus parameters of the device.
+ By default, the device uses its internally stored parameters for updating
+ the stimulus. Default: ``""``.
stop
- A floating point number (default: `infinity`) specifying the
- deactivation time in ms, relative to `origin`. The value of `stop`
- must be greater than or equal to `start`.
+ A floating point number specifying the deactivation time in ms, relative
+ to ``origin``. The value of ``stop`` must be greater than or equal to
+ ``start``. Default: ``infinity``.
EndUserDocs */
diff --git a/testsuite/pytests/sli2py_stimulating/test_pulsepacket_generator.py b/testsuite/pytests/sli2py_stimulating/test_pulsepacket_generator.py
new file mode 100644
index 0000000000..120d081639
--- /dev/null
+++ b/testsuite/pytests/sli2py_stimulating/test_pulsepacket_generator.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+#
+# test_pulsepacket_generator.py
+#
+# This file is part of NEST.
+#
+# Copyright (C) 2004 The NEST Initiative
+#
+# NEST is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 2 of the License, or
+# (at your option) any later version.
+#
+# NEST is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with NEST. If not, see .
+
+"""
+Test parameter setting and correct number of spikes emitted by `pulsepacket_generator`.
+"""
+
+import numpy as np
+import pandas as pd
+import pandas.testing as pdtest
+import pytest
+
+import nest
+
+
+@pytest.fixture(autouse=True)
+def reset():
+ nest.ResetKernel()
+
+
+def test_set_params_on_instance_and_model():
+ """
+ Test setting `pulsepacket_generator` parameters on instance and model.
+ """
+
+ params = {"pulse_times": [1.0, 2.5, 4.6], "activity": 150, "sdev": 0.1234}
+
+ # Set params on instance
+ ppg1 = nest.Create("pulsepacket_generator")
+ ppg1.set(params)
+
+ # Set params on model
+ nest.SetDefaults("pulsepacket_generator", params)
+ ppg2 = nest.Create("pulsepacket_generator")
+
+ # Verify that both ways to set params give same result
+ df_pgg1 = pd.DataFrame.from_dict(ppg1.get(params.keys()))
+ df_pgg2 = pd.DataFrame.from_dict(ppg2.get(params.keys()))
+ pdtest.assert_frame_equal(df_pgg1, df_pgg2)
+
+
+@pytest.mark.parametrize("params", [{"sdev": -5.0}, {"activity": -5}])
+def test_set_illegal_values(params):
+ """
+ Test that an error is raised if `sdev` or `activity` is set to negative value.
+ """
+
+ with pytest.raises(nest.kernel.NESTErrors.BadProperty):
+ nest.SetDefaults("pulsepacket_generator", params)
+
+
+def test_valid_to_pass_empty_pulse_times():
+ """
+ Assure that a `pulsepacket_generator` with empty `pulse_times` can be simulated.
+ """
+
+ params = {"pulse_times": [], "activity": 0, "sdev": 0.0}
+ ppg = nest.Create("pulsepacket_generator")
+ ppg.set(params)
+ nest.Simulate(1.0)
+
+
+def test_number_of_spikes():
+ """
+ Test that `pulsepacket_generator` emits expected number of spikes.
+
+ The test builds and simulates a system with `pulsepacket_generator`
+ connected to a `spike_recorder`. The test checks the number of
+ recorded spikes against our expectation.
+ """
+
+ nest.resolution = 0.1
+
+ tstart = 75.0
+ tstop = 225.0
+ nspk = 10
+ pulset = np.array([10.0, 125.0, 175.0, 275.0])
+ stddev = 5.0
+
+ # Find number of pulse centers in [tstart, tstop]
+ npulseff = np.count_nonzero(np.logical_and(pulset >= tstart, pulset <= tstop))
+
+ # Since tstart, tstop are far from pulse times, it is highly likely that
+ # only spikes belonging to the pulses with centers in [tstart, tstop] are
+ # fired and then we get for the total spike number
+ npsktot = nspk * npulseff
+
+ # Build and simulate system
+ params = {
+ "start": tstart,
+ "stop": tstop,
+ "pulse_times": pulset,
+ "activity": nspk,
+ "sdev": stddev,
+ }
+ ppg = nest.Create("pulsepacket_generator", params)
+ sr = nest.Create("spike_recorder")
+
+ nest.Connect(ppg, sr)
+
+ nest.Simulate(300.0)
+
+ actual_spikes = sr.events["times"]
+
+ # Check that min and max are inside [tstart, tstop]
+ assert np.min(actual_spikes) >= tstart
+ assert np.max(actual_spikes) <= tstop
+
+ # Check number of spikes
+ assert actual_spikes.size == npsktot
diff --git a/testsuite/unittests/test_pulsepacket_generator.sli b/testsuite/unittests/test_pulsepacket_generator.sli
deleted file mode 100644
index f67c9e50f7..0000000000
--- a/testsuite/unittests/test_pulsepacket_generator.sli
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * test_pulsepacket_generator.sli
- *
- * This file is part of NEST.
- *
- * Copyright (C) 2004 The NEST Initiative
- *
- * NEST is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 2 of the License, or
- * (at your option) any later version.
- *
- * NEST is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with NEST. If not, see .
- *
- */
-
-
- /** @BeginDocumentation
-Name: testsuite::test_pulsepacket_generator - minimal test of pulsepacket_generator
-
-Synopsis: (test_pulsepacket_generator) run -> dies if assertion fails
-
-Description:
-Tests parameter setting and statistical correctness for one application.
-
-Author: July 2008, Plesser
-SeeAlso: noise_generator, testsuite::test_poisson_ps_min_interval
-*/
-
-(unittest) run
-/unittest using
-
-% flatten arrays that may contain vectors and numbers
-/allflat {
- { { cva } stopped { ; errordict begin /newerror false def end } if } Map
- Flatten
-} def
-
-% First test: parameter setting on model and instance
-{
- ResetKernel
- /tdict << /pulse_times [ 1.0 2.5 4.6 ]
- /activity 150
- /sdev 0.1234 >> def
-
- /ng1 /pulsepacket_generator Create def
- ng1 tdict SetStatus
-
- /pulsepacket_generator tdict SetDefaults
- /ng2 /pulsepacket_generator Create def
-
- ng1 [tdict keys] get allflat
- ng2 [tdict keys] get allflat
- eq
-} assert_or_die
-clear
-ResetKernel
-
-% Second test: error if sdev negative
-{
- ResetKernel
- /pulsepacket_generator << /sdev -0.5 >> SetDefaults
-} fail_or_die
-
-% Third test: error if activity negative
-{
- ResetKernel
- /pulsepacket_generator << /activity -5 >> SetDefaults
-} fail_or_die
-
-% Fourth test: assure empty pulse times and zero otherwise is ok
-{
- ResetKernel
- /pulsepacket_generator Create
- << /pulse_times [] /activity 0 /sdev 0.0 >> SetStatus
- 1 Simulate
-} pass_or_die
-
-% Fifth test: feed spike recorder
-{
- ResetKernel
- << /resolution 0.1 >> SetKernelStatus
- /ppg /pulsepacket_generator Create def
- /sr /spike_recorder Create def
-
- /tstart 75.0 def
- /tstop 225.0 def
- /nspk 10 def
- /pulset [ 10.0 125.0 175.0 275.0 ] def
- /stddev 5.0 def
- % find number of pulse centers in start..stop
- /npulseff
- 0 pulset { dup tstart gt exch tstop lt and { 1 } { 0 } ifelse add } Fold
- def
- % since start, stop are far from pulse times, it is highly likely that
- % only spikes belonging to the pulses with centers in start..stop are
- % fired and then we get for the total spike number
- /nspktot nspk npulseff mul def
-
- ppg << /start tstart
- /stop tstop
- /pulse_times pulset
- /activity nspk
- /sdev stddev
- >> SetStatus
-
- ppg sr Connect
-
- 300 Simulate
-
- sr [ /events /times ] get cva /spks Set
-
- % check min and max are inside start .. stop
- tstart spks Min leq
- spks Max tstop leq and
-
- % check number of spikes
- spks length nspktot eq
- and
-
-} assert_or_die
-
-endusing