2009-03-20 12 views
11

Sto provando a rilevare la velocità del movimento del tocco e non ottengo sempre i risultati che mi aspetterei. (aggiunto: la velocità aumenta troppo) Qualcuno può individuare se sto facendo qualcosa di funky o suggerire un modo migliore di farlo?Rilevamento della velocità di movimento UITouch


- (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); 

} 

risposta

10

Si potrebbe provare (zero out distanceSinceStart e timeSinceStart in touchesBegan):

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

che vi darà la velocità media da quando hai iniziato il tocco (distanza totale/tempo totale).

Oppure si potrebbe fare una media mobile della velocità, forse una media mobile esponenziale:

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; 

È possibile regolare lambda a valori vicino a 1 se si vuole dare più peso ai valori recenti.

+0

Ehi ... ho problemi ad implementarlo. La funzione lambda è parte dell'obiettivo-c? Di cosa ho bisogno per implementarlo? tia – dizy

+2

No ... è una costante da te specificata. Più si avvicina a 1, più peso si posiziona sul valore più recente. Confronta con una media aritmetica di n valori. Ogni nuovo valore ha un peso di 1/n. Per l'esponenziale, impostare lambda = 2/(n + 1) dove n è il valore aritmetico equivalente. Quindi il nuovo valore è ponderato 2/(n + 1) invece di 1/n, e quindi la media mobile esistente viene ridimensionata di (1-lambda) = (n-1)/(n + 1) e le due sono aggiunto. Più chiaro? – Jim

3

Il problema principale è che il calcolo della velocità sarà molto impreciso quando timeSincePrevious è molto piccolo (alcuni millisecondi). Per vedere questo, supponiamo che timeSincePrevious sia 1ms. Poi la velocità calcolata sarà 0 se il distanceFromPrevious è 0, e 1000 se il distanceFromZero è 1.

Per questo suggerisco il seguente valore di lambda:

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

Vale a diciamo, usiamo un piccolo lambda quando lo timeSincePrevious è piccolo.

+0

Questa è l'unica risposta che utilizza un filtro di frequenza di campionamento variabile appropriato. E per farlo come un normale passa-basso di primo ordine: k = ; a = exp (-dt/k); filteredSpeed ​​= a * (dx/dt) + (1-a) * filteredSpeed; – kylefinn

1

Il suggerimento del filtro potrebbe essere corretto, ma non risolve il problema: il picco verrà appianato, ma resterà.

Se si sono disconnessi gli eventi tattili, questi picchi appariranno come un tocco con un tempo di ritardo molto piccolo rispetto al precedente (0,001215 ms), precedendo al tocco con un delta temporale 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 

Quello che faccio è calcolare una delta di tempo medio tra i recenti eventi touch, e se c'è un tocco con il tempo anomalo delta (± 30%), ignoro la sua velocità (mantenendo la velocità della precedente edizione)

Problemi correlati