neuron_model_izh_impl.c 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  2. // = Set up desired ODE solver implementation
  3. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  4. #define IMPL01 false // original SpiNNaker ESR implementation (corresponds to Iteration I)
  5. #define IMPL02 false // original Izhikevich implementation
  6. #define IMPL03 false // fixed-step size (h=1/16) symplectic forward Euler, precise threshold detection
  7. #define IMPL04 true // fixed-step size (h=1/16) symplectic forward Euler, precise threshold detection, FP conversion (corresponds to Iteration III)
  8. // = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
  9. #include "neuron_model_izh_impl.h"
  10. #include <debug.h>
  11. static global_neuron_params_pointer_t global_params;
  12. /*! \brief For linear membrane voltages, 1.5 is the correct value. However
  13. * with actual membrane voltage behaviour and tested over an wide range of
  14. * use cases 1.85 gives slightly better spike timings.
  15. */
  16. static const REAL SIMPLE_TQ_OFFSET = REAL_CONST(1.85);
  17. #if( IMPL01 )
  18. static inline void _rk2_kernel_midpoint(REAL h, neuron_pointer_t neuron,
  19. REAL input_this_timestep) {
  20. // to match Mathematica names
  21. REAL lastV1 = neuron->V;
  22. REAL lastU1 = neuron->U;
  23. REAL a = neuron->A;
  24. REAL b = neuron->B;
  25. REAL pre_alph = REAL_CONST(140.0) + input_this_timestep - lastU1;
  26. REAL alpha = pre_alph
  27. + ( REAL_CONST(5.0) + REAL_CONST(0.0400) * lastV1) * lastV1;
  28. REAL eta = lastV1 + REAL_HALF(h * alpha);
  29. // could be represented as a long fract?
  30. REAL beta = REAL_HALF(h * (b * lastV1 - lastU1) * a);
  31. neuron->V += h * (pre_alph - beta
  32. + ( REAL_CONST(5.0) + REAL_CONST(0.0400) * eta) * eta);
  33. neuron->U += a * h * (-lastU1 - beta + b * eta);
  34. }
  35. #endif
  36. #if( IMPL02 )
  37. // h = 1.0, i.e., simulation time-step must be set to 1.0 !
  38. static inline void _originalIzhikevich( REAL h, neuron_pointer_t neuron,
  39. REAL input_this_timestep) {
  40. REAL v = neuron->V;
  41. REAL u = neuron->U;
  42. REAL param_a = neuron->A;
  43. REAL param_b = neuron->B;
  44. v += REAL_HALF(( 0.04k * v + 5.0k) * v + 140.0k - u + input_this_timestep ); // for numerical stability
  45. v += REAL_HALF(( 0.04k * v + 5.0k) * v + 140.0k - u + input_this_timestep ); // time step is 0.5 ms
  46. u += param_a * ( param_b * v - u );
  47. neuron->V = v;
  48. neuron->U = u;
  49. }
  50. #endif
  51. #if( IMPL03 )
  52. // h = 1.0, i.e., simulation time-step must be set to 1.0 !
  53. static inline void _fixedStepSizeEuler( REAL h, neuron_pointer_t neuron,
  54. REAL input_this_timestep) {
  55. #define THRESHOLD_DETECTED 1024.0k // some high value above threshold to trigger spike event
  56. // Hiding and encoding information in the data to control
  57. // the program flow is not good practice!
  58. REAL v = neuron->V;
  59. REAL u = neuron->U;
  60. REAL param_a = neuron->A;
  61. REAL param_b = neuron->B;
  62. REAL a;
  63. REAL b;
  64. bool spikeEvent = false;
  65. int steps = 16;
  66. for( int cycles = 0; cycles; ++cycles ) {
  67. a = 0.04k * v;
  68. a *= v;
  69. b = 5.0k * v + 140.0k - u + input_this_timestep;
  70. v += 0.0625k * (a + b); // 0.0625 = 1/16
  71. u += 0.0625k * (param_a * ( param_b * v - u )); // 0.0625 = 1/16
  72. if( v >= 30.0k ) {
  73. spikeEvent = true;
  74. v = neuron->C;
  75. u += neuron->D;
  76. }
  77. }
  78. if( spikeEvent ) {
  79. neuron->V = v + THRESHOLD_DETECTED;
  80. }
  81. else {
  82. neuron->V = v;
  83. }
  84. neuron->U = u;
  85. }
  86. #endif
  87. #if( IMPL04 )
  88. // h = 1.0, i.e., simulation time-step must be set to 1.0 !
  89. static inline void _fixedStepSizeEulerWithFPConv( REAL h, neuron_pointer_t neuron,
  90. REAL input_this_timestep) {
  91. #define THRESHOLD_DETECTED 1024.0k // some high value above threshold to trigger spike event
  92. REAL v = neuron->V;
  93. REAL u = neuron->U;
  94. REAL param_a = neuron->A;
  95. REAL param_b = neuron->B;
  96. REAL param_a_RS = 5.12k; // 0.02 RS param_a s8.23
  97. REAL param_a_FS = 25.6k; // 0.1 FS param_a s8.23
  98. REAL param_b_FSRS = 51.2k; // 0.2 FS param_a s8.23
  99. REAL param_a_s8_23;
  100. REAL a;
  101. REAL b;
  102. REAL c;
  103. REAL d;
  104. bool spikeEvent = false;
  105. int steps = 16;
  106. for( int cycles = 0; cycles < (steps + 2); ++cycles ) { // (steps + 2) to supress unrolling the loop ..
  107. if(cycles < steps ) { // .. to prevent ITCM overflow (2 empty cyles)
  108. // (Corresponding compiler option did not work.)
  109. a = 10.24k * v; // byte left-shift
  110. a *= 0.00390625k; // byte right-shift
  111. a *= v;
  112. b = 5.0k * v + 140.0k - u + input_this_timestep;
  113. v += 0.0625k * (a + b); // 0.0625 = 1/16
  114. if( param_a > 0.05k ) { // identify neuron type
  115. param_a_s8_23 = param_a_FS;
  116. }
  117. else {
  118. param_a_s8_23 = param_a_RS;
  119. }
  120. d = param_b_FSRS * v;
  121. d *= 0.00390625k; // byte right-shift
  122. d -= u;
  123. c = 0.0625k * (param_a_s8_23 * ( d )); // 0.0625 = 1/16
  124. c *= 0.00390625k; // byte right-shift
  125. u += c;
  126. if( v >= 30.0k ) {
  127. spikeEvent = true;
  128. v = neuron->C;
  129. u += neuron->D;
  130. }
  131. }
  132. }
  133. if( spikeEvent ) {
  134. neuron->V = v + THRESHOLD_DETECTED;
  135. }
  136. else {
  137. neuron->V = v;
  138. }
  139. neuron->U = u;
  140. }
  141. #endif
  142. void neuron_model_set_global_neuron_params(
  143. global_neuron_params_pointer_t params) {
  144. global_params = params;
  145. }
  146. state_t neuron_model_state_update( input_t exc_input, input_t inh_input, input_t external_bias,
  147. neuron_pointer_t neuron) {
  148. input_t input_this_timestep = exc_input - inh_input + external_bias + neuron->I_offset;
  149. #if( IMPL01 )
  150. // the best AR update so far
  151. _rk2_kernel_midpoint(neuron->this_h, neuron, input_this_timestep);
  152. #endif
  153. #if( IMPL02 )
  154. _originalIzhikevich(neuron->this_h, neuron, input_this_timestep);
  155. #endif
  156. #if( IMPL03 )
  157. _fixedStepSizeEuler(neuron->this_h, neuron, input_this_timestep);
  158. #endif
  159. #if( IMPL04 )
  160. _fixedStepSizeEulerWithFPConv(neuron->this_h, neuron, input_this_timestep);
  161. #endif
  162. neuron->this_h = global_params->machine_timestep_ms;
  163. return neuron->V;
  164. }
  165. void neuron_model_has_spiked(neuron_pointer_t neuron) {
  166. #if( IMPL01 )
  167. // reset membrane voltage
  168. neuron->V = neuron->C;
  169. // offset 2nd state variable
  170. neuron->U += neuron->D;
  171. // simple threshold correction - next timestep (only) gets a bump
  172. neuron->this_h = global_params->machine_timestep_ms * SIMPLE_TQ_OFFSET;
  173. #endif
  174. #if( IMPL02 )
  175. neuron->V = neuron->C;
  176. neuron->U += neuron->D;
  177. #endif
  178. #if( IMPL03 || IMPL04 )
  179. neuron->V -= THRESHOLD_DETECTED;
  180. #endif
  181. }
  182. state_t neuron_model_get_membrane_voltage(neuron_pointer_t neuron) {
  183. return neuron->V;
  184. }
  185. void neuron_model_print_state_variables(restrict neuron_pointer_t neuron) {
  186. log_debug("V = %11.4k ", neuron->V);
  187. log_debug("U = %11.4k ", neuron->U);
  188. }
  189. void neuron_model_print_parameters(restrict neuron_pointer_t neuron) {
  190. log_debug("A = %11.4k ", neuron->A);
  191. log_debug("B = %11.4k ", neuron->B);
  192. log_debug("C = %11.4k ", neuron->C);
  193. log_debug("D = %11.4k ", neuron->D);
  194. log_debug("I = %11.4k \n", neuron->I_offset);
  195. }