2009-03-20 17 views
11

私はタッチの動きの速度を検出しようとしています。私はいつも期待していた結果を得ているわけではありません。 (追加:スピードがあまりにも急上昇)私が何かファンキーなことをしている、またはそれをやるより良い方法を提案してくれる人はいますか?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); 

} 

答えて

10

あなたが試みることができる(ゼロtouchesBeganでdistanceSinceStartとtimeSinceStartアウト):あなたはタッチ(総距離/総時間)を始めてから、あなたに平均速度を与える

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

それとも、おそらく指数移動平均速度の移動平均、行うことができます:あなたは、最近の値に多くの重量を与えたい場合は、1に近い値にラムダを調整することができ

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; 

を。

+0

ねえ...これを実装するのに問題があります。ラムダ関数はobjective-cの一部ですか?それを実装するためには何が必要ですか? tia – dizy

+2

いいえ...あなたが指定する定数です。 1に近ければ近いほど、最新の値に重点を置きます。 n値の算術平均と比較します。それぞれの新しい値は1/nの重みを取得します。 指数関数の場合、lambda = 2 /(n + 1)を設定します。ここで、nは等価算術値です。したがって、新しい値は1/nの代わりに2 /(n + 1)の重み付けされ、既存の移動平均は(1-λ)=(n-1)/(n + 1)追加されました。 もっと明瞭ですか? – Jim

3

主な問題は、timeSincePreviousが非常に小さい(数ミリ秒)ときには、速度計算が非常にと不正確になることです。これを見るには、timeSincePreviousが1msであるとします。

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

にある:distanceFromPreviousは0で、1000あればdistanceFromZeroが、私はラムダの次の値を示唆このため、1

されている場合、計算速度が0になります例えば、timeSincePreviousが小さいときは小さなラムダを使用します。

+0

これは、適切な可変サンプルレートフィルタを使用した唯一の回答です。標準的な1次ローパスのようにする: k = <応答時間>; a = exp(-dt/k);filteredSpeed = a *(dx/dt)+(1-a)* filteredSpeed; – kylefinn

1

フィルタの提案は問題ありませんが、問題は解決しません。ピークは平滑化されますが、残ります。

タッチイベントをログアウトした場合、これらのピークは、以前の(0.001215 ms)の時間デルタがほとんどなく、大きな時間デルタのタッチで先行するタッチのように見えます。

 
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 

私は何をすることは、最近のタッチイベント間の平均時間デルタを計算し、異常時のデルタ(±30%)との接触がある場合、私は(前のイベントの速度を維持する)その速度を無視

関連する問題