Эх сурвалжийг харах

Rework auto-pause resume-by-distance to use an anchor and persistence

The previous check compared net displacement over a fixed window
against a static multiple of the pause distance threshold, which could
be fooled by GPS jitter accumulating across windows. Anchor the check
on a running-average position taken while paused, scale the threshold
by HDOP (a poor fix needs to move further to count), and require the
condition to hold for most of a short sample history instead of firing
on a single sample.

distance() is exposed via gpx.h instead of being locally forward-declared
in gpx.c, since autopause.c now needs it too.
k4be 1 долоо хоног өмнө
parent
commit
6ea27a1b27
5 өөрчлөгдсөн 57 нэмэгдсэн , 8 устгасан
  1. 4 0
      gps-test-tool/main.h
  2. 49 7
      soft/autopause.c
  3. 3 0
      soft/autopause.h
  4. 0 1
      soft/gpx.c
  5. 1 0
      soft/gpx.h

+ 4 - 0
gps-test-tool/main.h

@@ -256,6 +256,9 @@ struct auto_pause_s {
     unsigned char point_counter;
     unsigned long int prev_distance;
     unsigned char speed_counter;
+    struct location_s pause_anchor;
+    unsigned int anchor_sample_count;
+    unsigned char resume_high_history;
 };
 extern struct auto_pause_s auto_pause;
 
@@ -312,6 +315,7 @@ void iso_time_to_filename(char *time);
 void gps_initialize(void);
 void add_distance(float dist);
 void add_elevation(float ele_change);
+float distance(struct location_s *pos1, struct location_s *pos2);
 
 /* The structured system log (soft/syslog.c) is compiled into this test tool
  * too (see syslog_wrapper.c), so its real log_reject()/log_jump()/log_prefix()

+ 49 - 7
soft/autopause.c

@@ -20,7 +20,16 @@ struct auto_pause_s auto_pause;
  * quiet window before the speed-based check or the next window catches the
  * resume), a false resume pollutes the moving/stopped split and the
  * odometer for as long as it isn't caught. */
-#define AUTO_PAUSE_RESUME_DIST_MULT_X100	150	/* 1.5x the configured distance threshold */
+#define AUTO_PAUSE_RESUME_MIN_DIST_M	15	/* resume distance-from-anchor floor, regardless of HDOP */
+#define AUTO_PAUSE_RESUME_HDOP_MULT	5	/* ...and scale up from there by this many meters per HDOP unit -
+						 * a standard rule-of-thumb for GPS position error (HDOP x a typical
+						 * few-meter UERE), so a poor fix needs to move further to count */
+#define AUTO_PAUSE_RESUME_HISTORY_LEN	7	/* the resume condition must hold for most (see MIN_COUNT below) of
+						 * the last this-many samples, not just instantaneously - the same
+						 * persistence idea used for the speed cap, so a few seconds of
+						 * genuine drift-free movement are needed, not one lucky sample */
+#define AUTO_PAUSE_RESUME_HISTORY_MASK	((1U << AUTO_PAUSE_RESUME_HISTORY_LEN) - 1)
+#define AUTO_PAUSE_RESUME_MIN_COUNT	5
 
 static void auto_unpause(void) {
 	if (!System.tracking_auto_paused)
@@ -38,6 +47,13 @@ static void auto_pause_activate(void) {
 	 * instantly flip-flopping straight back out of the pause this just
 	 * activated. */
 	auto_pause.speed_counter = 0;
+	/* Anchor the resume-by-distance check on where the pause actually
+	 * started, then let it drift towards the running average of positions
+	 * seen while paused (steadier than any single fix - see
+	 * auto_pause_process()). */
+	auto_pause.pause_anchor = location;
+	auto_pause.anchor_sample_count = 1;
+	auto_pause.resume_high_history = 0;
 	log_pause_event(1);
 	beep(50, 3);
 }
@@ -70,15 +86,41 @@ void auto_pause_process(void) {
 			auto_pause.speed_counter = 0;
 		}
 	}
+	/* Resume-by-distance: compared against an anchor updated to the running
+	 * average position seen while paused (steadier than any single fix),
+	 * scaled by HDOP (a poor fix needs to move further to count), and
+	 * required to persist for most of a short window rather than firing on
+	 * one sample - stationary GPS jitter (well under a meter per second) can
+	 * otherwise accumulate across enough net-movement windows to look like a
+	 * real departure. Evaluated every accepted point, not gated on the
+	 * auto_pause_time window below (that window is for the pause trigger
+	 * only), so the persistence history has one sample per point. */
+	if (System.tracking_auto_paused && gps_fix_trustworthy()) {
+		float resume_threshold_m = AUTO_PAUSE_RESUME_MIN_DIST_M;
+		float hdop_threshold_m = (System.hdop_x100/100.0f) * AUTO_PAUSE_RESUME_HDOP_MULT;
+		float dist_from_anchor_m;
+		unsigned char resumed_this_sample;
+
+		if (hdop_threshold_m > resume_threshold_m)
+			resume_threshold_m = hdop_threshold_m;
+
+		auto_pause.anchor_sample_count++;
+		auto_pause.pause_anchor.lat += (location.lat - auto_pause.pause_anchor.lat) / auto_pause.anchor_sample_count;
+		auto_pause.pause_anchor.lon += (location.lon - auto_pause.pause_anchor.lon) / auto_pause.anchor_sample_count;
+
+		dist_from_anchor_m = distance(&location, &auto_pause.pause_anchor);
+		resumed_this_sample = dist_from_anchor_m > resume_threshold_m;
+		auto_pause.resume_high_history = (auto_pause.resume_high_history << 1) | resumed_this_sample;
+		if (__builtin_popcount(auto_pause.resume_high_history & AUTO_PAUSE_RESUME_HISTORY_MASK) >= AUTO_PAUSE_RESUME_MIN_COUNT) {
+			auto_pause.point_counter = 0;
+			auto_unpause();
+			return;
+		}
+	}
 	if (++auto_pause.point_counter < System.conf.auto_pause_time)
 		return;
 	auto_pause.point_counter = 0;
-	if (System.tracking_auto_paused) {
-		unsigned long int resume_threshold = (unsigned long int)System.conf.auto_pause_dist
-			* AUTO_PAUSE_RESUME_DIST_MULT_X100 / 100;
-		if ((System.distance - auto_pause.prev_distance)/100 > resume_threshold)
-			auto_unpause(); /* unpause when distance exceeded */
-	} else {
+	if (!System.tracking_auto_paused) {
 		/* Net displacement over this window can be small even while genuinely
 		 * moving throughout it - a winding path folding back on itself, or a
 		 * short out-and-back - and pausing on that alone, only to have the

+ 3 - 0
soft/autopause.h

@@ -4,6 +4,9 @@ struct auto_pause_s {
 	unsigned char point_counter;
 	unsigned long int prev_distance;
 	unsigned char speed_counter;
+	struct location_s pause_anchor; /* running average position while paused */
+	unsigned int anchor_sample_count;
+	unsigned char resume_high_history; /* bit history: was the anchor-distance/speed resume condition met */
 };
 
 extern struct auto_pause_s auto_pause;

+ 0 - 1
soft/gpx.c

@@ -72,7 +72,6 @@ static struct gpx_s {
 
 float kalman_predict(struct kalman_s *k, float data);
 void kalman_init(struct kalman_s *k);
-float distance(struct location_s *pos1, struct location_s *pos2);
 float elevation_process(float alt, time_t time);
 void add_elevation_filtered(float amount, unsigned char is_gain);
 

+ 1 - 0
soft/gpx.h

@@ -9,6 +9,7 @@ unsigned char gpx_write(struct location_s *loc, FIL *file);
 unsigned char gpx_close(FIL *file);
 void gpx_process_point(struct location_s *loc, FIL *file);
 void gpx_save_single_point(struct location_s *loc);
+float distance(struct location_s *pos1, struct location_s *pos2);
 void add_distance(float dist);
 void add_elevation(float ele_change);
 unsigned char is_paused(void);