From f6c02be8b3b75b78f2abc9af6d2e3a8b8bc6bded Mon Sep 17 00:00:00 2001
From: amitjans <amitjans@ethz.ch>
Date: Tue, 6 Jul 2021 11:27:37 +0200
Subject: [PATCH] Display dark ion fit error

---
 templates/index.html |  7 +++++++
 tools.py             | 46 ++++++++++++++++++++++++++++++++++++++++----
 2 files changed, 49 insertions(+), 4 deletions(-)

diff --git a/templates/index.html b/templates/index.html
index e2fd576..38b5956 100644
--- a/templates/index.html
+++ b/templates/index.html
@@ -23,6 +23,7 @@
         <p style="font-size: 23px">Linearity: <span id="linearity" style="color: red"></span></p>
         <p style="font-size: 23px">Max spot size: <span id="max_spot_size" style="color: red"></span></p>
         <p style="font-size: 23px">Ion roundness: <span id="roundness" style="color: red"></span>%</p>
+        <p style="font-size: 23px">Fit error: <span id="fit_error" style="color: red"></span> (Moving avg: <span id="fit_avg" style="color: red"></span>) <span id="response" style="color: red"></span></p>
         <h2 style="font-size: 35px">Stream:</h2>
         <span class="img-container">
             <img src="{{ url_for('video_feed') }}" width="450" height="350" alt="Streaming">
@@ -36,6 +37,12 @@
                 for (let key in jsonResponse) {
                     document.getElementById(key).innerText = jsonResponse[key];
                 }
+                if (Number(document.getElementById("fit_avg").innerText) >= 20) {
+                document.getElementById("response").innerText = "Calibration needed!"
+                }
+                else{
+                    document.getElementById("response").innerText = ""
+            }
             };
 
             setInterval(() => {
diff --git a/tools.py b/tools.py
index 9d620a3..4f1b284 100644
--- a/tools.py
+++ b/tools.py
@@ -48,6 +48,7 @@ class Main:
         # Instantiate classes
         self.memory = Memory()
         self.count_avg = MovingAverage()
+        self.fit_avg = FitAverage()
         self.trap_state = TrapState()
 
         # Define class attributes
@@ -87,7 +88,9 @@ class Main:
                         'reorder_avg': self.count_avg.moving_avg,
                         'reorder_flag': -1,
                         'max_spot_size': -1,
-                        'roundness': -1
+                        'roundness': -1,
+                        'fit_error': -1,
+                        'fit_avg': -1
                         }
 
             elif not ion_cloud:
@@ -121,7 +124,8 @@ class Main:
             linearity = ion_linearity(coord)
 
             if len(coord) > 1 and dist_factor is not None:
-                coord = dark_ions(img, coord, dist_factor)
+                coord, fit_error = dark_ions(img, coord, dist_factor)
+                self.fit_avg.update_value(fit_error)
         else:
             roundness = 0
             max_int, num_pix = (0, 0)
@@ -163,7 +167,9 @@ class Main:
             'reorder_avg': self.count_avg.moving_avg,
             'reorder_flag': reorder_flag,
             'max_spot_size': int(max_spot_size),
-            'roundness': int(roundness)  
+            'roundness': int(roundness),
+            'fit_error': int(fit_error),
+            'fit_avg': int(self.fit_avg.moving_avg)
             }
 
     def _save_in_memory(self, output):
@@ -278,6 +284,38 @@ class Memory:
         return max_value
 
 
+class FitAverage:
+    """
+    Compute moving average of fit error
+    """
+    def __init__(self):
+        self.value = 0
+        self.value_history = [0]
+        self.moving_avg = 0
+
+        self.update_history()
+
+    def update_history(self):
+        """
+        Every second update history and compute moving average.
+        """
+        _thread = threading.Timer(1, self.update_history)
+        _thread.daemon = True
+        _thread.start()
+        self.value_history.append(self.value)
+        if len(self.value_history) > 60:
+            self.value_history.pop(0)
+        self.moving_avg = np.mean(self.value_history)
+        min_val = min(self.value_history)
+        self.value_history = [i - min_val for i in self.value_history]
+        self.value -= min_val
+
+    def update_value(self, value):
+        """
+        Update value.
+        """
+        self.value = value
+
 class MovingAverage:
     """
     Keep record of number of reorders of the ions and return a moving average of
@@ -603,7 +641,7 @@ def dark_ions(image, coord, dist_factor):
         #     warnings.warn("Loss is too high... "
         #     "Try calculating a new factor value using calibrate() function.")
 
-    return coord
+    return coord, loss.min()
 
 
 def acquire_semaphore_read(name: str, timeout=1):
-- 
GitLab