ODE求解器C程序系统的初值问题

时间:2018-12-09 13:12:30

标签: c differential-equations

所以我想用C程序实现月球绕地球的路径。 我的问题是您知道月球在Apogee和Perigee的速度和位置。 因此,我开始从Apogee解决它,但是我无法弄清楚如何将第二速度和位置添加为“初始值”。我用if进行了尝试,但结果之间没有任何区别。任何帮助表示赞赏!

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>

typedef void (*ode)(double* p, double t, double* k, double* dk);

void euler(ode f, double *p, double t, double* k, double h, int n, int N)
{
    double kn[N];
    double dk[N];
    double Rp = - 3.633 * pow(10,8); // x position at Perigee

    for(int i = 0; i < n; i++)
    {
        f(p, 0, k, dk);
        for (int j = 0; j < N; j++)
        {
            if (k[0] == Rp)     // this is the "if" I mentioned in my comment
                                // x coordinate at Perigee
            {                    
                k[1] = 0;   // y coordinate at Perigee
                k[2] = 0;   // x velocity component at Perigee
                k[3] = 1076; // y velocity component at Perigee
            }
            kn[j] = k[j] + h * dk[j];
            printf("%f ", kn[j]);
            k[j] = kn[j];
        }
        printf("\n");
    }
}

void gravity_equation(double* p, double t, double* k, double* dk)
{
    // Earth is at the (0, 0)

    double G = p[0]; // Gravitational constant
    double m = p[1]; // Earth mass
    double x = k[0]; // x coordinate at Apogee
    double y = k[1]; // y coordinate at Apogee
    double Vx = k[2]; // x velocity component at Apogee
    double Vy = k[3]; // y velocity component at Apogee
    dk[0] = Vx;
    dk[1] = Vy;
    dk[2] = (- G * m * x) / pow(sqrt((x * x)+(y * y)),3);
    dk[3] = (- G * m * y) / pow(sqrt((x * x)+(y * y)),3);

}

void run_gravity_equation()
{
    int N = 4;  // how many equations there are

    double initial_values[N];
    initial_values[0] = 4.055*pow(10,8); // x position at Apogee
    initial_values[1] = 0; // y position at Apogee
    initial_values[2] = 0; // x velocity component at Apogee
    initial_values[3] = (-1) * 964; //y velocity component at Perigee

    int p = 2; // how many parameters there are

    double parameters[p];
    parameters[0] = 6.67384 * pow(10, -11); // Gravitational constant
    parameters[1] = 5.9736 * pow(10, 24); // Earth mass


    double h = 3600; // step size
    int n = 3000; // the number of steps

    euler(&gravity_equation, parameters, 0, initial_values, h, n, N);
}

int main()
{
    run_gravity_equation();
    return 0;
}

1 个答案:

答案 0 :(得分:2)

您的界面是

euler(odefun, params, t0, y0, h, n, N)

其中

N = dimension of state space
n = number of steps to perform
h = step size
t0, y0 = initial time and value

此过程的预期功能似乎是在数组y0内返回更新后的值。没有理由插入一些hack来迫使状态具有一些初始条件。初始条件作为参数传递。就像您在void run_gravity_equation()中所做的一样。集成例程应该与物理模型的细节无关。

您极不可能在第二次在k[0] == Rp中达到相同的值。您可以做的是检查Vx中的符号变化,即k[1]以查找极端x坐标的点或线段。


尝试进一步解释您的描述,您想要做的是解决一个边值问题,其中x(0)=4.055e8x'(0)=0y'(0)=-964x(T)=-3.633e8,{{1 }}。这具有解决单次或多次射击的边值问题的高级任务,此外,其上限是可变的。


您可能希望使用 Kepler定律进一步了解该问题的参数,以便您可以通过正向集成来解决它。 第一项开普勒定律的开普勒椭圆具有以下公式(按x'(T)=0的Apogee缩放,phi=0的Perigee缩放)

phi=pi

这样

 r = R/(1-E*cos(phi))

给出

R/(1-E)=4.055e8  and  R/(1+E)=3.633e8, 

此外,角速度由第二开普勒定律

给出
R=3.633*(1+E)=4.055*(1-E)  
==>  E = (4.055-3.633)/(4.055+3.633) = 0.054891,
     R = 3.633e8*(1+0.05489)           = 3.8324e8 

给出Apogee(phi'*r^2 = const. = sqrt(R*G*m) )上的切线速度

r=R/(1-E)

和近地点(y'(0)=phi'*r = sqrt(R*G*m)*(1-E)/R = 963.9438

r=R/(1+E)

确实可以重现您在代码中使用的常量。

开普勒椭圆的面积是最小直径和最大直径乘积的-y'(T)=phi'*r = sqrt(R*G*m)*(1+E)/R = 1075.9130 倍。最小的直径可以在pi/4处找到,最大的是远地点和近地点半径之和,因此面积为

cos(phi)=E

同时,它是整个pi*R/sqrt(1-E^2)*(R/(1+E)+R/(1-E))/2= pi*R^2/(1-E^2)^1.5 期间0.5*phi*r^2的积分,因此等于

2*T

这是第三开普勒定律。这样可以将半周期计算为

sqrt(R*G*m)*T

对于T = pi/sqrt(G*m)*(R/(1-E^2))^1.5 = 1185821 ,应该在h = 3600n=329n=330)之间达到一半。与n=329.395和Euler步骤的集成提供了scipy.integrate.odeint的下表:

h=3600

n [ x[n], y[n] ] for odeint/lsode for Euler 328 [ -4.05469444e+08, 4.83941626e+06] [ -4.28090166e+08, 3.81898023e+07] 329 [ -4.05497554e+08, 1.36933874e+06] [ -4.28507841e+08, 3.48454695e+07] 330 [ -4.05494242e+08, -2.10084488e+06] [ -4.28897657e+08, 3.14986514e+07] h=36

相同
n=32939..32940

对于Euler方法而言,该方法稍微接近一点,但效果却好得多。