filter: explain the acceleration function in detail
authorPeter Hutterer <peter.hutterer@who-t.net>
Wed, 5 Aug 2015 03:39:33 +0000 (13:39 +1000)
committerPeter Hutterer <peter.hutterer@who-t.net>
Mon, 10 Aug 2015 23:19:55 +0000 (09:19 +1000)
And switch to a code-flow that's a bit more self-explanatory than the current
min/max combinations.

Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Jonas Ã…dahl <jadahl@gmail.com>
src/filter.c

index 425bc795c1c476ee0992b6c45dad957ded8bd675..467eb2251709653c53d856b5274f0b3308565d32 100644 (file)
@@ -421,19 +421,26 @@ pointer_accel_profile_linear_low_dpi(struct motion_filter *filter,
        struct pointer_accelerator *accel_filter =
                (struct pointer_accelerator *)filter;
 
-       double f1, f2; /* unitless */
        double max_accel = accel_filter->accel; /* unitless factor */
-       const double threshold = accel_filter->threshold; /* units/us */
+       double threshold = accel_filter->threshold; /* units/us */
        const double incline = accel_filter->incline;
        double factor; /* unitless */
        double dpi_factor = accel_filter->dpi_factor;
 
+       /* dpi_factor is always < 1.0, increase max_accel, reduce
+          the threshold so it kicks in earlier */
        max_accel /= dpi_factor;
+       threshold *= dpi_factor;
 
-       f1 = min(1, 0.3 + v_us2ms(speed_in) * 10.0);
-       f2 = 1 + (v_us2ms(speed_in) - v_us2ms(threshold) * dpi_factor) * incline;
+       /* see pointer_accel_profile_linear for a long description */
+       if (v_us2ms(speed_in) < 0.07)
+               factor = 10 * v_us2ms(speed_in) + 0.3;
+       else if (speed_in < threshold)
+               factor = 1;
+       else
+               factor = incline * v_us2ms(speed_in - threshold) + 1;
 
-       factor = min(max_accel, f2 > 1 ? f2 : f1);
+       factor = min(max_accel, factor);
 
        return factor;
 }
@@ -446,17 +453,67 @@ pointer_accel_profile_linear(struct motion_filter *filter,
 {
        struct pointer_accelerator *accel_filter =
                (struct pointer_accelerator *)filter;
-
-       double f1, f2; /* unitless */
        const double max_accel = accel_filter->accel; /* unitless factor */
        const double threshold = accel_filter->threshold; /* units/us */
        const double incline = accel_filter->incline;
        double factor; /* unitless */
 
-       f1 = min(1, 0.3 + v_us2ms(speed_in) * 10);
-       f2 = 1 + (v_us2ms(speed_in) - v_us2ms(threshold)) * incline;
+       /*
+          Our acceleration function calculates a factor to accelerate input
+          deltas with. The function is a double incline with a plateau,
+          with a rough shape like this:
+
+         accel
+        factor
+          ^
+          |        /
+          |  _____/
+          | /
+          |/
+          +-------------> speed in
+
+          The two inclines are linear functions in the form
+                  y = ax + b
+                  where y is speed_out
+                        x is speed_in
+                        a is the incline of acceleration
+                        b is minimum acceleration factor
+
+          for speeds up to 0.07 u/ms, we decelerate, down to 30% of input
+          speed.
+                  hence 1 = a * 0.07 + 0.3
+                      0.3 = a * 0.00 + 0.3 => a := 10
+                  deceleration function is thus:
+                       y = 10x + 0.3
+
+         Note:
+         * 0.07u/ms as threshold is a result of trial-and-error and
+           has no other intrinsic meaning.
+         * 0.3 is chosen simply because it is above the Nyquist frequency
+           for subpixel motion within a pixel.
+       */
+       if (v_us2ms(speed_in) < 0.07) {
+               factor = 10 * v_us2ms(speed_in) + 0.3;
+       /* up to the threshold, we keep factor 1, i.e. 1:1 movement */
+       } else if (speed_in < threshold) {
+               factor = 1;
+
+       } else {
+       /* Acceleration function above the threshold:
+               y = ax' + b
+               where T is threshold
+                     x is speed_in
+                     x' is speed
+               and
+                       y(T) == 1
+               hence 1 = ax' + 1
+                       => x' := (x - T)
+        */
+               factor = incline * v_us2ms(speed_in - threshold) + 1;
+       }
 
-       factor = min(max_accel, f2 > 1 ? f2 : f1);
+       /* Cap at the maximum acceleration factor */
+       factor = min(max_accel, factor);
 
        return factor;
 }
@@ -509,6 +566,12 @@ touchpad_lenovo_x230_accel_profile(struct motion_filter *filter,
                                  TP_MAGIC_LOW_RES_FACTOR; /* units/us */
        const double incline = accel_filter->incline * TP_MAGIC_LOW_RES_FACTOR;
 
+       /* Note: the magic values in this function are obtained by
+        * trial-and-error. No other meaning should be interpreted.
+        * The calculation is a compressed form of
+        * pointer_accel_profile_linear(), look at the git history of that
+        * function for an explaination of what the min/max/etc. does.
+        */
        speed_in *= TP_MAGIC_SLOWDOWN / TP_MAGIC_LOW_RES_FACTOR;
 
        f1 = min(1, v_us2ms(speed_in) * 5);