我有一个值表,告诉我信号电平如何随时间变化,我想模拟由此信号驱动的谐波振荡器。如果模拟不是100%准确则无关紧要。 我知道振荡器的频率。 我找到了很多公式,但他们都使用正弦波作为驱动程序。
答案 0 :(得分:3)
我想你想要进行一些时间离散模拟。众所周知的公式需要分析输入(参见格林函数)。如果你在某个时间点有一张力表,那么典型的分析公式对你来说就无济于事了。
这个想法是这样的:对于每个时间点t0,振荡器有一些给定的加速度,速度等。现在一个力作用于它 - 根据你给出的表 - 这将改变它的加速度(F = m) * 一个)。对于下一个时间步骤t1,我们假设加速度保持在该常数,因此我们可以对该时间帧应用具有dt =(t1-t0)的简单Newtonian equations(v = a * dt)。迭代直到模拟所需的时间范围。
此模拟的最重要参数是dt,即计算的细粒度。例如,您可能希望每秒有10个步骤,但这完全取决于您的输入参数。我们在这里所做的实质上是方程的Eulerian integration。
当然,这并不是全部 - 这种模拟可能非常复杂,尤其是在极端加速等情况下表现不佳的情况下。在这些情况下,您需要在一个帧内执行数字健全性检查,因为在一个帧中发生“极端”的事情。还需要一些数值积分,例如, Runge-Kutta algorithm。不过,我想这在这一点上会走得很远。
编辑:就在我发布这个之后,有人发表评论指向“Verlet Algorithm”的原始问题,这基本上是我上面描述的实现。
答案 1 :(得分:0)
http://en.wikipedia.org/wiki/Simple_harmonic_motion
http://en.wikipedia.org/wiki/Hooke“s_Law
http://en.wikipedia.org/wiki/Euler_method
答案 2 :(得分:0)
好吧,我终于想通了,并写了一个gui应用程序来测试它,直到它工作。但我的电脑不满意每秒1000 * 44100次,即使没有gui ^^
无论如何:这是我的测试代码(效果很好):
double lastTime;
const double deltaT = 1 / 44100.0;//length of a frame in seconds
double rFreq;
private void InitPendulum()
{
double freq = 2;//frequency in herz
rFreq = FToRSpeed(freq);
damp = Math.Pow(0.8, freq * deltaT);
}
private static double FToRSpeed(double p)
{
p *= 2;
p = Math.PI * p;
return p * p;
}
double damp;
double bHeight;
double bSpeed;
double lastchange;
private void timer1_Tick(object sender, EventArgs e)
{
double now=sw.ElapsedTicks/(double)Stopwatch.Frequency;
while (lastTime+deltaT <= now)
{
bHeight += bSpeed * deltaT;
double prevSpeed=bSpeed;
bSpeed += (mouseY - bHeight) * (rFreq*deltaT);
bSpeed *= damp;
if ((bSpeed > 0) != (prevSpeed > 0))
{
Console.WriteLine(lastTime - lastchange);
lastchange = lastTime;
}
lastTime += deltaT;
}
Invalidate();//No, i am not using gdi^^
}