数学:使用具有时间约束的 Hermite 曲线缓入、缓出位移

发布于 2024-09-12 05:43:32 字数 976 浏览 5 评论 0原文

我正在尝试编写一种方法,随着时间的推移,使用开始时的加速和结束时的减速(缓出/缓入)从 0 插值到 x(对象在一维中的位置),唯一的约束是 提供总时间,以及加速和减速的持续时间。运动应该复制惯性效应,我正在考虑非线性部分的 Hermite 曲线

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime)
{
    //...
}

有人可以指出我执行此操作的部分代码吗?我不知道如何积分埃尔米特曲线,因此不知道我将在加速部分或减速部分移动多少,反过来我也无法计算出线性速度是多少部分。

谢谢。

一些参考来说明我的问题。

编辑

  • 开始和结束速度为空,当前时间也是方法中参数的一部分,我已经更新了签名。
  • 基本上,这个想法是想象以恒定速度移动距离 d,这给出了总持续时间。然后我们添加加速和减速阶段,同时保持相同的持续时间,因此我们需要确定未知的新巡航速度(因为我们在 Hermite 阶段中的移动量比它们所取代的线性阶段中的移动量少)。与相同持续时间的线性移动相比,埃尔米特阶段中损失的移动量可能是曲线中顶部和底部面积之间的比率,这只是非专家的想法。

编辑:Roman 和 Bob10 提供了完整的工作解决方案。我实现了 Roman 的代码。谢谢你们俩,伙计们!我感谢您完美的支持和详细的解决方案,您节省了我漫长的搜索和试验。

I'm trying to write a method that interpolates from 0 to x (position of an object in one dimension) over time using acceleration at the beginning and deceleration at the end (ease out / ease in) with the only constraints that the total time is provided, as well as the duration of the acceleration and deceleration. the motion should replicate the inertia effect and I'm considering a Hermite curve for the non-linear portions.

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime)
{
    //...
}

Can someone point me out to a portion of code that does that? I don't know how to integrate the Hermite curve, hence don't know how much I'll move in the accelerating portion or in the decelerating portion, and in turn I can't figure out what will be the speed in the linear portion.

Thanks.

Some reference to illustrate my question.

Edit:

  • start and end speeds are null, and the current time is also part of the parameters in the method, I've updated the signature.
  • basically the idea is to imagine a move at constant speed on a distance d, this gives a total duration. Then we add the acceleration and deceleration phases, while maintaining the same duration, hence we have an unknown new cruise speed to determinate (because we move less in the Hermite phases than in the linear phases they have replaced). Maybe the amount of move lost in the Hermite phases, compared to a linear move of the same duration is the ratio between the top and bottom area in the curves, just an idea from a non expert.

Edit: Roman and Bob10 have provided full working solutions. I implemented the code from Roman. Thanks to you both, guys! I appreciate your perfect support and your detailed solutions, you saved me long searches and trials.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

新雨望断虹 2024-09-19 05:43:32

首先,让我们创建一个三次埃尔米特样条函数:

/*
  t  - in interval <0..1>
  p0 - Start position
  p1 - End position
  m0 - Start tangent
  m1 - End tangent
*/
double CubicHermite(double t, double p0, double p1, double m0, double m1) {
   t2 = t*t;
   t3 = t2*t;
   return (2*t3 - 3*t2 + 1)*p0 + (t3-2*t2+t)*m0 + (-2*t3+3*t2)*p1 + (t3-t2)*m1;
}

现在您的任务是计算缓入和缓出部分的 p0、p1、m0 和 m1。让我们添加一些变量以使数学更容易编写:

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime) {

    double t1 = timeToAccel;
    double t2 = timeCruising;
    double t3 = timeToDecel;
    double x = finalPosition;
    double t = currentTime;

我们需要指定当对象停止加速并开始减速时应该在哪里。您可以随意指定这些,并且仍然会产生平滑的运动,但是,我们想要一个有点“自然”的解决方案。

假设巡航速度为v。在巡航过程中,物体移动的距离为x2 = v * t2。现在,当物体从 0 加速到速度 v 时,它移动的距离为 x1 = v * t1 / 2。减速度也是如此 x3 = v * t3 / 2。把所有的放在一起:

x1 + x2 + x3 = x

v * t1 / 2 + v * t2 + v * t3 / 2 = x

由此我们可以计算我们的速度和距离:

    double v = x / (t1/2 + t2 + t3/2);
    double x1 = v * t1 / 2;
    double x2 = v * t2;
    double x3 = v * t3 / 2;

现在我们知道了一切,我们只需喂它在我们的三次 Hermite 样条插值器中,

    if(t <= t1) {
       // Acceleration
       return CubicHermite(t/t1, 0, x1, 0, v*t1);
    } else if(t <= t1+t2) {
       // Cruising
       return x1 + x2 * (t-t1) / t2;
    } else {
       // Deceleration
       return CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0);
    }
}

我在 Excel 中对此进行了测试,下面是可使用的等效 VBA 代码。边界条件有一些被零除的情况,我将对此进行修复作为读者的练习


Public Function CubicHermite(t As Double, p0 As Double, p1 As Double, _
m0 As Double, m1 As Double) As Double
   t2 = t * t
   t3 = t2 * t
   CubicHermite = (2 * t3 - 3 * t2 + 1) * p0 + _
(t3 - 2 * t2 + t) * m0 + (-2 * t3 + 3 * t2) * p1 + (t3 - t2) * m1
End Function

Public Function Interpolate(t1 As Double, t2 As Double, t3 As Double, _
x As Double, t As Double) As Double
    Dim x1 As Double, x2 As Double, x3 As Double

    v = x / (t1 / 2 + t2 + t3 / 2)
    x1 = v * t1 / 2
    x2 = v * t2
    x3 = v * t3 / 2

    If (t <= t1) Then
       Interpolate = CubicHermite(t / t1, 0, x1, 0, v*t1)
    ElseIf t <= t1 + t2 Then
       Interpolate = x1 + x2 * (t - t1) / t2
    Else
       Interpolate = CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0)
    End If
End Function

First, let's make a cubic hermite spline function:

/*
  t  - in interval <0..1>
  p0 - Start position
  p1 - End position
  m0 - Start tangent
  m1 - End tangent
*/
double CubicHermite(double t, double p0, double p1, double m0, double m1) {
   t2 = t*t;
   t3 = t2*t;
   return (2*t3 - 3*t2 + 1)*p0 + (t3-2*t2+t)*m0 + (-2*t3+3*t2)*p1 + (t3-t2)*m1;
}

Now your task is to calculate the p0, p1, m0 and m1 for both ease-in and ease-out portions. Let us add a few variables to make the math a bit easier to write:

double Interpolate(
    double timeToAccel, double timeCruising, double timeToDecel,
    double finalPosition,
    double currentTime) {

    double t1 = timeToAccel;
    double t2 = timeCruising;
    double t3 = timeToDecel;
    double x = finalPosition;
    double t = currentTime;

We need to specify where should the object be when it stops accelerating and starts decelerating. You can specify these however you please and still produce a smooth movement, however, we would like a somewhat "natural" solution.

Let's assume that the cruising speed is v. During crusing, the object travels distance x2 = v * t2. Now, when the object accelerates from 0 to speed v, it travels distance x1 = v * t1 / 2. Same for deceleration x3 = v * t3 / 2. Put all together:

x1 + x2 + x3 = x

v * t1 / 2 + v * t2 + v * t3 / 2 = x

From that we can calculate our speed and the distances:

    double v = x / (t1/2 + t2 + t3/2);
    double x1 = v * t1 / 2;
    double x2 = v * t2;
    double x3 = v * t3 / 2;

And now that we know everything, we just feed it into our cubic hermite spline interpolator

    if(t <= t1) {
       // Acceleration
       return CubicHermite(t/t1, 0, x1, 0, v*t1);
    } else if(t <= t1+t2) {
       // Cruising
       return x1 + x2 * (t-t1) / t2;
    } else {
       // Deceleration
       return CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0);
    }
}

I tested this in Excel, here's the equivalent VBA code to play with. There are some divisions by zero for boundary conditions, I leave fix to this as an excercise to the reader


Public Function CubicHermite(t As Double, p0 As Double, p1 As Double, _
m0 As Double, m1 As Double) As Double
   t2 = t * t
   t3 = t2 * t
   CubicHermite = (2 * t3 - 3 * t2 + 1) * p0 + _
(t3 - 2 * t2 + t) * m0 + (-2 * t3 + 3 * t2) * p1 + (t3 - t2) * m1
End Function

Public Function Interpolate(t1 As Double, t2 As Double, t3 As Double, _
x As Double, t As Double) As Double
    Dim x1 As Double, x2 As Double, x3 As Double

    v = x / (t1 / 2 + t2 + t3 / 2)
    x1 = v * t1 / 2
    x2 = v * t2
    x3 = v * t3 / 2

    If (t <= t1) Then
       Interpolate = CubicHermite(t / t1, 0, x1, 0, v*t1)
    ElseIf t <= t1 + t2 Then
       Interpolate = x1 + x2 * (t - t1) / t2
    Else
       Interpolate = CubicHermite((t-t1-t2)/t3, x1+x2, x, v*t3, 0)
    End If
End Function
年少掌心 2024-09-19 05:43:32

使用正常的恒定加速度,这很简单。那么问题就变成了您需要加速到什么速度(v)才能在正确的时间内完成行程,这将告诉您达到该速度所需的加速度。

如果总时间为 t_t,加速时间为 t_a,那么您就得到了两个加速和减速部分以及匀速部分的行进距离:

x = 2*(a*t_a*t_a/2) + v*(t_t-2*t_a)

这可以通过代入 v=a*t_a 来求解加速度,下面

a = x/(t_a*(t_t - t_a))

是一些使用并绘制这些方程结果的 Python 代码,它展示了如何使用方程以及结果的样子:

from pylab import *

t_a, t_t, D = 3., 10., 1.  # input values

a = D/(t_a*(t_t - t_a))
segments = (t_a, a), (t_t-2*t_a, 0.), (t_a, -a)  # durations and accelerations for each segment

t0, x0, v0 = 0.0, 0.0, 0.0  #initial values for the segment
tdata, xdata = [], []
for t_segment, a in segments: # loop over the three segments
    times = arange(0, t_segment, .01)
    x = x0 + v0*times + .5*a*times*times
    xdata.append(x)
    tdata.append(times+t0)
    x0 = x[-1] # the last x calculated in the segment above
    v0 += a*t_segment
    t0 += t_segment

plot(tdata[0], xdata[0], 'r', tdata[1], xdata[1], 'r', tdata[2], xdata[2], 'r')
xlabel("time")
ylabel("position")
show()

替代文本

This is straightforward using normal constant acceleration. Then the question becomes what velocity (v) do you need to accelerate to in order to complete the trip in the right amount of time, and this will tell you the acceleration you need to get to that velocity.

If the total time is t_t and the time of acceleration is t_a, then you have the distance traveled as the two accelerating and decelerating parts, and the constant velocity part:

x = 2*(a*t_a*t_a/2) + v*(t_t-2*t_a)

This can be solved for the acceleration by subbing in v=a*t_a, to find

a = x/(t_a*(t_t - t_a))

Here's some Python code that uses and plots the result of these equations, that shows both how to use the equations and what the result looks like:

from pylab import *

t_a, t_t, D = 3., 10., 1.  # input values

a = D/(t_a*(t_t - t_a))
segments = (t_a, a), (t_t-2*t_a, 0.), (t_a, -a)  # durations and accelerations for each segment

t0, x0, v0 = 0.0, 0.0, 0.0  #initial values for the segment
tdata, xdata = [], []
for t_segment, a in segments: # loop over the three segments
    times = arange(0, t_segment, .01)
    x = x0 + v0*times + .5*a*times*times
    xdata.append(x)
    tdata.append(times+t0)
    x0 = x[-1] # the last x calculated in the segment above
    v0 += a*t_segment
    t0 += t_segment

plot(tdata[0], xdata[0], 'r', tdata[1], xdata[1], 'r', tdata[2], xdata[2], 'r')
xlabel("time")
ylabel("position")
show()

alt text

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文