4 ms·
Yeah; say for example you're trying to recognize a swipe with a certain velocity on a touchscreen: def touchDown(): velocity = 0 lastTime =
by panic 8y ago
Yeah; say for example you're trying to recognize a swipe with a certain velocity on a touchscreen:
def touchDown():
velocity = 0
lastTime = now
def touchMoved(from, to):
velocity = (to - from) / (now - lastTime)
lastTime = now
def touchFinished():
if velocity.x > threshold:
performGesture()
You test it out, and discover that the gesture is kind of flaky. Sometimes it works properly, but just as often it fails when it feels like it should have worked. It turns out that maintaining a constant velocity is hard—as your finger moves across the screen, the velocity can fluctuate around between samples. The test in touchFinished() looks at only the last sample taken, which is often the worst, as your finger has just lifted off from the screen.
So instead of just looking at the last velocity, you keep track of a "smoothedVelocity" which averages your velocity samples together:
def touchDown():
smoothedVelocity = 0
lastTime = now
def touchMoved(from, to):
velocity = (to - from) / (now - lastTime)
smoothedVelocity = 0.25 * velocity + 0.75 * smoothedVelocity
lastTime = now
def touchFinished():
if smoothedVelocity.x > threshold:
performGesture()
With this change, your smoothedVelocity moves a bit toward the measured velocity with each sample, but won't jump directly there. This feels a lot more predictable. Stopping your finger momentarily as it lifts off the screen won't stop the gesture from being performed, for example.
The smoothedVelocity code implements a low-pass IIR filter (it filters out the high-frequency fluctuations while letting the lower-frequency motion pass through). You could also imagine just keeping the last 2 velocities and averaging them together at the end: that would be an FIR filter.
- ttoinou 8y agoGood example. I would add that you don't need to understand DSP and IIR to understand that particular example (IIR with only one memory case), it's only a 1D barycenter between previous version and last weighted value.