views:

958

answers:

15

I'm implementing the scrolling behaviour of a touch screen UI but I'm too tired in the moment to wrap my mind around some supposedly trivial piece of math:

y (distance/velocity)
|********
|        ******
|              ****
|                  ***
|                     ***
|                        **
|                          **
|                            *
|                             *
-------------------------------- x (time)

f(x)->?

The UI is supposed to allow the user to drag and "throw" a view in any direction and to keep it scrolling for a while even after he releases the finger from the screen. It's sort of having a momentum that depends on how fast the user was dragging before he took off the finger.

So I have a starting velocity (v0) and every 20ms I scroll by a amount relative to the current velocity. With every scrolling iteration I lower the velocity a bit until it falls below a threshold when I stop it. It just doesn't look right when I decrement it by a fixed amount (linear), so I need to model a negative acceleration but fail to come up with a decent simple formula how to calculate the amount by which I have to lower the velocity in every iteration.

Update:

Thank you for your responses so far but I still didn't manage to derive a satisfying function from the feedback yet. I probably didn't describe the desired solution good enough, so I'll try to give a real world example that should illustrate what kind of calculation I would like to do:

Assume there is a certain car driving on a certain street and the driver hits the brakes to a max until the car comes to a halt. The driver does this with the same car on the same street multiple times but begins to brake at varying velocities. While the car is slowing down I want to be able to calculate the velocity it will have exactly one second later solely based on it's current velocity. For this calculation it should not matter at which speed the car was driving when the driver began to break since all environmential factors remain the same. Of course there will be some constants in the formula but when the car is down to i.e. 30 m/s it will go the same distance in the next second, regardless whether it was driving 100 or 50 m/s when the driver began to break. So the time since hitting the breaks would also not be a parameter of the function. The deceleration at a certain velocity would always be the same.

How do you calculate the velocity one second later in such a situation assuming some arbitrary constants for deceleration, mass, friction or whatever and ignoring complicating influences like air resistance? I'm only after the kinetic energy and the it's dissipation due to the friction from breaking the car.

Update 2 I see now that the acceleration of the car would be liniear and this is actually not what I was looking for. I'll clean this up and try out the new suggestions tomorrow. Thank you for your input so far.

+5  A: 

After reading the comments, I'd like to change my answer: Multiply the velocity by k < 1, like k = 0.955, to make it decay exponentially.

Explanation (with graphs, and a tuneable equation!) follows...

I interpret the graph in your original question as showing velocity staying near the starting value, then decreasing increasingly rapidly. But if you imagine sliding a book across a table, it moves away from you quickly, then slows down, then coasts to a stop. I agree with @Chris Farmer that the right model to use is a drag force that is proportional to speed. I'm going to take this model and derive the answer I suggested above. I apologize in advance for the length of this. I'm sure someone better at math could simplify this considerably. Also, I put links to the graphs in directly, there are some characters in the links that the SO parser doesn't like. URLs fixed now.

I'm going to use the following definitions:

x -> time
a(x) -> acceleration as a function of time
v(x) -> velocity as a function of time
y(x) -> position as a function of time
u -> constant coefficient of drag
colon : denotes proportionality

We know that the force due to drag is proportional to speed. We also know that force is proportional to acceleration.

a(x) : -u v(x)        (Eqn. 1)

The minus sign ensures that the acceleration is opposite the current direction of travel.

We know that velocity is the integrated acceleration.

v(x) : integral( -u v(x) dx )        (Eqn. 2)

This means the velocity is proportional to its own integral. We know that e^x satisfies this condition. So we suppose that

v(x) : e^(-u x)        (Eqn. 3)

The drag coefficient in the exponent is so that when we solve the integral in Eqn. 2 the u cancels to get back to Eqn. 3.

Now we need to figure out the value of u. As @BlueRaja pointed out, e^x never equals zero, regardless of x. But it approaches zero for sufficiently negative x. Let's consider 1% of our original speed to be 'stopped' (your idea of a threshold), and let's say we want to stop within x = 2 seconds (you can tune this later). Then we need to solve

e^(-2u) = 0.01        (Eqn. 4)

which leads us to calculate

u = -ln(0.01)/2 ~= 2.3        (Eqn. 5)

Let's graph v(x).

Looks like it exponentially decays to a small value in 2 seconds. So far, so good.

We don't necessarily want to calculate exponentials in our GUI. We know that we can convert exponential bases easily,

e^(-u x) = (e^-u)^x        (Eqn. 6)

We also don't want to keep track of time in seconds. We know we have an update rate of 20 ms, so let's define a timetick n with a tick rate of 50 ticks/sec.

n = 50 x        (Eqn. 7)

Substituting the value of u from Eqn. 5 into Eqn. 6, combining with Eqn. 7, and substituting into Eqn. 3, we get

v(n) : k^n, k = e^(ln(0.01)/2/50) ~= 0.955        (Eqn. 8)

Let's plot this with our new x-axis in timeticks.

Again, our velocity function is proportional to something that decays to 1% in the desired number of iterations, and follows a 'coasting under the influence of friction' model. We can now multiply our initial velocity v0 by Eqn. 8 to get the actual velocity at any timestep n:

v(n) = v0 k^n        (Eqn. 9)

Note that in implementation, it is not necessary to keep track of v0! We can convert the closed form v0 * k^n to a recursion to get the final answer

v(n+1) = v(n)*k        (Eqn. 10)

This answer satisfies your constraint of not caring what the initial velocity is - the next velocity can always be calculated using just the current velocity.

It's worth checking to make sure the position behavior makes sense. The position following such a velocity model is

y(n) = y0 + sum(0..n)(v(n))        (Eqn. 11)

The sum in Eqn. 11 is easily solved using the form of Eqn 9. Using an index variable p:

sum(p = 0..n-1)(v0 k^p) = v0 (1-k^n)/(1-k)        (Eqn. 12)

So we have

y(n) = y0 + v0 (1-k^n)/(1-k)        (Eqn. 13)

Let's plot this with y0 = 0 and v0 = 1.

So we see a rapid move away from the origin, followed a graceful coast to a stop. I believe this graph is a more faithful depiction of sliding than your original graph.

In general, you can tune k by using the equation

k = e^(ln(Threshold)/Time/Tickrate)        (Eqn. 14)
where:
Threshold is the fraction of starting velocity at which static friction kicks in
Time is the time in seconds at which the speed should drop to Threshold
Tickrate is your discrete sampling interval

(THANKS to @poke for demonstrating the use of Wolfram Alpha for plots - that's pretty sweet.)

OLD ANSWER

Multiply the velocity by k < 1, like k = 0.98, to make it decay exponentially.

mtrw
+1. I think it's called damping
mhaller
Isn't this the opposite of what I'm trying to do? With x*0.98 I get larger decreases at the beginning and smaller towards the end, but I want it to stop quicker not slower as the velocity goes down.
x4u
I think it's called drag.
Chris Farmer
This is absolutely incorrect - if this is how acceleration worked, nothing would ever stop!
BlueRaja - Danny Pflughoeft
@x4u: Then the car analogy may be wrong. Cars don't stop quicker as the velocity goes down. They just feel like they do because they stop *percentually* quicker. It feels like quicker braking to go from 25 m/s to 5 m/s in 1 second than to go from 120 m/s to 90 m/s in 1 second, but a 20 m/s drop in velocity is smaller than a 30 m/s drop.
Emilio M Bumachar
Yes, you all are right, I understand now that the car analogy is wrong regarding the acceleration that I think I would like to model. The velocity decrease of the car would be linear which is what I had at the very beginning. When I wrote the car analogy I basically wanted to make clear that I want something that doesn't depend on the starting velocity or the time passed so far.
x4u
@x4u: I'm afraid that comment doesn't make sense to me. The "car-model" is called constant acceleration, and is the *only* model in which the change-in-velocity doesn't depend the starting velocity (*"change-in-velocity"* is, by definition, acceleration) or time. If you meant you don't want the velocity itself to not be dependent on time, the *only* way to do that is `v(t) = C` - a constant velocity!
BlueRaja - Danny Pflughoeft
@BlueRaja He wants `v(t+dt)=f(v(t),dt)`, if I get it right (i.e. take current speed and time delta and get the speed at the next moment _regardless of the movement history which led the speed to its current value_). Becides he wants `w(t)=dv(t)/dt` to be a descending function :))
mlvljr
@BlueRaja - I believe what happens is the object slides according to the drag model until it reaches a low speed. At the low speed, the surface interaction switches from drag (or kinetic) friction to static friction i.e., it stops.@mlvjr - I think @x4u just wants an algorithm that doesn't require multiple states.
mtrw
@mtrv: the link to the last plot is kind of broken. What are "multiple states"? And btw, why not use an arbitrary (but satisfying certain conditions, for ex., "phisycally" realistic sliding) `v(t)` function, as it simplifies things a lot?
mlvljr
Also, It would probably have been much better for us all (including OP), if we came to an agreement over _programmatic_ interface of the appropriate routines (I myself think it is really a question of implementing a function `double velocity(double old_velocity, double time_delta)`), which satisfies some conds.
mlvljr
@mlvljr - 1. I fixed the links, sorry about that.2. By 'state' I mean the number of past velocities (or positions or accelerations) required to calculate a new velocity.3. I'm not sure there's a simpler equation than `v(t) = v0 e^(-u t)` (Eqn. 3) that is still realistic.4. It can be summed up in the C function`double velocity(double old_velocity, double time_delta) { return old_velocity * exp(-const_u * time_delta); }`or, if for performance reasons you convert to calling on each timetick:`double velocity(double old_velocity){ return old_velocity * const_k; }`
mtrw
Will not this `exp` function never actually degrade to zero? Also, what we are looking for is really `double v(double old_v, double dt) {t = t_for(old_v); new_t = t - dt; return (new_t <= 0)?0:v_for(t);}`, where `double t_for(double v)` and `double v_for(double t)` are the functions to get the coordinates from what is called "velocity curve" in my answer (a `v`-to-`t` function effectively specifying the movement, which we can construct almost arbitrarily, given that it is monothonic and defined for `v >=0')
mlvljr
@mlvljr - You're absolutely correct that I left out the threshold in my simple functions. As you suggest, the functions should be `double v(double old_v, double dt) {return (old_v < VELTHRESH) ? 0 : old_v*exp(-U*dt);}` or `double v(double old_v) {return (old_v < VELTHRESH) ? 0 : old_v*K;}` Both functions are monotonic, as required. And they simulate nature. I'm not sure why the solution should be made more complicated.
mtrw
@mtrv: The last one seems fine, and as for the strictness and complexity of the solution, it really depends on the GUI requirements, stemming from the ergonomics of user experince. Note though, its _extremely_ easy to get almost any "drag" behaviour you would like by essentially just specifying a biderectional `t`-to-`v` mapping. This also will not bring any computation overhead (in the extreme, that function may be parameterized by a set of `(v,t)` points and perform a cheap linear or quadratic interpolation, I even imagine a special editor tool to construct it:)).
mlvljr
A: 

You could keep track of the velocity and cut that down by a fraction of the velocity each time. That would simulate friction quite well I believe.

ridecar2
A: 
acceleration = (force / mass) 
velocity = (acceleration * time)
(force from user's finger) = acceleration / mass = velocity / time
  1. give the view a mass (tweak it until things seem reasonable, and let the user tweak it)
  2. identify some new force (drag)
  3. give the new force (drag) a magnitude (tweak until reasonable, let the user tweak it)
  4. apply the new force to the object and watch it slow down
atk
-1: Acceleration is not force*mass. You mean force = mass * acceleration
kigurai
Oops! That was supposed to be a division sign. Corrected.
atk
+2  A: 

Seems like you are looking for deceleration which increases over time.

Try computing

Delta_v = -(A*t + B) , selecting reasonable constants A and B, which suit you.

t is the total time till that point.

Change your velocity by adding Delta_v.

This basically corresponds to linear negative acceleration.

You can basically select any function which increases over time (say f(t))

and compute

Delta_v = -f(t)

An appropriate choice for f(t) would give you the effect you desire.

Some examples you could use:

f(t) = At + B.
f(t) = A*exp(Bt)

Of course, you will have to play around a bit and try to figure out the right constants.

Moron
This is what I tried and looks not bad (`v'=v-t*0.1`) but it bothers me that I have to keep track of the time and it behaved differently depending on how fast I started. I think it must be possible to calculate v'=f(v) for a constant acceleration and a constant time difference.
x4u
Well you don't have to keep track of time. DeltaV(t+dt) - Deltav(t) = -A(dt). So you can keep track of the last DeltaV instead of time. Also, it probably behaves differently because you have v - t*0.1 and v is the initial velocity? (just guessing).
Moron
A: 

I would cut down velocity as something like v=v*0.9 Then i would have a velocity which is considered the stopped velocity. This way the object would come to rest eventually and not continue consuming resources as moving. so something like for(v=startingVelocity;v<1.0;v*=0.9) { x+=v; }

This would go to 0 asymptotically, the function would describe a left curve. We need a right curve.
Svante
A: 

Acceleration is the first order derivative of velocity and second order derivative of distance. Your graph looks like a second order parabola something like C-k*x^2 for some constants C and k. If y is really distance you need a=-2k, if y is velocity you need a=-2kx. In either case velocity v(x) = V0 + a(x)*x. (Where x is actually time. I am following your convention and not using t.)

Szere Dyeri
+2  A: 

You can just reduce velocity by a constant amount each iteration. Example: you start with a velocity of 50, next iteration it is 40, then 30, 20, 10, stop. This would represent a constant "friction", independent of velocity, and this is actually quite close to reality (see friction on Wikipedia).

If you do not like the appearance of this, you need to make friction dependent on velocity. I would assume that a linear relationship friction = base-friction + (coefficient * velocity), with a rather small coefficient, would be enough.

Svante
+1: For using friction. But I think you would have to tie the friction to the change of object velocity (applying a force to the object) for it to be a complete answer.
kigurai
The change of object velocity is just `time` times `friction`.
Svante
+4  A: 

While the car is slowing down I want to be able to calculate the velocity it will have exactly one second later solely based on it's current velocity.

That would be the definition of acceleration. For instance, if the acceleration was a = -9 meters/sec/sec, and the velocity right now is 20 meters/sec, then 1 second from now the velocity will be 11 meters/sec.

In otherwords, the change in velocity Δv between now and t seconds from now (assuming constant acceleration) would be

Δv = a*t

meaning that the (classic physics) equation for the velocity at any time t, given the initial velocity at t=0 (this velocity is called v0) is

v(t) = v0+ a*t


Using what you'll learn in the first two weeks of calculus class, you can also get the equation for x(t) (the distance of the car at time t) from the above equation; this would give you

x(t) = x0+ v0*t + 0.5*a*t2

(it is also possible to derive this without calculus, see here)


Finally, if you are doing this for a game, and not a physics simulation (meaning you don't need exactly precise results), you will want to simply change the position and velocity every frame, rather than recalculate the position every frame. To do this, you will want to do the following every frame, assuming velocity (and acceleration) is measured in pixels-per-second(-per-second):

velocity_new = velocity_old + acceleration/frames_per_second
position_new = position_old + velocity_old/frames_per_second
BlueRaja - Danny Pflughoeft
+1 for the last two lines (of code) which neatly solves most velocity related problem when integrating in real-time.
Martin Wickman
+5  A: 
mlvljr
Thank you for your efforts. I'll try this out tomorrow.
x4u
wow, didn't know that autowiki thing, beware: http://meta.stackoverflow.com/questions/8654/so-is-too-eager-to-turn-my-edited-answers-into-community-wiki :))
mlvljr
+2  A: 

If you want increasing deceleration as you say in your comment at mtrw's answer, and you are NOT very picky about physical realism, the equation below may be what you're looking for:

V(t+dt) = V(t) - K1 + K2 x V(t)

V(t)= current speed V(t+dt)= speed at next time increment K1 and K2 are constants you calibrate. Just make sure (K2 x Vmax) < K1, or you'll accelerate at high speeds.

If it still doesn't feel right, try V(t+dt) = V(t) - K1 + K2 x f(V(t))

where f(x) is a monotonically increasing function you pick, maybe square or square root depending of where you want to take the feeling. Just make sure (K2 x f(V(t))) < K1 for every possible V(t).

(monotonically increasing function means f(x) always increases when x increases)

Emilio M Bumachar
+1  A: 

A non-linear change in velocity means that acceleration is not constant. A non-constant acceleration means that the system is under the influence of jerk. Take all your acceleration equations and add "(1/6)jt3". Fix a, and give j a small negative value until v hits 0.

Ignacio Vazquez-Abrams
Yeah, that must be some jerk.. (if the acceleration is changing) :))
mlvljr
A: 

I have tried this, which works (in Ruby). Not sure if the math is sound but the output looks right, meaning that you get faster as you get towards the center:

velocity=100;
(100.downto(0)).each { |distance_from_black_hole |  velocity=velocity+9.8/distance_from_black_hole; puts velocity; }
Yar
+2  A: 
Alok
+1: I also think that friction is what the OP is looking for.
kigurai
A: 

A bit of non programming discussion about the car example.

First, I'll assume that the driver cannot cause the brakes to lock at speed.

The first thing (or maybe the second or third thing) most new drivers learn is that the natural tendency when braking is to hold the brake pedal at a fixed position. The result is a sudden lurch forward as the car goes from moving slowly to stopping. This happens because the brakes are transitioning from dynamic friction, where braking force is proportional to brake pressure, to static friction, where braking force is restoring the forward momentum of the car. this sudden jump in acceleration is unpleasant, and the new driver learns to feather the pedal at the very end of deceleration to stop.

This behavior masks another pecularity, but this can be noticed during normal acceleration in a manual transmission car. when accelerating (or decelerating), if the driver suddenly pops the transmission out of gear, all of the passengers will suddenly lurch forward. What is actually happening, is the accelerating force that was pressing them into the backs of their seats is suddenly removed, and they spring back to a neutral sitting position. A more comfortable way to drive is to gradually feather the clutch so the motive force of the engine is removed gradually.

In both cases, the more aesthetic driving style involves smoothing the acceleration, removing sudden jumps. This is basically another way of talking about continious second derivative. Almost any motion with this property will seem natural.

TokenMacGuy
A: 
y(x) = y0 - a * e ^ ( k * x )

where y0 is the start constant, and a and k are factors.

Example plot.

poke