/*
* ppd_sup_generator.h
*
* 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 <http://www.gnu.org/licenses/>.
*
*/
#ifndef ppd_sup_generator_H
#define ppd_sup_generator_H
#include <vector>
#include "nest.h"
#include "event.h"
#include "node.h"
#include "stimulating_device.h"
#include "scheduler.h"
#include "binomial_randomdev.h"
#include "poisson_randomdev.h"
#include "connection.h"
/*BeginDocumentation
Name: ppd_sup_generator - simulate the superimposed spike train of a population of Poisson processes with dead time.
Description:
The ppd_sup_generator generator simulates the pooled spike train of a
population of neurons firing independently with Poisson process with dead
time statistics.
The rate parameter can also be sine-modulated. The generator does not
initialize to equilibrium in this case, initial transients might occur.
Parameters:
The following parameters appear in the element's status dictionary:
rate - mean firing rate of the component processes. (double, var)
dead_time - minimal time between two spikes of the component processes. (double, var)
n_proc - number of superimposed independent component processes. (long, var)
frequency - rate modulation frequency. (double, var)
amplitude - relative rate modulation amplitude. (double, var)
Note:
The generator has been published in Deger, Helias, Boucsein, Rotter (2011)
Statistical properties of superimposed stationary spike trains,
Journal of Computational Neuroscience.
URL: http://www.springerlink.com/content/u75211r381p08301/
DOI: 10.1007/s10827-011-0362-8
Authors:
June 2009, Moritz Deger, Moritz Helias
SeeAlso: gamma_sup_generator, poisson_generator_ps, spike_generator, Device, StimulatingDevice
*/
namespace nest{
/**
* Generator of the spike output of a population of Poisson processes with dead time.
*
* This Poisson process with dead time superposition generator sends different spike
* trains to all its targets.
*
* @ingroup Devices
*/
class ppd_sup_generator: public Node
{
public:
typedef Node base;
ppd_sup_generator();
ppd_sup_generator(const ppd_sup_generator&);
bool has_proxies() const {return false;}
bool is_off_grid() const {return false;} // does not use off_grid events
using Node::event_hook;
port check_connection(Connection&, port);
void get_status(DictionaryDatum &) const;
void set_status(const DictionaryDatum &);
private:
void init_state_(const Node&);
void init_buffers_();
void calibrate();
/**
* Update state.
* Update cannot send spikes directly, since we need to identify each
* target to know the age distribution of the component processes.
* Since target information is in the Connectors, we send a DSSpikeEvent
* to all targets, which is reflected to this->event_hook() with target
* information.
* @see event_hook, DSSpikeEvent
*/
void update(Time const &, const long_t, const long_t);
/**
* Send out spikes.
* Called once per target to dispatch actual output spikes.
* @param contains target information.
*/
void event_hook(DSSpikeEvent&);
// ------------------------------------------------------------
/**
* Store independent parameters of the model.
*/
struct Parameters_ {
double_t rate_; //!< process rate [Hz]
double_t dead_time_; //!< dead time [ms]
ulong_t n_proc_; //!< number of component processes
double_t frequency_; //!< rate modulation frequency [Hz]
double_t amplitude_; //!< rate modulation amplitude [Hz]
/**
* Number of targets.
* This is a hidden parameter; must be placed in parameters,
* even though it is an implementation detail, since it
* concerns the connections and must not be affected by resets.
*/
size_t num_targets_;
Parameters_(); //!< Sets default parameter values
void get(DictionaryDatum&) const; //!< Store current values in dictionary
void set(const DictionaryDatum&); //!< Set values from dicitonary
};
// ------------------------------------------------------------
class Age_distribution_ {
librandom::BinomialRandomDev bino_dev_; //!< random deviate generator
librandom::PoissonRandomDev poisson_dev_; //!< random deviate generator
std::vector<ulong_t> occ_refractory_; //!< occupation numbers of ages below dead time
ulong_t occ_active_; //!< summed occupation number of ages above dead time
size_t activate_; //!< rotating pointer
public:
Age_distribution_(size_t num_age_bins, ulong_t ini_occ_ref, ulong_t ini_occ_act); //!< initialize age dist
ulong_t update(double_t hazard_rate, librandom::RngPtr rng); //!< update age dist and generate spikes
};
struct Buffers_ {
/**
* Age distribution of component Poisson processes with dead time of the superposition.
*/
std::vector<Age_distribution_> age_distributions_;
};
// ------------------------------------------------------------
struct Variables_ {
double_t hazard_step_; //!< base hazard rate in units of time step
double_t hazard_step_t_; //!< hazard rate at time t in units of time step
double_t omega_; //!< angular velocity of rate modulation [rad/ms]
/**
* @name update-hook communication.
* The following variables are used for direct communication from
* update() to event_hook(). They rely on the fact that event_hook()
* is called instantaneuously from update().
* Spikes are sent at times t that fulfill
*
* t_min_active_ < t <= t_max_active_
*/
//@{
double_t t_min_active_; //!< start of generator activity in slice
double_t t_max_active_; //!< end of generator activity in slice
//@}
};
// ------------------------------------------------------------
StimulatingDevice<CurrentEvent> device_;
Parameters_ P_;
Variables_ V_;
Buffers_ B_;
};
inline
port ppd_sup_generator::check_connection(Connection& c, port receptor_type)
{
DSSpikeEvent e;
e.set_sender(*this);
c.check_event(e);
port receptor = c.get_target()->connect_sender(e, receptor_type);
++P_.num_targets_; // count number of targets
return receptor;
}
inline
void ppd_sup_generator::get_status(DictionaryDatum &d) const
{
P_.get(d);
device_.get_status(d);
}
inline
void ppd_sup_generator::set_status(const DictionaryDatum &d)
{
Parameters_ ptmp = P_; // temporary copy in case of errors
ptmp.set(d); // throws if BadProperty
// We now know that ptmp is consistent. We do not write it back
// to P_ before we are also sure that the properties to be set
// in the parent class are internally consistent.
device_.set_status(d);
// if we get here, temporaries contain consistent set of properties
P_ = ptmp;
}
} // namespace
#endif //PPD_SUP_GENERATOR_H