常微分方程组解算器C程序的初值问题
所以我想用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)(
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]