14

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

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

有人可以指出我的一部分代码吗?我不知道如何整合 Hermite 曲线,因此不知道我将在加速部分或减速部分移动多少,进而我无法弄清楚线性的速度是多少部分。

谢谢。

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

编辑

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

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

4

2 回答 2

22

首先,让我们创建一个三次 Hermite 样条函数:

/*
  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
于 2010-07-29T22:52:53.020 回答
8

这很简单,使用正常的恒定加速度。然后问题变成了你需要加速到什么速度 (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()

替代文字

于 2010-07-30T05:09:30.590 回答