# Custom STDP rule

**URL:** <https://brian.discourse.group/t/custom-stdp-rule/1091>\
**Category:** Science, Projects, and Showcases\
**Created:** [5 December 2023 10:53 UTC](https://brian.discourse.group/t/custom-stdp-rule/1091 "2023-12-05T10:53:43Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![mallard1707](https://avatars.discourse-cdn.com/v4/letter/m/67e7ee/32.png) [@mallard1707](https://brian.discourse.group/u/mallard1707)\
**Post date:** [5 December 2023 10:53 UTC](https://brian.discourse.group/t/custom-stdp-rule/1091/1 "2023-12-05T10:53:43Z")

</div>

Hi,  
I am trying to implement the following STDP learning rule in brian2 between 2 groups of LIF neurons (784x400):

 ![image](https://global.discourse-cdn.com/free1/uploads/brian/original/1X/f3e7a0e2bea82d1c466d1cc7888a37ca04aa5174.png)

I have completed the implementation of the STDP part that updates w as follows:

```auto
from brian2 import *

defaultclock.dt = 0.001*us

tau1 = 10*us
tau2 = 20*us
mu = 1.7
gamma1 = 9.0
gamma2 = 15.0
wmax = 900.0

stdp='''
    w : 1
    '''     
on_pre='''
        lastspike_pre = t
        delta_t = (lastspike_pre - lastspike_post)
        w -= gamma2*((w/wmax)**mu)*exp(-delta_t/tau2)
        '''
on_post='''
        lastspike_post = t
        delta_t = (lastspike_post - lastspike_pre)
        w += gamma1*((1-w/wmax)**mu)*exp(-delta_t/tau1)
        '''

G = NeuronGroup(101, '''
spike_when : second (constant)
lastspike : second # remove when model uses refractory
''',
threshold='timestep(t, dt) == timestep(spike_when, dt)') # spike at pre-defined time
G.lastspike = -1e9*second
G.spike_when[0] = 60*us
G.spike_when[1:] = np.linspace(10, 110, 100)*us

S = Synapses(G, G, stdp, on_pre= on_pre, on_post=on_post)

S.connect(i=0, j=np.arange(1, 101)) # Connect first neuron to all other neurons
S.w = 0

run(120*us)

plt.title('Potentiation curve at w = 0 (minimum)')
#plt.ylim(880, 900)
plt.plot((G.spike_when[1:] - G.spike_when[0])/us, S.w[:], color='r')
plt.axhline(linestyle=':', color='k')
plt.axvline(linestyle=':', color='k')
plt.show()

```

And I get the desired STDP behavior as per the paper.

But, I am still not sure about how equation (3) will be implemented. I thought of adding the line

```auto
I_post += I0*w*(exp(-(t-lastspike_pre)/tau_m) - exp(-(t-lastspike_post)/tau_s))

```

to both on\_pre and on\_post, but I am not sure if this is correct.

Thanks

---

<div class="post-metadata">

**Author:** ![mstimberg](https://yyz2.discourse-cdn.com/free1/user_avatar/brian.discourse.group/mstimberg/32/11_2.png) [@mstimberg](https://brian.discourse.group/u/mstimberg)\
**Post date:** [6 December 2023 17:49 UTC](https://brian.discourse.group/t/custom-stdp-rule/1091/2 "2023-12-06T17:49:37Z")

</div>

Hi @mallard1707 . Indeed, your implementation of the STDP rule looks correct to me, and your approach to verifying it looks good as well 😉

> [@mallard1707](#):
>
> But, I am still not sure about how equation (3) will be implemented. I thought of adding the line
> 
> ```auto
> I_post += I0*w*(exp(-(t-lastspike_pre)/tau_m) - exp(-(t-lastspike_post)/tau_s))
> 
> ```
> 
> to both on\_pre and on\_post, but I am not sure if this is correct.

This will not quite work like this : the `on_pre`/`on_post` statements would set the post-synaptic current at a single time point, but the equation is meant to describe the current over time.

Since the shape of the synaptic current is the same for all synapses (only the height changes with w\_{i,j}), you can include the synaptic current in the post-synaptic cell. The shape is a bi-exponential function of time, which you’d implement with two exponential functions as explained here: [Converting from integrated form to ODEs — Brian 2 2.5.4 documentation](https://brian2.readthedocs.io/en/stable/user/converting_from_integrated_form.html) In the documentation, this is a model of a bi-exponential postsynaptic _potential_, but in your case it would be a _current_, so the neuron equations would have something like:

```python
''''
...
dI/dt = ((tau_S / tau_M) ** (tau_M / (tau_S - tau_M))*x-V)/tau_1 : amp
dx/dt = -x/tau_S : amp
'''

```

and the synapse would have `on_pre = 'x_post += I0*w'`. The somewhat complicated `tau_S`/`tau_M` stuff in the equation is only there as a normalization factor – it might be that this is not necessary in your equations.

---

<div class="post-metadata">

**Author:** ![mallard1707](https://avatars.discourse-cdn.com/v4/letter/m/67e7ee/32.png) [@mallard1707](https://brian.discourse.group/u/mallard1707)\
**Post date:** [7 December 2023 05:31 UTC](https://brian.discourse.group/t/custom-stdp-rule/1091/3 "2023-12-07T05:31:32Z")

</div>

Hi @mstimberg ,

Thank you for the detailed response. I had a question regarding the conversion of the biexponential synapse to ODE form:  
I am trying to derive the expression mentioned in the wiki before proceeding to my own case. After differentiating the example, I get:  
 ![image](https://global.discourse-cdn.com/free1/uploads/brian/original/1X/fbf4ab7db99cfabf4eb4442d795272627fdd0de7.png)  
Now, the example has taken x to be:  
 ![image](https://global.discourse-cdn.com/free1/uploads/brian/original/1X/7dc90a753faa457d4d08f6637a56f2d642b05f5d.png)  
Why haven’t they taken x to be a simpler term that is just the exponential? I didn’t quite understand what you meant by the normalization term.

---

<div class="post-metadata">

**Author:** ![mallard1707](https://avatars.discourse-cdn.com/v4/letter/m/67e7ee/32.png) [@mallard1707](https://brian.discourse.group/u/mallard1707)\
**Post date:** [10 December 2023 09:20 UTC](https://brian.discourse.group/t/custom-stdp-rule/1091/5 "2023-12-10T09:20:20Z")

</div>

Thank you Marcel, I was able to get the STDP and synaptic current to work properly.
