| 1 | COMMENT |
|---|
| 2 | This mechanism emits spike events at the times given in a supplied Vector. |
|---|
| 3 | |
|---|
| 4 | Example usage: |
|---|
| 5 | objref vs |
|---|
| 6 | vs = new VecStim(.5) |
|---|
| 7 | vs.play(spikevec) |
|---|
| 8 | |
|---|
| 9 | This is a modified version of the original vecstim.mod (author unknown?) which |
|---|
| 10 | allows multiple vectors to be used sequentially. This saves memory in a long |
|---|
| 11 | simulation, as the same storage can be reused. |
|---|
| 12 | |
|---|
| 13 | The mechanism checks at intervals `ping` whether a new vector has been provided |
|---|
| 14 | using the play() procedure and if so resets its pointer to the first element |
|---|
| 15 | in the new vector. Note that any spikes remaining in the first vector will be |
|---|
| 16 | lost. Any spiketimes in the new vector that are earlier than the current time |
|---|
| 17 | are ignored. |
|---|
| 18 | |
|---|
| 19 | The mechanism actually checks slightly after the ping interval, to avoid play() |
|---|
| 20 | and the ping check occurring at the same time step but in the wrong order. |
|---|
| 21 | |
|---|
| 22 | |
|---|
| 23 | Extracts from the comments on the original vecstim: |
|---|
| 24 | |
|---|
| 25 | The idiom for getting a Vector argument in a model description is encapsulated |
|---|
| 26 | in the "play" procedure. There are potentially many VecStim instances and so the |
|---|
| 27 | Vector pointer must be stored in the space allocated for the particular instance |
|---|
| 28 | when "play" is called. The assigned variable "space" gives us space for a double |
|---|
| 29 | precision number, 64 bits, which is sufficient to store an opaque pointer. |
|---|
| 30 | The "element" procedure uses this opaque pointer to make sure that the requested |
|---|
| 31 | "index" element is within the size of the vector and assigns the "etime" double |
|---|
| 32 | precision variable to the value of that element. Since index is defined at the |
|---|
| 33 | model description level it is a double precision variable as well and must be |
|---|
| 34 | treated as such in the VERBATIM block. An index value of -1 means that no |
|---|
| 35 | further events should be sent from this instance. Fortunately, space for model |
|---|
| 36 | data is cleared when it is first allocated. So if play is not called, the |
|---|
| 37 | pointer will be 0 and the test in the element procedure would turn off the |
|---|
| 38 | VecStim by setting index to -1. Also, because the existence of the first |
|---|
| 39 | argument is checked in the "play" procedure, one can turn off the VecStim with |
|---|
| 40 | vs.play() |
|---|
| 41 | No checking is done if the stimvec is destroyed (when the reference count for |
|---|
| 42 | the underlying Vector becomes 0). Continued use of the VecStim instance in this |
|---|
| 43 | case would cause a memory error. So it is up to the user to call vs.play() or to |
|---|
| 44 | destroy the VecStim instance before running another simulation. |
|---|
| 45 | |
|---|
| 46 | The strategy of the INITIAL and NET_RECEIVE blocks is to send a self event |
|---|
| 47 | (with flag 1) to be delivered at the time specified by the index of the Vector |
|---|
| 48 | starting at index 0. When the self event is delivered to the NET_RECEIVE block, |
|---|
| 49 | it causes an immediate input event on every NetCon which has this VecStim as its |
|---|
| 50 | source. These events, would then be delivered to their targets after the |
|---|
| 51 | appropriate delay specified for each NetCon. |
|---|
| 52 | ENDCOMMENT |
|---|
| 53 | |
|---|
| 54 | |
|---|
| 55 | : Vector stream of events |
|---|
| 56 | |
|---|
| 57 | NEURON { |
|---|
| 58 | ARTIFICIAL_CELL VecStim |
|---|
| 59 | RANGE ping |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | PARAMETER { |
|---|
| 63 | ping = 1 (ms) |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | ASSIGNED { |
|---|
| 67 | index |
|---|
| 68 | etime (ms) |
|---|
| 69 | space |
|---|
| 70 | } |
|---|
| 71 | |
|---|
| 72 | INITIAL { |
|---|
| 73 | index = 0 |
|---|
| 74 | element() |
|---|
| 75 | if (index > 0) { |
|---|
| 76 | net_send(etime - t, 1) |
|---|
| 77 | } |
|---|
| 78 | if (ping > 0) { |
|---|
| 79 | net_send(ping, 2) |
|---|
| 80 | } |
|---|
| 81 | } |
|---|
| 82 | |
|---|
| 83 | NET_RECEIVE (w) { |
|---|
| 84 | if (flag == 1) { |
|---|
| 85 | net_event(t) |
|---|
| 86 | element() |
|---|
| 87 | if (index > 0) { |
|---|
| 88 | if (etime < t) { |
|---|
| 89 | printf("Warning in VecStim: spike time (%g ms) before current time (%g ms)\n",etime,t) |
|---|
| 90 | } else { |
|---|
| 91 | net_send(etime - t, 1) |
|---|
| 92 | } |
|---|
| 93 | } |
|---|
| 94 | } else if (flag == 2) { : ping - reset index to 0 |
|---|
| 95 | :printf("flag=2, etime=%g, t=%g, ping=%g, index=%g\n",etime,t,ping,index) |
|---|
| 96 | if (index == -2) { : play() has been called |
|---|
| 97 | :printf("Detected new vector\n") |
|---|
| 98 | index = 0 |
|---|
| 99 | : the following loop ensures that if the vector |
|---|
| 100 | : contains spiketimes earlier than the current |
|---|
| 101 | : time, they are ignored. |
|---|
| 102 | while (etime < t && index >= 0) { |
|---|
| 103 | element() |
|---|
| 104 | :printf("element(): index=%g, etime=%g, t=%g\n",index,etime,t) |
|---|
| 105 | } |
|---|
| 106 | if (index > 0) { |
|---|
| 107 | net_send(etime - t, 1) |
|---|
| 108 | } |
|---|
| 109 | } |
|---|
| 110 | net_send(ping, 2) |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | |
|---|
| 114 | |
|---|
| 115 | VERBATIM |
|---|
| 116 | extern double* vector_vec(); |
|---|
| 117 | extern int vector_capacity(); |
|---|
| 118 | extern void* vector_arg(); |
|---|
| 119 | ENDVERBATIM |
|---|
| 120 | |
|---|
| 121 | PROCEDURE element() { |
|---|
| 122 | VERBATIM |
|---|
| 123 | { void* vv; int i, size; double* px; |
|---|
| 124 | i = (int)index; |
|---|
| 125 | if (i >= 0) { |
|---|
| 126 | vv = *((void**)(&space)); |
|---|
| 127 | if (vv) { |
|---|
| 128 | size = vector_capacity(vv); |
|---|
| 129 | px = vector_vec(vv); |
|---|
| 130 | if (i < size) { |
|---|
| 131 | etime = px[i]; |
|---|
| 132 | index += 1.; |
|---|
| 133 | } else { |
|---|
| 134 | index = -1.; |
|---|
| 135 | } |
|---|
| 136 | } else { |
|---|
| 137 | index = -1.; |
|---|
| 138 | } |
|---|
| 139 | } |
|---|
| 140 | } |
|---|
| 141 | ENDVERBATIM |
|---|
| 142 | } |
|---|
| 143 | |
|---|
| 144 | PROCEDURE play() { |
|---|
| 145 | VERBATIM |
|---|
| 146 | void** vv; |
|---|
| 147 | vv = (void**)(&space); |
|---|
| 148 | *vv = (void*)0; |
|---|
| 149 | if (ifarg(1)) { |
|---|
| 150 | *vv = vector_arg(1); |
|---|
| 151 | } |
|---|
| 152 | index = -2; |
|---|
| 153 | ENDVERBATIM |
|---|
| 154 | } |
|---|