00001 #pragma ident "$Id: SphericalHarmonicGravity.cpp 2457 2010-08-18 14:20:12Z coandrei $"
00002
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 #include "SphericalHarmonicGravity.hpp"
00033 #include "ASConstant.hpp"
00034 #include "IERS.hpp"
00035 #include "ReferenceFrames.hpp"
00036 #include "SpecialFunctions.hpp"
00037
00038 namespace gpstk
00039 {
00040
00041
00042
00043
00044 SphericalHarmonicGravity::SphericalHarmonicGravity(int n, int m)
00045 : desiredDegree(n),
00046 desiredOrder(m),
00047 correctSolidTide(false),
00048 correctOceanTide(false),
00049 correctPoleTide(false)
00050 {
00051 const int size = desiredDegree;
00052
00053 V.resize( size + 3, size + 3, 0.0);
00054 W.resize( size + 3, size + 3, 0.0);
00055
00056
00057
00058 }
00059
00060
00061
00062
00063
00064
00065 void SphericalHarmonicGravity::computeVW(Vector<double> r, Matrix<double> E)
00066 {
00067
00068
00069 if((r.size()!=3) || (E.rows()!=3) || (E.cols()!=3))
00070 {
00071 Exception e("Wrong input for computeVW");
00072 GPSTK_THROW(e);
00073 }
00074
00075
00076 Vector<double> r_bf = E * r;
00077
00078 const double R_ref = gmData.refDistance;
00079
00080
00081 double r_sqr = dot(r_bf, r_bf);
00082 double rho = R_ref * R_ref / r_sqr;
00083
00084
00085 double x0 = R_ref * r_bf(0) / r_sqr;
00086 double y0 = R_ref * r_bf(1) / r_sqr;
00087 double z0 = R_ref * r_bf(2) / r_sqr;
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099 V[0][0] = R_ref / std::sqrt(r_sqr);
00100 W[0][0] = 0.0;
00101
00102 V[1][0] = z0 * V[0][0];
00103 W[1][0] = 0.0;
00104
00105 for(int n = 2; n <= (desiredDegree+2); n++)
00106 {
00107 V[n][0] = ((2*n - 1) * z0 * V[n-1][0] - (n - 1) * rho * V[n-2][0]) /n;
00108 W[n][0] = 0.0;
00109 }
00110
00111
00112 for (int m = 1; m <= (desiredOrder+2); m++)
00113 {
00114
00115
00116 V[m][m] = (2 * m - 1) * ( x0 * V[m-1][m-1] - y0 * W[m-1][m-1] );
00117 W[m][m] = (2 * m - 1) * ( x0 * W[m-1][m-1] + y0 * V[m-1][m-1] );
00118
00119 if (m <= (desiredDegree+1) )
00120 {
00121 V[m+1][m] = (2 * m + 1) * z0 * V[m][m];
00122 W[m+1][m] = (2 * m + 1) * z0 * W[m][m];
00123 }
00124
00125 for (int n = (m+2); n <= (desiredDegree+2); n++)
00126 {
00127 V[n][m] = ((2*n-1)*z0*V[n-1][m] - (n+m-1)*rho*V[n-2][m]) / (n-m);
00128 W[n][m] = ((2*n-1)*z0*W[n-1][m] - (n+m-1)*rho*W[n-2][m]) / (n-m);
00129 }
00130
00131 }
00132
00133 }
00134
00135
00136
00137
00138
00139
00140
00141 Vector<double> SphericalHarmonicGravity::gravity(Vector<double> r, Matrix<double> E)
00142 {
00143
00144
00145 if((r.size()!=3) || (E.rows()!=3) || (E.cols()!=3))
00146 {
00147 Exception e("Wrong input for computeVW");
00148 GPSTK_THROW(e);
00149 }
00150
00151 Matrix<double> CS = gmData.unnormalizedCS;
00152
00153
00154
00155 double ax(0.0), ay(0.0), az(0.0);
00156
00157 for (int m = 0; m <= desiredOrder; m++)
00158 {
00159 for (int n = m; n <= desiredDegree; n++)
00160 {
00161 if (m==0)
00162 {
00163 double C = CS[n][0];
00164
00165 ax -= C * V[n+1][1];
00166 ay -= C * W[n+1][1];
00167 az -= (n+1)*C * V[n+1][0];
00168 }
00169 else
00170 {
00171 double C = CS[n][m];
00172 double S = CS[m-1][n];
00173 double Fac = 0.5 * (n-m+1) * (n-m+2);
00174
00175 ax += 0.5*(-C*V[n+1][m+1] - S*W[n+1][m+1]) + Fac*(C*V[n+1][m-1] + S*W[n+1][m-1]);
00176 ay += 0.5*(-C*W[n+1][m+1] + S*V[n+1][m+1]) + Fac*(-C*W[n+1][m-1] + S*V[n+1][m-1]);
00177 az += (n-m+1)*(-C*V[n+1][m] - S*W[n+1][m]);
00178 }
00179
00180 }
00181
00182 }
00183
00184
00185 Vector<double> a_bf(3,0.0);
00186 a_bf(0) = ax;
00187 a_bf(1) = ay;
00188 a_bf(2) = az;
00189
00190 a_bf = a_bf * ( gmData.GM / (gmData.refDistance * gmData.refDistance) );
00191
00192
00193 Matrix<double> Etrans = transpose(E);
00194 Vector<double> out = Etrans * a_bf;
00195
00196 return out;
00197
00198 }
00199
00200
00201
00202
00203
00204
00205
00206 Matrix<double> SphericalHarmonicGravity::gravityGradient(gpstk::Vector<double> r, gpstk::Matrix<double> E)
00207 {
00208
00209
00210 if((r.size()!=3) || (E.rows()!=3) || (E.cols()!=3))
00211 {
00212 Exception e("Wrong input for gravityGradient");
00213 GPSTK_THROW(e);
00214 }
00215
00216 Matrix<double> CS = gmData.unnormalizedCS;
00217
00218
00219 double xx = 0.0;
00220 double xy = 0.0;
00221 double xz = 0.0;
00222 double yy = 0.0;
00223 double yz = 0.0;
00224 double zz = 0.0;
00225
00226 Matrix<double> out(3, 3, 0.0);
00227
00228 for (int m = 0; m <= desiredOrder; m++)
00229 {
00230 for (int n = m; n <= desiredDegree; n++)
00231 {
00232 double Fac = (n-m+2)*(n-m+1);
00233
00234 double C = CS[n][m];
00235 double S = (m==0) ? 0.0 : CS[m-1][n];
00236
00237
00238 zz += Fac*(C*V[n+2][m] + S*W[n+2][m]);
00239
00240 if (m==0)
00241 {
00242 C = CS[n][0];
00243
00244 Fac = (n+2)*(n+1);
00245 xx += 0.5 * (C*V[n+2][2] - Fac*C*V[n+2][0]);
00246 xy += 0.5 * C * W[n+2][2];
00247
00248 Fac = n + 1;
00249 xz += Fac * C * V[n+2][1];
00250 yz += Fac * C * W[n+2][1];
00251 }
00252 if (m > 0)
00253 {
00254 C = CS[n][m];
00255 S = CS[m-1][n];
00256
00257 double f1 = 0.5*(n-m+1);
00258 double f2 = (n-m+3)*(n-m+2)*f1;
00259
00260 xz += f1*(C*V[n+2][m+1]+S*W[n+2][m+1])-f2*(C*V[n+2][m-1]+S*W[n+2][m-1]);
00261 yz += f1*(C*W[n+2][m+1]-S*V[n+2][m+1])+f2*(C*W[n+2][m-1]-S*V[n+2][m-1]);
00262
00263 if (m == 1)
00264 {
00265 Fac = (n+1)*n;
00266 xx += 0.25*(C*V[n+2][3]+S*W[n+2][3]-Fac*(3.0*C*V[n+2][1]+S*W[n+2][1]));
00267 xy += 0.25*(C*W[n+2][3]-S*V[n+2][3]-Fac*(C*W[n+2][1]+S*V[n+2][1]));
00268 }
00269 if (m > 1)
00270 {
00271 f1 = 2.0*(n-m+2)*(n-m+1);
00272 f2 = (n-m+4)*(n-m+3)*f1*0.5;
00273 xx += 0.25*(C*V[n+2][m+2]+S*W[n+2][m+2]-f1*(C*V[n+2][m]+S*W[n+2][m])+f2*(C*V[n+2][m-2]+S*W[n+2][m-2]));
00274
00275 xy += 0.25*(C*W[n+2][m+2]-S*V[n+2][m+2]+f2*(-C*W[n+2][m-2]+S*V[n+2][m-2]));
00276 }
00277 }
00278 }
00279 yy = -xx - zz;
00280
00281 out(0,0) = xx;
00282 out(0,1) = xy;
00283 out(0,2) = xz;
00284 out(1,0) = xy;
00285 out(1,1) = yy;
00286 out(1,2) = yz;
00287 out(2,0) = xz;
00288 out(2,1) = yz;
00289 out(2,2) = zz;
00290
00291 }
00292
00293 const double R_ref = gmData.refDistance;
00294 out = out * (gmData.GM / (R_ref * R_ref * R_ref));
00295
00296
00297 Matrix<double> Etrans = transpose(E);
00298 out = Etrans*(out*E);
00299
00300 return out;
00301
00302 }
00303
00304
00305
00312 void SphericalHarmonicGravity::doCompute(UTCTime utc, EarthBody& rb, Spacecraft& sc)
00313 {
00314
00315 Matrix<double> C2T = ReferenceFrames::J2kToECEFMatrix(utc);
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 correctCSTides(utc, correctSolidTide, correctOceanTide, correctPoleTide);
00337
00338
00339 computeVW(sc.R(), C2T);
00340
00341
00342 a = gravity(sc.R(), C2T);
00343
00344
00345 da_dr = gravityGradient(sc.R(), C2T);
00346
00347
00348 da_dv.resize(3,3,0.0);
00349
00350
00351
00352 }
00353
00354
00355 void SphericalHarmonicGravity::correctCSTides(UTCTime t,bool solidFlag,bool oceanFlag,bool poleFlag)
00356 {
00357
00358 Matrix<double> CS = gmData.unnormalizedCS;
00359 Vector<double> Sn0(CS.rows(),0.0);
00360
00361
00362 double mjd = t.MJD();
00363 double leapYears = (mjd-gmData.refMJD)/365.25;
00364
00365 double detC20 = normFactor(2,0)*leapYears*gmData.dotC20;
00366 double detC21 = normFactor(2,1)*leapYears*gmData.dotC21;
00367 double detS21 = normFactor(2,1)*leapYears*gmData.dotS21;
00368
00369 CS(2,0) += detC20;
00370 CS(2,1) += detC21;
00371 CS(0,2) += detS21;
00372
00373
00374 if(solidFlag)
00375 {
00376
00377 double dc[10] = {0.0};
00378 double ds[10] = {0.0};
00379 solidTide.getSolidTide(t.mjdUTC(),dc,ds);
00380
00381
00382 CS(2,0) += normFactor(2,0)*dc[0];
00383 CS(2,1) += normFactor(2,1)*dc[1];
00384 CS(2,2) += normFactor(2,2)*dc[2];
00385 CS(3,0) += normFactor(3,0)*dc[3];
00386 CS(3,1) += normFactor(3,1)*dc[4];
00387 CS(3,2) += normFactor(3,2)*dc[5];
00388 CS(3,3) += normFactor(3,3)*dc[6];
00389 CS(4,0) += normFactor(4,0)*dc[7];
00390 CS(4,1) += normFactor(4,1)*dc[8];
00391 CS(4,2) += normFactor(4,2)*dc[9];
00393 Sn0(2) += normFactor(2,0)*ds[0];
00394 CS(0,2) += normFactor(2,1)*ds[1];
00395 CS(1,2) += normFactor(2,2)*ds[2];
00396 Sn0(3) += normFactor(3,0)*ds[3];
00397 CS(0,3) += normFactor(3,1)*ds[4];
00398 CS(1,3) += normFactor(3,2)*ds[5];
00399 CS(2,3) += normFactor(3,3)*ds[6];
00400 Sn0(4) += normFactor(4,0)*ds[7];
00401 CS(0,4) += normFactor(4,1)*ds[8];
00402 CS(1,4) += normFactor(4,2)*ds[9];
00403
00404 }
00405
00406
00407 if(oceanFlag)
00408 {
00409
00410 double dc[12] = {0.0};
00411 double ds[12] = {0.0};
00412 oceanTide.getOceanTide(t.mjdUTC(),dc,ds);
00413
00414
00415 CS(2,0) += normFactor(2,0)*dc[0];
00416 CS(2,1) += normFactor(2,1)*dc[1];
00417 CS(2,2) += normFactor(2,2)*dc[2];
00418 CS(3,0) += normFactor(3,0)*dc[3];
00419 CS(3,1) += normFactor(3,1)*dc[4];
00420 CS(3,2) += normFactor(3,2)*dc[5];
00421 CS(3,3) += normFactor(3,3)*dc[6];
00422 CS(4,0) += normFactor(4,0)*dc[7];
00423 CS(4,1) += normFactor(4,1)*dc[8];
00424 CS(4,2) += normFactor(4,2)*dc[9];
00425 CS(4,3) += normFactor(4,3)*dc[10];
00426 CS(4,4) += normFactor(4,4)*dc[11];
00427
00428
00430 Sn0(2) += normFactor(2,0)*ds[0];
00431 CS(0,2) += normFactor(2,1)*ds[1];
00432 CS(1,2) += normFactor(2,2)*ds[2];
00433 Sn0(3) += normFactor(3,0)*ds[3];
00434 CS(0,3) += normFactor(3,1)*ds[4];
00435 CS(1,3) += normFactor(3,2)*ds[5];
00436 CS(2,3) += normFactor(3,3)*ds[6];
00437 Sn0(4) += normFactor(4,0)*ds[7];
00438 CS(1,4) += normFactor(4,1)*ds[8];
00439 CS(2,4) += normFactor(4,2)*ds[9];
00440 CS(3,4) += normFactor(4,1)*ds[10];
00441 CS(4,4) += normFactor(4,2)*ds[11];
00442
00443 }
00444
00445
00446 if(poleFlag)
00447 {
00448 double dC21=0.0;
00449 double dS21=0.0;
00450 poleTide.getPoleTide(t.mjdUTC(),dC21,dS21);
00451
00452 CS(2,1) += normFactor(2,1)*dC21;
00453 CS(0,2) += normFactor(2,1)*dS21;
00454 }
00455
00456 }
00457
00458
00459 double SphericalHarmonicGravity::normFactor(int n, int m)
00460 {
00461
00462
00463 double fac(1.0);
00464 for(int i = (n-m+1); i <= (n+m); i++)
00465 {
00466 fac = fac * double(i);
00467 }
00468
00469 double delta = (m == 0) ? 1.0 : 0.0;
00470
00471 double num = (2.0 * n + 1.0) * (2.0 - delta);
00472
00473
00474
00475 double out = std::sqrt(num/fac);
00476
00477 return out;
00478
00479 }
00480
00481 void SphericalHarmonicGravity::test()
00482 {
00483
00484 Vector<double> r(3,0.0);
00485 Matrix<double> E(3,3,0.0);
00486
00487 r(0) = 6525.919e3;
00488 r(1) = 1710.416e3;
00489 r(2) = 2508.886e3;
00490
00491 E = ident<double>(3);
00492
00493 computeVW(r, E);
00494
00495
00496 Vector<double> a = gravity(r, E);
00497
00498 Matrix<double> da_dr = gravityGradient(r, E);
00499
00500 cout<<setprecision(12)<<a<<endl;
00501 cout<<da_dr<<endl;
00502
00503 int aaa = 0;
00504
00505 }
00506
00507 }
00508