2009-03-20 9 views
11

Estoy tratando de detectar la velocidad del movimiento táctil y no siempre obtengo los resultados que esperaba. (añadido: Picos de velocidad demasiado) ¿Alguien puede detectar si estoy haciendo algo funky o sugerir una forma mejor de hacerlo?UITouch detección de la velocidad de movimiento


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
    self.previousTimestamp = event.timestamp; 
} 
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{ 
    UITouch *touch = [touches anyObject]; 
    CGPoint location = [touch locationInView:self.view]; 
    CGPoint prevLocation = [touch previousLocationInView:self.view]; 
    CGFloat distanceFromPrevious = distanceBetweenPoints(location,prevLocation); 
    NSTimeInterval timeSincePrevious = event.timestamp - self.previousTimestamp; 
    CGFloat speed = distanceFromPrevious/timeSincePrevious; 
    self.previousTimestamp = event.timestamp; 
    NSLog(@"dist %f | time %f | speed %f",distanceFromPrevious, timeSincePrevious, speed); 

} 

Respuesta

10

Usted podría intentar (cero a cabo distanceSinceStart y timeSinceStart en touchesBegan):

distanceSinceStart = distanceSinceStart + distanceFromPrevious; 
timeSinceStart = timeSincestart + timeSincePrevious; 
speed = distanceSinceStart/timeSinceStart; 

que le dará la velocidad media desde que empezó el toque (distancia total/tiempo total).

O usted podría hacer una media móvil de la velocidad, tal vez una media móvil exponencial:

const float lambda = 0.8f; // the closer to 1 the higher weight to the next touch 

newSpeed = (1.0 - lambda) * oldSpeed + lambda* (distanceFromPrevious/timeSincePrevious); 
oldSpeed = newSpeed; 

Puede ajustar los valores de lambda a cerca de 1 si se quiere dar más peso a los valores recientes.

+0

Oye ... tengo problemas para implementar esto. ¿La función lambda es parte del objetivo-c? ¿Qué necesito para implementarlo? tia – dizy

+2

No ... es una constante que usted mismo especifica. Cuanto más cerca esté de 1, más peso colocará en el valor más nuevo. Compare con una media aritmética de n valores. Cada nuevo valor tiene un peso de 1/n. Para exponencial, establezca lambda = 2/(n + 1) donde n es el valor aritmético equivalente. Entonces, el nuevo valor se pondera 2/(n + 1) en lugar de 1/n, y luego el promedio móvil existente se reduce por (1-lambda) = (n-1)/(n + 1) y los dos son adicional. ¿Más claro? – Jim

3

El problema principal es que el cálculo de velocidad será muy inexacto cuando timeSincePrevious es muy pequeño (unos pocos milisegundos). Para ver esto, digamos que timeSincePrevious es 1ms. A continuación, la velocidad calculada será 0 si el distanceFromPrevious es 0, y 1000 si el distanceFromZero es 1.

Por esta razón sugiero el siguiente valor de lambda:

const float labmda = (timeSincePrevious>0.2? 1: timeSincePrevious/0.2); 

Eso es decir, usamos una lambda pequeña cuando el timeSincePrevious es pequeño.

+0

Esta es la única respuesta que utiliza un filtro de frecuencia de muestreo variable adecuado. Y para hacerlo como un paso bajo estándar de primer orden: k = ; a = exp (-dt/k); filteredSpeed ​​= a * (dx/dt) + (1-a) * filteredSpeed; – kylefinn

1

La sugerencia de filtro podría estar bien, pero no resuelve el problema: el pico se suavizará, pero se mantendrá.

Si cerró sesión en los eventos táctiles, estos picos se verán como un toque con muy poco delta de tiempo desde el anterior (0.001215 ms), precediendo al tacto con un delta de tiempo grande.

 
distance = 17.269917, timeDelta = 0.016132, speed = 1070.504639 
distance = 15.206906, timeDelta = 0.017494, speed = 869.251709 
distance = 15.882380, timeDelta = 0.017583, speed = 903.297546 
distance = 14.983324, timeDelta = 0.030101, speed = 497.771088  //low peak 
distance = 15.435349, timeDelta = 0.001215, speed = 12703.991211 //high peak! 
distance = 15.882380, timeDelta = 0.017343, speed = 915.795898 
distance = 15.890248, timeDelta = 0.016302, speed = 974.742249 
distance = 16.560495, timeDelta = 0.016468, speed = 1005.606445 
distance = 16.101242, timeDelta = 0.017291, speed = 931.201050 

Lo que hago es calcular un delta de tiempo promedio entre eventos de toque recientes, y si hay un toque con el delta de tiempo anormal (± 30%), no hago caso de su velocidad (manteniendo la velocidad de la edición anterior)

Cuestiones relacionadas