void
nest::pp_psc_delta::update( Time const& origin, const long_t from, const long_t to )
{

    assert( to >= 0 && ( delay ) from < kernel().connection_builder_manager.get_min_delay() );
    assert( from < to );

    for ( long_t lag = from; lag < to; ++lag )
    {

        S_.y3_ = V_.P30_ * ( S_.y0_ + P_.I_e_ ) + V_.P33_ * S_.y3_ + B_.spikes_.get_value( lag );

        double_t q_temp_ = 0;
        for ( uint_t i = 0; i < S_.q_elems_.size(); i++ )
        {

            S_.q_elems_[ i ] = V_.Q33_[ i ] * S_.q_elems_[ i ];

            q_temp_ += S_.q_elems_[ i ];
        }

        S_.q_ = q_temp_;

        if ( S_.r_ == 0 )
        {
            // Neuron not refractory

            // Calculate instantaneous rate from transfer function:
            //     rate = c1 * y3' + c2 * exp(c3 * y3')
            // Adaptive threshold leads to effective potential V_eff instead of y3

            double_t V_eff;

            V_eff = S_.y3_ - S_.q_;

            double_t rate = ( P_.c_1_ * V_eff + P_.c_2_ * std::exp( P_.c_3_ * V_eff ) );

            if ( rate > 0.0 )
            {
                ulong_t n_spikes = 0;

                if ( P_.dead_time_ > 0.0 )
                {
                    // Draw random number and compare to prob to have a spike
                    if ( V_.rng_->drand() <= -numerics::expm1( -rate * V_.h_ * 1e-3 ) )
                    {
                        n_spikes = 1;
                    }
                }
                else
                {
                    // Draw Poisson random number of spikes
                    V_.poisson_dev_.set_lambda( rate * V_.h_ * 1e-3 );
                    n_spikes = V_.poisson_dev_.ldev( V_.rng_ );
                }

                if ( n_spikes > 0 ) // Is there a spike? Then set the new dead time.
                {
                    // Set dead time interval according to paramters
                    if ( P_.dead_time_random_ )
                    {
                        S_.r_ = Time( Time::ms( V_.gamma_dev_( V_.rng_ ) / V_.dt_rate_ ) ).get_steps();
                    }
                    else
                        S_.r_ = V_.DeadTimeCounts_;


                    for ( uint_t i = 0; i < S_.q_elems_.size(); i++ )
                    {
                        S_.q_elems_[ i ] += P_.q_sfa_[ i ] * n_spikes;
                    }


                    // And send the spike event
                    SpikeEvent se;
                    se.set_multiplicity( n_spikes );
                    kernel().event_delivery_manager.send( *this, se, lag );

                    // set spike time for STDP to work,
                    // see https://github.com/nest/nest-simulator/issues/77
                    for ( uint_t i = 0; i < n_spikes; i++ )
                    {
                        set_spiketime( Time::step( origin.get_steps() + lag + 1 ) );
                    }

                    // Reset the potential if applicable
                    if ( P_.with_reset_ )
                    {
                        S_.y3_ = 0.0;
                    }
                } // S_.y3_ = P_.V_reset_;
            }   // if (rate > 0.0)
        }
        else // Neuron is within dead time
        {
            --S_.r_;
        }

        // Set new input current
        S_.y0_ = B_.currents_.get_value( lag );

        // Voltage logging
        B_.logger_.record_data( origin.get_steps() + lag );
    }
}
Exemplo n.º 2
0
void
nest::pp_pop_psc_delta::update( Time const& origin, const long_t from, const long_t to )
{
  assert( to >= 0 && ( delay ) from < kernel().connection_builder_manager.get_min_delay() );
  assert( from < to );

  for ( long_t lag = from; lag < to; ++lag )
  {


    S_.h_ = S_.h_ * V_.P33_ + V_.P30_ * ( S_.y0_ + P_.I_e_ ) + B_.spikes_.get_value( lag );


    // get_thetas_ages
    std::vector< double_t > tmp_vector;
    double_t integral = 0;
    tmp_vector.clear();


    for ( uint_t i = 0; i < V_.eta_kernel_.size(); i++ )
    {
      tmp_vector.push_back( V_.eta_kernel_[ i ]
        * S_.n_spikes_past_[ ( S_.p_n_spikes_past_ + i ) % S_.n_spikes_past_.size() ] * V_.h_
        * 0.001 );
      integral += tmp_vector[ i ];
    }

    S_.thetas_ages_.clear();
    S_.thetas_ages_.push_back( integral );

    for ( uint_t i = 1; i < V_.eta_kernel_.size(); i++ )
      S_.thetas_ages_.push_back( S_.thetas_ages_[ i - 1 ] - tmp_vector[ i - 1 ] );

    for ( uint_t i = 0; i < V_.eta_kernel_.size(); i++ )
      S_.thetas_ages_[ i ] += V_.theta_kernel_[ i ];

    S_.thetas_ages_.push_back( 0 );

    // get_escape_rate
    for ( uint_t i = 0; i < S_.rhos_ages_.size(); i++ )
      S_.rhos_ages_[ i ] = P_.rho_0_ * std::exp( ( S_.h_ + S_.thetas_ages_[ i ] ) / P_.delta_u_ );


    double p_argument;

    // generate_spikes
    for ( uint_t i = 0; i < S_.age_occupations_.size(); i++ )
    {

      if ( S_.age_occupations_[ ( S_.p_age_occupations_ + i ) % S_.age_occupations_.size() ] > 0 )
      {

        p_argument = -numerics::expm1( -S_.rhos_ages_[ i ] * V_.h_
                       * 0.001 ); // V_.h_ is in ms, S_.rhos_ages_ is in Hz

        if ( p_argument > V_.min_double_ )
        {
          V_.binom_dev_.set_p_n( p_argument,
            S_.age_occupations_[ ( S_.p_age_occupations_ + i ) % S_.age_occupations_.size() ] );
          S_.n_spikes_ages_[ i ] = V_.binom_dev_.ldev( V_.rng_ );
        }
        else
        {
          S_.n_spikes_ages_[ i ] = 0;
        }
      }
      else
        S_.n_spikes_ages_[ i ] = 0;
    }


    S_.p_n_spikes_past_ = ( S_.p_n_spikes_past_ - 1 + S_.n_spikes_past_.size() )
      % S_.n_spikes_past_.size(); // shift to the right

    int_t temp_sum = 0;
    for ( uint_t i = 0; i < S_.n_spikes_ages_.size(); i++ ) // cumulative sum
      temp_sum += S_.n_spikes_ages_[ i ];

    S_.n_spikes_past_[ S_.p_n_spikes_past_ ] = temp_sum;


    // update_age_occupations
    for ( uint_t i = 0; i < S_.age_occupations_.size(); i++ )
      S_.age_occupations_[ ( S_.p_age_occupations_ + i ) % S_.age_occupations_.size() ] -=
        S_.n_spikes_ages_[ i ];

    int_t last_element_value =
      S_.age_occupations_[ ( S_.p_age_occupations_ - 1 + S_.age_occupations_.size() )
        % S_.age_occupations_.size() ]; // save the last element

    S_.p_age_occupations_ = ( S_.p_age_occupations_ - 1 + S_.age_occupations_.size() )
      % S_.age_occupations_.size(); // shift to the right
    S_.age_occupations_[ ( S_.p_age_occupations_ - 1 + S_.age_occupations_.size() )
      % S_.age_occupations_.size() ] += last_element_value;
    S_.age_occupations_[ S_.p_age_occupations_ ] = S_.n_spikes_past_[ S_.p_n_spikes_past_ ];

    // Set new input current
    S_.y0_ = B_.currents_.get_value( lag );

    // Voltage logging
    B_.logger_.record_data( origin.get_steps() + lag );


    // test if S_.n_spikes_past_[S_.p_n_spikes_past_]!=0, generate spike and send this number as the
    // parameter

    if ( S_.n_spikes_past_[ S_.p_n_spikes_past_ ] > 0 ) // Is there any spike?
    {
      SpikeEvent se;
      se.set_multiplicity( S_.n_spikes_past_[ S_.p_n_spikes_past_ ] );
      kernel().event_delivery_manager.send( *this, se, lag );
    }
  }
}