常微分方程组解算器C程序的初值问题

常微分方程组解算器C程序的初值问题,c,differential-equations,C,Differential Equations,所以我想用C程序实现月球绕地球的轨道。 我的问题是你知道月球在远地点和近地点的速度和位置。 所以我开始从远地点解它,但我不知道如何把第二个速度和位置加起来作为它的“初始值”。我用if尝试了一下,但是我看不出结果之间有什么区别。感谢您的帮助 这是我的密码: #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> typedef void (*ode)(

所以我想用C程序实现月球绕地球的轨道。 我的问题是你知道月球在远地点和近地点的速度和位置。 所以我开始从远地点解它,但我不知道如何把第二个速度和位置加起来作为它的“初始值”。我用
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;
}
#包括
#包括
#包括
#包括
类型定义无效(*ode)(双*p、双t、双*k、双*dk);
空欧拉(常微分方程f,双*p,双t,双*k,双h,整数n,整数n)
{
双千牛[N];
双dk[N];
双Rp=-3.633*功率(10,8);//近地点的x位置
对于(int i=0;i
您的界面是

euler(odefun, params, t0, y0, h, n, N)
在哪里

此过程的预期功能似乎是在数组
y0
内返回更新的值。没有理由插入一些黑客来迫使国家有一些初始条件。初始条件作为参数传递。正如您在
中所做的那样,运行重力方程()。集成例程应保持对物理模型细节的不可知性

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


试图更仔细地解释您的描述,您要做的是解决一个边值问题,其中
x(0)=4.055e8
x'(0)=0
y'(0)=-964
x(T)=-3.633e8
x'(T)=0
。这有高级任务来解决单次或多次射击的边值问题,此外,上边界是可变的


您可能希望使用开普勒定律进一步深入了解此问题的参数,以便只需进行正向积分即可解决此问题。第一开普勒定律的开普勒椭圆有一个公式(在
phi=0
的远地点标度,在
phi=pi
的近地点标度)

所以

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 
此外,角速度由第二开普勒定律给出

phi'*r^2 = const. = sqrt(R*G*m)
给出了远地点的切向速度(
r=r/(1-E)

和近地点(
r=r/(1+E)

它确实复制了代码中使用的常量

开普勒椭圆的面积是最小和最大直径乘积的π/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=3600
时,应达到
n=329
n=330
n=329.395
)之间的半点。与
scipy.integrate.odeint
的集成与Euler steps的集成给出了
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

 n      [ x[n], y[n] ] for odeint/lsode              for Euler

32938 [ -4.05499997e+08   5.06668940e+04]    [ -4.05754415e+08   3.93845978e+05]
32939 [ -4.05500000e+08   1.59649309e+04]    [ -4.05754462e+08   3.59155385e+05]
32940 [ -4.05500000e+08  -1.87370323e+04]    [ -4.05754505e+08   3.24464789e+05]
32941 [ -4.05499996e+08  -5.34389954e+04]    [ -4.05754545e+08   2.89774191e+05]

这对于Euler方法来说更接近,但不是更好。

-3.633*pow(10,8)
最好用C编写为
-3.633e8
@AnttiHaapala我现在才知道!谢谢大家!@AnttiHaapala实际上是任何支持浮点文字的语言。包括每所学校使用的袖珍计算器。@Tooonest for this site好吧,我不会走那么远;)但是,是的,在C、C++、爪哇、C、D、Python、Perl、Ruby、JavaScript、Basic、斯卡拉、Culjule、通用LISP、Proto案、Prolog等方面,请看为什么Euler方法在轨道仿真中是非常糟糕的。你的答案非常有用!现在,一切都很清楚!
sqrt(R*G*m)*T
T = pi/sqrt(G*m)*(R/(1-E^2))^1.5 = 1185821
 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]
 n      [ x[n], y[n] ] for odeint/lsode              for Euler

32938 [ -4.05499997e+08   5.06668940e+04]    [ -4.05754415e+08   3.93845978e+05]
32939 [ -4.05500000e+08   1.59649309e+04]    [ -4.05754462e+08   3.59155385e+05]
32940 [ -4.05500000e+08  -1.87370323e+04]    [ -4.05754505e+08   3.24464789e+05]
32941 [ -4.05499996e+08  -5.34389954e+04]    [ -4.05754545e+08   2.89774191e+05]