iaf_psc_exp.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #include "sys.hpp" // for libcwd
  2. #include "debug.hpp" // for libcwd
  3. #include "iaf_psc_exp.h"
  4. #include <limits>
  5. #include <cmath>
  6. #include <iostream>
  7. /* ----------------------------------------------------------------
  8. * Default constructors defining default parameters and state
  9. * ---------------------------------------------------------------- */
  10. iaf_psc_exp::Parameters_::Parameters_()
  11. : Tau_ ( 10.0 ), // in ms
  12. C_ ( 250.0 ), // in pF
  13. t_ref_ ( 2.0 ), // in ms
  14. U0_ ( -70.0 ), // in mV
  15. I_e_ ( 0.0 ), // in pA
  16. Theta_ ( -55.0 - U0_ ), // relative U0_
  17. V_reset_ ( -70.0 - U0_ ), // in mV
  18. tau_ex_ ( 2.0 ), // in ms
  19. tau_in_ ( 2.0 ) // in ms
  20. {}
  21. void iaf_psc_exp::Parameters_::set(double Tau_m, double C, double t_ref, double U0,
  22. double I_e, double Theta, double V_reset, double tau_ex, double tau_in)
  23. {
  24. Tau_ = Tau_m;
  25. C_ = C;
  26. t_ref_ = t_ref;
  27. U0_ = U0;
  28. I_e_ = I_e;
  29. Theta_ = Theta;
  30. V_reset_ = V_reset;
  31. tau_ex_ = tau_ex;
  32. tau_in_ = tau_in;
  33. }
  34. iaf_psc_exp::State_::State_()
  35. : i_0_ ( 0.0 ),
  36. V_m_ ( 0.0 ),
  37. r_ref_ ( 0 )
  38. {}
  39. iaf_psc_exp::iaf_psc_exp(int n): layer(n), i_syn_ex_(n, 0), i_syn_in_(n, 0), currents(n, 0)
  40. {
  41. pS_ = new State_[n];
  42. }
  43. iaf_psc_exp::~iaf_psc_exp()
  44. {
  45. delete[] pS_;
  46. }
  47. float* iaf_psc_exp::GetInputPointer(csimInputChannel InputNumber)
  48. {
  49. Dout(dc::layer, "InputNumber=" << int(InputNumber) << "");
  50. switch (InputNumber) {
  51. case csimInputChannel_AMPA: {
  52. Dout(dc::layer, "Excitatory Input");
  53. return &i_syn_ex_[0];
  54. } break;
  55. case csimInputChannel_GABAa: {
  56. Dout(dc::layer, "Inhibitory Input");
  57. return &i_syn_in_[0];
  58. } break;
  59. case csimInputChannel_Membrane: {
  60. Dout(dc::layer, "Membrane Input");
  61. return &currents[0];
  62. } break;
  63. default:
  64. return &i_syn_ex_[0];
  65. }
  66. return 0;
  67. }
  68. inline double fexp(const double& val)
  69. {
  70. return std::exp(static_cast<long double>(val));
  71. }
  72. void iaf_psc_exp::calibrate()
  73. {
  74. const double h = dt;
  75. // numbering of state vaiables: i_0 = 0, i_syn_ = 1, V_m_ = 2
  76. // commented out propagators: forward Euler
  77. // needed to exactly reproduce Tsodyks network
  78. // these P are independent
  79. V_.P11ex_ = fexp(-h/P_.tau_ex_);
  80. //P11ex_ = 1.0-h/tau_ex_;
  81. V_.P11in_ = fexp(-h/P_.tau_in_);
  82. //P11in_ = 1.0-h/tau_in_;
  83. V_.P22_ = fexp(-h/P_.Tau_);
  84. //P22_ = 1.0-h/Tau_;
  85. // these depend on the above. Please do not change the order.
  86. // TODO: use expm1 here to improve accuracy for small time steps
  87. V_.P21ex_ = P_.Tau_/(P_.C_*(1.0-P_.Tau_/P_.tau_ex_)) * V_.P11ex_ * (1.0 - fexp(h*(1.0/P_.tau_ex_-1.0/P_.Tau_)));
  88. //P21ex_ = h/C_;
  89. V_.P21in_ = P_.Tau_/(P_.C_*(1.0-P_.Tau_/P_.tau_in_)) * V_.P11in_ * (1.0 - fexp(h*(1.0/P_.tau_in_-1.0/P_.Tau_)));
  90. //P21in_ = h/C_;
  91. V_.P20_ = P_.Tau_/P_.C_*(1.0 - V_.P22_);
  92. //P20_ = h/C_;
  93. // TauR specifies the length of the absolute refractory period as
  94. // a double_t in ms. The grid based iaf_psc_exp can only handle refractory
  95. // periods that are integer multiples of the computation step size (h).
  96. // To ensure consistency with the overall simulation scheme such conversion
  97. // should be carried out via objects of class nest::Time. The conversion
  98. // requires 2 steps:
  99. // 1. A time object r is constructed defining representation of
  100. // TauR in tics. This representation is then converted to computation time
  101. // steps again by a strategy defined by class nest::Time.
  102. // 2. The refractory time in units of steps is read out get_steps(), a member
  103. // function of class nest::Time.
  104. //
  105. // Choosing a TauR that is not an integer multiple of the computation time
  106. // step h will leed to accurate (up to the resolution h) and self-consistent
  107. // results. However, a neuron model capable of operating with real valued spike
  108. // time may exhibit a different effective refractory time.
  109. //
  110. V_.RefractoryCounts_ = P_.t_ref_ / dt;
  111. if ( V_.RefractoryCounts_ < 1 )
  112. throw BadProperty("Absolute refractory time must be at least one time step.");
  113. }
  114. int iaf_psc_exp::proceede(int TotalTime)
  115. {
  116. int t = TotalTime % MacroTimeStep;
  117. // evolve from timestep 'from' to timestep 'to' with steps of h each
  118. for ( int n=0; n<N; ++n)
  119. {
  120. State_& S_ = pS_[n];
  121. if ( S_.r_ref_ == 0 ) // neuron not refractory, so evolve V
  122. S_.V_m_ = S_.V_m_*V_.P22_ + i_syn_ex_[n]*V_.P21ex_ + i_syn_in_[n]*V_.P21in_ + (P_.I_e_+S_.i_0_)*V_.P20_ + currents[n]*dt;
  123. else
  124. --S_.r_ref_; // neuron is absolute refractory
  125. currents[n] = 0; // reset direct membrane input
  126. // exponential decaying PSCs
  127. i_syn_ex_[n] *= V_.P11ex_;
  128. i_syn_in_[n] *= V_.P11in_;
  129. if ( S_.V_m_ >= P_.Theta_ ) // threshold crossing
  130. {
  131. S_.r_ref_ = V_.RefractoryCounts_;
  132. S_.V_m_ = P_.V_reset_;
  133. firings[N_firings ][0]=t;
  134. firings[N_firings++][1]=n;
  135. if (N_firings == N_firings_max) {
  136. ThrowTooManySpikes(t);
  137. }
  138. }
  139. }
  140. return 0;
  141. }
  142. /*
  143. *
  144. * : Tau_ ( 10.0 ), // in ms
  145. C_ ( 250.0 ), // in pF
  146. t_ref_ ( 2.0 ), // in ms
  147. U0_ ( -70.0 ), // in mV
  148. I_e_ ( 0.0 ), // in pA
  149. Theta_ ( -55.0 - U0_ ), // relative U0_
  150. V_reset_ ( -70.0 - U0_ ), // in mV
  151. tau_ex_ ( 2.0 ), // in ms
  152. tau_in_ ( 2.0 ) // in ms
  153. *
  154. */
  155. int iaf_psc_exp::WriteSimInfo(fstream &fw)
  156. {
  157. stringstream sstr;
  158. sstr << "<LayerType value=\"" << "iaf_psc_exp" << "\"/> \n";
  159. sstr << "<Tau value=\"" << P_.Tau_<< "\"/> \n";
  160. sstr << "<C value=\"" << P_.C_ << "\"/> \n";
  161. sstr << "<t_ref value=\"" << P_.t_ref_ << "\"/> \n";
  162. sstr << "<U0 value=\"" << P_.U0_<< "\"/> \n";
  163. sstr << "<I_e value=\"" << P_.I_e_ << "\"/> \n";
  164. sstr << "<Theta value=\"" << P_.Theta_ << "\"/> \n";
  165. sstr << "<V_reset value=\"" << P_.V_reset_ << "\"/> \n";
  166. sstr << "<tau_ex value=\"" << P_.tau_ex_ << "\"/> \n";
  167. sstr << "<tau_in value=\"" << P_.tau_in_ << "\"/> \n";
  168. layer::WriteSimInfo(fw, sstr.str());
  169. }
  170. /** Starts binary recording of membrane potential and synaptic potentials
  171. *
  172. * @param nobserve number of neurons to observe
  173. * @param NNumber starting number. Neurons in the range [NNumber,NNumber+nobserve-1] are recorded
  174. * @return
  175. */
  176. int iaf_psc_exp::StartBinRec(int nobserve, int NNumber)
  177. {
  178. // not implemented
  179. return 0;
  180. }
  181. int iaf_psc_exp::reset(int t)
  182. {
  183. State_ reset_state;
  184. for ( int n=0; n<N; ++n)
  185. {
  186. pS_[n] = reset_state;
  187. }
  188. return 0;
  189. }