summaryrefslogtreecommitdiff
path: root/pyspike/cython
diff options
context:
space:
mode:
Diffstat (limited to 'pyspike/cython')
-rw-r--r--pyspike/cython/cython_distances.pyx55
-rw-r--r--pyspike/cython/cython_profiles.pyx61
-rw-r--r--pyspike/cython/python_backend.py53
3 files changed, 109 insertions, 60 deletions
diff --git a/pyspike/cython/cython_distances.pyx b/pyspike/cython/cython_distances.pyx
index c4f2349..41baa60 100644
--- a/pyspike/cython/cython_distances.pyx
+++ b/pyspike/cython/cython_distances.pyx
@@ -176,6 +176,8 @@ def spike_distance_cython(double[:] t1, double[:] t2,
cdef double t_p1, t_f1, t_p2, t_f2, dt_p1, dt_p2, dt_f1, dt_f2
cdef double isi1, isi2, s1, s2
cdef double y_start, y_end, t_last, t_current, spike_value
+ cdef double[:] t_aux1 = np.empty(2)
+ cdef double[:] t_aux2 = np.empty(2)
spike_value = 0.0
@@ -184,19 +186,27 @@ def spike_distance_cython(double[:] t1, double[:] t2,
with nogil: # release the interpreter to allow multithreading
t_last = t_start
- t_p1 = t_start
- t_p2 = t_start
+ # t_p1 = t_start
+ # t_p2 = t_start
+ # auxiliary spikes for edge correction - consistent with first/last ISI
+ t_aux1[0] = fmin(t_start, t1[0]-(t1[1]-t1[0]))
+ t_aux1[1] = fmax(t_end, t1[N1-1]+(t1[N1-1]-t1[N1-2]))
+ t_aux2[0] = fmin(t_start, t2[0]-(t2[1]-t2[0]))
+ t_aux2[1] = fmax(t_end, t2[N2-1]+(t2[N2-1]-t2[N2-2]))
+ t_p1 = t_start if (t1[0] == t_start) else t_aux1[0]
+ t_p2 = t_start if (t2[0] == t_start) else t_aux2[0]
if t1[0] > t_start:
# dt_p1 = t2[0]-t_start
t_f1 = t1[0]
- dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_start, t_end)
+ dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_aux2[0], t_aux2[1])
isi1 = fmax(t_f1-t_start, t1[1]-t1[0])
dt_p1 = dt_f1
- s1 = dt_p1*(t_f1-t_start)/isi1
+ # s1 = dt_p1*(t_f1-t_start)/isi1
+ s1 = dt_p1
index1 = -1
else:
t_f1 = t1[1]
- dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_start, t_end)
+ dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_aux2[0], t_aux2[1])
dt_p1 = 0.0
isi1 = t1[1]-t1[0]
s1 = dt_p1
@@ -204,14 +214,15 @@ def spike_distance_cython(double[:] t1, double[:] t2,
if t2[0] > t_start:
# dt_p1 = t2[0]-t_start
t_f2 = t2[0]
- dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_start, t_end)
+ dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_aux1[0], t_aux1[1])
dt_p2 = dt_f2
isi2 = fmax(t_f2-t_start, t2[1]-t2[0])
- s2 = dt_p2*(t_f2-t_start)/isi2
+ # s2 = dt_p2*(t_f2-t_start)/isi2
+ s2 = dt_p2
index2 = -1
else:
t_f2 = t2[1]
- dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_start, t_end)
+ dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_aux1[0], t_aux1[1])
dt_p2 = 0.0
isi2 = t2[1]-t2[0]
s2 = dt_p2
@@ -233,7 +244,7 @@ def spike_distance_cython(double[:] t1, double[:] t2,
if index1 < N1-1:
t_f1 = t1[index1+1]
else:
- t_f1 = t_end
+ t_f1 = t_aux1[1]
t_curr = t_p1
s2 = (dt_p2*(t_f2-t_p1) + dt_f2*(t_p1-t_p2)) / isi2
y_end = (s1*isi2 + s2*isi1)/isi_avrg_cython(isi1, isi2)
@@ -243,14 +254,16 @@ def spike_distance_cython(double[:] t1, double[:] t2,
# now the next interval start value
if index1 < N1-1:
dt_f1 = get_min_dist_cython(t_f1, t2, N2, index2,
- t_start, t_end)
+ t_aux2[0], t_aux2[1])
isi1 = t_f1-t_p1
s1 = dt_p1
else:
dt_f1 = dt_p1
isi1 = fmax(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
# s1 needs adjustment due to change of isi1
- s1 = dt_p1*(t_end-t1[N1-1])/isi1
+ # s1 = dt_p1*(t_end-t1[N1-1])/isi1
+ # Eero's correction: no adjustment
+ s1 = dt_p1
# s2 is the same as above, thus we can compute y2 immediately
y_start = (s1*isi2 + s2*isi1)/isi_avrg_cython(isi1, isi2)
elif (index2 < N2-1) and (t_f1 > t_f2 or index1 == N1-1):
@@ -264,7 +277,7 @@ def spike_distance_cython(double[:] t1, double[:] t2,
if index2 < N2-1:
t_f2 = t2[index2+1]
else:
- t_f2 = t_end
+ t_f2 = t_aux2[1]
t_curr = t_p2
s1 = (dt_p1*(t_f1-t_p2) + dt_f1*(t_p2-t_p1)) / isi1
y_end = (s1*isi2 + s2*isi1) / isi_avrg_cython(isi1, isi2)
@@ -274,14 +287,16 @@ def spike_distance_cython(double[:] t1, double[:] t2,
# now the next interval start value
if index2 < N2-1:
dt_f2 = get_min_dist_cython(t_f2, t1, N1, index1,
- t_start, t_end)
+ t_aux1[0], t_aux1[1])
isi2 = t_f2-t_p2
s2 = dt_p2
else:
dt_f2 = dt_p2
isi2 = fmax(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
# s2 needs adjustment due to change of isi2
- s2 = dt_p2*(t_end-t2[N2-1])/isi2
+ # s2 = dt_p2*(t_end-t2[N2-1])/isi2
+ # Eero's correction: no adjustment
+ s2 = dt_p2
# s1 is the same as above, thus we can compute y2 immediately
y_start = (s1*isi2 + s2*isi1)/isi_avrg_cython(isi1, isi2)
else: # t_f1 == t_f2 - generate only one event
@@ -298,27 +313,27 @@ def spike_distance_cython(double[:] t1, double[:] t2,
if index1 < N1-1:
t_f1 = t1[index1+1]
dt_f1 = get_min_dist_cython(t_f1, t2, N2, index2,
- t_start, t_end)
+ t_aux2[0], t_aux2[1])
isi1 = t_f1 - t_p1
else:
- t_f1 = t_end
+ t_f1 = t_aux1[1]
dt_f1 = dt_p1
isi1 = fmax(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
if index2 < N2-1:
t_f2 = t2[index2+1]
dt_f2 = get_min_dist_cython(t_f2, t1, N1, index1,
- t_start, t_end)
+ t_aux1[0], t_aux1[1])
isi2 = t_f2 - t_p2
else:
- t_f2 = t_end
+ t_f2 = t_aux2[1]
dt_f2 = dt_p2
isi2 = fmax(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
index += 1
t_last = t_curr
# isi1 = max(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
# isi2 = max(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
- s1 = dt_f1*(t_end-t1[N1-1])/isi1
- s2 = dt_f2*(t_end-t2[N2-1])/isi2
+ s1 = dt_f1 # *(t_end-t1[N1-1])/isi1
+ s2 = dt_f2 # *(t_end-t2[N2-1])/isi2
y_end = (s1*isi2 + s2*isi1) / isi_avrg_cython(isi1, isi2)
spike_value += 0.5*(y_start + y_end) * (t_end - t_last)
# end nogil
diff --git a/pyspike/cython/cython_profiles.pyx b/pyspike/cython/cython_profiles.pyx
index f9893eb..f08de6e 100644
--- a/pyspike/cython/cython_profiles.pyx
+++ b/pyspike/cython/cython_profiles.pyx
@@ -181,6 +181,8 @@ def spike_profile_cython(double[:] t1, double[:] t2,
cdef double[:] spike_events
cdef double[:] y_starts
cdef double[:] y_ends
+ cdef double[:] t_aux1 = np.empty(2)
+ cdef double[:] t_aux2 = np.empty(2)
cdef int N1, N2, index1, index2, index
cdef double t_p1, t_f1, t_p2, t_f2, dt_p1, dt_p2, dt_f1, dt_f2
@@ -189,6 +191,10 @@ def spike_profile_cython(double[:] t1, double[:] t2,
N1 = len(t1)
N2 = len(t2)
+ # we can assume at least two spikes per spike train
+ assert N1 > 1
+ assert N2 > 1
+
spike_events = np.empty(N1+N2+2)
y_starts = np.empty(len(spike_events)-1)
@@ -196,19 +202,27 @@ def spike_profile_cython(double[:] t1, double[:] t2,
with nogil: # release the interpreter to allow multithreading
spike_events[0] = t_start
- t_p1 = t_start
- t_p2 = t_start
+ # t_p1 = t_start
+ # t_p2 = t_start
+ # auxiliary spikes for edge correction - consistent with first/last ISI
+ t_aux1[0] = fmin(t_start, t1[0]-(t1[1]-t1[0]))
+ t_aux1[1] = fmax(t_end, t1[N1-1]+(t1[N1-1]-t1[N1-2]))
+ t_aux2[0] = fmin(t_start, t2[0]-(t2[1]-t2[0]))
+ t_aux2[1] = fmax(t_end, t2[N2-1]+(t2[N2-1]-t2[N2-2]))
+ t_p1 = t_start if (t1[0] == t_start) else t_aux1[0]
+ t_p2 = t_start if (t2[0] == t_start) else t_aux2[0]
if t1[0] > t_start:
# dt_p1 = t2[0]-t_start
t_f1 = t1[0]
- dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_start, t_end)
+ dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_aux2[0], t_aux2[1])
isi1 = fmax(t_f1-t_start, t1[1]-t1[0])
dt_p1 = dt_f1
- s1 = dt_p1*(t_f1-t_start)/isi1
+ # s1 = dt_p1*(t_f1-t_start)/isi1
+ s1 = dt_p1
index1 = -1
else:
t_f1 = t1[1]
- dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_start, t_end)
+ dt_f1 = get_min_dist_cython(t_f1, t2, N2, 0, t_aux2[0], t_aux2[1])
dt_p1 = 0.0
isi1 = t1[1]-t1[0]
s1 = dt_p1
@@ -216,14 +230,15 @@ def spike_profile_cython(double[:] t1, double[:] t2,
if t2[0] > t_start:
# dt_p1 = t2[0]-t_start
t_f2 = t2[0]
- dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_start, t_end)
+ dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_aux1[0], t_aux1[1])
dt_p2 = dt_f2
isi2 = fmax(t_f2-t_start, t2[1]-t2[0])
- s2 = dt_p2*(t_f2-t_start)/isi2
+ # s2 = dt_p2*(t_f2-t_start)/isi2
+ s2 = dt_p2
index2 = -1
else:
t_f2 = t2[1]
- dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_start, t_end)
+ dt_f2 = get_min_dist_cython(t_f2, t1, N1, 0, t_aux1[0], t_aux1[1])
dt_p2 = 0.0
isi2 = t2[1]-t2[0]
s2 = dt_p2
@@ -245,7 +260,7 @@ def spike_profile_cython(double[:] t1, double[:] t2,
if index1 < N1-1:
t_f1 = t1[index1+1]
else:
- t_f1 = t_end
+ t_f1 = t_aux1[1]
spike_events[index] = t_p1
s2 = (dt_p2*(t_f2-t_p1) + dt_f2*(t_p1-t_p2)) / isi2
y_ends[index-1] = (s1*isi2 + s2*isi1)/isi_avrg_cython(isi1,
@@ -253,14 +268,16 @@ def spike_profile_cython(double[:] t1, double[:] t2,
# now the next interval start value
if index1 < N1-1:
dt_f1 = get_min_dist_cython(t_f1, t2, N2, index2,
- t_start, t_end)
+ t_aux2[0], t_aux2[1])
isi1 = t_f1-t_p1
s1 = dt_p1
else:
dt_f1 = dt_p1
isi1 = fmax(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
# s1 needs adjustment due to change of isi1
- s1 = dt_p1*(t_end-t1[N1-1])/isi1
+ # s1 = dt_p1*(t_end-t1[N1-1])/isi1
+ # Eero's correction: no adjustment
+ s1 = dt_p1
# s2 is the same as above, thus we can compute y2 immediately
y_starts[index] = (s1*isi2 + s2*isi1)/isi_avrg_cython(isi1,
isi2)
@@ -275,7 +292,7 @@ def spike_profile_cython(double[:] t1, double[:] t2,
if index2 < N2-1:
t_f2 = t2[index2+1]
else:
- t_f2 = t_end
+ t_f2 = t_aux2[1]
spike_events[index] = t_p2
s1 = (dt_p1*(t_f1-t_p2) + dt_f1*(t_p2-t_p1)) / isi1
y_ends[index-1] = (s1*isi2 + s2*isi1) / isi_avrg_cython(isi1,
@@ -283,14 +300,16 @@ def spike_profile_cython(double[:] t1, double[:] t2,
# now the next interval start value
if index2 < N2-1:
dt_f2 = get_min_dist_cython(t_f2, t1, N1, index1,
- t_start, t_end)
+ t_aux1[0], t_aux1[1])
isi2 = t_f2-t_p2
s2 = dt_p2
else:
dt_f2 = dt_p2
isi2 = fmax(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
# s2 needs adjustment due to change of isi2
- s2 = dt_p2*(t_end-t2[N2-1])/isi2
+ # s2 = dt_p2*(t_end-t2[N2-1])/isi2
+ # Eero's correction: no adjustment
+ s2 = dt_p2
# s2 is the same as above, thus we can compute y2 immediately
y_starts[index] = (s1*isi2 + s2*isi1)/isi_avrg_cython(isi1, isi2)
else: # t_f1 == t_f2 - generate only one event
@@ -306,19 +325,19 @@ def spike_profile_cython(double[:] t1, double[:] t2,
if index1 < N1-1:
t_f1 = t1[index1+1]
dt_f1 = get_min_dist_cython(t_f1, t2, N2, index2,
- t_start, t_end)
+ t_aux2[0], t_aux2[1])
isi1 = t_f1 - t_p1
else:
- t_f1 = t_end
+ t_f1 = t_aux1[1]
dt_f1 = dt_p1
isi1 = fmax(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
if index2 < N2-1:
t_f2 = t2[index2+1]
dt_f2 = get_min_dist_cython(t_f2, t1, N1, index1,
- t_start, t_end)
+ t_aux1[0], t_aux1[1])
isi2 = t_f2 - t_p2
else:
- t_f2 = t_end
+ t_f2 = t_aux2[1]
dt_f2 = dt_p2
isi2 = fmax(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
index += 1
@@ -330,8 +349,10 @@ def spike_profile_cython(double[:] t1, double[:] t2,
# the ending value of the last interval
isi1 = max(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
isi2 = max(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
- s1 = dt_f1*(t_end-t1[N1-1])/isi1
- s2 = dt_f2*(t_end-t2[N2-1])/isi2
+ # s1 = dt_f1*(t_end-t1[N1-1])/isi1
+ # s2 = dt_f2*(t_end-t2[N2-1])/isi2
+ s1 = dt_f1
+ s2 = dt_f2
y_ends[index-1] = (s1*isi2 + s2*isi1) / isi_avrg_cython(isi1, isi2)
# end nogil
diff --git a/pyspike/cython/python_backend.py b/pyspike/cython/python_backend.py
index 69a420f..a5f7ae4 100644
--- a/pyspike/cython/python_backend.py
+++ b/pyspike/cython/python_backend.py
@@ -144,35 +144,44 @@ def spike_distance_python(spikes1, spikes2, t_start, t_end):
y_starts = np.empty(len(spike_events)-1)
y_ends = np.empty(len(spike_events)-1)
+ t_aux1 = np.zeros(2)
+ t_aux2 = np.zeros(2)
+ t_aux1[0] = min(t_start, t1[0]-(t1[1]-t1[0]))
+ t_aux1[1] = max(t_end, t1[N1-1]+(t1[N1-1]-t1[N1-2]))
+ t_aux2[0] = min(t_start, t2[0]-(t2[1]-t2[0]))
+ t_aux2[1] = max(t_end, t2[N2-1]+(t2[N2-1]-t2[N2-2]))
+ t_p1 = t_start if (t1[0] == t_start) else t_aux1[0]
+ t_p2 = t_start if (t2[0] == t_start) else t_aux2[0]
+
spike_events[0] = t_start
- t_p1 = t_start
- t_p2 = t_start
if t1[0] > t_start:
t_f1 = t1[0]
- dt_f1 = get_min_dist(t_f1, t2, 0, t_start, t_end)
+ dt_f1 = get_min_dist(t_f1, t2, 0, t_aux2[0], t_aux2[1])
dt_p1 = dt_f1
isi1 = max(t_f1-t_start, t1[1]-t1[0])
- s1 = dt_p1*(t_f1-t_start)/isi1
+ # s1 = dt_p1*(t_f1-t_start)/isi1
+ s1 = dt_p1
index1 = -1
else:
dt_p1 = 0.0
t_f1 = t1[1]
- dt_f1 = get_min_dist(t_f1, t2, 0, t_start, t_end)
+ dt_f1 = get_min_dist(t_f1, t2, 0, t_aux2[0], t_aux2[1])
isi1 = t1[1]-t1[0]
s1 = dt_p1
index1 = 0
if t2[0] > t_start:
# dt_p1 = t2[0]-t_start
t_f2 = t2[0]
- dt_f2 = get_min_dist(t_f2, t1, 0, t_start, t_end)
+ dt_f2 = get_min_dist(t_f2, t1, 0, t_aux1[0], t_aux1[1])
dt_p2 = dt_f2
isi2 = max(t_f2-t_start, t2[1]-t2[0])
- s2 = dt_p2*(t_f2-t_start)/isi2
+ # s2 = dt_p2*(t_f2-t_start)/isi2
+ s2 = dt_p2
index2 = -1
else:
dt_p2 = 0.0
t_f2 = t2[1]
- dt_f2 = get_min_dist(t_f2, t1, 0, t_start, t_end)
+ dt_f2 = get_min_dist(t_f2, t1, 0, t_aux1[0], t_aux1[1])
isi2 = t2[1]-t2[0]
s2 = dt_p2
index2 = 0
@@ -193,20 +202,22 @@ def spike_distance_python(spikes1, spikes2, t_start, t_end):
if index1 < N1-1:
t_f1 = t1[index1+1]
else:
- t_f1 = t_end
+ t_f1 = t_aux1[1]
spike_events[index] = t_p1
s2 = (dt_p2*(t_f2-t_p1) + dt_f2*(t_p1-t_p2)) / isi2
y_ends[index-1] = (s1*isi2 + s2*isi1) / (0.5*(isi1+isi2)**2)
# now the next interval start value
if index1 < N1-1:
- dt_f1 = get_min_dist(t_f1, t2, index2, t_start, t_end)
+ dt_f1 = get_min_dist(t_f1, t2, index2, t_aux2[0], t_aux2[1])
isi1 = t_f1-t_p1
s1 = dt_p1
else:
dt_f1 = dt_p1
isi1 = max(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
# s1 needs adjustment due to change of isi1
- s1 = dt_p1*(t_end-t1[N1-1])/isi1
+ # s1 = dt_p1*(t_end-t1[N1-1])/isi1
+ # Eero's correction: no adjustment
+ s1 = dt_p1
# s2 is the same as above, thus we can compute y2 immediately
y_starts[index] = (s1*isi2 + s2*isi1) / (0.5*(isi1+isi2)**2)
elif (index2 < N2-1) and (t_f1 > t_f2 or index1 == N1-1):
@@ -220,20 +231,22 @@ def spike_distance_python(spikes1, spikes2, t_start, t_end):
if index2 < N2-1:
t_f2 = t2[index2+1]
else:
- t_f2 = t_end
+ t_f2 = t_aux2[1]
spike_events[index] = t_p2
s1 = (dt_p1*(t_f1-t_p2) + dt_f1*(t_p2-t_p1)) / isi1
y_ends[index-1] = (s1*isi2 + s2*isi1) / (0.5*(isi1+isi2)**2)
# now the next interval start value
if index2 < N2-1:
- dt_f2 = get_min_dist(t_f2, t1, index1, t_start, t_end)
+ dt_f2 = get_min_dist(t_f2, t1, index1, t_aux1[0], t_aux1[1])
isi2 = t_f2-t_p2
s2 = dt_p2
else:
dt_f2 = dt_p2
isi2 = max(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
# s2 needs adjustment due to change of isi2
- s2 = dt_p2*(t_end-t2[N2-1])/isi2
+ # s2 = dt_p2*(t_end-t2[N2-1])/isi2
+ # Eero's adjustment: no correction
+ s2 = dt_p2
# s2 is the same as above, thus we can compute y2 immediately
y_starts[index] = (s1*isi2 + s2*isi1) / (0.5*(isi1+isi2)**2)
else: # t_f1 == t_f2 - generate only one event
@@ -248,18 +261,18 @@ def spike_distance_python(spikes1, spikes2, t_start, t_end):
y_starts[index] = 0.0
if index1 < N1-1:
t_f1 = t1[index1+1]
- dt_f1 = get_min_dist(t_f1, t2, index2, t_start, t_end)
+ dt_f1 = get_min_dist(t_f1, t2, index2, t_aux2[0], t_aux2[1])
isi1 = t_f1 - t_p1
else:
- t_f1 = t_end
+ t_f1 = t_aux1[1]
dt_f1 = dt_p1
isi1 = max(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
if index2 < N2-1:
t_f2 = t2[index2+1]
- dt_f2 = get_min_dist(t_f2, t1, index1, t_start, t_end)
+ dt_f2 = get_min_dist(t_f2, t1, index1, t_aux1[0], t_aux1[1])
isi2 = t_f2 - t_p2
else:
- t_f2 = t_end
+ t_f2 = t_aux2[1]
dt_f2 = dt_p2
isi2 = max(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
index += 1
@@ -271,8 +284,8 @@ def spike_distance_python(spikes1, spikes2, t_start, t_end):
# the ending value of the last interval
isi1 = max(t_end-t1[N1-1], t1[N1-1]-t1[N1-2])
isi2 = max(t_end-t2[N2-1], t2[N2-1]-t2[N2-2])
- s1 = dt_f1*(t_end-t1[N1-1])/isi1
- s2 = dt_f2*(t_end-t2[N2-1])/isi2
+ s1 = dt_f1 # *(t_end-t1[N1-1])/isi1
+ s2 = dt_f2 # *(t_end-t2[N2-1])/isi2
y_ends[index-1] = (s1*isi2 + s2*isi1) / (0.5*(isi1+isi2)**2)
# use only the data added above