00001 #pragma ident "$Id: KeplerOrbit.cpp 2457 2010-08-18 14:20:12Z coandrei $"
00002
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include "KeplerOrbit.hpp"
00032 #include <limits>
00033 #include <cmath>
00034 #include "ASConstant.hpp"
00035 #include "ReferenceFrames.hpp"
00036
00037 namespace gpstk
00038 {
00039 using namespace std;
00040
00041 const double KeplerOrbit::eps_mach = numeric_limits<double>::epsilon();
00042
00043
00044
00045
00046
00047
00048 double KeplerOrbit::EccentricAnomaly(double M, double e)
00049 {
00050 const int maxit = 15;
00051 const double eps = 100.0*eps_mach;
00052
00053
00054 int i=0;
00055 double E, f;
00056
00057
00058
00059 M = Modulo(M, 2.0*ASConstant::PI);
00060 if (e<0.8) E=M; else E= ASConstant::PI;
00061
00062
00063 do
00064 {
00065 f = E - e*std::sin(E) - M;
00066 E = E - f / ( 1.0 - e*std::cos(E) );
00067 ++i;
00068 if (i == maxit)
00069 {
00070 cerr << " convergence problems in EccAnom" << endl;
00071 break;
00072 }
00073 }
00074 while (fabs(f) > eps);
00075
00076 return E;
00077
00078 }
00079
00080
00081
00082
00083
00084
00085
00086 double KeplerOrbit::TrueAnomaly (double M, double e)
00087 {
00088 double E = EccentricAnomaly(M, e);
00089
00090 double scta = std::sqrt(1.0-e*e)*std::sin(E)/(1.0-e*std::cos(E));
00091 double ccta = (std::cos(E)-e)/(1.0-e*std::cos(E));
00092
00093 return atan2(scta, ccta);
00094 }
00095
00096
00102 double KeplerOrbit::MeanAnomaly (double cta, double e)
00103 {
00104 double sinE = (std::sqrt(1.0-e*e)*std::sin(cta))/(1.0+e*std::cos(cta));
00105 double cosE = (e+std::cos(cta))/(1.0+e*std::cos(cta));
00106 double E = atan2(sinE,cosE);
00107
00108 return (E- e * std::sin(E));
00109 }
00110
00111
00112
00113
00114
00115
00116
00117
00118 double KeplerOrbit::FindEta (const Vector<double>& r_a,
00119 const Vector<double>& r_b,
00120 double tau)
00121 {
00122
00123
00124 const int maxit = 30;
00125 const double delta = 100.0*eps_mach;
00126
00127
00128
00129 double kappa, m, l, s_a, s_b, eta_min, eta1, eta2, F1, F2, d_eta;
00130
00131
00132
00133
00134 s_a = norm(r_a);
00135 s_b = norm(r_b);
00136
00137 kappa = std::sqrt ( 2.0*(s_a*s_b+dot(r_a,r_b)) );
00138
00139 m = tau*tau / std::pow(kappa,3);
00140 l = (s_a+s_b) / (2.0*kappa) - 0.5;
00141
00142 eta_min = std::sqrt(m/(l+1.0));
00143
00144
00145
00146 eta2 = ( 12.0 + 10.0*std::sqrt(1.0+(44.0/9.0)*m /(l+5.0/6.0)) ) / 22.0;
00147 eta1 = eta2 + 0.1;
00148
00149
00150
00151 F1 = F(eta1, m, l);
00152 F2 = F(eta2, m, l);
00153
00154 int i = 0;
00155
00156 while (std::fabs(F2-F1) > delta)
00157 {
00158 d_eta = -F2*(eta2-eta1)/(F2-F1);
00159 eta1 = eta2; F1 = F2;
00160 while (eta2+d_eta<=eta_min) d_eta *= 0.5;
00161 eta2 += d_eta;
00162 F2 = F(eta2,m,l); ++i;
00163
00164 if ( i == maxit )
00165 {
00166 cerr << "WARNING: Convergence problems in FindEta" << endl;
00167 break;
00168 }
00169 }
00170
00171 return eta2;
00172 }
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 Vector<double> KeplerOrbit::State( double GM, const Vector<double>& Kep, double dt )
00185 {
00186
00187
00188 const double a = Kep(0);
00189 const double e = Kep(1);
00190 const double i = Kep(2);
00191 const double Omega = Kep(3);
00192 const double omega = Kep(4);
00193 const double M0 = Kep(5);
00194
00195
00196 double M = M0 + std::sqrt(GM/(a*a*a)) * dt;
00197
00198
00199
00200 double E = EccentricAnomaly(M,e);
00201
00202 double cosE = std::cos(E);
00203 double sinE = std::sin(E);
00204
00205
00206
00207 double fac = std::sqrt( (1.0-e)*(1.0+e) );
00208
00209 double R = a*(1.0-e*cosE);
00210 double V = std::sqrt(GM*a)/R;
00211
00212 Vector<double> r(3,0.0),v(3,0.0);
00213 r(0) = a * (cosE - e);
00214 r(1) = a * fac * sinE;
00215 r(2) = 0.0;
00216
00217 v(0) = -V * sinE;
00218 v(1) = +V * fac * cosE;
00219 v(2) = 0.0;
00220
00221
00222 Matrix<double> PQW(3,3,0.0);
00223 PQW = ReferenceFrames::Rz(-Omega)
00224 * ReferenceFrames::Rx(-i)
00225 * ReferenceFrames::Rz(-omega);
00226
00227 r = PQW * r;
00228 v = PQW * v;
00229
00230 return Stack(r,v);
00231
00232 }
00233
00234
00235 Vector<double> KeplerOrbit::Stack(Vector<double> r,Vector<double> v)
00236 {
00237 const int n = r.size() + v.size();
00238 Vector<double> rv(n,0.0);
00239
00240 for(int i=0;i<n;i++)
00241 {
00242 if(i<r.size())
00243 {
00244 rv(i) = r(i);
00245 }
00246 else
00247 {
00248 rv(i) = v(i-r.size());
00249 }
00250 }
00251
00252 return rv;
00253 }
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267 Matrix<double> KeplerOrbit::StatePartials ( double GM, const Vector<double>& Kep, double dt )
00268 {
00269
00270
00271
00272
00273 Vector<double> dPdi(3),dPdO(3),dPdo(3),dQdi(3),dQdO(3),dQdo(3);
00274 Vector<double> dYda(6),dYde(6),dYdi(6),dYdO(6),dYdo(6),dYdM(6);
00275 Matrix<double> dYdA(6,6);
00276
00277
00278
00279 const double a = Kep(0);
00280 const double e = Kep(1);
00281 const double i = Kep(2);
00282 const double Omega = Kep(3);
00283 const double omega = Kep(4);
00284 const double M0 = Kep(5);
00285
00286
00287
00288 double n = std::sqrt (GM/(a*a*a));
00289 double M = M0 +n*dt;
00290 double E = EccentricAnomaly(M,e);
00291
00292
00293
00294 double cosE = std::cos(E);
00295 double sinE = std::sin(E);
00296 double fac = std::sqrt((1.0-e)*(1.0+e));
00297
00298 double r = a*(1.0-e*cosE);
00299 double v = std::sqrt(GM*a)/r;
00300
00301 double x = +a*(cosE-e);
00302 double y = +a*fac*sinE;
00303 double vx = -v*sinE;
00304 double vy = +v*fac*cosE;
00305
00306
00307 Matrix<double> PQW(3,3,0.0);
00308 PQW = ReferenceFrames::Rz(-Omega)
00309 * ReferenceFrames::Rx(-i)
00310 * ReferenceFrames::Rz(-omega);
00311
00312
00313 Vector<double> P(3),Q(3),W(3),e_z(3),N(3);
00314 P(0) = PQW(0,0);
00315 P(1) = PQW(1,0);
00316 P(2) = PQW(2,0);
00317
00318 Q(0) = PQW(0,1);
00319 Q(1) = PQW(1,1);
00320 Q(2) = PQW(2,1);
00321
00322 W(0) = PQW(0,2);
00323 W(1) = PQW(1,2);
00324 W(2) = PQW(2,2);
00325
00326
00327 e_z(0) = 0.0;
00328 e_z(1) = 0.0;
00329 e_z(2) = 1.0;
00330
00331
00332 N = cross(e_z,W); N = N/norm(N);
00333
00334 dPdi = cross(N,P); dPdO = cross(e_z,P); dPdo = Q;
00335 dQdi = cross(N,Q); dQdO = cross(e_z,Q); dQdo = -1.0*P;
00336
00337
00338 dYda = Stack ( (x/a)*P + (y/a)*Q,
00339 (-vx/(2*a))*P + (-vy/(2*a))*Q );
00340
00341
00342 dYde = Stack ( (-a-std::pow(y/fac,2)/r)*P + (x*y/(r*fac*fac))*Q ,
00343 (vx*(2*a*x+e*std::pow(y/fac,2))/(r*r))*P
00344 + ((n/fac)*std::pow(a/r,2)*(x*x/r-std::pow(y/fac,2)/a))*Q );
00345
00346
00347 dYdM = Stack ( (vx*P+vy*Q)/n, (-n*std::pow(a/r,3))*(x*P+y*Q) );
00348
00349
00350
00351 dYdi = Stack ( x*dPdi+y*dQdi, vx*dPdi+vy*dQdi );
00352 dYdO = Stack ( x*dPdO+y*dQdO, vx*dPdO+vy*dQdO );
00353 dYdo = Stack ( x*dPdo+y*dQdo, vx*dPdo+vy*dQdo );
00354
00355
00356
00357 double dMda = -1.5*(n/a)*dt;
00358
00359
00360
00361 for (int k=0; k<6; k++)
00362 {
00363 dYdA(k,0) = dYda(k) + dYdM(k)*dMda;
00364 dYdA(k,1) = dYde(k);
00365 dYdA(k,2) = dYdi(k);
00366 dYdA(k,3) = dYdO(k);
00367 dYdA(k,4) = dYdo(k);
00368 dYdA(k,5) = dYdM(k);
00369 }
00370
00371 return dYdA;
00372
00373 }
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383 Vector<double> KeplerOrbit::Elements( double GM, const Vector<double>& y )
00384 {
00385
00386 Vector<double> r(3),v(3);
00387 r(0) = y(0);
00388 r(1) = y(1);
00389 r(2) = y(2);
00390 v(0) = y(3);
00391 v(1) = y(4);
00392 v(2) = y(5);
00393
00394 Vector<double> h = cross(r,v);
00395 double H = norm(h);
00396
00397 double Omega = atan2( h(0), -h(1) );
00398 Omega = Modulo(Omega,2.0*ASConstant::PI);
00399
00400 double i = std::atan2( std::sqrt(h(0)*h(0)+h(1)*h(1)), h(2) );
00401
00402 double u = std::atan2( r(2)*H, -r(0)*h(1)+r(1)*h(0) );
00403 double R = norm(r);
00404
00405 double a = 1.0 / (2.0/R-dot(v,v)/GM);
00406
00407 double eCosE = 1.0-R/a;
00408 double eSinE = dot(r,v)/std::sqrt(GM*a);
00409
00410 double e2 = eCosE*eCosE +eSinE*eSinE;
00411 double e = std::sqrt(e2);
00412 double E = std::atan2(eSinE,eCosE);
00413
00414 double M = Modulo(E-eSinE,2.0*ASConstant::PI);
00415
00416 double nu = std::atan2(std::sqrt(1.0-e2)*eSinE, eCosE-e2);
00417
00418 double omega = Modulo(u-nu,2.0*ASConstant::PI);
00419
00420
00421
00422 Vector<double> Kep(6,0.0);
00423 Kep(0) = a;
00424 Kep(1) = e;
00425 Kep(2) = i;
00426 Kep(3) = Omega;
00427 Kep(4) = omega;
00428 Kep(5) = M;
00429
00430 return Kep;
00431
00432 }
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 Vector<double> KeplerOrbit::Elements( double GM, double Mjda, double Mjdb,
00448 const Vector<double>& ra, const Vector<double>& rb )
00449 {
00450
00451
00452 double a, e, i, Omega, omega, M;
00453
00454
00455
00456
00457 double s_a = norm(ra);
00458 Vector<double> e_a = ra/s_a;
00459
00460 double s_b = norm(rb);
00461 double fac = dot(rb,e_a);
00462 Vector<double> r_0 = rb-fac*e_a;
00463
00464 double s_0 = norm(r_0);
00465 Vector<double> e_0 = r_0/s_0;
00466
00467
00468
00469 Vector<double> W = cross(e_a,e_0);
00470 Omega = std::atan2( W(0), -W(1) );
00471 Omega = Modulo(Omega,2.0*ASConstant::PI);
00472 i = std::atan2( std::sqrt(W(0)*W(0)+W(1)*W(1)), W(2) );
00473
00474 double u(0.0);
00475 if (i==0.0)
00476 u = std::atan2( ra(1), ra(0) );
00477 else
00478 u = std::atan2( +e_a(2) , -e_a(0)*W(1)+e_a(1)*W(0) );
00479
00480
00481
00482 double tau = std::sqrt(GM) * 86400.0*fabs(Mjdb-Mjda);
00483 double eta = FindEta( ra, rb, tau );
00484 double p = std::pow( s_a*s_0*eta/tau, 2 );
00485
00486
00487
00488 double cos_dnu = fac / s_b;
00489 double sin_dnu = s_0 / s_b;
00490
00491 double ecos_nu = p / s_a - 1.0;
00492 double esin_nu = ( ecos_nu * cos_dnu - (p/s_b-1.0) ) / sin_dnu;
00493
00494 e = std::sqrt( ecos_nu*ecos_nu + esin_nu*esin_nu );
00495 double nu = std::atan2(esin_nu,ecos_nu);
00496
00497 omega = Modulo(u-nu,2.0*ASConstant::PI);
00498
00499
00500
00501 a = p/(1.0-e*e);
00502 double n = std::sqrt( GM / std::fabs(a*a*a) );
00503
00504
00505
00506 if (e<1.0) {
00507 double E = std::atan2( std::sqrt((1.0-e)*(1.0+e)) * esin_nu, ecos_nu + e*e );
00508 M = Modulo( E - e*std::sin(E), 2.0*ASConstant::PI );
00509 }
00510 else
00511 {
00512 double sinhH = std::sqrt((e-1.0)*(e+1.0)) * esin_nu / ( e + e * ecos_nu );
00513 M = e * sinhH - std::log ( sinhH + std::sqrt(1.0+sinhH*sinhH) );
00514 }
00515
00516
00517
00518 gpstk::Vector<double> Kep(6,0.0);
00519 Kep(0) = a;
00520 Kep(1) = e;
00521 Kep(2) = i;
00522 Kep(3) = Omega;
00523 Kep(4) = omega;
00524 Kep(5) = M;
00525
00526 return Kep;
00527
00528 }
00529
00530
00543 void KeplerOrbit::TwoBody( double GM, const Vector<double>& Y0, double dt,
00544 Vector<double>& Y, Matrix<double>& dYdY0 )
00545 {
00546 double a,e,i,n, sqe2,naa;
00547 double P_aM, P_eM, P_eo, P_io, P_iO;
00548 gpstk::Vector<double> A0(6);
00549 gpstk::Matrix<double> dY0dA0(6,6), dYdA0(6,6), dA0dY0(6,6);
00550
00551
00552 A0 = Elements(GM,Y0);
00553
00554 a = A0(0); e = A0(1); i = A0(2);
00555
00556 n = std::sqrt(GM/(a*a*a));
00557
00558
00559
00560 Y = State(GM,A0,dt);
00561
00562
00563
00564 dY0dA0 = StatePartials(GM,A0,0.0);
00565 dYdA0 = StatePartials(GM,A0,dt);
00566
00567
00568
00569 sqe2 = std::sqrt((1.0-e)*(1.0+e));
00570 naa = n*a*a;
00571
00572 P_aM = -2.0/(n*a);
00573 P_eM = -(1.0-e)*(1.0+e)/(naa*e);
00574 P_eo = +sqe2/(naa*e);
00575 P_io = -1.0/(naa*sqe2*std::tan(i));
00576 P_iO = +1.0/(naa*sqe2*std::sin(i));
00577
00578
00579
00580 for(int k=0;k<3;k++)
00581 {
00582
00583 dA0dY0(0,k) = + P_aM*dY0dA0(k+3,5);
00584 dA0dY0(0,k+3) = - P_aM*dY0dA0(k ,5);
00585
00586 dA0dY0(1,k) = + P_eo*dY0dA0(k+3,4) + P_eM*dY0dA0(k+3,5);
00587 dA0dY0(1,k+3) = - P_eo*dY0dA0(k ,4) - P_eM*dY0dA0(k ,5);
00588
00589 dA0dY0(2,k) = + P_iO*dY0dA0(k+3,3) + P_io*dY0dA0(k+3,4);
00590 dA0dY0(2,k+3) = - P_iO*dY0dA0(k ,3) - P_io*dY0dA0(k ,4);
00591
00592 dA0dY0(3,k) = - P_iO*dY0dA0(k+3,2);
00593 dA0dY0(3,k+3) = + P_iO*dY0dA0(k ,2);
00594
00595 dA0dY0(4,k) = - P_eo*dY0dA0(k+3,1) - P_io*dY0dA0(k+3,2);
00596 dA0dY0(4,k+3) = + P_eo*dY0dA0(k ,1) + P_io*dY0dA0(k ,2);
00597
00598 dA0dY0(5,k) = - P_aM*dY0dA0(k+3,0) - P_eM*dY0dA0(k+3,1);
00599 dA0dY0(5,k+3) = + P_aM*dY0dA0(k ,0) + P_eM*dY0dA0(k ,1);
00600
00601 };
00602
00603
00604 dYdY0 = dYdA0 * dA0dY0;
00605
00606 }
00607
00608
00609
00610
00611
00612 double KeplerOrbit::F (double eta, double m, double l)
00613 {
00614
00615 const double eps = 100.0 * eps_mach;
00616
00617 double w,W,a,n,g;
00618
00619 w = m/(eta*eta)-l;
00620
00621 if (std::fabs(w)<0.1)
00622 {
00623 W = a = 4.0/3.0; n = 0.0;
00624 do
00625 {
00626 n += 1.0; a *= w*(n+2.0)/(n+1.5); W += a;
00627 }
00628 while (std::fabs(a) >= eps);
00629 }
00630 else
00631 {
00632 if (w > 0.0)
00633 {
00634 g = 2.0 * std::asin(std::sqrt(w));
00635 W = (2.0*g - std::sin(2.0*g)) / std::pow(std::sin(g), 3);
00636 }
00637 else
00638 {
00639 g = 2.0*std::log(std::sqrt(-w)+std::sqrt(1.0-w));
00640 W = (std::sinh(2.0*g) - 2.0*g) / std::pow(std::sinh(g), 3);
00641 }
00642 }
00643
00644 return ( 1.0 - eta + (w+l)*W );
00645
00646 }
00647
00648 double KeplerOrbit::getPeriod(double GM, const Vector<double>& Kep)
00649 {
00650 const double n = std::sqrt(GM / std::pow(Kep(0),3));
00651 return 2.0 * ASConstant::PI / n;
00652 }
00653
00654 double KeplerOrbit::getApogee(double GM, const Vector<double>& Kep)
00655 {
00656
00657 double p = Kep(0) * (1.0 - Kep(1) * Kep(1));
00658 return p / (1 - Kep(1));
00659 }
00660
00661 double KeplerOrbit::getPerigee(double GM, const Vector<double>& Kep)
00662 {
00663
00664 double p = Kep(0) * (1.0 - Kep(1) * Kep(1));
00665
00666 return p / (1 + Kep(1));
00667 }
00668
00669
00670
00671 void KeplerOrbit::test()
00672 {
00673 const double GM_Earth = 398600.4415e+9;
00674
00675 const double Deg = 180.0 / ASConstant::PI;
00676
00677 double rv[6]={-6345.000e3, -3723.000e3, -580.000e3, +2.169000e3, -9.266000e3, -1.079000e3 };
00678
00679 Vector<double> Y0_ref(6);
00680 Y0_ref = rv;
00681
00682 Vector<double> Kep = Elements ( GM_Earth, Y0_ref );
00683 double ceta = KeplerOrbit::TrueAnomaly(Kep(5),Kep(1));
00684 double ecc = KeplerOrbit::EccentricAnomaly(Kep(5),Kep(1));
00685
00686 cout<<fixed<<setprecision(6);
00687 cout << "Orbital elements:" << endl << endl
00688 << setprecision(3)
00689 << " Semimajor axis " << setw(10) << Kep(0)/1000.0 << " km" << endl
00690 << setprecision(7)
00691 << " Eccentricity " << setw(10) << Kep(1)<< endl
00692 << setprecision(3)
00693 << " Inclination " << setw(10) << Kep(2)*Deg << " deg"<< endl
00694 << " RA ascend. node " << setw(10) << Kep(3)*Deg << " deg"<< endl
00695 << " Arg. of perigee " << setw(10) << Kep(4)*Deg << " deg"<< endl
00696 << " Mean anomaly " << setw(10) << Kep(5)*Deg << " deg"<< endl
00697 << " True anomaly " << setw(10) << ceta*Deg << " deg"<< endl
00698 << " Eccentric anomaly" << setw(10) << ecc*Deg << " deg"<< endl
00699 << endl;
00700
00701
00702 Vector<double> Y_ref = State(GM_Earth,Kep,0);
00703 Vector<double> Y(6);
00704 Matrix<double> phi(6,6);
00705
00706 KeplerOrbit::TwoBody ( GM_Earth,Y0_ref,0, Y,phi);
00707
00708 cout<<fixed<<setw(12)<<setprecision(8);
00709 for(int i=0;i<6;i++)
00710 {
00711 cout<<Y(i)<<endl;
00712 }
00713
00714 for(int i=0;i<6;i++)
00715 {
00716 for(int j=0;j<6;j++)
00717 {
00718 cout<<phi(i,j)<< " ";
00719 }
00720 cout<<endl;
00721 }
00722
00723 Vector<double> Y2(6),diff(6);
00724 Y2 = phi*Y0_ref;
00725
00726 diff = Y2-Y;
00727 for(int i=0;i<6;i++)
00728 {
00729 cout<<diff(i)<<endl;
00730 }
00731
00732
00733 }
00734
00735
00736 }
00737
00738
00739
00740
00741