数学:缓和,使用具有时间约束的Hermite曲线缓和位移

时间:2010-07-29 22:00:55

标签: math interpolation spline smoothing

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

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

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

感谢。

Some reference来说明我的问题。

修改

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

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

2 个答案:

答案 0 :(得分: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。在crusing期间,对象移动距离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

答案 1 :(得分: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()

alt text http://i26.tinypic.com/34sqzpi.png