整合功能

Integrate function

我有这个功能来达到某个一维值加速和超调阻尼。即:给定一个初始值、一个速度和一个加速度 (force/mass),通过加速达到目标值并在接近目标值时逐渐增加阻尼。

一切正常,但是如果我想知道时间 't' 之后的 TotalAngle 是多少,我必须 运行 这个函数说 N 步 'small' dt 才能找到'limit'。 我想知道我是否可以(以及如何)通过 dt 进行整合,以便可以在给定时间 't' 最初确定 TotalAngle。

此致,Tanks 提供任何帮助。

dt = delta time step per frame
input = 1
TotalAngle = 0 at t=0
Velocity   = 0 at t=0

void FAccelDampedWithOvershoot::Update(float dt, float input, float& Velocity, float& TotalAngle)
{
const float Force = 500000.f;
const float DampForce = 5000.f;
const float MaxAngle  = 45.f;
const float InvMass   = 1.f / 162400.f;

float target  = MaxAngle * input;
float ratio   = (target - TotalAngle) / MaxAngle;
float fMove   = Force * ratio;
float fDamp   = -Velocity * DampForce;

Velocity   += (fMove + fDamp) * invMass * dt;
TotalAngle += Velocity * dt;
}

这不是一个完整的答案,我相信其他人可以解决,但评论中没有空间,它可能会帮助您找到更好的解决方案。

下图显示了函数在时间步 1 积分时的速度(蓝色)。红色显示了下面计算时间 t 值的函数

函数 F(t)

F(t) = sin((t / f) * pi * 2) * (1 / (((t / f) + a) ^ c)) * b

f = 23.7a = 1.4c = 2b= 50 给出上图中的红色图

所有数值均为近似值。

f判断频率接近匹配, abc 控制振幅衰减,是肉眼估计。

如果你有一个完美的匹配并不重要那么这对你有用。 totalAngle 使用相同的函数,但 t 增加了 0.25。不幸的是,我没有得到 abctotalAngle 的任何值,我确实注意到它是偏移的,所以你必须添加偏移值 d(我将所有内容归一化,所以不知道 totalAngle 的范围是多少)

totalAngle

的函数 F(t)

F(t) = sin(((t+0.25) / f) * pi * 2) * (1 / ((((t+0.25) / f) + a) ^ c)) * b + d

抱歉,只有 f = 23.7c= 2a~1.4 b=? d=?

已更新,修复了数学中的错误

最初我已经失去了几次质量和最大角度。这就是为什么你应该先在纸上解决它然后进入 SO 而不是试图在文本编辑器中解决它。

无论如何,我已经修正了数学问题,现在它似乎工作得相当不错。我把固定的解决方案放在前一个上。

好吧,这看起来像是牛顿力学,意思是微分方程。让我们尝试解决它们。

SO对数学公式不是很友好而且我有点厌烦输入字符所以这是我使用的:

  • F = Force
  • Fd = DampForce
  • MA = MaxAngle
  • A=TotalAngle
  • v = Velocity
  • m = 1 / InvMass
  • ' 对于导数,即 something't 的一阶导数,而 something'' 是二阶导数

如果我将最后两行代码除以 dt 并合并我能得到的所有其他行(我还假设 input = 1 因为其他情况显然是对称的)

v' = ([F * (1 - A / MA)]  - v * Fd) / m

并应用 A' = v 我们得到

m * A'' = F(1 - A/MA)  - Fd * A' 

或者向一侧移动,我们得到一个简单的二阶微分方程

m * A'' + Fd * A'  + F/MA * A  = F

IIRC,解法是先解特征方程,这里是

m * x^2 + Fd * x + F/MA = 0

x[1,2] = (-Fd +/- sqrt(Fd^2 - 4*F*m/MA))/ (2*m)

我预计 sqrt 下的部分,即 (Fd^2 - 4*F*m/MA) 是否定的,因此解决方案应采用以下形式。让

Dm =  Fd/(2*m)
K =  sqrt(F/MA/m - Dm^2)

(注意 sqrt 下的负值,所以它现在有效)然后

A(t) = e^(-Dm*t) * [P * sin(K*t) + Q * cos(K*t)] + C

其中 PQC 是一些常量。

解决方案作为两个解决方案的总和更容易找到:

的一些特定解决方案
m * A'' + Fd * A'  + F/MA * A  = F

和齐次的一般解决方案

m * A'' + Fd * A'  + F/MA * A  = 0

这使得原始条件适合。显然特定的解决方案 A(t) = MA 有效,因此 C = MA。所以现在我们需要拟合 PQ 的通解来匹配起始条件。要找到它们,我们需要

A(0) = - MA
A'(0) = V(0) = 0

鉴于 e^0 = 1,sin(0) = 0 和 cos(0) = 1 你会得到类似

Q = -MA
P = 0

P = 0
Q = - MA
C = MA

因此

A(t) = MA * [1 - e^(-Dm*t) * cos(K*t)]
where 
Dm =  Fd/(2*m)
K =  sqrt(F/MA/m - Dm^2)

根据您的任务,哪种方式有意义。

另请注意,此等式假设一切都以弧度而不是度数发生(即 [sin(t)]' 的导数只是 cos(t)),因此您应该相应地转换所有常量或转换解决方案。

const float Force = 500000.f * M_PI / 180;
const float DampForce = 5000.f * M_PI / 180;
const float MaxAngle = M_PI_4;

在我的机器上生成

Dm = 0.000268677541
K  = 0.261568546

这似乎与原始功能相似,我使用 dt = 0.01f 步进,主要障碍似乎是精度损失,因为 float

希望对您有所帮助!