2014-01-21 56 views
1

我一直在研究4阶Runge-Kutta求解器,并且遇到一些困难。我已经根据文章on gafferongames编写了求解器,但是当我运行一个小型包含示例时,即使对于简单的重力,我得到的错误也远远低于我用简单的欧拉积分得到的结果。我已经整理成一个自包含的示例(约60行代码,包括打印),但它需要运行GLM。
它显示了我的问题的完整。第55行显示了分析解决方案和RK4解决方案之间的差异。这应该是相对较小的,但即使经过了10个奇数步骤,它也会爆炸。Runge-Kutta 4阶积分器出错

#include <iostream> 
#include <glm/glm.hpp> 
struct State{ 
    glm::vec3 position, velocity; 
}; 
class Particle{ 
public: 
    glm::vec3 position, velocity, force; 
    float mass; 

    void solve(float dt); 
    glm::vec3 acceleration() const {return force/mass;} 
    State evalDerivative(float dt, const State& curr); 
    void analytic(float t, glm::vec3 a); 
}; 
int main(int argc, char* argv[]){ 
    Particle p; 
    p.position = glm::vec3(0.f); 
    p.mass = 1.0f; 
    for(int i = 1; i <= 10; i++) { 
     p.force = glm::vec3(0.f, -9.81f, 0.f); 
     p.solve(.016f); 
     p.analytic(i*.016f, glm::vec3(0.f, -9.81f, 0.f)); 
    } 
    getchar(); 
    return 0; 
} 
void Particle::solve(float dt){ 
    State t;t.position = glm::vec3(0.f); t.velocity = glm::vec3(0.f); 
    State k1 = evalDerivative(0, t); 
    State k2 = evalDerivative(dt*.5f, k1); 
    State k3 = evalDerivative(dt*.5f, k2); 
    State k4 = evalDerivative(dt, k3); 

    position += (k1.position + 2.f*(k2.position + k3.position) + k4.position)/6.f; 
    velocity += (k1.velocity + 2.f*(k2.velocity + k3.velocity) + k4.velocity)/6.f; 
    force = glm::vec3(0.f); 
} 
State Particle::evalDerivative(float dt, const State& curr){ 
    State s; 
    s.position = position + curr.position*dt; 
    s.velocity = velocity + curr.velocity*dt; 

    s.position = s.velocity; 
    s.velocity = acceleration(); 
    return s; 
} 
void Particle::analytic(float t, glm::vec3 a){ 
    glm::vec3 tPos = glm::vec3(0.f) + 0.5f*a*t*t; 
    glm::vec3 tVel = glm::vec3(0.f) + a*t; 

    glm::vec3 posdiff = tPos - position; 
    glm::vec3 veldiff = tVel - velocity; 
    std::cout << "POSITION: " << posdiff.x << ' ' << posdiff.y << ' ' << posdiff.z << std::endl; 
    std::cout << "VELOCITY: " << veldiff.x << ' ' << veldiff.y << ' ' << veldiff.z << std::endl << std::endl; 
} 

如果任何人都可以帮助我在这里,我在我的系绳结束与此。

回答

1

嗯,我觉得很蠢。我一直工作在这几个小时了,我错过了一小步:

position += (k1.position + 2.f*(k2.position + k3.position) + k4.position)/6.f; 
velocity += (k1.velocity + 2.f*(k2.velocity + k3.velocity) + k4.velocity)/6.f; 

应该

position += (k1.position + 2.f*(k2.position + k3.position) + k4.position)*dt/6.f; 
velocity += (k1.velocity + 2.f*(k2.velocity + k3.velocity) + k4.velocity)*dt/6.f;