[PATCH synaptics] Add hysteresis-based noise reduction

Simon Thum simon.thum at gmx.de
Mon Feb 7 14:32:27 PST 2011


This introduces hysteresis into the driver's processing. It significantly
reduces noise motion, i.e. now the pad does no longer generate a stream of
sub-pixel events when just holding the position with the finger down.
Also, taking off the finger no longer generates additional motion,
scrolling becomes flicker-free etc.

Signed-off-by: Simon Thum <simon.thum at gmx.de>
---

What's missing is a complementing property, if the patch is acceptable
otherwiese I'm willing to add it.

 man/synaptics.man  |    9 +++++++
 src/synaptics.c    |   62
++++++++++++++++++++++++++++++++++++++++++---------
 src/synapticsstr.h |    3 ++
 3 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/man/synaptics.man b/man/synaptics.man
index 3f1ca9d..06e4976 100644
--- a/man/synaptics.man
+++ b/man/synaptics.man
@@ -222,6 +222,15 @@ Motion Factor"
 Greatest setting for pressure motion factor. Property: "Synaptics Pressure
 Motion Factor"
 .TP
+.BI "Option \*qHorizHysteresis\*q \*q" integer \*q
+The minimum horizontal HW distance required to generate motion events.
Can be
+specified as a percentage. Increase if noise motion is a problem for you.
+Default: 4 percent of the diagonal.
+.TP
+.BI "Option \*qVertHysteresis\*q \*q" integer \*q
+The minimum vertical HW distance required to generate motion events. See
+\fBHorizHysteresis\fR.
+.TP
 .BI "Option \*qUpDownScrolling\*q \*q" boolean \*q
 If on, the up/down buttons generate button 4/5 events.
 .
diff --git a/src/synaptics.c b/src/synaptics.c
index 88bd024..b571d36 100644
--- a/src/synaptics.c
+++ b/src/synaptics.c
@@ -387,18 +387,19 @@ calculate_edge_widths(SynapticsPrivate *priv, int
*l, int *r, int *t, int *b)
  * the log message.
  */
 static int set_percent_option(pointer options, const char* optname,
-                              const int range, const int offset)
+                              const int range, const int offset,
+                              const int defVal)
 {
     int result;
 #if GET_ABI_MAJOR(ABI_XINPUT_VERSION) >= 11
-    int percent = xf86CheckPercentOption(options, optname, -1);
+    double percent = xf86CheckPercentOption(options, optname, -1);
 -    if (percent != -1) {
+    if (percent >= 0.0) {
         percent = xf86SetPercentOption(options, optname, -1);
         result = percent/100.0 * range + offset;
     } else
 #endif
-        result = xf86SetIntOption(options, optname, 0);
+        result = xf86SetIntOption(options, optname, defVal);
      return result;
 }
@@ -427,6 +428,7 @@ static void set_default_parameters(InputInfoPtr pInfo)
     int horizResolution = 1;
     int vertResolution = 1;
     int width, height, diag, range;
+    int horizHyst, vertHyst;
      /* read the parameters */
     if (priv->synshm)
@@ -458,6 +460,10 @@ static void set_default_parameters(InputInfoPtr pInfo)
     edgeMotionMaxSpeed = diag * .080;
     accelFactor = 200.0 / diag; /* trial-and-error */
 +    /* hysteresis */
+    horizHyst = diag * 0.005;
+    vertHyst = diag * 0.005;
+
     range = priv->maxp - priv->minp;
      /* scaling based on defaults and a pressure of 256 */
@@ -513,10 +519,13 @@ static void set_default_parameters(InputInfoPtr pInfo)
     pars->top_edge = xf86SetIntOption(opts, "TopEdge", t);
     pars->bottom_edge = xf86SetIntOption(opts, "BottomEdge", b);
 -    pars->area_top_edge = set_percent_option(opts, "AreaTopEdge",
height, priv->miny);
-    pars->area_bottom_edge = set_percent_option(opts, "AreaBottomEdge",
height, priv->miny);
-    pars->area_left_edge = set_percent_option(opts, "AreaLeftEdge",
width, priv->minx);
-    pars->area_right_edge = set_percent_option(opts, "AreaRightEdge",
width, priv->minx);
+    pars->area_top_edge = set_percent_option(opts, "AreaTopEdge",
height, priv->miny, 0);
+    pars->area_bottom_edge = set_percent_option(opts, "AreaBottomEdge",
height, priv->miny, 0);
+    pars->area_left_edge = set_percent_option(opts, "AreaLeftEdge",
width, priv->minx, 0);
+    pars->area_right_edge = set_percent_option(opts, "AreaRightEdge",
width, priv->minx, 0);
+
+    pars->hyst_x = set_percent_option(opts, "HorizHysteresis", width,
0, horizHyst);
+    pars->hyst_y = set_percent_option(opts, "VertHysteresis", height,
0, vertHyst);
      pars->finger_low = xf86SetIntOption(opts, "FingerLow", fingerLow);
     pars->finger_high = xf86SetIntOption(opts, "FingerHigh", fingerHigh);
@@ -1713,6 +1722,26 @@ estimate_delta(double x0, double x1, double x2,
double x3)
     return x0 * 0.3 + x1 * 0.1 - x2 * 0.1 - x3 * 0.3;
 }
 +/**
+ * applies a hysteresis. center is shifted such that it is in range with
+ * in by the margin again.
+ */
+static int hysteresis(int in, int* center, int margin) {
+    int diff = in - *center;
+    if (abs(diff) < margin)
+	return 0;
+
+    if (diff > margin) {
+	*center += diff - margin;
+	return diff - margin;
+    } else if (diff < -margin) {
+	*center += diff + margin;
+	return diff + margin;
+    } else {
+	return 0;
+    }
+}
+
 static int
 ComputeDeltas(SynapticsPrivate *priv, const struct SynapticsHwState *hw,
 	      edge_type edge, int *dxP, int *dyP, Bool inside_area)
@@ -1746,9 +1775,11 @@ ComputeDeltas(SynapticsPrivate *priv, const
struct SynapticsHwState *hw,
 	!priv->vert_scroll_edge_on && !priv->horiz_scroll_edge_on &&
 	!priv->vert_scroll_twofinger_on && !priv->horiz_scroll_twofinger_on &&
 	!priv->circ_scroll_on && priv->prevFingers == hw->numFingers) {
-	/* FIXME: Wtf?? what's with 13? */
-	delay = MIN(delay, 13);
-	if (priv->count_packet_finger > 3) { /* min. 3 packets */
+	/* to create fluid edge motion, call back 'soon'
+	 * even in the absence of new hardware events */
+	delay = 13;
+
+	if (priv->count_packet_finger > 3) { /* min. 3 packets, see below */
 	    double tmpf;
 	    int x_edge_speed = 0;
 	    int y_edge_speed = 0;
@@ -1761,6 +1792,7 @@ ComputeDeltas(SynapticsPrivate *priv, const struct
SynapticsHwState *hw,
 		dx = dx * dtime * para->trackstick_speed;
 		dy = dy * dtime * para->trackstick_speed;
 	    } else if (moving_state == MS_TOUCHPAD_RELATIVE) {
+		/* HIST is full enough: priv->count_packet_finger > 3 */
 		dx = estimate_delta(hw->x, HIST(0).x, HIST(1).x, HIST(2).x);
 		dy = estimate_delta(hw->y, HIST(0).y, HIST(1).y, HIST(2).y);
 @@ -2384,6 +2416,14 @@ HandleState(InputInfoPtr pInfo, struct
SynapticsHwState *hw)
 	edge = NO_EDGE;
  	dx = dy = 0;
+    } else {
+	/* apply hysteresis before doing anything serious. This cancels
+	 * out a lot of noise which might surface in strange phenomena
+	 * like flicker in scrolling or noise motion. */
+	hysteresis(hw->x, &priv->hyst_center_x, para->hyst_x);
+	hysteresis(hw->y, &priv->hyst_center_y, para->hyst_y);
+	hw->x = priv->hyst_center_x;
+	hw->y = priv->hyst_center_y;
     }
      /* these two just update hw->left, right, etc. */
diff --git a/src/synapticsstr.h b/src/synapticsstr.h
index 9ad8638..9ee3b7b 100644
--- a/src/synapticsstr.h
+++ b/src/synapticsstr.h
@@ -160,6 +160,7 @@ typedef struct _SynapticsParameters
     unsigned int resolution_horiz;          /* horizontal resolution of
touchpad in units/mm */
     unsigned int resolution_vert;           /* vertical resolution of
touchpad in units/mm */
     int area_left_edge, area_right_edge, area_top_edge,
area_bottom_edge; /* area coordinates absolute */
+    int hyst_x, hyst_y;			    /* x and y width of hysteresis box */
 } SynapticsParameters;
  @@ -183,6 +184,8 @@ typedef struct _SynapticsPrivateRec
     Bool absolute_events;               /* post absolute motion events
instead of relative */
     SynapticsMoveHistRec move_hist[SYNAPTICS_MOVE_HISTORY]; /* movement
history */
     int hist_index;			/* Last added entry in move_hist[] */
+    int hyst_center_x;			/* center x of hysteresis*/
+    int hyst_center_y;			/* center y of hysteresis*/
     int scroll_y;			/* last y-scroll position */
     int scroll_x;			/* last x-scroll position */
     double scroll_a;			/* last angle-scroll position */
-- 
1.7.3.4



More information about the xorg-devel mailing list