1
\$\begingroup\$

I am looking at non-linear accelerations using the following values:

  • initial_acceleration
  • time_to_max_velocity
  • max_velocity
  • current_velocity

Initial_acceleration is the per frame acceleration we start with from 0 velocity. Over the course of "time_to_max," the acceleration is supposed to follow an interpolation from this value to whatever it needs to be to be to hit max_velocity at the end of this time. I need code both to generate the velocity generated by this function at a given point in time, and code for an inverse function that gives me the time given a current velocity.

enter image description here

It sounds like what I want is a type of quadratic interpolation or spline, but I have been unable to work out the details. Above I've graphed some values:

  • Red shows the case where: initial_acceleration * time_to_max == max_velocity
  • Green shows the case where: initial_acceleration * time_to_max > max_velocity
  • Blue shows the case where: initial_acceleration * time_to_max < max_velocity

The speed curves I've tried in code chaining lerp operations together always end up doing weird things like curving over my max speed and then back down to max speed again. If anyone can supply code, or math, that could get me even halfway towards an answer, I would be very appreciative.

\$\endgroup\$
0
\$\begingroup\$

Let's say we want our acceleration to be an affine function of time, meaning we have a constant jerk. That makes our velocity vs time graph take the form of a parabola, with its directrix parallel to the time axis.

The general equation for such a curve is:

$$v(t) = a \cdot t^2 + b \cdot t + c$$

Since your parabola goes through the point \$(t, v(t)) = (0, 0)\$, we can conclude that \$c = 0\$.

Next, the derivative of this equation is:

$$\frac {d v(t)} {d t} = 2 a \cdot t + b$$

So if you want the initial acceleration to be \$a_0\$ then we can conclude \$b = a_0\$

Then if we want \$v(T_{max}) = v_{max}\$, we can solve for \$a\$:

$$\begin{align} v_{max} &= a \cdot T_{max}^2 + a_0 \cdot T_{max}\\ v_{max} - a_0 \cdot T_{max} &= a \cdot T_{max}^2\\ \frac {v_{max}} {T_{max}^2} - \frac {a_0} {T_{max}} &= a \end{align}$$

So we end up with the equation for speed:

$$v(t) = \left( \frac {v_{max}} {T_{max}^2} - \frac {a_0} {T_{max}} \right) \cdot t^2 + a_0 \cdot t$$

...which you can solve for \$t\$ using the quadratic formula (taking the positive root):

$$t = \frac {-a_0 + \sqrt{a_0^2 + 4 v \left( \frac {v_{max}} {T_{max}^2} - \frac {a_0} {T_{max}} \right) }} {2 \left( \frac {v_{max}} {T_{max}^2} - \frac {a_0} {T_{max}} \right) }$$

Note that with this construction, you need to keep \$a_0 \cdot T_{max} <= 2 v_{max}\$ if you want the velocity function to be non-decreasing over the interval \$t \in [0, T_{max}]\$. If your initial acceleration is too steep or your time horizon is too short, your velocity will have to exceed your max, then slow down again to hit your target. If you need curves in this range, then we'll need to fall back on a different class of function with a more aggressive braking behaviour than the constant jerk we use here.


Here's another approach that works better for higher values of the initial acceleration, based on a kind of hyperbolic function:

$$x = \frac t {T_{max}}\\ v(t) = v_{max}\cdot x \cdot \frac {k + 1} {x + k}$$

Where

$$k = \frac 1 {T_{max} \frac {a_0} {v_{max}} - 1}$$

This one can handle arbitrarily high values of \$a_0\$, but it blows up for the constant acceleration case \$a_0 = \frac {v_{max}} {T_{max}}\$, so you'd need to special-case values in that vicinity. It also tends to make a sharper "corner" than the quadratic approach I showed first:

Function Comparison

(Quadratic / constant jerk curve in blue, new hyperbolic function in orange)

The hyperbolic function is reasonably straightforward to invert too:

$$vx + vk = v_{max} x k + v_{max}x\\ vk = x \left(v_{max}(k + 1) - v\right)\\ x = \frac {vk} {v_{max}(k + 1) - v}\\ t = T_{max}\cdot x =T_{max}\frac {vk} {v_{max}(k + 1) - v}$$

\$\endgroup\$
8
  • \$\begingroup\$ This is a wonderful discussion, but it would seem to confirm my fear that a quadratic arc will not serve my purposes as the case where a0 * Tmax > Vmax is one I'd hoped to make allowances for as per the green line in my diagram. Would you be able to suggest a smooth function that could accomplish this?I had the idea of a quadratic spline shape with the control point at the point where the initial velocity would intersect with max speed, but don't know how I'd go about translating it into something I could us. \$\endgroup\$ – Lake Oct 21 '20 at 2:56
  • \$\begingroup\$ I was just typing up an extended answer as your comment came in. See the edit above - would that serve your needs, @Lake? (Also, there was a typo in my original answer: the quadratic approach can serve up to a0*Tmax <= 2 * Vmax, so it can work for the green line as long as it's only about as steep as the example in your diagram) \$\endgroup\$ – DMGregory Oct 21 '20 at 2:58
  • \$\begingroup\$ Actually, your hyperbolic solution looks like it would work wonderfully. for my needs. I have no objection to hard-coding the case of linear acceleration. \$\endgroup\$ – Lake Oct 21 '20 at 3:06
  • \$\begingroup\$ Credit for the seed of that hyperbolic function goes to this GDC talk by Gilbert Sanders on vegetation rendering in Horizon Zero Dawn, about 15 minutes in. 😊 They use it to vary how much different plants' and trees' leaves react to wind speeds. \$\endgroup\$ – DMGregory Oct 21 '20 at 3:11
  • \$\begingroup\$ The first hyperbolic function is looking very good in my code so far. It's behaving precisely as I had wanted. I am having more trouble understanding the terms of the inverse function, however. Namely, I'm not sure what vx and vk mean, or why they are added in the first line. Are they just multiplications? \$\endgroup\$ – Lake Oct 21 '20 at 18:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.