Smoothing out didAccelerate messages
I'm working on something similar to an inclinometer. I rotate an image based on the angle calculated in d开发者_StackOverflow社区idAccelerate (from UIAccelerometerDelegate) using the passed in UIAcceleration variable. The image is jittery or twitchy. Even when the phone is laying on its back and not moving. There are some inclinometers in the app store that are super smooth. I've tried to smooth it out by checking the last reading and if it is within a range, don't do anything. That stops some of the twitching but then you get into something that looks like stop animation. How can I get a smoother affect?
I would suggest smoothing using a 'critically damped spring'.
Essentially what you do is calculate your target rotation (which is what you have now). Instead of applying this directly to the image rotation, you attach the image rotation to the target rotation with a spring, or piece of elastic. The spring is damped such that you get no oscillations.
You will need one constant to tune how quickly the system reacts, we'll call this the SpringConstant.
Basically we apply two forces to the rotation, then integrate this over time. The first force is that applied by the spring, Fs = SpringConstant * DistanceToTarget. The second is the damping force, Fd = -CurrentVelocity * 2 * sqrt(SpringConstant)
The CurrentVelocity forms part of the state of the system, and can be initialised to zero.
In each step, you multiply the sum of these two forces by the time step. This gives you the change in the value of the CurrentVelocity.
Multiply this by the time step again and it will give you the displacement.
We add this to the actual rotation of the image.
In c++ code:
float CriticallyDampedSpring( float a_Target,
float a_Current,
float & a_Velocity,
float a_TimeStep )
{
float currentToTarget = a_Target - a_Current;
float springForce = currentToTarget * SPRING_CONSTANT;
float dampingForce = -a_Velocity * 2 * sqrt( SPRING_CONSTANT );
float force = springForce + dampingForce;
a_Velocity += force * a_TimeStep;
float displacement = a_Velocity * a_TimeStep;
return a_Current + displacement;
}
I imagine you have two dimensions of rotation. You just need to use this once for each dimension, and keep track of the velocity of each dimension separately.
In systems I was working with 5 was a good value for the spring constant, but you will have to experiment for your situation. Setting it too high will not get rid of the jerkiness, setting it too low it will react too slowly.
Also, you might be best to make a class that keeps the velocity state rather than have to pass it into the function over and over.
I hope this is helpful :)
精彩评论