整合功能
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.7
、a = 1.4
、c = 2
和 b= 50
给出上图中的红色图
所有数值均为近似值。
f
判断频率接近匹配,
a
、b
、c
控制振幅衰减,是肉眼估计。
如果你有一个完美的匹配并不重要那么这对你有用。 totalAngle
使用相同的函数,但 t 增加了 0.25。不幸的是,我没有得到 a
、b
、c
和 totalAngle
的任何值,我确实注意到它是偏移的,所以你必须添加偏移值 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.7
、c= 2
、a~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
其中 P
、Q
和 C
是一些常量。
解决方案作为两个解决方案的总和更容易找到:
的一些特定解决方案
m * A'' + Fd * A' + F/MA * A = F
和齐次的一般解决方案
m * A'' + Fd * A' + F/MA * A = 0
这使得原始条件适合。显然特定的解决方案 A(t) = MA
有效,因此 C = MA
。所以现在我们需要拟合 P
和 Q
的通解来匹配起始条件。要找到它们,我们需要
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
希望对您有所帮助!
我有这个功能来达到某个一维值加速和超调阻尼。即:给定一个初始值、一个速度和一个加速度 (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.7
、a = 1.4
、c = 2
和 b= 50
给出上图中的红色图
所有数值均为近似值。
f
判断频率接近匹配,
a
、b
、c
控制振幅衰减,是肉眼估计。
如果你有一个完美的匹配并不重要那么这对你有用。 totalAngle
使用相同的函数,但 t 增加了 0.25。不幸的是,我没有得到 a
、b
、c
和 totalAngle
的任何值,我确实注意到它是偏移的,所以你必须添加偏移值 d
(我将所有内容归一化,所以不知道 totalAngle
的范围是多少)
totalAngle
F(t) = sin(((t+0.25) / f) * pi * 2) * (1 / ((((t+0.25) / f) + a) ^ c)) * b + d
抱歉,只有 f = 23.7
、c= 2
、a~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
其中 P
、Q
和 C
是一些常量。
解决方案作为两个解决方案的总和更容易找到:
的一些特定解决方案m * A'' + Fd * A' + F/MA * A = F
和齐次的一般解决方案
m * A'' + Fd * A' + F/MA * A = 0
这使得原始条件适合。显然特定的解决方案 A(t) = MA
有效,因此 C = MA
。所以现在我们需要拟合 P
和 Q
的通解来匹配起始条件。要找到它们,我们需要
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
希望对您有所帮助!