中华农历论坛知识讨论区历法知识 → 用开普勒方程求解行星运动


  共有17398人关注过本帖树形打印

主题:用开普勒方程求解行星运动

帅哥哟,离线,有人找我吗?
xjw01
  1楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:蝙蝠侠 帖子:866 积分:3804 威望:3 精华:20 注册:2008/3/20 22:14:00
用开普勒方程求解行星运动  发帖心情 Post By:2009/6/17 22:35:00

//说明:本程序列是我早期利用开普勒定律编写的,参考了国外的一篇文章,精度一般。其中地球坐标的精度约为2角秒

 

double poly2(double *d,double x,int n){ //多项式计算
  //计算:d0 + d1*x + d2*x^2 + d3*x^3 +...+ dn*x^n
  int i; double c=0,xn=1;
  for(i=0;i<n;i++,xn*=x)
    c+=d[i]*xn;
  return c;
}
double rad2mrad(double v){ //对超过0-2PI的角度转为0-2PI
  v=fmod(v,2*M_PI);
  if(v<0) return v+2*M_PI;
  return v;
}
void llrConv(double *JWsrc, double *JW,double E){ //球面坐标旋转
  //黄道赤道坐标变换,赤到黄E取负
  double HJ=rad2mrad(JWsrc[0]), HW=JWsrc[1];
  double sinE =sin(E),cosE =cos(E);
  double sinW=cosE*sin(HW)+sinE*cos(HW)*sin(HJ);
  double J=atan2( sin(HJ)*cosE-tan(HW)*sinE, cos(HJ) );
  JW[0]=rad2mrad(J);
  JW[1]=asin(sinW);
}

struct Orb_elem{//行星轨道要素表
 //主要参数
  double N;  //升交点的黄经,J2000坐标中
  double i;  //行星轨道与地球轨道的夹角(倾角)
  double w;  //轨道近日点到升交点的夹角
  double M;  //轨道平近点角(行星当前位置到近日点的角度),角度按时间积累
  double a;  //轨道半长径
  double e;  //轨道离心率(e=0是圆,e=0-1是椭贺,e=1的抛物线)
  double pM; //平近点角速度(用于速度计算)
  //其它参数(以下参数可由主参数算出)
  double L;  //平黄经
  double P;  //P=a^1.5,轨道周期,a的单位是天文单au时,P的单位是地球公转年
  double q,Q;//q=a*(1-e)近日距离,Q=a*(1+e);远日距离
  double v,E;//v=真近点角(0至360度),E=偏近点角(正圆上的仿射角)
  double llr[3];//在黄道上的坐标
  double Vr,Vh; //Vr径向速度,Vh横向速度
};

//xn=8月球,地心黄道分点坐标,a的单位千米。xn=其它:日心Date黄道分点坐标,a为AU
//xn值:0水,1金,2地,3火,4木,5土,6天,7海(日心坐标)
void getPos_xx(double jd,int xn,Orb_elem &ob,int jing=0);

//=========以下是利用轨道要素计算行星坐标的函数===============
//这些计算不含章动岁差等,粗算Date平黄道坐标下的行星坐标等参数
//============================================================
void getPosFromOrb(Orb_elem &ob){//转入轨道要素返回经纬等
  //求偏近点角E,它与平近点角M的关系是:M=E-e*sin(E),式中e是离心率
  //该式可由开普勒周期定律或动力学方程导出
  double c, E=ob.M, M=ob.M, e=ob.e; int i;
  for(i=0;i<10;i++){ //牛顿求根法计算偏近点角E
    c=(E-e*sin(E)-M)/(1-e*cos(E)); //迭代修正量
    if(fabs(c)<1e-13) break;
    E-=c;
  }
  ob.E=E;
  double rx=ob.a*(cos(E)-e);         //分解在长轴上的分量
  double ry=ob.a*sqrt(1-e*e)*sin(E); //分解短轴上的分量
  ob.v=atan2(ry,rx);                 //真近点角
  ob.llr[0]=ob.w+ob.v;ob.llr[1]=0;   //在行星天道中的经度及纬度
  ob.llr[2]=sqrt(rx*rx+ry*ry);       //该时刻对坐标中心距离
  llrConv(ob.llr,ob.llr,ob.i);       //从行星天道坐标转到Date黄道坐标
  ob.llr[0]+=ob.N;                   //ob.N是升交点在黄道中的经度
  //其它参数计算
  double a=ob.a, pE=ob.pM*a*a/ob.llr[2];  //M'=C[1]平近点角速度,(单位:au/每日)
  ob.Vh=pE*sqrt(1-e*e);//横向速度Vh=r*v'
  ob.Vr=pE*(E-M);      //径向速度
  ob.L =ob.w+ob.N+ob.M;//平经度
  ob.P =a*sqrt(a);     //周期
  ob.q =a*(1-ob.e);    //近点距
  ob.Q =a*(1+ob.e);    //远点距
}
void getPos_xx(double jd,int xn,Orb_elem &ob,int jing){
  //计算行星位置(Date黄道坐标),含岁差,不含章动光行差等修正
  //本函数计算误差较大,适用于快速计算,xn是行星的编号
  //jing是精度控制(计算地球时jing=1采用较高精度)
  if(xn==9) {ob.llr[0]=ob.llr[1]=ob.llr[2]=0; return;} //太阳
  static double cs[9][12]={
   //xn=8月球,地心黄道分点坐标,a的单位千米。xn=其它:日心Date黄道分点坐标,a为AU
   //xn值:0水,1金,2地,3火,4木,5土,6天,7海(日心坐标), 每行为N(0,1),i(0,1),w(0,1),M(0,1),a(0,1),e(0,1)
   { 48.3313, 3.24587E-5, 7.0047, 5.000E-8,  29.1241, 1.01444E-5, 174.7947,4.0923344368, 0.387098,0, 0.205635, 5.59E-10},//0水
   { 76.6799, 2.46590E-5, 3.3946, 2.750E-8,  54.891,  1.38374E-5,  50.4084,1.6021302244, 0.723330,0, 0.006773,-1.302E-9},//1金
   {  0,      0.00000   , 0,      0.000,    102.9405, 4.70935E-5, 357.5254,0.9856002585, 1.0,     0, 0.016709,-1.151E-9},//2地
   { 49.5574, 2.11081E-5, 1.8497,-1.780E-8, 286.5016, 2.92961E-5,  19.3881,0.5240207766, 1.523688,0, 0.093405, 2.516E-9},//3火
   {100.4542, 2.76854E-5, 1.3030,-1.557E-7, 273.8777, 1.64505E-5,  20.0196,0.0830853001, 5.20256, 0, 0.048498, 4.469E-9},//4木
   {113.6634, 2.38980E-5, 2.4886,-1.081E-7, 339.3939, 2.97661E-5, 317.0172,0.0334442282, 9.55475, 0, 0.055546,-9.499E-9},//5土
   { 74.0005, 1.39780E-5, 0.7733, 1.900E-8, 96.6612,  3.05650E-5, 142.6081,0.0117258060, 19.18171,-1.550E-8, 0.047318,7.45E-9},//6天
   {131.7806, 3.01730E-5, 1.7700,-2.550E-7, 272.8461,-6.02700E-6, 260.2561,0.0059951470, 30.05826, 3.313E-8, 0.008606,2.15E-9},//7海
   {125.0434,-0.0529538083, 5.1454,0, 318.3099,0.1643573223, 134.9629,13.0649929509, 384402, 0, 0.054900, 0       } //8月
  };
  static int init=0;  int i,j;
  if(!init){ init=1;
    for(i=0;i<9;i++) //全部转为弧度
    for(j=0;j<8;j++) cs[i][j]=D2R(cs[i][j]);
  }
  double *p=cs[xn];
  ob.N=poly2(p,  jd,2); ob.i=poly2(p+2,jd,2);
  ob.w=poly2(p+4,jd,2); ob.M=poly2(p+6,jd,2);
  ob.a=poly2(p+8,jd,2); ob.e=poly2(p+10,jd,2);
  ob.pM=p[1];         //平近点角速度

  //由已上要素计算出经纬及速度等
  getPosFromOrb(ob);

  //处理主要摄动问题
  double d0=0,d1=0,d2=0, tt=jd/365250;
  if(xn==0) d0+=(3.0+29*tt+108.4*tt*tt)/rad; //平均误差8秒
  if(xn==1) d0+=(2.8+12*tt+108.2*tt*tt)/rad; //平均误差11秒
  if(xn==2){ //对地球受到的摄动进行修正
    //地球的千年内精度为2角秒,最大误正负6角秒
    if(jing){
     d0+=3.417571E-5 * cos( 2.829+     3.523*tt); d0+=3.497056E-5 * cos( 2.744+  5753.385*tt);
     d0+=3.135896E-5 * cos( 3.628+ 77713.771*tt); d0+=2.676218E-5 * cos( 4.418+  7860.419*tt);
     d0+=2.342687E-5 * cos( 6.135+  3930.210*tt); d0+=1.273166E-5 * cos( 2.037+   529.690*tt);
     d0+=1.324292E-5 * cos( 0.742+ 11506.770*tt); d0+=0.901855E-5 * cos( 2.045+    26.298*tt);
     d0+=1.199167E-5 * cos( 1.110+  1577.344*tt); d0+=0.857223E-5 * cos( 3.508+   398.149*tt);
     d0+=0.779786E-5 * cos( 1.179+  5223.694*tt); d0+=0.990250E-5 * cos( 5.233+  5884.927*tt);
     d0+=0.753141E-5 * cos( 2.533+  5507.553*tt); d0+=0.505264E-5 * cos( 4.583+ 18849.228*tt);
     d0+=0.492379E-5 * cos( 4.205+   775.523*tt); d0+=0.356655E-5 * cos( 2.920+     0.067*tt);
     d0+=0.284125E-5 * cos( 1.899+   796.298*tt); d0+=0.242810E-5 * cos( 0.345+  5486.778*tt);
     d0+=0.317087E-5 * cos( 5.849+ 11790.629*tt); d0+=0.271039E-5 * cos( 0.315+ 10977.079*tt);
     d0+=0.206160E-5 * cos( 4.806+  2544.314*tt); d0+=0.205385E-5 * cos( 1.869+  5573.143*tt);
     d0+=0.202261E-5 * cos( 2.458+  6069.777*tt);
     d0+=0.425264E-5 * cos( 1.590+     3.523*tt)*tt; d0+=0.108977E-5 * cos( 2.966+1577.344*tt)*tt;
     d0+=0.093478E-5 * cos( 2.592+ 18849.228*tt)*tt; d0+=0.119261E-5 * cos( 5.796+  26.298*tt)*tt;
     d0+=8.719837E-5 * cos( 1.572+  6283.076*tt)*tt*tt/3.3;
     //纬度摄动修正
     d1+=0.279620E-5 * cos( 3.20+  84334.662*tt); d1+=0.101643E-5 * cos( 5.42+   5507.553*tt);
     d1+=0.080445E-5 * cos( 3.88+   5223.694*tt); d1+=0.043806E-5 * cos( 3.70+   2352.866*tt);
     d1+=0.031933E-5 * cos( 4.00+   1577.344*tt); d1+=0.022724E-5 * cos( 3.98+   1047.747*tt);
    }
    d0+=(2.264089+10.667444*tt+108.680755*tt*tt)/rad; //长期项
  }
  if(xn==3){ //误差20秒(J2000前后1000年)
    d0+=2.7745E-4 *cos( 5.97+     3.523*tt); d0+=1.0610E-4 *cos( 2.94+  2281.230*tt);
    d0+=1.2316E-4 *cos( 0.85+  2810.921*tt); d0+=0.8927E-4 *cos( 4.16+     0.017*tt);
    d0+=0.8716E-4 *cos( 6.11+ 13362.450*tt); d0+=0.6798E-4 *cos( 0.36+   398.149*tt);
    d0+=0.7775E-4 *cos( 3.34+  5621.843*tt); d0+=(-43.1-122.6*tt+111.2*tt*tt)/rad;
  }
  if(xn==4){//处理木星摄动,误差1分
    d0+=5.7361E-3 *cos( 1.44+   7.114*tt); d0+=0.9718E-3 *cos( 4.14+ 632.784*tt);
    d0+=0.7290E-3 *cos( 3.64+ 522.577*tt); d0+=0.6426E-3 *cos( 3.41+ 103.093*tt);
    d0+=0.3981E-3 *cos( 2.29+ 419.485*tt); d0+=0.3886E-3 *cos( 1.27+ 316.392*tt);
    d0+=0.2796E-3 *cos( 1.78+ 536.805*tt); d0+=2.2892E-3 *cos( 6.03+   7.114*tt)*tt;
  }
  if(xn==5){//处理土星摄动,误差3分
    d0+=0.014142 *cos( 4.586+   7.114*tt); d0+=0.003984 *cos( 0.521+ 206.186*tt);
    d0+=0.002068 *cos( 0.247+ 103.093*tt); d0+=0.005643 *cos( 2.885+   7.114*tt)*tt;
    d0+=0.001077 *cos( 2.278+ 206.186*tt)*tt;
  }
  if(xn==6) d0+=(40.1-125.7*tt+2903*tt*tt)/rad; //处理天王星摄动,误差5分
  if(xn==8){ //处理月球摄动
    double ws=D2R(282.9405+4.70935E-5*jd);  //取太阳平近点角
    double Ms=D2R(357.5254+0.9856002585*jd);//太阳近地点到升交点夹角
    double Ls = Ms + ws;        //太阳升交点平黄经Ns=0
    double Mm = ob.M;           //取月球平近点角
    double Lm = ob.L;           //月球平黄经Mm + wm + Nm
    double D  = Lm - Ls;        //日月对地角距(夹角)
    double F  = Mm + ob.w;      //月球到升角点角度
    d0+=-0.02224*sin(Mm-2*D);    d0+= 0.01148*sin(2*D);      //经度摄动值
    d0+=-0.00325*sin(Ms);        d0+=-0.00103*sin(2*Mm-2*D);
    d0+=-0.00099*sin(Mm-2*D+Ms); d0+= 0.00093*sin(Mm+2*D);
    d0+= 0.00080*sin(2*D-Ms);    d0+= 0.00072*sin(Mm-Ms);
    d0+=-0.00061*sin(D);         d0+=-0.00054*sin(Mm+Ms);
    d1 =-0.00302*sin(F-2*D);     d1+=-0.00096*sin(Mm-F-2*D); //纬度摄动值
    d1+=-0.00080*sin(Mm+F-2*D);  d1+= 0.00058*sin(F+2*D);
    d1+= 0.00030*sin(2*Mm+F);
    d2 =-3700*cos(Mm-2*D);       d2+=-2934*cos(2*D); //距离摄动值
  }
  ob.llr[0] =rad2mrad(ob.llr[0]+d0); //加上黄纬摄动量
  ob.llr[1]+=d1; //加上黄纬摄动
  ob.llr[2]+=d2; //加上距离摄动
}


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部

返回版面帖子列表

用开普勒方程求解行星运动








签名