如何计算负加速度?

发布于 2024-08-22 09:23:17 字数 1172 浏览 3 评论 0原文

我正在实现触摸屏 UI 的滚动行为,但我现在太累了,无法将注意力集中在一些看似微不足道的数学片段上:

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

f(x)->?

UI 应该允许用户向任何方向拖动和“抛出”视图,并且即使在手指从屏幕上松开后也能保持视图滚动一段时间。它的动量取决于用户在松开手指之前拖动的速度。

所以我有一个起始速度 (v0),并且每 20 毫秒我滚动一个相对于当前速度的量。每次滚动迭代时,我都会稍微降低速度,直到停止时速度降至阈值以下。当我将其减少固定量(线性)时,它看起来不太正确,因此我需要对负加速度进行建模,但无法想出一个像样的简单公式来计算我必须降低速度的量在每次迭代中。

更新:

感谢您迄今为止的回复,但我仍然无法从反馈中得出令人满意的函数。我可能没有足够好地描述所需的解决方案,所以我将尝试给出一个现实世界的例子来说明我想要做的计算:

假设有一辆汽车在某条街道上行驶,并且驾驶员将刹车踩到最大,直到汽车停下来。驾驶员在同一条街道上多次使用同一辆车进行此操作,但开始以不同的速度制动。当汽车减速时,我希望能够仅根据当前速度计算出一秒钟后的速度。对于此计算,当驾驶员开始刹车时汽车行驶的速度并不重要,因为所有环境因素保持不变。当然,公式中会有一些常数,但是当汽车速度降至 30 m/s 时,无论驾驶员开始刹车时的速度是 100 还是 50 m/s,下一秒它都会行驶相同的距离。因此,自到达中断点以来的时间也不会成为该函数的参数。某个速度下的减速度总是相同的。

在这种情况下,假设减速度、质量、摩擦力等任意常数并忽略空气阻力等复杂影响,如何计算一秒钟后的速度?我只追求动能以及由于汽车破裂时的摩擦而耗散的动能。

更新2 我现在看到汽车的加速度是线性的,这实际上不是我想要的。明天我会清理这个并尝试新的建议。感谢您迄今为止的投入。

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.

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

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

发布评论

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

评论(15

又怨 2024-08-29 09:23:17

[简短回答(假设C语法)]

double v(double old_v, double dt) {
    t = t_for(old_v); 
    new_t = t - dt; 
    return (new_t <= 0)?0:v_for(t);
} 

double t_for(double v)double v_for(double t)是 v 到 t 双向映射(数学意义上的函数)的返回值,它是任意的,但具有单调性并为 v >=0 定义(因此有一点其中v=0)。一个例子是:

double v_for(double t) { return pow(t, k); }
double t_for(double v) { return pow(v, 1.0/k); }

其中,

  1. k>1 给出减速度随着时间的推移以模数减小。
  2. k<1 给出随时间流逝以模数增加的减速度。
  3. k=1 提供恒定的减速度。

[更长的一个(带有基本原理和图表)]

所以目标本质上是:

  1. 找到一个函数v(t+dt)=f(v(t),dt) 它采用当前速度值 v 和时间增量 dt 并返回 t+dt 时刻的速度(它不需要实际上指定 t,因为 v(t) 已知并作为参数提供,而 dt 只是时间增量)。 换句话说,任务是实现具有特定属性的例程 double next_v(curr_v, dt);(见下文)。

  2. [请注意]所讨论的函数有一个有用的(和期望的)属性,无论先前速度变化的“历史”如何,都会返回相同的结果。这意味着,例如,如果一系列连续速度为 [100, 50, 10, 0](对于起始速度 v0=100),则任何其他大于此的序列都将具有相同的“tail”:[150, 100, 50, 10, 0](对于起始速度v0=150)等换句话说,无论起始速度如何,所有速度-时间图实际上都是彼此的副本,只是沿着时间轴偏移各自的值(参见下图,注意线之间的图部分t=0.0t=2.0 相同)

  3. 此外,加速度w(t)=dv(t)/dt必须是时间t的递减函数(为了视觉上美观和“直观”我们在此建模的移动 GUI 对象的行为)。

建议的想法是:

  1. 首先选择具有所需属性的单调速度函数(在您的情况下,它逐渐减小加速度,但如下面的示例所示,使用“加速”更容易)。 此函数不得还有上限,以便您可以将其用于任何较大的速度值。此外,它必须有一个速度为零的点。一些例子是:v(t) = k*t(不完全是你的情况,因为减速度k在这里是常数),v=sqrt(-t) (这个没问题,在区间 t <= 0 上定义)。

  2. 然后,对于任何给定的速度,您可以在上述函数的绘图上找到具有该速度值的点(将会有一个点,因为该函数没有绑定,并且只有一个点,因为它是单调的),按时间增量前进朝向较小的速度值,从而获取下一个。迭代将逐渐(并且不可避免地)将您带到速度为零的点。

  3. 基本上就是这样,甚至不需要生成一些“最终”公式,对时间值或初始(不是当前)速度的依赖消失,编程变得非常简单 .

对于两个简单的情况,这个小 python 脚本生成下面的图(给出的初始速度为 1.010.0),并且,如您所见,来自任何给定的速度“水平”和“向下”,绘图“表现”相同,这是理所当然的,因为无论以什么速度开始减慢(减速),你沿着同一条曲线“移动”相对于速度为零的点

import numpy
import pylab

import math


class VelocityCurve(object):
    """
    An interface for the velocity 'curve'.
    Must represent a _monotonically_ _growing_
        (i.e. with one-to-one correspondence
        between argument and value) function
        (think of a deceleration reverse-played)
    Must be defined for all larger-than-zero 'v' and 't'
    """
    def v(self, t):
        raise NotImplementedError

    def t(self, v):
        raise NotImplementedError



class VelocityValues(object):

    def __init__(self, v0, velocity_curve):
        assert v0 >= 0
        assert velocity_curve

        self._v = v0
        self._vc = velocity_curve

    def next_v(self, dt):
        t = self._vc.t(self._v)
        new_t = t - dt

        if new_t <= 0:
            self._v = 0
        else:
            self._v = self._vc.v(new_t)

        return self._v


class LinearVelocityCurve(VelocityCurve):

    def __init__(self, k):
        """k is for 'v(t)=k*t'"""
        super(LinearVelocityCurve, self).__init__()

        self._k = k

    def v(self, t):
        assert t >= 0
        return self._k*t

    def t(self, v):
        assert v >= 0
        return v/self._k


class RootVelocityCurve(VelocityCurve):

    def __init__(self, k):
        """k is for 'v(t)=t^(1/k)'"""
        super(RootVelocityCurve, self).__init__()

        self._k = k

    def v(self, t):
        assert t >= 0
        return math.pow(t, 1.0/self._k)

    def t(self, v):
        assert v >= 0
        return math.pow(v, self._k)


def plot_v_arr(v0, velocity_curve, dt):
    vel = VelocityValues(v0, velocity_curve)
    v_list = [v0]

    while True:
        v = vel.next_v(dt)
        v_list.append(v)

        if v <= 0:
            break

    v_arr = numpy.array(list(v_list))
    t_arr = numpy.array(xrange(len(v_list)))*dt

    pylab.plot(t_arr, v_arr)


dt = 0.1

for v0 in range(1, 11):
    plot_v_arr(v0, LinearVelocityCurve(1), dt)

for v0 in range(1, 11):
    plot_v_arr(v0, RootVelocityCurve(2), dt)


pylab.xlabel('Time ')
pylab.ylabel('Velocity')

pylab.grid(True)

pylab.show()

这给出了以下图(线性减速(即恒定减速)的线性图,“曲线” -- 对于“平方根”的情况(参见上面的代码)):

另请请注意,要运行上述脚本,需要安装 pylab、numpy 等(但仅限于绘图部分,“核心”类不依赖任何内容,当然可以单独使用)。

PS 通过这种方法,人们可以真正“构建”(例如,针对不同的t间隔增强不同的功能,甚至平滑手绘(记录的)“人体工程学”曲线)他喜欢的“阻力” :)

[Short answer (assuming C syntax)]

double v(double old_v, double dt) {
    t = t_for(old_v); 
    new_t = t - dt; 
    return (new_t <= 0)?0:v_for(t);
} 

double t_for(double v) and double v_for(double t) are return values from a v-to-t bidirectional mapping (function in mathematical sence), which is arbitrary with the constraint that it is monothonic and defined for v >=0 (and hence has a point where v=0). An example is:

double v_for(double t) { return pow(t, k); }
double t_for(double v) { return pow(v, 1.0/k); }

where having:

  1. k>1 gives deceleration decreasing by modulo as time passes.
  2. k<1 gives deceleration increasing by modulo as time passes.
  3. k=1 gives constant deceleration.

[A longer one (with rationale and plots)]

So the goal essentialy is:

  1. To find a function v(t+dt)=f(v(t),dt) which takes current velocity value v and time delta dt and returns the velocity at the moment t+dt (it does not require actually specifying t since v(t) is already known and supplied as a parameter and dt is just time delta). In other words, the task is to implement a routine double next_v(curr_v, dt); with specific properties (see below).

  2. [Please Note] The function in question has a useful (and desired) property of returning the same result regardless of the "history" of previous velocity changes. That means, that, for example, if the series of consecutive velocities is [100, 50, 10, 0] (for the starting velocity v0=100), any other sequence larger than this will have the same "tail": [150, 100, 50, 10, 0] (for the starting velocity v0=150), etc. In other words, regardless of the starting velocity, all velocity-to-time plots will effectively be copies of each other just offset along the time axis each by its own value (see the graph below, note the plots' parts between the lines t=0.0 and t=2.0 are identical) .

  3. Besides, acceleration w(t)=dv(t)/dt must be a descending function of time t (for the purpose of visually pleasing and "intuitive" behaviour of the moving GUI object which we model here).

The proposed idea is:

  1. First you choose a monothonic velocity function with desired properties (in your case it is gradually decreasing acceleration, though, as the example below shows, it is easier to use "accelerated" ones). This function must not also have an upper boundary, so that you could use it for whatever large velocity values. Also, it must have a point where velocity is zero. Some examples are: v(t) = k*t (not exactly your case, since deceleration k is constant here), v=sqrt(-t) (this one is ok, being defined on the interval t <= 0).

  2. Then, for any given velocity, you find the point with this velocity value on the above function's plot (there will be a point, since the function is not bound, and only one since it is monothonic), advance by time delta towards smaller velocity values, thus acquiring the next one. Iteration will gradually (and inevitably) bring you to the point where velocity is zero.

  3. That's basically all, there is even no need to produce some "final" formula, dependencies on time value or initial (not current) velocities go away, and the programming becomes really simple.

For two simple cases this small python script produces the plots below (initial velocities given were 1.0 to 10.0), and, as you can see, from any given velocity "level" and "downwards" the plots "behave" the same which is of couse because no matter at what velocity you start to slow down (decelerate), you are "moving" along the same curve RELATIVE to the point where velocity is (becomes) zero:

import numpy
import pylab

import math


class VelocityCurve(object):
    """
    An interface for the velocity 'curve'.
    Must represent a _monotonically_ _growing_
        (i.e. with one-to-one correspondence
        between argument and value) function
        (think of a deceleration reverse-played)
    Must be defined for all larger-than-zero 'v' and 't'
    """
    def v(self, t):
        raise NotImplementedError

    def t(self, v):
        raise NotImplementedError



class VelocityValues(object):

    def __init__(self, v0, velocity_curve):
        assert v0 >= 0
        assert velocity_curve

        self._v = v0
        self._vc = velocity_curve

    def next_v(self, dt):
        t = self._vc.t(self._v)
        new_t = t - dt

        if new_t <= 0:
            self._v = 0
        else:
            self._v = self._vc.v(new_t)

        return self._v


class LinearVelocityCurve(VelocityCurve):

    def __init__(self, k):
        """k is for 'v(t)=k*t'"""
        super(LinearVelocityCurve, self).__init__()

        self._k = k

    def v(self, t):
        assert t >= 0
        return self._k*t

    def t(self, v):
        assert v >= 0
        return v/self._k


class RootVelocityCurve(VelocityCurve):

    def __init__(self, k):
        """k is for 'v(t)=t^(1/k)'"""
        super(RootVelocityCurve, self).__init__()

        self._k = k

    def v(self, t):
        assert t >= 0
        return math.pow(t, 1.0/self._k)

    def t(self, v):
        assert v >= 0
        return math.pow(v, self._k)


def plot_v_arr(v0, velocity_curve, dt):
    vel = VelocityValues(v0, velocity_curve)
    v_list = [v0]

    while True:
        v = vel.next_v(dt)
        v_list.append(v)

        if v <= 0:
            break

    v_arr = numpy.array(list(v_list))
    t_arr = numpy.array(xrange(len(v_list)))*dt

    pylab.plot(t_arr, v_arr)


dt = 0.1

for v0 in range(1, 11):
    plot_v_arr(v0, LinearVelocityCurve(1), dt)

for v0 in range(1, 11):
    plot_v_arr(v0, RootVelocityCurve(2), dt)


pylab.xlabel('Time ')
pylab.ylabel('Velocity')

pylab.grid(True)

pylab.show()

This gives the following plots (linear ones for the linear decelerating (i.e. constant deceleration), "curvy" -- for the case of the "square root" one (see the code above)):

Also please beware that to run the above script one needs pylab, numpy and friends installed (but only for the plotting part, the "core" classes depend on nothing and can be of course used on their own).

P.S. With this approach, one can really "construct" (for example, augmenting different functions for different t intervals or even smoothing a hand-drawn (recorded) "ergonomic" curve) a "drag" he likes:)

自由如风 2024-08-29 09:23:17

看了大家的评论,我想修改一下我的答案:
将速度乘以 k < 1,如k = 0.955,使其呈指数衰减。

解释(带有图表和可调方程!)如下...

我将原始问题中的图表解释为显示速度保持在起始值附近,然后逐渐迅速减小。但如果你想象将一本书滑过桌子,它会迅速远离你,然后减慢速度,然后慢慢停下来。我同意 @Chris Farmer 的观点,即正确使用的模型是与速度成正比的阻力模型。我将采用这个模型并得出我上面建议的答案。我提前为本文的篇幅表示歉意。我确信数学更好的人可以大大简化这个过程。 另外,我直接将图表的链接放入其中,链接中有些字符是 SO 解析器不喜欢的。
URL 现已修复。

我将使用以下定义:

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

我们知道阻力产生的力与速度成正比。我们还知道力与加速度成正比。

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

负号确保加速度与当前行进方向相反。

我们知道速度是加速度的积分。

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

这意味着速度与其自身的积分成正比。我们知道e^x满足这个条件。所以我们假设

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

指数中的阻力系数是这样的,当我们求解方程式中的积分时, 2 u 取消返回方程。 3.

现在我们需要计算出u的值。正如 @BlueRaja 指出的,无论 x 如何,e^x 永远不等于 0。但当 x 足够负时,它接近于零。让我们考虑“停止”原始速度的 1%(您对阈值的想法),假设我们希望在 x = 2 秒内停止(您可以稍后调整)。然后我们需要解决

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

导致我们计算

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

让我们绘制v(x)的问题。

看起来它在 2 秒内呈指数衰减到一个小值。到目前为止,一切都很好。

我们不一定想在 GUI 中计算指数。我们知道我们可以轻松地转换指数基数,

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

我们也不想以秒为单位记录时间。我们知道更新率为 20 毫秒,因此我们定义一个时间周期 n,其周期速率为 50 周期/秒。

n = 50 x        (Eqn. 7)

代入等式中的 u 值。 5代入方程式。 6、结合方程。 7,并代入方程。 3,我们得到

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

让我们用新的x轴以时间为单位绘制它。

同样,我们的速度函数与在所需的迭代次数中衰减到 1%,并遵循“在摩擦影响下滑行”模型。现在我们可以将初始速度 v0 乘以方程: 8 获取任意时间步的实际速度 n:

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

请注意,在实现中,没有必要跟踪 v0!我们可以将封闭形式 v0 * k^n 转换为递归以获得最终答案

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

这个答案满足您不关心初始速度是什么 - 下一个速度的约束始终可以仅使用当前速度进行计算。

值得检查以确保位置行为有意义。遵循这种速度模型的位置是

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

方程中的总和。 11 使用方程 9 的形式可以轻松求解。使用索引变量 p:

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

所以我们有

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

让我们用 y0 = 0v0 绘制它= 1.

因此,我们看到快速远离原点,沿着优雅的海岸线到达终点。我相信这张图比你原来的图更忠实地描述了滑动。

一般来说,您可以使用方程调整k

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

(感谢@poke演示了Wolfram Alpha在绘图中的使用 - 这非常好。)

旧答案

将速度乘以 k < 1,如k = 0.98,使其呈指数衰减。

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.

清风无影 2024-08-29 09:23:17

当汽车减速时,我希望能够仅根据当前速度计算出一秒后的速度。

这就是加速度的定义。例如,如果加速度为 a = -9 米/秒/秒,现在的速度为 20 米/秒,那么 1 秒后速度将为11米/秒

换句话说,从现在到 t 秒后的速度 Δv 变化(假设加速度恒定)将是

Δv = a*t

表示给定 处的初始速度,任何时间 t 的速度的(经典物理)方程t=0 (该速度称为 v0

v(t) = v0+ a*t


利用您在前两周微积分课程中学到的知识,您还可以从上面的方程得到x(t)的方程(汽车在时间t时的距离);这会给你

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

(也可以在不使用微积分的情况下得出此结果,请参阅此处)


最后,如果您是为了游戏而不是物理模拟(意味着您不需要精确的结果)执行此操作,您将需要简单地更改位置和速度每一帧,而不是每一帧重新计算位置。为此,您需要在每一帧执行以下操作,假设速度(和加速度)以每秒像素(-每秒)为单位测量:

velocity_new = velocity_old + acceleration/frames_per_second
position_new = position_old + velocity_old/frames_per_second

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
戏蝶舞 2024-08-29 09:23:17

似乎您正在寻找随着时间的推移而增加的减速度。

尝试计算

Delta_v = -(A*t + B) ,选择适合您的合理常数 A 和 B。

t 是到该点的总时间。

通过添加 Delta_v 来更改速度。

这基本上对应于线性负加速度。

您基本上可以选择任何随时间增加的函数(例如 f(t))

并计算

Delta_v = -f(t)

f(t) 的适当选择将为您提供所需的效果。

您可以使用的一些示例:

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

当然,您必须稍微尝试一下并尝试找出正确的常量。

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.

北方的韩爷 2024-08-29 09:23:17

您可以在每次迭代时将速度降低一个恒定量。示例:您以 50 的速度开始,下一次迭代为 40,然后是 30、20、10,停止。这将代表一个恒定的“摩擦”,与速度无关,这实际上非常接近现实(参见摩擦在维基百科上)。

如果您不喜欢这种外观,则需要使摩擦力取决于速度。我假设线性关系摩擦力=基础摩擦力+(系数*速度),具有相当小的系数,就足够了。

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.

那些过往 2024-08-29 09:23:17

如果您想要增加减速度,正如您在 mtrw 的答案中评论中所说的那样,并且您对物理现实主义不是很挑剔,那么下面的方程式可能就是您正在寻找的:

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

V(t)= 当前速度
V(t+dt)=下一次增量时的速度
K1 和 K2 是您校准的常数。只需确保 (K2 x Vmax) < K1,否则你会高速加速。

如果还是感觉不合适,请尝试
V(t+dt) = V(t) - K1 + K2 xf(V(t))

其中 f(x) 是您选择的单调递增函数,可能是平方或平方根,具体取决于您想要的感觉。只需确保 (K2 xf(V(t))) < K1 对于每个可能的 V(t)。

(单调递增函数意味着当 x 增加时 f(x) 总是增加)

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)

握住你手 2024-08-29 09:23:17

我也会添加一个想法。看起来您不想要恒定(负)加速度。这将产生如下方程:

v(t) = v(0) + a*t,

其中 a 是负加速度,t 是时间,v(t) 是时间上的速度t。这给你:

v(t2) - v(t1) = a(t2-t1),

这意味着对于给定的 Δt,速度差等于 aΔt,一个常数。

您可能正在寻找“摩擦”术语,它取决于当前速度。在这个假设下,速度的变化率与当前速度成正比:

d v(t) / d t = -b*v(t).

解决上述问题很容易,你可以得到:v(t) = v(0) e−b t

对这个方程进行积分,我们得到 x(t) = v(0)(1−e−b t) / b,其中 x 是位置。 v(0) = 1, b = 0.1 的位置图1 看起来像您可以使用的东西。您可能想要调整 b 的值,并在方程中添加比例因子。


1 http://www.wolframalpha.com/input/?i=plot+%281+-+1+e^%28-0.1+x%29+%29+%2F +0.1+for+x+%3D+0+到+100

I will add a thought as well. Looks like you don't want a constant (negative) acceleration. That would result in an equation like:

v(t) = v(0) + a*t,

where a is the negative acceleration, t is the time, and v(t) is velocity at time t. This gives you:

v(t2) - v(t1) = a(t2-t1),

and that means that for a given Δt the velocity difference is equal to aΔt, a constant.

What you may be looking for is for a "friction" term, that depends upon the current velocity. Under that assumption, the rate of change of velocity is proportional to the current velocity:

d v(t) / d t = -b*v(t).

Solving the above is easy, and you get: v(t) = v(0) e−b t.

Integrating this equation, we get x(t) = v(0)(1−e−b t) / b, where x is the position. The position plot1 for v(0) = 1, b = 0.1 looks like something you could use. Playing with the values of b, and adding a scale factor to the equation might be what you want to do.


1 http://www.wolframalpha.com/input/?i=plot+%281+-+1+e^%28-0.1+x%29+%29+%2F+0.1+for+x+%3D+0+to+100

你好,陌生人 2024-08-29 09:23:17

速度的非线性变化意味着加速度不是恒定的。非恒定加速度意味着系统受到jerk。取出所有加速度方程并添加“(1/6)jt3”。固定 a,并给 ja 一个小的负值,直到 v 达到 0。

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.

往事风中埋 2024-08-29 09:23:17

您可以跟踪速度并每次将其降低速度的一小部分。我相信这可以很好地模拟摩擦力。

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.

夜未央樱花落 2024-08-29 09:23:17

我会将速度降低为 v=v*0.9
然后我会有一个被认为是停止速度的速度。这样,物体最终会静止下来,而不会在移动时继续消耗资源。
所以像
for(v=起始速度;v<1.0;v*=0.9)
{
x+=v;
}

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;
}

我家小可爱 2024-08-29 09:23:17

加速度是速度的一阶导数和距离的二阶导数。对于某些常数 C 和 k,您的图看起来像二阶抛物线,类似于 Ck*x^2。如果 y 确实是距离,则需要 a=-2k,如果 y 是速度,则需要 a=-2kx。无论哪种情况,速度 v(x) = V0 + a(x)*x。 (其中 x 实际上是时间。我遵循您的约定,而不使用 t。)

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.)

倦话 2024-08-29 09:23:17

我已经尝试过这个,它有效(在 Ruby 中)。不确定数学是否合理,但输出看起来正确,这意味着当你接近中心时你会变得更快:

velocity=100;
(100.downto(0)).each { |distance_from_black_hole |  velocity=velocity+9.8/distance_from_black_hole; puts velocity; }

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; }
看春风乍起 2024-08-29 09:23:17

关于汽车示例的一些非编程讨论。

首先,我假设驾驶员无法在高速行驶时锁定刹车。

大多数新驾驶员学到的第一件事(或者可能是第二件事或第三件事)是制动时的自然趋势是将制动踏板保持在固定位置。结果是汽车从缓慢行驶到停止时突然向前倾斜。发生这种情况是因为制动器正在从动态摩擦(制动力与制动压力成正比)转变为静态摩擦(制动力恢复汽车的前进动力)。这种突然的加速跳跃令人不快,新驾驶员学会在减速结束时轻踩踏板以停止。

这种行为掩盖了另一个特殊性,但在手动变速箱汽车的正常加速过程中可以注意到这一点。当加速(或减速)时,如果驾驶员突然松开变速箱,所有乘客都会突然向前倾斜。实际发生的情况是,将他们压入座椅靠背的加速力突然消失,他们弹回中立的坐姿。更舒适的驾驶方式是逐渐轻踩离合器,从而逐渐消除发动机的动力。

在这两种情况下,更美观的驾驶风格包括平滑加速,消除突然的跳跃。这基本上是谈论连续二阶导数的另一种方式。几乎任何具有这种性质的运动都会显得很自然。

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.

匿名的好友 2024-08-29 09:23:17
y(x) = y0 - a * e ^ ( k * x )

其中,y0 是起始常量,ak 是因子。

示例图

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

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

Example plot.

信愁 2024-08-29 09:23:17
acceleration = (force / mass) 
velocity = (acceleration * time)
(force from user's finger) = acceleration / mass = velocity / time
  1. 给视图一个质量(调整它直到事情看起来合理,然后让用户调整它)
  2. 识别一些新的力(阻力)
  3. 给新的力(阻力)一个大小(调整直到合理,让用户调整它)
  4. 应用新的力 (阻力)对物体施力并观察其减速
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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文