VelocityTracker.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928
  1. /*
  2. * Copyright (C) 2012 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #define LOG_TAG "VelocityTracker"
  17. //#define LOG_NDEBUG 0
  18. // Log debug messages about velocity tracking.
  19. #define DEBUG_VELOCITY 0
  20. // Log debug messages about the progress of the algorithm itself.
  21. #define DEBUG_STRATEGY 0
  22. #include <math.h>
  23. #include <limits.h>
  24. #include <cutils/properties.h>
  25. #include <input/VelocityTracker.h>
  26. #include <utils/BitSet.h>
  27. #include <utils/String8.h>
  28. #include <utils/Timers.h>
  29. namespace android {
  30. // Nanoseconds per milliseconds.
  31. static const nsecs_t NANOS_PER_MS = 1000000;
  32. // Threshold for determining that a pointer has stopped moving.
  33. // Some input devices do not send ACTION_MOVE events in the case where a pointer has
  34. // stopped. We need to detect this case so that we can accurately predict the
  35. // velocity after the pointer starts moving again.
  36. static const nsecs_t ASSUME_POINTER_STOPPED_TIME = 40 * NANOS_PER_MS;
  37. static float vectorDot(const float* a, const float* b, uint32_t m) {
  38. float r = 0;
  39. while (m--) {
  40. r += *(a++) * *(b++);
  41. }
  42. return r;
  43. }
  44. static float vectorNorm(const float* a, uint32_t m) {
  45. float r = 0;
  46. while (m--) {
  47. float t = *(a++);
  48. r += t * t;
  49. }
  50. return sqrtf(r);
  51. }
  52. #if DEBUG_STRATEGY || DEBUG_VELOCITY
  53. static String8 vectorToString(const float* a, uint32_t m) {
  54. String8 str;
  55. str.append("[");
  56. while (m--) {
  57. str.appendFormat(" %f", *(a++));
  58. if (m) {
  59. str.append(",");
  60. }
  61. }
  62. str.append(" ]");
  63. return str;
  64. }
  65. static String8 matrixToString(const float* a, uint32_t m, uint32_t n, bool rowMajor) {
  66. String8 str;
  67. str.append("[");
  68. for (size_t i = 0; i < m; i++) {
  69. if (i) {
  70. str.append(",");
  71. }
  72. str.append(" [");
  73. for (size_t j = 0; j < n; j++) {
  74. if (j) {
  75. str.append(",");
  76. }
  77. str.appendFormat(" %f", a[rowMajor ? i * n + j : j * m + i]);
  78. }
  79. str.append(" ]");
  80. }
  81. str.append(" ]");
  82. return str;
  83. }
  84. #endif
  85. // --- VelocityTracker ---
  86. // The default velocity tracker strategy.
  87. // Although other strategies are available for testing and comparison purposes,
  88. // this is the strategy that applications will actually use. Be very careful
  89. // when adjusting the default strategy because it can dramatically affect
  90. // (often in a bad way) the user experience.
  91. const char* VelocityTracker::DEFAULT_STRATEGY = "lsq2";
  92. VelocityTracker::VelocityTracker(const char* strategy) :
  93. mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
  94. char value[PROPERTY_VALUE_MAX];
  95. // Allow the default strategy to be overridden using a system property for debugging.
  96. if (!strategy) {
  97. int length = property_get("debug.velocitytracker.strategy", value, NULL);
  98. if (length > 0) {
  99. strategy = value;
  100. } else {
  101. strategy = DEFAULT_STRATEGY;
  102. }
  103. }
  104. // Configure the strategy.
  105. if (!configureStrategy(strategy)) {
  106. ALOGD("Unrecognized velocity tracker strategy name '%s'.", strategy);
  107. if (!configureStrategy(DEFAULT_STRATEGY)) {
  108. LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%s'!",
  109. strategy);
  110. }
  111. }
  112. }
  113. VelocityTracker::~VelocityTracker() {
  114. delete mStrategy;
  115. }
  116. bool VelocityTracker::configureStrategy(const char* strategy) {
  117. mStrategy = createStrategy(strategy);
  118. return mStrategy != NULL;
  119. }
  120. VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
  121. if (!strcmp("lsq1", strategy)) {
  122. // 1st order least squares. Quality: POOR.
  123. // Frequently underfits the touch data especially when the finger accelerates
  124. // or changes direction. Often underestimates velocity. The direction
  125. // is overly influenced by historical touch points.
  126. return new LeastSquaresVelocityTrackerStrategy(1);
  127. }
  128. if (!strcmp("lsq2", strategy)) {
  129. // 2nd order least squares. Quality: VERY GOOD.
  130. // Pretty much ideal, but can be confused by certain kinds of touch data,
  131. // particularly if the panel has a tendency to generate delayed,
  132. // duplicate or jittery touch coordinates when the finger is released.
  133. return new LeastSquaresVelocityTrackerStrategy(2);
  134. }
  135. if (!strcmp("lsq3", strategy)) {
  136. // 3rd order least squares. Quality: UNUSABLE.
  137. // Frequently overfits the touch data yielding wildly divergent estimates
  138. // of the velocity when the finger is released.
  139. return new LeastSquaresVelocityTrackerStrategy(3);
  140. }
  141. if (!strcmp("wlsq2-delta", strategy)) {
  142. // 2nd order weighted least squares, delta weighting. Quality: EXPERIMENTAL
  143. return new LeastSquaresVelocityTrackerStrategy(2,
  144. LeastSquaresVelocityTrackerStrategy::WEIGHTING_DELTA);
  145. }
  146. if (!strcmp("wlsq2-central", strategy)) {
  147. // 2nd order weighted least squares, central weighting. Quality: EXPERIMENTAL
  148. return new LeastSquaresVelocityTrackerStrategy(2,
  149. LeastSquaresVelocityTrackerStrategy::WEIGHTING_CENTRAL);
  150. }
  151. if (!strcmp("wlsq2-recent", strategy)) {
  152. // 2nd order weighted least squares, recent weighting. Quality: EXPERIMENTAL
  153. return new LeastSquaresVelocityTrackerStrategy(2,
  154. LeastSquaresVelocityTrackerStrategy::WEIGHTING_RECENT);
  155. }
  156. if (!strcmp("int1", strategy)) {
  157. // 1st order integrating filter. Quality: GOOD.
  158. // Not as good as 'lsq2' because it cannot estimate acceleration but it is
  159. // more tolerant of errors. Like 'lsq1', this strategy tends to underestimate
  160. // the velocity of a fling but this strategy tends to respond to changes in
  161. // direction more quickly and accurately.
  162. return new IntegratingVelocityTrackerStrategy(1);
  163. }
  164. if (!strcmp("int2", strategy)) {
  165. // 2nd order integrating filter. Quality: EXPERIMENTAL.
  166. // For comparison purposes only. Unlike 'int1' this strategy can compensate
  167. // for acceleration but it typically overestimates the effect.
  168. return new IntegratingVelocityTrackerStrategy(2);
  169. }
  170. if (!strcmp("legacy", strategy)) {
  171. // Legacy velocity tracker algorithm. Quality: POOR.
  172. // For comparison purposes only. This algorithm is strongly influenced by
  173. // old data points, consistently underestimates velocity and takes a very long
  174. // time to adjust to changes in direction.
  175. return new LegacyVelocityTrackerStrategy();
  176. }
  177. return NULL;
  178. }
  179. void VelocityTracker::clear() {
  180. mCurrentPointerIdBits.clear();
  181. mActivePointerId = -1;
  182. mStrategy->clear();
  183. }
  184. void VelocityTracker::clearPointers(BitSet32 idBits) {
  185. BitSet32 remainingIdBits(mCurrentPointerIdBits.value & ~idBits.value);
  186. mCurrentPointerIdBits = remainingIdBits;
  187. if (mActivePointerId >= 0 && idBits.hasBit(mActivePointerId)) {
  188. mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
  189. }
  190. mStrategy->clearPointers(idBits);
  191. }
  192. void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
  193. while (idBits.count() > MAX_POINTERS) {
  194. idBits.clearLastMarkedBit();
  195. }
  196. if ((mCurrentPointerIdBits.value & idBits.value)
  197. && eventTime >= mLastEventTime + ASSUME_POINTER_STOPPED_TIME) {
  198. #if DEBUG_VELOCITY
  199. ALOGD("VelocityTracker: stopped for %0.3f ms, clearing state.",
  200. (eventTime - mLastEventTime) * 0.000001f);
  201. #endif
  202. // We have not received any movements for too long. Assume that all pointers
  203. // have stopped.
  204. mStrategy->clear();
  205. }
  206. mLastEventTime = eventTime;
  207. mCurrentPointerIdBits = idBits;
  208. if (mActivePointerId < 0 || !idBits.hasBit(mActivePointerId)) {
  209. mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
  210. }
  211. mStrategy->addMovement(eventTime, idBits, positions);
  212. #if DEBUG_VELOCITY
  213. ALOGD("VelocityTracker: addMovement eventTime=%lld, idBits=0x%08x, activePointerId=%d",
  214. eventTime, idBits.value, mActivePointerId);
  215. for (BitSet32 iterBits(idBits); !iterBits.isEmpty(); ) {
  216. uint32_t id = iterBits.firstMarkedBit();
  217. uint32_t index = idBits.getIndexOfBit(id);
  218. iterBits.clearBit(id);
  219. Estimator estimator;
  220. getEstimator(id, &estimator);
  221. ALOGD(" %d: position (%0.3f, %0.3f), "
  222. "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
  223. id, positions[index].x, positions[index].y,
  224. int(estimator.degree),
  225. vectorToString(estimator.xCoeff, estimator.degree + 1).string(),
  226. vectorToString(estimator.yCoeff, estimator.degree + 1).string(),
  227. estimator.confidence);
  228. }
  229. #endif
  230. }
  231. void VelocityTracker::addMovement(const MotionEvent* event) {
  232. int32_t actionMasked = event->getActionMasked();
  233. switch (actionMasked) {
  234. case AMOTION_EVENT_ACTION_DOWN:
  235. case AMOTION_EVENT_ACTION_HOVER_ENTER:
  236. // Clear all pointers on down before adding the new movement.
  237. clear();
  238. break;
  239. case AMOTION_EVENT_ACTION_POINTER_DOWN: {
  240. // Start a new movement trace for a pointer that just went down.
  241. // We do this on down instead of on up because the client may want to query the
  242. // final velocity for a pointer that just went up.
  243. BitSet32 downIdBits;
  244. downIdBits.markBit(event->getPointerId(event->getActionIndex()));
  245. clearPointers(downIdBits);
  246. break;
  247. }
  248. case AMOTION_EVENT_ACTION_MOVE:
  249. case AMOTION_EVENT_ACTION_HOVER_MOVE:
  250. break;
  251. default:
  252. // Ignore all other actions because they do not convey any new information about
  253. // pointer movement. We also want to preserve the last known velocity of the pointers.
  254. // Note that ACTION_UP and ACTION_POINTER_UP always report the last known position
  255. // of the pointers that went up. ACTION_POINTER_UP does include the new position of
  256. // pointers that remained down but we will also receive an ACTION_MOVE with this
  257. // information if any of them actually moved. Since we don't know how many pointers
  258. // will be going up at once it makes sense to just wait for the following ACTION_MOVE
  259. // before adding the movement.
  260. return;
  261. }
  262. size_t pointerCount = event->getPointerCount();
  263. if (pointerCount > MAX_POINTERS) {
  264. pointerCount = MAX_POINTERS;
  265. }
  266. BitSet32 idBits;
  267. for (size_t i = 0; i < pointerCount; i++) {
  268. idBits.markBit(event->getPointerId(i));
  269. }
  270. uint32_t pointerIndex[MAX_POINTERS];
  271. for (size_t i = 0; i < pointerCount; i++) {
  272. pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
  273. }
  274. nsecs_t eventTime;
  275. Position positions[pointerCount];
  276. size_t historySize = event->getHistorySize();
  277. for (size_t h = 0; h < historySize; h++) {
  278. eventTime = event->getHistoricalEventTime(h);
  279. for (size_t i = 0; i < pointerCount; i++) {
  280. uint32_t index = pointerIndex[i];
  281. positions[index].x = event->getHistoricalX(i, h);
  282. positions[index].y = event->getHistoricalY(i, h);
  283. }
  284. addMovement(eventTime, idBits, positions);
  285. }
  286. eventTime = event->getEventTime();
  287. for (size_t i = 0; i < pointerCount; i++) {
  288. uint32_t index = pointerIndex[i];
  289. positions[index].x = event->getX(i);
  290. positions[index].y = event->getY(i);
  291. }
  292. addMovement(eventTime, idBits, positions);
  293. }
  294. bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
  295. Estimator estimator;
  296. if (getEstimator(id, &estimator) && estimator.degree >= 1) {
  297. *outVx = estimator.xCoeff[1];
  298. *outVy = estimator.yCoeff[1];
  299. return true;
  300. }
  301. *outVx = 0;
  302. *outVy = 0;
  303. return false;
  304. }
  305. bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const {
  306. return mStrategy->getEstimator(id, outEstimator);
  307. }
  308. // --- LeastSquaresVelocityTrackerStrategy ---
  309. const nsecs_t LeastSquaresVelocityTrackerStrategy::HORIZON;
  310. const uint32_t LeastSquaresVelocityTrackerStrategy::HISTORY_SIZE;
  311. LeastSquaresVelocityTrackerStrategy::LeastSquaresVelocityTrackerStrategy(
  312. uint32_t degree, Weighting weighting) :
  313. mDegree(degree), mWeighting(weighting) {
  314. clear();
  315. }
  316. LeastSquaresVelocityTrackerStrategy::~LeastSquaresVelocityTrackerStrategy() {
  317. }
  318. void LeastSquaresVelocityTrackerStrategy::clear() {
  319. mIndex = 0;
  320. mMovements[0].idBits.clear();
  321. }
  322. void LeastSquaresVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
  323. BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
  324. mMovements[mIndex].idBits = remainingIdBits;
  325. }
  326. void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
  327. const VelocityTracker::Position* positions) {
  328. if (++mIndex == HISTORY_SIZE) {
  329. mIndex = 0;
  330. }
  331. Movement& movement = mMovements[mIndex];
  332. movement.eventTime = eventTime;
  333. movement.idBits = idBits;
  334. uint32_t count = idBits.count();
  335. for (uint32_t i = 0; i < count; i++) {
  336. movement.positions[i] = positions[i];
  337. }
  338. }
  339. /**
  340. * Solves a linear least squares problem to obtain a N degree polynomial that fits
  341. * the specified input data as nearly as possible.
  342. *
  343. * Returns true if a solution is found, false otherwise.
  344. *
  345. * The input consists of two vectors of data points X and Y with indices 0..m-1
  346. * along with a weight vector W of the same size.
  347. *
  348. * The output is a vector B with indices 0..n that describes a polynomial
  349. * that fits the data, such the sum of W[i] * W[i] * abs(Y[i] - (B[0] + B[1] X[i]
  350. * + B[2] X[i]^2 ... B[n] X[i]^n)) for all i between 0 and m-1 is minimized.
  351. *
  352. * Accordingly, the weight vector W should be initialized by the caller with the
  353. * reciprocal square root of the variance of the error in each input data point.
  354. * In other words, an ideal choice for W would be W[i] = 1 / var(Y[i]) = 1 / stddev(Y[i]).
  355. * The weights express the relative importance of each data point. If the weights are
  356. * all 1, then the data points are considered to be of equal importance when fitting
  357. * the polynomial. It is a good idea to choose weights that diminish the importance
  358. * of data points that may have higher than usual error margins.
  359. *
  360. * Errors among data points are assumed to be independent. W is represented here
  361. * as a vector although in the literature it is typically taken to be a diagonal matrix.
  362. *
  363. * That is to say, the function that generated the input data can be approximated
  364. * by y(x) ~= B[0] + B[1] x + B[2] x^2 + ... + B[n] x^n.
  365. *
  366. * The coefficient of determination (R^2) is also returned to describe the goodness
  367. * of fit of the model for the given data. It is a value between 0 and 1, where 1
  368. * indicates perfect correspondence.
  369. *
  370. * This function first expands the X vector to a m by n matrix A such that
  371. * A[i][0] = 1, A[i][1] = X[i], A[i][2] = X[i]^2, ..., A[i][n] = X[i]^n, then
  372. * multiplies it by w[i]./
  373. *
  374. * Then it calculates the QR decomposition of A yielding an m by m orthonormal matrix Q
  375. * and an m by n upper triangular matrix R. Because R is upper triangular (lower
  376. * part is all zeroes), we can simplify the decomposition into an m by n matrix
  377. * Q1 and a n by n matrix R1 such that A = Q1 R1.
  378. *
  379. * Finally we solve the system of linear equations given by R1 B = (Qtranspose W Y)
  380. * to find B.
  381. *
  382. * For efficiency, we lay out A and Q column-wise in memory because we frequently
  383. * operate on the column vectors. Conversely, we lay out R row-wise.
  384. *
  385. * http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
  386. * http://en.wikipedia.org/wiki/Gram-Schmidt
  387. */
  388. static bool solveLeastSquares(const float* x, const float* y,
  389. const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
  390. #if DEBUG_STRATEGY
  391. ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
  392. vectorToString(x, m).string(), vectorToString(y, m).string(),
  393. vectorToString(w, m).string());
  394. #endif
  395. // Expand the X vector to a matrix A, pre-multiplied by the weights.
  396. float a[n][m]; // column-major order
  397. for (uint32_t h = 0; h < m; h++) {
  398. a[0][h] = w[h];
  399. for (uint32_t i = 1; i < n; i++) {
  400. a[i][h] = a[i - 1][h] * x[h];
  401. }
  402. }
  403. #if DEBUG_STRATEGY
  404. ALOGD(" - a=%s", matrixToString(&a[0][0], m, n, false /*rowMajor*/).string());
  405. #endif
  406. // Apply the Gram-Schmidt process to A to obtain its QR decomposition.
  407. float q[n][m]; // orthonormal basis, column-major order
  408. float r[n][n]; // upper triangular matrix, row-major order
  409. for (uint32_t j = 0; j < n; j++) {
  410. for (uint32_t h = 0; h < m; h++) {
  411. q[j][h] = a[j][h];
  412. }
  413. for (uint32_t i = 0; i < j; i++) {
  414. float dot = vectorDot(&q[j][0], &q[i][0], m);
  415. for (uint32_t h = 0; h < m; h++) {
  416. q[j][h] -= dot * q[i][h];
  417. }
  418. }
  419. float norm = vectorNorm(&q[j][0], m);
  420. if (norm < 0.000001f) {
  421. // vectors are linearly dependent or zero so no solution
  422. #if DEBUG_STRATEGY
  423. ALOGD(" - no solution, norm=%f", norm);
  424. #endif
  425. return false;
  426. }
  427. float invNorm = 1.0f / norm;
  428. for (uint32_t h = 0; h < m; h++) {
  429. q[j][h] *= invNorm;
  430. }
  431. for (uint32_t i = 0; i < n; i++) {
  432. r[j][i] = i < j ? 0 : vectorDot(&q[j][0], &a[i][0], m);
  433. }
  434. }
  435. #if DEBUG_STRATEGY
  436. ALOGD(" - q=%s", matrixToString(&q[0][0], m, n, false /*rowMajor*/).string());
  437. ALOGD(" - r=%s", matrixToString(&r[0][0], n, n, true /*rowMajor*/).string());
  438. // calculate QR, if we factored A correctly then QR should equal A
  439. float qr[n][m];
  440. for (uint32_t h = 0; h < m; h++) {
  441. for (uint32_t i = 0; i < n; i++) {
  442. qr[i][h] = 0;
  443. for (uint32_t j = 0; j < n; j++) {
  444. qr[i][h] += q[j][h] * r[j][i];
  445. }
  446. }
  447. }
  448. ALOGD(" - qr=%s", matrixToString(&qr[0][0], m, n, false /*rowMajor*/).string());
  449. #endif
  450. // Solve R B = Qt W Y to find B. This is easy because R is upper triangular.
  451. // We just work from bottom-right to top-left calculating B's coefficients.
  452. float wy[m];
  453. for (uint32_t h = 0; h < m; h++) {
  454. wy[h] = y[h] * w[h];
  455. }
  456. for (uint32_t i = n; i-- != 0; ) {
  457. outB[i] = vectorDot(&q[i][0], wy, m);
  458. for (uint32_t j = n - 1; j > i; j--) {
  459. outB[i] -= r[i][j] * outB[j];
  460. }
  461. outB[i] /= r[i][i];
  462. }
  463. #if DEBUG_STRATEGY
  464. ALOGD(" - b=%s", vectorToString(outB, n).string());
  465. #endif
  466. // Calculate the coefficient of determination as 1 - (SSerr / SStot) where
  467. // SSerr is the residual sum of squares (variance of the error),
  468. // and SStot is the total sum of squares (variance of the data) where each
  469. // has been weighted.
  470. float ymean = 0;
  471. for (uint32_t h = 0; h < m; h++) {
  472. ymean += y[h];
  473. }
  474. ymean /= m;
  475. float sserr = 0;
  476. float sstot = 0;
  477. for (uint32_t h = 0; h < m; h++) {
  478. float err = y[h] - outB[0];
  479. float term = 1;
  480. for (uint32_t i = 1; i < n; i++) {
  481. term *= x[h];
  482. err -= term * outB[i];
  483. }
  484. sserr += w[h] * w[h] * err * err;
  485. float var = y[h] - ymean;
  486. sstot += w[h] * w[h] * var * var;
  487. }
  488. *outDet = sstot > 0.000001f ? 1.0f - (sserr / sstot) : 1;
  489. #if DEBUG_STRATEGY
  490. ALOGD(" - sserr=%f", sserr);
  491. ALOGD(" - sstot=%f", sstot);
  492. ALOGD(" - det=%f", *outDet);
  493. #endif
  494. return true;
  495. }
  496. bool LeastSquaresVelocityTrackerStrategy::getEstimator(uint32_t id,
  497. VelocityTracker::Estimator* outEstimator) const {
  498. outEstimator->clear();
  499. // Iterate over movement samples in reverse time order and collect samples.
  500. float x[HISTORY_SIZE];
  501. float y[HISTORY_SIZE];
  502. float w[HISTORY_SIZE];
  503. float time[HISTORY_SIZE];
  504. uint32_t m = 0;
  505. uint32_t index = mIndex;
  506. const Movement& newestMovement = mMovements[mIndex];
  507. do {
  508. const Movement& movement = mMovements[index];
  509. if (!movement.idBits.hasBit(id)) {
  510. break;
  511. }
  512. nsecs_t age = newestMovement.eventTime - movement.eventTime;
  513. if (age > HORIZON) {
  514. break;
  515. }
  516. const VelocityTracker::Position& position = movement.getPosition(id);
  517. x[m] = position.x;
  518. y[m] = position.y;
  519. w[m] = chooseWeight(index);
  520. time[m] = -age * 0.000000001f;
  521. index = (index == 0 ? HISTORY_SIZE : index) - 1;
  522. } while (++m < HISTORY_SIZE);
  523. if (m == 0) {
  524. return false; // no data
  525. }
  526. // Calculate a least squares polynomial fit.
  527. uint32_t degree = mDegree;
  528. if (degree > m - 1) {
  529. degree = m - 1;
  530. }
  531. if (degree >= 1) {
  532. float xdet, ydet;
  533. uint32_t n = degree + 1;
  534. if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
  535. && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) {
  536. outEstimator->time = newestMovement.eventTime;
  537. outEstimator->degree = degree;
  538. outEstimator->confidence = xdet * ydet;
  539. #if DEBUG_STRATEGY
  540. ALOGD("estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
  541. int(outEstimator->degree),
  542. vectorToString(outEstimator->xCoeff, n).string(),
  543. vectorToString(outEstimator->yCoeff, n).string(),
  544. outEstimator->confidence);
  545. #endif
  546. return true;
  547. }
  548. }
  549. // No velocity data available for this pointer, but we do have its current position.
  550. outEstimator->xCoeff[0] = x[0];
  551. outEstimator->yCoeff[0] = y[0];
  552. outEstimator->time = newestMovement.eventTime;
  553. outEstimator->degree = 0;
  554. outEstimator->confidence = 1;
  555. return true;
  556. }
  557. float LeastSquaresVelocityTrackerStrategy::chooseWeight(uint32_t index) const {
  558. switch (mWeighting) {
  559. case WEIGHTING_DELTA: {
  560. // Weight points based on how much time elapsed between them and the next
  561. // point so that points that "cover" a shorter time span are weighed less.
  562. // delta 0ms: 0.5
  563. // delta 10ms: 1.0
  564. if (index == mIndex) {
  565. return 1.0f;
  566. }
  567. uint32_t nextIndex = (index + 1) % HISTORY_SIZE;
  568. float deltaMillis = (mMovements[nextIndex].eventTime- mMovements[index].eventTime)
  569. * 0.000001f;
  570. if (deltaMillis < 0) {
  571. return 0.5f;
  572. }
  573. if (deltaMillis < 10) {
  574. return 0.5f + deltaMillis * 0.05;
  575. }
  576. return 1.0f;
  577. }
  578. case WEIGHTING_CENTRAL: {
  579. // Weight points based on their age, weighing very recent and very old points less.
  580. // age 0ms: 0.5
  581. // age 10ms: 1.0
  582. // age 50ms: 1.0
  583. // age 60ms: 0.5
  584. float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime)
  585. * 0.000001f;
  586. if (ageMillis < 0) {
  587. return 0.5f;
  588. }
  589. if (ageMillis < 10) {
  590. return 0.5f + ageMillis * 0.05;
  591. }
  592. if (ageMillis < 50) {
  593. return 1.0f;
  594. }
  595. if (ageMillis < 60) {
  596. return 0.5f + (60 - ageMillis) * 0.05;
  597. }
  598. return 0.5f;
  599. }
  600. case WEIGHTING_RECENT: {
  601. // Weight points based on their age, weighing older points less.
  602. // age 0ms: 1.0
  603. // age 50ms: 1.0
  604. // age 100ms: 0.5
  605. float ageMillis = (mMovements[mIndex].eventTime - mMovements[index].eventTime)
  606. * 0.000001f;
  607. if (ageMillis < 50) {
  608. return 1.0f;
  609. }
  610. if (ageMillis < 100) {
  611. return 0.5f + (100 - ageMillis) * 0.01f;
  612. }
  613. return 0.5f;
  614. }
  615. case WEIGHTING_NONE:
  616. default:
  617. return 1.0f;
  618. }
  619. }
  620. // --- IntegratingVelocityTrackerStrategy ---
  621. IntegratingVelocityTrackerStrategy::IntegratingVelocityTrackerStrategy(uint32_t degree) :
  622. mDegree(degree) {
  623. }
  624. IntegratingVelocityTrackerStrategy::~IntegratingVelocityTrackerStrategy() {
  625. }
  626. void IntegratingVelocityTrackerStrategy::clear() {
  627. mPointerIdBits.clear();
  628. }
  629. void IntegratingVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
  630. mPointerIdBits.value &= ~idBits.value;
  631. }
  632. void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
  633. const VelocityTracker::Position* positions) {
  634. uint32_t index = 0;
  635. for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
  636. uint32_t id = iterIdBits.clearFirstMarkedBit();
  637. State& state = mPointerState[id];
  638. const VelocityTracker::Position& position = positions[index++];
  639. if (mPointerIdBits.hasBit(id)) {
  640. updateState(state, eventTime, position.x, position.y);
  641. } else {
  642. initState(state, eventTime, position.x, position.y);
  643. }
  644. }
  645. mPointerIdBits = idBits;
  646. }
  647. bool IntegratingVelocityTrackerStrategy::getEstimator(uint32_t id,
  648. VelocityTracker::Estimator* outEstimator) const {
  649. outEstimator->clear();
  650. if (mPointerIdBits.hasBit(id)) {
  651. const State& state = mPointerState[id];
  652. populateEstimator(state, outEstimator);
  653. return true;
  654. }
  655. return false;
  656. }
  657. void IntegratingVelocityTrackerStrategy::initState(State& state,
  658. nsecs_t eventTime, float xpos, float ypos) const {
  659. state.updateTime = eventTime;
  660. state.degree = 0;
  661. state.xpos = xpos;
  662. state.xvel = 0;
  663. state.xaccel = 0;
  664. state.ypos = ypos;
  665. state.yvel = 0;
  666. state.yaccel = 0;
  667. }
  668. void IntegratingVelocityTrackerStrategy::updateState(State& state,
  669. nsecs_t eventTime, float xpos, float ypos) const {
  670. const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
  671. const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
  672. if (eventTime <= state.updateTime + MIN_TIME_DELTA) {
  673. return;
  674. }
  675. float dt = (eventTime - state.updateTime) * 0.000000001f;
  676. state.updateTime = eventTime;
  677. float xvel = (xpos - state.xpos) / dt;
  678. float yvel = (ypos - state.ypos) / dt;
  679. if (state.degree == 0) {
  680. state.xvel = xvel;
  681. state.yvel = yvel;
  682. state.degree = 1;
  683. } else {
  684. float alpha = dt / (FILTER_TIME_CONSTANT + dt);
  685. if (mDegree == 1) {
  686. state.xvel += (xvel - state.xvel) * alpha;
  687. state.yvel += (yvel - state.yvel) * alpha;
  688. } else {
  689. float xaccel = (xvel - state.xvel) / dt;
  690. float yaccel = (yvel - state.yvel) / dt;
  691. if (state.degree == 1) {
  692. state.xaccel = xaccel;
  693. state.yaccel = yaccel;
  694. state.degree = 2;
  695. } else {
  696. state.xaccel += (xaccel - state.xaccel) * alpha;
  697. state.yaccel += (yaccel - state.yaccel) * alpha;
  698. }
  699. state.xvel += (state.xaccel * dt) * alpha;
  700. state.yvel += (state.yaccel * dt) * alpha;
  701. }
  702. }
  703. state.xpos = xpos;
  704. state.ypos = ypos;
  705. }
  706. void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
  707. VelocityTracker::Estimator* outEstimator) const {
  708. outEstimator->time = state.updateTime;
  709. outEstimator->confidence = 1.0f;
  710. outEstimator->degree = state.degree;
  711. outEstimator->xCoeff[0] = state.xpos;
  712. outEstimator->xCoeff[1] = state.xvel;
  713. outEstimator->xCoeff[2] = state.xaccel / 2;
  714. outEstimator->yCoeff[0] = state.ypos;
  715. outEstimator->yCoeff[1] = state.yvel;
  716. outEstimator->yCoeff[2] = state.yaccel / 2;
  717. }
  718. // --- LegacyVelocityTrackerStrategy ---
  719. const nsecs_t LegacyVelocityTrackerStrategy::HORIZON;
  720. const uint32_t LegacyVelocityTrackerStrategy::HISTORY_SIZE;
  721. const nsecs_t LegacyVelocityTrackerStrategy::MIN_DURATION;
  722. LegacyVelocityTrackerStrategy::LegacyVelocityTrackerStrategy() {
  723. clear();
  724. }
  725. LegacyVelocityTrackerStrategy::~LegacyVelocityTrackerStrategy() {
  726. }
  727. void LegacyVelocityTrackerStrategy::clear() {
  728. mIndex = 0;
  729. mMovements[0].idBits.clear();
  730. }
  731. void LegacyVelocityTrackerStrategy::clearPointers(BitSet32 idBits) {
  732. BitSet32 remainingIdBits(mMovements[mIndex].idBits.value & ~idBits.value);
  733. mMovements[mIndex].idBits = remainingIdBits;
  734. }
  735. void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
  736. const VelocityTracker::Position* positions) {
  737. if (++mIndex == HISTORY_SIZE) {
  738. mIndex = 0;
  739. }
  740. Movement& movement = mMovements[mIndex];
  741. movement.eventTime = eventTime;
  742. movement.idBits = idBits;
  743. uint32_t count = idBits.count();
  744. for (uint32_t i = 0; i < count; i++) {
  745. movement.positions[i] = positions[i];
  746. }
  747. }
  748. bool LegacyVelocityTrackerStrategy::getEstimator(uint32_t id,
  749. VelocityTracker::Estimator* outEstimator) const {
  750. outEstimator->clear();
  751. const Movement& newestMovement = mMovements[mIndex];
  752. if (!newestMovement.idBits.hasBit(id)) {
  753. return false; // no data
  754. }
  755. // Find the oldest sample that contains the pointer and that is not older than HORIZON.
  756. nsecs_t minTime = newestMovement.eventTime - HORIZON;
  757. uint32_t oldestIndex = mIndex;
  758. uint32_t numTouches = 1;
  759. do {
  760. uint32_t nextOldestIndex = (oldestIndex == 0 ? HISTORY_SIZE : oldestIndex) - 1;
  761. const Movement& nextOldestMovement = mMovements[nextOldestIndex];
  762. if (!nextOldestMovement.idBits.hasBit(id)
  763. || nextOldestMovement.eventTime < minTime) {
  764. break;
  765. }
  766. oldestIndex = nextOldestIndex;
  767. } while (++numTouches < HISTORY_SIZE);
  768. // Calculate an exponentially weighted moving average of the velocity estimate
  769. // at different points in time measured relative to the oldest sample.
  770. // This is essentially an IIR filter. Newer samples are weighted more heavily
  771. // than older samples. Samples at equal time points are weighted more or less
  772. // equally.
  773. //
  774. // One tricky problem is that the sample data may be poorly conditioned.
  775. // Sometimes samples arrive very close together in time which can cause us to
  776. // overestimate the velocity at that time point. Most samples might be measured
  777. // 16ms apart but some consecutive samples could be only 0.5sm apart because
  778. // the hardware or driver reports them irregularly or in bursts.
  779. float accumVx = 0;
  780. float accumVy = 0;
  781. uint32_t index = oldestIndex;
  782. uint32_t samplesUsed = 0;
  783. const Movement& oldestMovement = mMovements[oldestIndex];
  784. const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id);
  785. nsecs_t lastDuration = 0;
  786. while (numTouches-- > 1) {
  787. if (++index == HISTORY_SIZE) {
  788. index = 0;
  789. }
  790. const Movement& movement = mMovements[index];
  791. nsecs_t duration = movement.eventTime - oldestMovement.eventTime;
  792. // If the duration between samples is small, we may significantly overestimate
  793. // the velocity. Consequently, we impose a minimum duration constraint on the
  794. // samples that we include in the calculation.
  795. if (duration >= MIN_DURATION) {
  796. const VelocityTracker::Position& position = movement.getPosition(id);
  797. float scale = 1000000000.0f / duration; // one over time delta in seconds
  798. float vx = (position.x - oldestPosition.x) * scale;
  799. float vy = (position.y - oldestPosition.y) * scale;
  800. accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
  801. accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
  802. lastDuration = duration;
  803. samplesUsed += 1;
  804. }
  805. }
  806. // Report velocity.
  807. const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id);
  808. outEstimator->time = newestMovement.eventTime;
  809. outEstimator->confidence = 1;
  810. outEstimator->xCoeff[0] = newestPosition.x;
  811. outEstimator->yCoeff[0] = newestPosition.y;
  812. if (samplesUsed) {
  813. outEstimator->xCoeff[1] = accumVx;
  814. outEstimator->yCoeff[1] = accumVy;
  815. outEstimator->degree = 1;
  816. } else {
  817. outEstimator->degree = 0;
  818. }
  819. return true;
  820. }
  821. } // namespace android