diff --git a/preload/apps/ecg/__init__.py b/preload/apps/ecg/__init__.py
index 0b3fe79108c2caace9792d273e02fbd95381dc09..6a0dd08886f37173306c49bbf40eee792d105f89 100644
--- a/preload/apps/ecg/__init__.py
+++ b/preload/apps/ecg/__init__.py
@@ -49,9 +49,9 @@ beta = 3
 
 def update_history(datasets):
     global history, moving_average, alpha, beta
-    for i in range(len(datasets)):
-        history.append(datasets[i] - moving_average)
-        moving_average = (alpha * moving_average + beta * datasets[i]) / (alpha + beta)
+    for val in datasets:
+        history.append(val - moving_average)
+        moving_average = (alpha * moving_average + beta * val) / (alpha + beta)
 
     # trim old elements
     history = history[-HISTORY_MAX:]
@@ -65,25 +65,35 @@ r_threshold = 1
 q_spike = -ECG_RATE
 
 
+def neighbours(n, lst):
+    """
+    neighbours(2, "ABCDE") = ("AB", "BC", "CD", "DE")
+    neighbours(3, "ABCDE") = ("ABC", "BCD", "CDE")
+    """
+
+    for i in range(len(lst) - (n - 1)):
+        yield lst[i : i + n]
+
+
 def detect_pulse(num_new_samples):
     global history, pulse, samples_since_last_pulse, q_threshold, r_threshold, q_spike
-    for i in range(len(history) - num_new_samples - 1, len(history) - 1):
-        if i <= 0:
-            continue
+
+    # look at 3 consecutive samples, starting 2 samples before the samples that were just added, e.g.:
+    # existing samples: "ABCD"
+    # new samples: "EF" => "ABCDEF"
+    # consider ["CDE", "DEF"]
+    # new samples: "GHI" => "ABCDEFGHI"
+    # consider ["EFG", "FGH", "GHI"]
+    for [prev, cur, next_] in neighbours(3, history[-(num_new_samples + 2) :]):
         samples_since_last_pulse += 1
 
-        if (
-            history[i - 1] > history[i]
-            and history[i + 1] > history[i]
-            and history[i] < q_threshold
-        ):
+        if prev > cur < next_ and cur < q_threshold:
             q_spike = samples_since_last_pulse
             # we expect the next q-spike to be at least 60% as high as this one
-            q_threshold = (history[i] * 3) // 5
+            q_threshold = (cur * 3) // 5
         elif (
-            history[i - 1] < history[i]
-            and history[i + 1] < history[i]
-            and history[i] > r_threshold
+            prev < cur > next_
+            and cur > r_threshold
             and samples_since_last_pulse - q_spike < ECG_RATE // 10
         ):
             # the full QRS complex is < 0.1s long, so the q and r spike in particular cannot be more than ECG_RATE//10 samples apart
@@ -93,7 +103,7 @@ def detect_pulse(num_new_samples):
             if pulse < 30 or pulse > 210:
                 pulse = -1
             # we expect the next r-spike to be at least 60% as high as this one
-            r_threshold = (history[i] * 3) // 5
+            r_threshold = (cur * 3) // 5
         elif samples_since_last_pulse > 2 * ECG_RATE:
             q_threshold = -1
             r_threshold = 1