Hi Thorben,
After doing a diff with the iaf_psc_exp source code, I believe this is
the problematic part:
if ( S_.r_ref_ == 0 ) // neuron not refractory, so evolve
V S_.V_m_ = S_.V_m_ * V_.P22_ + S_.i_syn_ex_ *
V_.P21ex_ //
membrane potential equals membrane potential times exponetial decay
plus postsynpatic excitatory/inhibitory currents time numerical
stability factor plus new input current times exponential
decay + S_.i_syn_in_ * V_.P21in_ + ( P_.I_e_ + S_.i_0_ ) *
V_.P20_; // S_.V_m : membrane
potential else
// V_.P22 : membrane potential
decay {
// S_.i_syn_ex /
S_.i_syn_in : excitatory / inhibitory postsynaptic
current }
// V_.P21in / V_.P21ex
: numeric stability criterion
parameter
// P_.I_e : static
input
current {
// S_.i_0_ : presynaptic input current
this
timestep }
// S_.i_1_ :
presynaptic input current next
timestep { } --S_.r_ref_; // neuron
is absolute refractory
The syntax seems wrong for the ELSE part (maybe due to automatic source
code formatting), with the presence of empty brackets. This means
--S_.r_ref_ is executed at every timestep and thus the IF
part S_.r_ref_ == 0 (which updates V_m) is never executed.Just remove
the unnecessary brackets in the ELSE part.
if ( S_.r_ref_ == 0 ) // neuron not refractory, so evolve V
S_.V_m_ = S_.V_m_ * V_.P22_ + S_.i_syn_ex_ * V_.P21ex_ +
S_.i_syn_in_ * V_.P21in_ + ( P_.I_e_ + S_.i_0_ ) * V_.P20_;
else --S_.r_ref_; // neuron is absolute refractory
I hope this helps.
Cordially,Simon
On Tue, 2019-07-02 at 09:51 +0000, tschoepe(a)techfak.uni-bielefeld.de
wrote:
Dear All,
I am relatively new to nest and want to implement a new neuron model.
I've worked a lot with SpiNNaker previously.
I am a research assistant and PhD student at the Technical Faculty in
Bielefeld, Germany.
Currently, I am trying to implement a new neuron model into nest.
Because I want to use
this model later on in the neurorbotics platform (NRP) I directly
installed the NRP
and I am using the nest version installed together with the NRP.
I followed the instructions at:
https://nest.github.io/nest-simulator/extension_modules
I am able to install mymodule and to run the neuron model
pif_psc_alpha coming with it.
Now I tried to extend mymodule with a new neuron model. To achieve
that I copied the
iaf_psc_exp model's cpp and h file, renamed them to iaf_psc_exp_semd
and changed them
according to pif_psc_alpha.
I was able to include the model into the nest library and run a short
example script.
Unfortunately, the iaf_psc_exp_semd model doesn't react to any
stimulation with spikes.
The membrane potential always stays at E_L.
When I use the same python script but with the iad_psc_exp model I
see a clear change
in the membrane potential.
Could someone check the files I've created for the new
iaf_psc_exp_semd model to see
what is wrong/missing?
Thanks a lot and best regards,
Thorben Schoepe
First file:
/*
* iaf_psc_exp_semd.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 IAF_PSC_EXP_SEMD_H
#define IAF_PSC_EXP_SEMD_H
// Includes from nestkernel:
#include "archiving_node.h"
#include "connection.h"
#include "event.h"
#include "nest_types.h"
#include "recordables_map.h"
#include "ring_buffer.h"
#include "universal_data_logger.h"
// Includes from sli:
#include "dictdatum.h"
namespace mynest
{
/* BeginDocumentation
Name: iaf_psc_exp - Leaky integrate-and-fire neuron model with
exponential
PSCs.
Description:
iaf_psc_expp is an implementation of a leaky integrate-and-fire
model
with exponential shaped postsynaptic currents (PSCs) according to
[1].
Thus, postsynaptic currents have an infinitely short rise time.
The threshold crossing is followed by an absolute refractory
period (t_ref)
during which the membrane potential is clamped to the resting
potential
and spiking is prohibited.
The linear subthresold dynamics is integrated by the Exact
Integration scheme [2]. The neuron dynamics is solved on the time
grid given by the computation step size. Incoming as well as
emitted
spikes are forced to that grid.
An additional state variable and the corresponding differential
equation represents a piecewise constant external current.
The general framework for the consistent formulation of systems
with
neuron like dynamics interacting by point events is described in
[2]. A flow chart can be found in [3].
Remarks:
The present implementation uses individual variables for the
components of the state vector and the non-zero matrix elements of
the propagator. Because the propagator is a lower triangular
matrix
no full matrix multiplication needs to be carried out and the
computation can be done "in place" i.e. no temporary state vector
object is required.
The template support of recent C++ compilers enables a more
succinct
formulation without loss of runtime performance already at minimal
optimization levels. A future version of iaf_psc_exp will probably
address the problem of efficient usage of appropriate vector and
matrix objects.
Parameters:
The following parameters can be set in the status dictionary.
E_L double - Resting membrane potential in mV.
C_m double - Capacity of the membrane in pF
tau_m double - Membrane time constant in ms.
tau_syn_ex double - Time constant of postsynaptic excitatory
currents in ms
tau_syn_in double - Time constant of postsynaptic inhibitory
currents in ms
t_ref double - Duration of refractory period (V_m =
V_reset) in ms.
V_m double - Membrane potential in mV
V_th double - Spike threshold in mV.
V_reset double - Reset membrane potential after a spike in
mV.
I_e double - Constant input current in pA.
t_spike double - Point in time of last spike in ms.
Remarks:
If tau_m is very close to tau_syn_ex or tau_syn_in, the model
will numerically behave as if tau_m is equal to tau_syn_ex or
tau_syn_in, respectively, to avoid numerical instabilities.
For details, please see IAF_Neruons_Singularity.ipynb in the
NEST source code (docs/model_details).
iaf_psc_exp can handle current input in two ways: Current input
through receptor_type 0 are handled as stepwise constant current
input as in other iaf models, i.e., this current directly enters
the membrane potential equation. Current input through
receptor_type 1, in contrast, is filtered through an exponential
kernel with the time constant of the excitatory synapse,
tau_syn_ex. For an example application, see [4].
References:
[1] Misha Tsodyks, Asher Uziel, and Henry Markram (2000) Synchrony
Generation
in Recurrent Networks with Frequency-Dependent Synapses, The
Journal of
Neuroscience, 2000, Vol. 20 RC50 p. 1-5
[2] Rotter S & Diesmann M (1999) Exact simulation of time-
invariant linear
systems with applications to neuronal modeling. Biologial
Cybernetics
81:381-402.
[3] Diesmann M, Gewaltig M-O, Rotter S, & Aertsen A (2001) State
space
analysis of synchronous spiking in cortical neural networks.
Neurocomputing 38-40:565-571.
[4] Schuecker J, Diesmann M, Helias M (2015) Modulated escape from
a
metastable state driven by colored noise.
Physical Review E 92:052119
Sends: SpikeEvent
Receives: SpikeEvent, CurrentEvent, DataLoggingRequest
SeeAlso: iaf_psc_exp_ps
FirstVersion: March 2006
Author: Moritz Helias
*/
/**
* Leaky integrate-and-fire neuron with exponential PSCs.
*/
class iaf_psc_exp_semd : public nest::Archiving_Node
{
public:
iaf_psc_exp_semd();
iaf_psc_exp_semd( const iaf_psc_exp_semd& );
/**
* Import sets of overloaded virtual functions.
* @see Technical Issues / Virtual Functions: Overriding,
Overloading, and
* Hiding
*/
using nest::Node::handle;
using nest::Node::handles_test_event;
nest::port send_test_event( Node&, nest::port, nest::synindex, bool
);
void handle( nest::SpikeEvent& );
void handle( nest::CurrentEvent& );
void handle( nest::DataLoggingRequest& );
nest::port handles_test_event( nest::SpikeEvent&, nest::port );
nest::port handles_test_event( nest::CurrentEvent&, nest::port );
nest::port handles_test_event( nest::DataLoggingRequest&,
nest::port );
void get_status( DictionaryDatum& ) const;
void set_status( const DictionaryDatum& );
private:
void init_state_( const Node& proto );
void init_buffers_();
void calibrate();
void update(nest::Time const&, const long, const long );
// The next two classes need to be friends to access the State_
class/member
friend class nest::RecordablesMap< iaf_psc_exp_semd >;
friend class nest::UniversalDataLogger< iaf_psc_exp_semd >;
// ----------------------------------------------------------------
/**
* Independent parameters of the model.
*/
struct Parameters_
{
/** Membrane time constant in ms. */
double Tau_;
/** Membrane capacitance in pF. */
double C_;
/** Refractory period in ms. */
double t_ref_;
/** Resting potential in mV. */
double E_L_;
/** External current in pA */
double I_e_;
/** Threshold, RELATIVE TO RESTING POTENTAIL(!).
I.e. the real threshold is (E_L_+Theta_). */
double Theta_;
/** reset value of the membrane potential */
double V_reset_;
/** Time constant of excitatory synaptic current in ms. */
double tau_ex_;
/** Time constant of inhibitory synaptic current in ms. */
double tau_in_;
Parameters_(); //!< Sets default parameter values
void get( DictionaryDatum& ) const; //!< Store current values in
dictionary
/** Set values from dictionary.
* @returns Change in reversal potential E_L, to be passed to
State_::set()
*/
double set( const DictionaryDatum& );
};
// ----------------------------------------------------------------
/**
* State variables of the model.
*/
struct State_
{
// state variables
//! synaptic stepwise constant input current, variable 0
double i_0_;
double i_1_; //!< presynaptic stepwise constant input
current
double i_syn_ex_; //!< postsynaptic current for exc. inputs,
variable 1
double i_syn_in_; //!< postsynaptic current for inh. inputs,
variable 1
double V_m_; //!< membrane potential, variable 2
//! absolute refractory counter (no membrane potential
propagation)
int r_ref_;
State_(); //!< Default initialization
void get( DictionaryDatum&, const Parameters_& ) const;
/** Set values from dictionary.
* @param dictionary to take data from
* @param current parameters
* @param Change in reversal potential E_L specified by this dict
*/
void set( const DictionaryDatum&, const Parameters_&, const
double );
};
// ----------------------------------------------------------------
/**
* Buffers of the model.
*/
struct Buffers_
{
Buffers_( iaf_psc_exp_semd& );
Buffers_( const Buffers_&, iaf_psc_exp_semd& );
/** buffers and sums up incoming spikes/currents */
nest::RingBuffer spikes_ex_;
nest::RingBuffer spikes_in_;
std::vector< nest::RingBuffer > currents_;
//! Logger for all analog data
nest::UniversalDataLogger< iaf_psc_exp_semd > logger_;
};
// ----------------------------------------------------------------
/**
* Internal variables of the model.
*/
struct Variables_
{
/** Amplitude of the synaptic current.
This value is chosen such that a post-synaptic potential with
weight one has an amplitude of 1 mV.
@note mog - I assume this, not checked.
*/
// double PSCInitialValue_;
// time evolution operator
double P20_;
double P11ex_;
double P11in_;
double P21ex_;
double P21in_;
double P22_;
double weighted_spikes_ex_;
double weighted_spikes_in_;
int RefractoryCounts_;
};
// Access functions for UniversalDataLogger ---------------------
----------
//! Read out the real membrane potential
inline double
get_V_m_() const
{
return S_.V_m_ + P_.E_L_;
}
inline double
get_weighted_spikes_ex_() const
{
return V_.weighted_spikes_ex_;
}
inline double
get_weighted_spikes_in_() const
{
return V_.weighted_spikes_in_;
}
inline double
get_I_syn_ex_() const
{
return S_.i_syn_ex_;
}
inline double
get_I_syn_in_() const
{
return S_.i_syn_in_;
}
// ----------------------------------------------------------------
/**
* @defgroup iaf_psc_exp_data
* Instances of private data structures for the different types
* of data pertaining to the model.
* @note The order of definitions is important for speed.
* @{
*/
Parameters_ P_;
State_ S_;
Variables_ V_;
Buffers_ B_;
/** @} */
//! Mapping of recordables names to access functions
static nest::RecordablesMap< iaf_psc_exp_semd > recordablesMap_;
};
inline nest::port
mynest::iaf_psc_exp_semd::send_test_event( Node& target,
nest::port receptor_type,
nest::synindex,
bool )
{
nest::SpikeEvent e;
e.set_sender( *this );
return target.handles_test_event( e, receptor_type );
}
inline nest::port
mynest::iaf_psc_exp_semd::handles_test_event( nest::SpikeEvent&,
nest::port receptor_type )
{
if ( receptor_type != 0 )
throw nest::UnknownReceptorType( receptor_type, get_name() );
return 0;
}
inline nest::port
mynest::iaf_psc_exp_semd::handles_test_event( nest::CurrentEvent&,
nest::port receptor_type )
{
if ( receptor_type == 0 )
return 0;
else if ( receptor_type == 1 )
return 1;
else
throw nest::UnknownReceptorType( receptor_type, get_name() );
}
inline nest::port
mynest::iaf_psc_exp_semd::handles_test_event(
nest::DataLoggingRequest& dlr, nest::port receptor_type )
{
if ( receptor_type != 0 )
throw nest::UnknownReceptorType( receptor_type, get_name() );
return B_.logger_.connect_logging_device( dlr, recordablesMap_ );
}
inline void
iaf_psc_exp_semd::get_status( DictionaryDatum& d ) const
{
P_.get( d );
S_.get( d, P_ );
Archiving_Node::get_status( d );
( *d )[ nest::names::recordables ] = recordablesMap_.get_list();
}
inline void
iaf_psc_exp_semd::set_status( const DictionaryDatum& d )
{
Parameters_ ptmp = P_; // temporary copy in case of
errors
const double delta_EL = ptmp.set( d ); // throws if BadProperty
State_ stmp = S_; // temporary copy in case of
errors
stmp.set( d, ptmp, delta_EL ); // throws if BadProperty
// We now know that (ptmp, stmp) are consistent. We do not
// write them back to (P_, S_) before we are also sure that
// the properties to be set in the parent class are internally
// consistent.
Archiving_Node::set_status( d );
// if we get here, temporaries contain consistent set of properties
P_ = ptmp;
S_ = stmp;
}
} // namespace
#endif // IAF_PSC_EXP_SEMD_H
Second file:
/*
* iaf_psc_exp_semd.cpp
*
* 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/>.
*
*/
#include "iaf_psc_exp_semd.h"
// C++ includes:
#include <limits>
// Includes from libnestutil:
#include "numerics.h"
#include "propagator_stability.h"
// Includes from nestkernel:
#include "event_delivery_manager_impl.h"
#include "exceptions.h"
#include "kernel_manager.h"
#include "universal_data_logger_impl.h"
// Includes from sli:
#include "dict.h"
#include "dictutils.h"
#include "doubledatum.h"
#include "integerdatum.h"
#include "lockptrdatum.h"
using namespace nest;
/* ----------------------------------------------------------------
* Recordables map
* ----------------------------------------------------------------
*/
nest::RecordablesMap< mynest::iaf_psc_exp_semd >
mynest::iaf_psc_exp_semd::recordablesMap_;
namespace nest
{
// Override the create() method with one call to
RecordablesMap::insert_()
// for each quantity to be recorded.
template <>
void
RecordablesMap< mynest::iaf_psc_exp_semd >::create()
{
// use standard names whereever you can for consistency!
insert_( names::V_m, &mynest::iaf_psc_exp_semd::get_V_m_ );
insert_( names::weighted_spikes_ex,
&mynest::iaf_psc_exp_semd::get_weighted_spikes_ex_ );
insert_( names::weighted_spikes_in,
&mynest::iaf_psc_exp_semd::get_weighted_spikes_in_ );
insert_( names::I_syn_ex, &mynest::iaf_psc_exp_semd::get_I_syn_ex_
);
insert_( names::I_syn_in, &mynest::iaf_psc_exp_semd::get_I_syn_in_
);
}
}
/* ----------------------------------------------------------------
* Default constructors defining default parameters and state
* ----------------------------------------------------------------
*/
mynest::iaf_psc_exp_semd::Parameters_::Parameters_()
: Tau_( 10.0 ) // in ms
, C_( 250.0 ) // in pF
, t_ref_( 2.0 ) // in ms
, E_L_( -70.0 ) // in mV
, I_e_( 0.0 ) // in pA
, Theta_( -55.0 - E_L_ ) // relative E_L_
, V_reset_( -70.0 - E_L_ ) // in mV
, tau_ex_( 2.0 ) // in ms
, tau_in_( 2.0 ) // in ms
{
}
mynest::iaf_psc_exp_semd::State_::State_()
: i_0_( 0.0 )
, i_syn_ex_( 0.0 )
, i_syn_in_( 0.0 )
, V_m_( 0.0 )
, r_ref_( 0 )
{
}
/* ----------------------------------------------------------------
* Parameter and state extractions and manipulation functions
* ----------------------------------------------------------------
*/
void
mynest::iaf_psc_exp_semd::Parameters_::get( DictionaryDatum& d )
const
{
def< double >( d, names::E_L, E_L_ ); // resting potential
def< double >( d, names::I_e, I_e_ );
def< double >( d, names::V_th, Theta_ + E_L_ ); // threshold value
def< double >( d, names::V_reset, V_reset_ + E_L_ );
def< double >( d, names::C_m, C_ );
def< double >( d, names::tau_m, Tau_ );
def< double >( d, names::tau_syn_ex, tau_ex_ );
def< double >( d, names::tau_syn_in, tau_in_ );
def< double >( d, names::t_ref, t_ref_ );
}
double
mynest::iaf_psc_exp_semd::Parameters_::set( const DictionaryDatum& d
)
{
// if E_L_ is changed, we need to adjust all variables defined
relative to
// E_L_
const double ELold = E_L_;
updateValue< double >( d, names::E_L, E_L_ );
const double delta_EL = E_L_ - ELold;
if ( updateValue< double >( d, names::V_reset, V_reset_ ) )
V_reset_ -= E_L_;
else
V_reset_ -= delta_EL;
if ( updateValue< double >( d, names::V_th, Theta_ ) )
Theta_ -= E_L_;
else
Theta_ -= delta_EL;
updateValue< double >( d, names::I_e, I_e_ );
updateValue< double >( d, names::C_m, C_ );
updateValue< double >( d, names::tau_m, Tau_ );
updateValue< double >( d, names::tau_syn_ex, tau_ex_ );
updateValue< double >( d, names::tau_syn_in, tau_in_ );
updateValue< double >( d, names::t_ref, t_ref_ );
if ( V_reset_ >= Theta_ )
throw nest::BadProperty( "Reset potential must be smaller than
threshold." );
if ( C_ <= 0 )
throw nest::BadProperty( "Capacitance must be strictly positive."
);
if ( Tau_ <= 0 || tau_ex_ <= 0 || tau_in_ <= 0 )
throw nest::BadProperty(
"Membrane and synapse time constants must be strictly
positive." );
if ( t_ref_ < 0 )
throw nest::BadProperty( "Refractory time must not be negative."
);
return delta_EL;
}
void
mynest::iaf_psc_exp_semd::State_::get( DictionaryDatum& d, const
Parameters_& p ) const
{
def< double >( d, names::V_m, V_m_ + p.E_L_ ); // Membrane
potential
}
void
mynest::iaf_psc_exp_semd::State_::set( const DictionaryDatum& d,
const Parameters_& p,
double delta_EL )
{
if ( updateValue< double >( d, names::V_m, V_m_ ) )
V_m_ -= p.E_L_;
else
V_m_ -= delta_EL;
}
mynest::iaf_psc_exp_semd::Buffers_::Buffers_( iaf_psc_exp_semd& n )
: logger_( n )
{
}
mynest::iaf_psc_exp_semd::Buffers_::Buffers_( const Buffers_&,
iaf_psc_exp_semd& n )
: logger_( n )
{
}
/* ----------------------------------------------------------------
* Default and copy constructor for node
* ----------------------------------------------------------------
*/
mynest::iaf_psc_exp_semd::iaf_psc_exp_semd()
: Archiving_Node()
, P_()
, S_()
, B_( *this )
{
recordablesMap_.create();
}
mynest::iaf_psc_exp_semd::iaf_psc_exp_semd( const iaf_psc_exp_semd& n
)
: Archiving_Node( n )
, P_( n.P_ )
, S_( n.S_ )
, B_( n.B_, *this )
{
}
/* ----------------------------------------------------------------
* Node initialization functions
* ----------------------------------------------------------------
*/
void
mynest::iaf_psc_exp_semd::init_state_( const Node& proto )
{
const iaf_psc_exp_semd& pr = downcast< iaf_psc_exp_semd >( proto );
S_ = pr.S_;
}
void
mynest::iaf_psc_exp_semd::init_buffers_()
{
B_.spikes_ex_.clear(); // includes resize
B_.spikes_in_.clear(); // includes resize
B_.currents_.clear(); // includes resize
B_.logger_.reset();
Archiving_Node::clear_history();
}
void
mynest::iaf_psc_exp_semd::calibrate()
{
B_.currents_.resize( 2 );
// ensures initialization in case mm connected after Simulate
B_.logger_.init();
const double h = Time::get_resolution().get_ms();
// numbering of state vaiables: i_0 = 0, i_syn_ = 1, V_m_ = 2
// commented out propagators: forward Euler
// needed to exactly reproduce Tsodyks network
// these P are independent
V_.P11ex_ = std::exp( -h / P_.tau_ex_ );
// P11ex_ = 1.0-h/tau_ex_;
V_.P11in_ = std::exp( -h / P_.tau_in_ );
// P11in_ = 1.0-h/tau_in_;
V_.P22_ = std::exp( -h / P_.Tau_ );
// P22_ = 1.0-h/Tau_;
// these are determined according to a numeric stability criterion
V_.P21ex_ = propagator_32( P_.tau_ex_, P_.Tau_, P_.C_, h );
V_.P21in_ = propagator_32( P_.tau_in_, P_.Tau_, P_.C_, h );
// P21ex_ = h/C_;
// P21in_ = h/C_;
V_.P20_ = P_.Tau_ / P_.C_ * ( 1.0 - V_.P22_ );
// P20_ = h/C_;
// TauR specifies the length of the absolute refractory period as
// a double in ms. The grid based iaf_psc_exp can only handle
refractory
// periods that are integer multiples of the computation step size
(h).
// To ensure consistency with the overall simulation scheme such
conversion
// should be carried out via objects of class nest::Time. The
conversion
// requires 2 steps:
// 1. A time object r is constructed defining representation
of
// TauR in tics. This representation is then converted to
computation
// time steps again by a strategy defined by class
nest::Time.
// 2. The refractory time in units of steps is read out
get_steps(), a
// member function of class nest::Time.
//
// Choosing a TauR that is not an integer multiple of the
computation time
// step h will leed to accurate (up to the resolution h) and self-
consistent
// results. However, a neuron model capable of operating with real
valued
// spike time may exhibit a different effective refractory time.
V_.RefractoryCounts_ = Time( Time::ms( P_.t_ref_ ) ).get_steps();
// since t_ref_ >= 0, this can only fail in error
assert( V_.RefractoryCounts_ >= 0 );
}
void
mynest::iaf_psc_exp_semd::update( const Time& origin, const long
from, const long to )
{
assert(
to >= 0 && ( delay ) from <
kernel().connection_manager.get_min_delay() );
assert( from < to );
// evolve from timestep 'from' to timestep 'to' with steps of h
each
for ( long lag = from; lag < to; ++lag )
{
if ( S_.r_ref_ == 0 ) // neuron not refractory, so evolve V
S_.V_m_ = S_.V_m_ * V_.P22_ + S_.i_syn_ex_ * V_.P21ex_
// membrane potential
equals membrane potential times exponetial decay plus postsynpatic
excitatory/inhibitory currents time numerical stability factor plus
new input current times exponential decay
+ S_.i_syn_in_ * V_.P21in_ + ( P_.I_e_ + S_.i_0_ ) * V_.P20_;
// S_.V_m : membrane
potential
else
// V_.P22 : membrane potential decay
{
// S_.i_syn_ex / S_.i_syn_in :
excitatory / inhibitory postsynaptic current
}
// V_.P21in / V_.P21ex :
numeric stability criterion parameter
// P_.I_e : static input
current
{
// S_.i_0_ : presynaptic input current this
timestep
}
// S_.i_1_ : presynaptic input
current next timestep
{
}
--S_.r_ref_; // neuron is absolute refractory
// exponential decaying PSCs
S_.i_syn_ex_ *= V_.P11ex_;
S_.i_syn_in_ *= V_.P11in_;
// add evolution of presynaptic input current
S_.i_syn_ex_ += ( 1. - V_.P11ex_ ) * S_.i_1_;
// the spikes arriving at T+1 have an immediate effect on the
state of the
// neuron
V_.weighted_spikes_ex_ = B_.spikes_ex_.get_value( lag );
V_.weighted_spikes_in_ = B_.spikes_in_.get_value( lag );
S_.i_syn_ex_ += V_.weighted_spikes_ex_;
S_.i_syn_in_ += V_.weighted_spikes_in_;
if ( S_.V_m_ >= P_.Theta_ ) // threshold crossing
{
S_.r_ref_ = V_.RefractoryCounts_;
S_.V_m_ = P_.V_reset_;
set_spiketime( Time::step( origin.get_steps() + lag + 1 ) );
SpikeEvent se;
kernel().event_delivery_manager.send( *this, se, lag );
}
// set new input current
S_.i_0_ = B_.currents_[ 0 ].get_value( lag );
S_.i_1_ = B_.currents_[ 1 ].get_value( lag );
// log state data
B_.logger_.record_data( origin.get_steps() + lag );
}
}
void
mynest::iaf_psc_exp_semd::handle( SpikeEvent& e )
{
assert( e.get_delay() > 0 );
if ( e.get_weight() >= 0.0 )
B_.spikes_ex_.add_value( e.get_rel_delivery_steps(
kernel().simulation_manager.get_slice_
origin() ),
e.get_weight() * e.get_multiplicity() );
else
B_.spikes_in_.add_value( e.get_rel_delivery_steps(
kernel().simulation_manager.get_slice_
origin() ),
e.get_weight() * e.get_multiplicity() );
}
void
mynest::iaf_psc_exp_semd::handle( CurrentEvent& e )
{
assert( e.get_delay() > 0 );
const double c = e.get_current();
const double w = e.get_weight();
// add weighted current; HEP 2002-10-04
if ( 0 == e.get_rport() )
{
B_.currents_[ 0 ].add_value(
e.get_rel_delivery_steps(
kernel().simulation_manager.get_slice_origin() ),
w * c );
}
if ( 1 == e.get_rport() )
{
B_.currents_[ 1 ].add_value(
e.get_rel_delivery_steps(
kernel().simulation_manager.get_slice_origin() ),
w * c );
}
}
void
mynest::iaf_psc_exp_semd::handle( DataLoggingRequest& e )
{
B_.logger_.handle( e );
}
_______________________________________________
NEST Users mailing list -- users(a)nest-simulator.org
To unsubscribe send an email to users-leave(a)nest-simulator.org
--
___________________________________________________
Simon Brodeur
Étudiant au doctorat
Université de Sherbrooke
Département génie électrique et génie informatique
Laboratoire NECOTIS, C1-3036
Tél. : (819) 821-8000 poste 62187
Courriel: Simon.Brodeur(a)USherbrooke.ca
___________________________________________________