Simon1994PlanetaryPositions.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. import Cartesian3 from "./Cartesian3.js";
  2. import defined from "./defined.js";
  3. import DeveloperError from "./DeveloperError.js";
  4. import JulianDate from "./JulianDate.js";
  5. import CesiumMath from "./Math.js";
  6. import Matrix3 from "./Matrix3.js";
  7. import TimeConstants from "./TimeConstants.js";
  8. import TimeStandard from "./TimeStandard.js";
  9. /**
  10. * Contains functions for finding the Cartesian coordinates of the sun and the moon in the
  11. * Earth-centered inertial frame.
  12. *
  13. * @namespace Simon1994PlanetaryPositions
  14. */
  15. const Simon1994PlanetaryPositions = {};
  16. function computeTdbMinusTtSpice(daysSinceJ2000InTerrestrialTime) {
  17. /* STK Comments ------------------------------------------------------
  18. * This function uses constants designed to be consistent with
  19. * the SPICE Toolkit from JPL version N0051 (unitim.c)
  20. * M0 = 6.239996
  21. * M0Dot = 1.99096871e-7 rad/s = 0.01720197 rad/d
  22. * EARTH_ECC = 1.671e-2
  23. * TDB_AMPL = 1.657e-3 secs
  24. *--------------------------------------------------------------------*/
  25. //* Values taken as specified in STK Comments except: 0.01720197 rad/day = 1.99096871e-7 rad/sec
  26. //* Here we use the more precise value taken from the SPICE value 1.99096871e-7 rad/sec converted to rad/day
  27. //* All other constants are consistent with the SPICE implementation of the TDB conversion
  28. //* except where we treat the independent time parameter to be in TT instead of TDB.
  29. //* This is an approximation made to facilitate performance due to the higher prevalance of
  30. //* the TT2TDB conversion over TDB2TT in order to avoid having to iterate when converting to TDB for the JPL ephemeris.
  31. //* Days are used instead of seconds to provide a slight improvement in numerical precision.
  32. //* For more information see:
  33. //* http://www.cv.nrao.edu/~rfisher/Ephemerides/times.html#TDB
  34. //* ftp://ssd.jpl.nasa.gov/pub/eph/planets/ioms/ExplSupplChap8.pdf
  35. const g = 6.239996 + 0.0172019696544 * daysSinceJ2000InTerrestrialTime;
  36. return 1.657e-3 * Math.sin(g + 1.671e-2 * Math.sin(g));
  37. }
  38. const TdtMinusTai = 32.184;
  39. const J2000d = 2451545;
  40. function taiToTdb(date, result) {
  41. //Converts TAI to TT
  42. result = JulianDate.addSeconds(date, TdtMinusTai, result);
  43. //Converts TT to TDB
  44. const days = JulianDate.totalDays(result) - J2000d;
  45. result = JulianDate.addSeconds(result, computeTdbMinusTtSpice(days), result);
  46. return result;
  47. }
  48. const epoch = new JulianDate(2451545, 0, TimeStandard.TAI); //Actually TDB (not TAI)
  49. const MetersPerKilometer = 1000.0;
  50. const RadiansPerDegree = CesiumMath.RADIANS_PER_DEGREE;
  51. const RadiansPerArcSecond = CesiumMath.RADIANS_PER_ARCSECOND;
  52. const MetersPerAstronomicalUnit = 1.4959787e11; // IAU 1976 value
  53. const perifocalToEquatorial = new Matrix3();
  54. function elementsToCartesian(
  55. semimajorAxis,
  56. eccentricity,
  57. inclination,
  58. longitudeOfPerigee,
  59. longitudeOfNode,
  60. meanLongitude,
  61. result
  62. ) {
  63. if (inclination < 0.0) {
  64. inclination = -inclination;
  65. longitudeOfNode += CesiumMath.PI;
  66. }
  67. //>>includeStart('debug', pragmas.debug);
  68. if (inclination < 0 || inclination > CesiumMath.PI) {
  69. throw new DeveloperError(
  70. "The inclination is out of range. Inclination must be greater than or equal to zero and less than or equal to Pi radians."
  71. );
  72. }
  73. //>>includeEnd('debug')
  74. const radiusOfPeriapsis = semimajorAxis * (1.0 - eccentricity);
  75. const argumentOfPeriapsis = longitudeOfPerigee - longitudeOfNode;
  76. const rightAscensionOfAscendingNode = longitudeOfNode;
  77. const trueAnomaly = meanAnomalyToTrueAnomaly(
  78. meanLongitude - longitudeOfPerigee,
  79. eccentricity
  80. );
  81. const type = chooseOrbit(eccentricity, 0.0);
  82. //>>includeStart('debug', pragmas.debug);
  83. if (
  84. type === "Hyperbolic" &&
  85. Math.abs(CesiumMath.negativePiToPi(trueAnomaly)) >=
  86. Math.acos(-1.0 / eccentricity)
  87. ) {
  88. throw new DeveloperError(
  89. "The true anomaly of the hyperbolic orbit lies outside of the bounds of the hyperbola."
  90. );
  91. }
  92. //>>includeEnd('debug')
  93. perifocalToCartesianMatrix(
  94. argumentOfPeriapsis,
  95. inclination,
  96. rightAscensionOfAscendingNode,
  97. perifocalToEquatorial
  98. );
  99. const semilatus = radiusOfPeriapsis * (1.0 + eccentricity);
  100. const costheta = Math.cos(trueAnomaly);
  101. const sintheta = Math.sin(trueAnomaly);
  102. const denom = 1.0 + eccentricity * costheta;
  103. //>>includeStart('debug', pragmas.debug);
  104. if (denom <= CesiumMath.Epsilon10) {
  105. throw new DeveloperError("elements cannot be converted to cartesian");
  106. }
  107. //>>includeEnd('debug')
  108. const radius = semilatus / denom;
  109. if (!defined(result)) {
  110. result = new Cartesian3(radius * costheta, radius * sintheta, 0.0);
  111. } else {
  112. result.x = radius * costheta;
  113. result.y = radius * sintheta;
  114. result.z = 0.0;
  115. }
  116. return Matrix3.multiplyByVector(perifocalToEquatorial, result, result);
  117. }
  118. function chooseOrbit(eccentricity, tolerance) {
  119. //>>includeStart('debug', pragmas.debug);
  120. if (eccentricity < 0) {
  121. throw new DeveloperError("eccentricity cannot be negative.");
  122. }
  123. //>>includeEnd('debug')
  124. if (eccentricity <= tolerance) {
  125. return "Circular";
  126. } else if (eccentricity < 1.0 - tolerance) {
  127. return "Elliptical";
  128. } else if (eccentricity <= 1.0 + tolerance) {
  129. return "Parabolic";
  130. }
  131. return "Hyperbolic";
  132. }
  133. // Calculates the true anomaly given the mean anomaly and the eccentricity.
  134. function meanAnomalyToTrueAnomaly(meanAnomaly, eccentricity) {
  135. //>>includeStart('debug', pragmas.debug);
  136. if (eccentricity < 0.0 || eccentricity >= 1.0) {
  137. throw new DeveloperError("eccentricity out of range.");
  138. }
  139. //>>includeEnd('debug')
  140. const eccentricAnomaly = meanAnomalyToEccentricAnomaly(
  141. meanAnomaly,
  142. eccentricity
  143. );
  144. return eccentricAnomalyToTrueAnomaly(eccentricAnomaly, eccentricity);
  145. }
  146. const maxIterationCount = 50;
  147. const keplerEqConvergence = CesiumMath.EPSILON8;
  148. // Calculates the eccentric anomaly given the mean anomaly and the eccentricity.
  149. function meanAnomalyToEccentricAnomaly(meanAnomaly, eccentricity) {
  150. //>>includeStart('debug', pragmas.debug);
  151. if (eccentricity < 0.0 || eccentricity >= 1.0) {
  152. throw new DeveloperError("eccentricity out of range.");
  153. }
  154. //>>includeEnd('debug')
  155. const revs = Math.floor(meanAnomaly / CesiumMath.TWO_PI);
  156. // Find angle in current revolution
  157. meanAnomaly -= revs * CesiumMath.TWO_PI;
  158. // calculate starting value for iteration sequence
  159. let iterationValue =
  160. meanAnomaly +
  161. (eccentricity * Math.sin(meanAnomaly)) /
  162. (1.0 - Math.sin(meanAnomaly + eccentricity) + Math.sin(meanAnomaly));
  163. // Perform Newton-Raphson iteration on Kepler's equation
  164. let eccentricAnomaly = Number.MAX_VALUE;
  165. let count;
  166. for (
  167. count = 0;
  168. count < maxIterationCount &&
  169. Math.abs(eccentricAnomaly - iterationValue) > keplerEqConvergence;
  170. ++count
  171. ) {
  172. eccentricAnomaly = iterationValue;
  173. const NRfunction =
  174. eccentricAnomaly -
  175. eccentricity * Math.sin(eccentricAnomaly) -
  176. meanAnomaly;
  177. const dNRfunction = 1 - eccentricity * Math.cos(eccentricAnomaly);
  178. iterationValue = eccentricAnomaly - NRfunction / dNRfunction;
  179. }
  180. //>>includeStart('debug', pragmas.debug);
  181. if (count >= maxIterationCount) {
  182. throw new DeveloperError("Kepler equation did not converge");
  183. // STK Components uses a numerical method to find the eccentric anomaly in the case that Kepler's
  184. // equation does not converge. We don't expect that to ever be necessary for the reasonable orbits used here.
  185. }
  186. //>>includeEnd('debug')
  187. eccentricAnomaly = iterationValue + revs * CesiumMath.TWO_PI;
  188. return eccentricAnomaly;
  189. }
  190. // Calculates the true anomaly given the eccentric anomaly and the eccentricity.
  191. function eccentricAnomalyToTrueAnomaly(eccentricAnomaly, eccentricity) {
  192. //>>includeStart('debug', pragmas.debug);
  193. if (eccentricity < 0.0 || eccentricity >= 1.0) {
  194. throw new DeveloperError("eccentricity out of range.");
  195. }
  196. //>>includeEnd('debug')
  197. // Calculate the number of previous revolutions
  198. const revs = Math.floor(eccentricAnomaly / CesiumMath.TWO_PI);
  199. // Find angle in current revolution
  200. eccentricAnomaly -= revs * CesiumMath.TWO_PI;
  201. // Calculate true anomaly from eccentric anomaly
  202. const trueAnomalyX = Math.cos(eccentricAnomaly) - eccentricity;
  203. const trueAnomalyY =
  204. Math.sin(eccentricAnomaly) * Math.sqrt(1 - eccentricity * eccentricity);
  205. let trueAnomaly = Math.atan2(trueAnomalyY, trueAnomalyX);
  206. // Ensure the correct quadrant
  207. trueAnomaly = CesiumMath.zeroToTwoPi(trueAnomaly);
  208. if (eccentricAnomaly < 0) {
  209. trueAnomaly -= CesiumMath.TWO_PI;
  210. }
  211. // Add on previous revolutions
  212. trueAnomaly += revs * CesiumMath.TWO_PI;
  213. return trueAnomaly;
  214. }
  215. // Calculates the transformation matrix to convert from the perifocal (PQW) coordinate
  216. // system to inertial cartesian coordinates.
  217. function perifocalToCartesianMatrix(
  218. argumentOfPeriapsis,
  219. inclination,
  220. rightAscension,
  221. result
  222. ) {
  223. //>>includeStart('debug', pragmas.debug);
  224. if (inclination < 0 || inclination > CesiumMath.PI) {
  225. throw new DeveloperError("inclination out of range");
  226. }
  227. //>>includeEnd('debug')
  228. const cosap = Math.cos(argumentOfPeriapsis);
  229. const sinap = Math.sin(argumentOfPeriapsis);
  230. const cosi = Math.cos(inclination);
  231. const sini = Math.sin(inclination);
  232. const cosraan = Math.cos(rightAscension);
  233. const sinraan = Math.sin(rightAscension);
  234. if (!defined(result)) {
  235. result = new Matrix3(
  236. cosraan * cosap - sinraan * sinap * cosi,
  237. -cosraan * sinap - sinraan * cosap * cosi,
  238. sinraan * sini,
  239. sinraan * cosap + cosraan * sinap * cosi,
  240. -sinraan * sinap + cosraan * cosap * cosi,
  241. -cosraan * sini,
  242. sinap * sini,
  243. cosap * sini,
  244. cosi
  245. );
  246. } else {
  247. result[0] = cosraan * cosap - sinraan * sinap * cosi;
  248. result[1] = sinraan * cosap + cosraan * sinap * cosi;
  249. result[2] = sinap * sini;
  250. result[3] = -cosraan * sinap - sinraan * cosap * cosi;
  251. result[4] = -sinraan * sinap + cosraan * cosap * cosi;
  252. result[5] = cosap * sini;
  253. result[6] = sinraan * sini;
  254. result[7] = -cosraan * sini;
  255. result[8] = cosi;
  256. }
  257. return result;
  258. }
  259. // From section 5.8
  260. const semiMajorAxis0 = 1.0000010178 * MetersPerAstronomicalUnit;
  261. const meanLongitude0 = 100.46645683 * RadiansPerDegree;
  262. const meanLongitude1 = 1295977422.83429 * RadiansPerArcSecond;
  263. // From table 6
  264. const p1u = 16002;
  265. const p2u = 21863;
  266. const p3u = 32004;
  267. const p4u = 10931;
  268. const p5u = 14529;
  269. const p6u = 16368;
  270. const p7u = 15318;
  271. const p8u = 32794;
  272. const Ca1 = 64 * 1e-7 * MetersPerAstronomicalUnit;
  273. const Ca2 = -152 * 1e-7 * MetersPerAstronomicalUnit;
  274. const Ca3 = 62 * 1e-7 * MetersPerAstronomicalUnit;
  275. const Ca4 = -8 * 1e-7 * MetersPerAstronomicalUnit;
  276. const Ca5 = 32 * 1e-7 * MetersPerAstronomicalUnit;
  277. const Ca6 = -41 * 1e-7 * MetersPerAstronomicalUnit;
  278. const Ca7 = 19 * 1e-7 * MetersPerAstronomicalUnit;
  279. const Ca8 = -11 * 1e-7 * MetersPerAstronomicalUnit;
  280. const Sa1 = -150 * 1e-7 * MetersPerAstronomicalUnit;
  281. const Sa2 = -46 * 1e-7 * MetersPerAstronomicalUnit;
  282. const Sa3 = 68 * 1e-7 * MetersPerAstronomicalUnit;
  283. const Sa4 = 54 * 1e-7 * MetersPerAstronomicalUnit;
  284. const Sa5 = 14 * 1e-7 * MetersPerAstronomicalUnit;
  285. const Sa6 = 24 * 1e-7 * MetersPerAstronomicalUnit;
  286. const Sa7 = -28 * 1e-7 * MetersPerAstronomicalUnit;
  287. const Sa8 = 22 * 1e-7 * MetersPerAstronomicalUnit;
  288. const q1u = 10;
  289. const q2u = 16002;
  290. const q3u = 21863;
  291. const q4u = 10931;
  292. const q5u = 1473;
  293. const q6u = 32004;
  294. const q7u = 4387;
  295. const q8u = 73;
  296. const Cl1 = -325 * 1e-7;
  297. const Cl2 = -322 * 1e-7;
  298. const Cl3 = -79 * 1e-7;
  299. const Cl4 = 232 * 1e-7;
  300. const Cl5 = -52 * 1e-7;
  301. const Cl6 = 97 * 1e-7;
  302. const Cl7 = 55 * 1e-7;
  303. const Cl8 = -41 * 1e-7;
  304. const Sl1 = -105 * 1e-7;
  305. const Sl2 = -137 * 1e-7;
  306. const Sl3 = 258 * 1e-7;
  307. const Sl4 = 35 * 1e-7;
  308. const Sl5 = -116 * 1e-7;
  309. const Sl6 = -88 * 1e-7;
  310. const Sl7 = -112 * 1e-7;
  311. const Sl8 = -80 * 1e-7;
  312. const scratchDate = new JulianDate(0, 0.0, TimeStandard.TAI);
  313. // Gets a point describing the motion of the Earth-Moon barycenter according to the equations described in section 6.
  314. function computeSimonEarthMoonBarycenter(date, result) {
  315. // t is thousands of years from J2000 TDB
  316. taiToTdb(date, scratchDate);
  317. const x =
  318. scratchDate.dayNumber -
  319. epoch.dayNumber +
  320. (scratchDate.secondsOfDay - epoch.secondsOfDay) /
  321. TimeConstants.SECONDS_PER_DAY;
  322. const t = x / (TimeConstants.DAYS_PER_JULIAN_CENTURY * 10.0);
  323. const u = 0.3595362 * t;
  324. const semimajorAxis =
  325. semiMajorAxis0 +
  326. Ca1 * Math.cos(p1u * u) +
  327. Sa1 * Math.sin(p1u * u) +
  328. Ca2 * Math.cos(p2u * u) +
  329. Sa2 * Math.sin(p2u * u) +
  330. Ca3 * Math.cos(p3u * u) +
  331. Sa3 * Math.sin(p3u * u) +
  332. Ca4 * Math.cos(p4u * u) +
  333. Sa4 * Math.sin(p4u * u) +
  334. Ca5 * Math.cos(p5u * u) +
  335. Sa5 * Math.sin(p5u * u) +
  336. Ca6 * Math.cos(p6u * u) +
  337. Sa6 * Math.sin(p6u * u) +
  338. Ca7 * Math.cos(p7u * u) +
  339. Sa7 * Math.sin(p7u * u) +
  340. Ca8 * Math.cos(p8u * u) +
  341. Sa8 * Math.sin(p8u * u);
  342. const meanLongitude =
  343. meanLongitude0 +
  344. meanLongitude1 * t +
  345. Cl1 * Math.cos(q1u * u) +
  346. Sl1 * Math.sin(q1u * u) +
  347. Cl2 * Math.cos(q2u * u) +
  348. Sl2 * Math.sin(q2u * u) +
  349. Cl3 * Math.cos(q3u * u) +
  350. Sl3 * Math.sin(q3u * u) +
  351. Cl4 * Math.cos(q4u * u) +
  352. Sl4 * Math.sin(q4u * u) +
  353. Cl5 * Math.cos(q5u * u) +
  354. Sl5 * Math.sin(q5u * u) +
  355. Cl6 * Math.cos(q6u * u) +
  356. Sl6 * Math.sin(q6u * u) +
  357. Cl7 * Math.cos(q7u * u) +
  358. Sl7 * Math.sin(q7u * u) +
  359. Cl8 * Math.cos(q8u * u) +
  360. Sl8 * Math.sin(q8u * u);
  361. // All constants in this part are from section 5.8
  362. const eccentricity = 0.0167086342 - 0.0004203654 * t;
  363. const longitudeOfPerigee =
  364. 102.93734808 * RadiansPerDegree + 11612.3529 * RadiansPerArcSecond * t;
  365. const inclination = 469.97289 * RadiansPerArcSecond * t;
  366. const longitudeOfNode =
  367. 174.87317577 * RadiansPerDegree - 8679.27034 * RadiansPerArcSecond * t;
  368. return elementsToCartesian(
  369. semimajorAxis,
  370. eccentricity,
  371. inclination,
  372. longitudeOfPerigee,
  373. longitudeOfNode,
  374. meanLongitude,
  375. result
  376. );
  377. }
  378. // Gets a point describing the position of the moon according to the equations described in section 4.
  379. function computeSimonMoon(date, result) {
  380. taiToTdb(date, scratchDate);
  381. const x =
  382. scratchDate.dayNumber -
  383. epoch.dayNumber +
  384. (scratchDate.secondsOfDay - epoch.secondsOfDay) /
  385. TimeConstants.SECONDS_PER_DAY;
  386. const t = x / TimeConstants.DAYS_PER_JULIAN_CENTURY;
  387. const t2 = t * t;
  388. const t3 = t2 * t;
  389. const t4 = t3 * t;
  390. // Terms from section 3.4 (b.1)
  391. let semimajorAxis = 383397.7725 + 0.004 * t;
  392. let eccentricity = 0.055545526 - 0.000000016 * t;
  393. const inclinationConstant = 5.15668983 * RadiansPerDegree;
  394. let inclinationSecPart =
  395. -0.00008 * t + 0.02966 * t2 - 0.000042 * t3 - 0.00000013 * t4;
  396. const longitudeOfPerigeeConstant = 83.35324312 * RadiansPerDegree;
  397. let longitudeOfPerigeeSecPart =
  398. 14643420.2669 * t - 38.2702 * t2 - 0.045047 * t3 + 0.00021301 * t4;
  399. const longitudeOfNodeConstant = 125.04455501 * RadiansPerDegree;
  400. let longitudeOfNodeSecPart =
  401. -6967919.3631 * t + 6.3602 * t2 + 0.007625 * t3 - 0.00003586 * t4;
  402. const meanLongitudeConstant = 218.31664563 * RadiansPerDegree;
  403. let meanLongitudeSecPart =
  404. 1732559343.4847 * t - 6.391 * t2 + 0.006588 * t3 - 0.00003169 * t4;
  405. // Delaunay arguments from section 3.5 b
  406. const D =
  407. 297.85019547 * RadiansPerDegree +
  408. RadiansPerArcSecond *
  409. (1602961601.209 * t - 6.3706 * t2 + 0.006593 * t3 - 0.00003169 * t4);
  410. const F =
  411. 93.27209062 * RadiansPerDegree +
  412. RadiansPerArcSecond *
  413. (1739527262.8478 * t - 12.7512 * t2 - 0.001037 * t3 + 0.00000417 * t4);
  414. const l =
  415. 134.96340251 * RadiansPerDegree +
  416. RadiansPerArcSecond *
  417. (1717915923.2178 * t + 31.8792 * t2 + 0.051635 * t3 - 0.0002447 * t4);
  418. const lprime =
  419. 357.52910918 * RadiansPerDegree +
  420. RadiansPerArcSecond *
  421. (129596581.0481 * t - 0.5532 * t2 + 0.000136 * t3 - 0.00001149 * t4);
  422. const psi =
  423. 310.17137918 * RadiansPerDegree -
  424. RadiansPerArcSecond *
  425. (6967051.436 * t + 6.2068 * t2 + 0.007618 * t3 - 0.00003219 * t4);
  426. // Add terms from Table 4
  427. const twoD = 2.0 * D;
  428. const fourD = 4.0 * D;
  429. const sixD = 6.0 * D;
  430. const twol = 2.0 * l;
  431. const threel = 3.0 * l;
  432. const fourl = 4.0 * l;
  433. const twoF = 2.0 * F;
  434. semimajorAxis +=
  435. 3400.4 * Math.cos(twoD) -
  436. 635.6 * Math.cos(twoD - l) -
  437. 235.6 * Math.cos(l) +
  438. 218.1 * Math.cos(twoD - lprime) +
  439. 181.0 * Math.cos(twoD + l);
  440. eccentricity +=
  441. 0.014216 * Math.cos(twoD - l) +
  442. 0.008551 * Math.cos(twoD - twol) -
  443. 0.001383 * Math.cos(l) +
  444. 0.001356 * Math.cos(twoD + l) -
  445. 0.001147 * Math.cos(fourD - threel) -
  446. 0.000914 * Math.cos(fourD - twol) +
  447. 0.000869 * Math.cos(twoD - lprime - l) -
  448. 0.000627 * Math.cos(twoD) -
  449. 0.000394 * Math.cos(fourD - fourl) +
  450. 0.000282 * Math.cos(twoD - lprime - twol) -
  451. 0.000279 * Math.cos(D - l) -
  452. 0.000236 * Math.cos(twol) +
  453. 0.000231 * Math.cos(fourD) +
  454. 0.000229 * Math.cos(sixD - fourl) -
  455. 0.000201 * Math.cos(twol - twoF);
  456. inclinationSecPart +=
  457. 486.26 * Math.cos(twoD - twoF) -
  458. 40.13 * Math.cos(twoD) +
  459. 37.51 * Math.cos(twoF) +
  460. 25.73 * Math.cos(twol - twoF) +
  461. 19.97 * Math.cos(twoD - lprime - twoF);
  462. longitudeOfPerigeeSecPart +=
  463. -55609 * Math.sin(twoD - l) -
  464. 34711 * Math.sin(twoD - twol) -
  465. 9792 * Math.sin(l) +
  466. 9385 * Math.sin(fourD - threel) +
  467. 7505 * Math.sin(fourD - twol) +
  468. 5318 * Math.sin(twoD + l) +
  469. 3484 * Math.sin(fourD - fourl) -
  470. 3417 * Math.sin(twoD - lprime - l) -
  471. 2530 * Math.sin(sixD - fourl) -
  472. 2376 * Math.sin(twoD) -
  473. 2075 * Math.sin(twoD - threel) -
  474. 1883 * Math.sin(twol) -
  475. 1736 * Math.sin(sixD - 5.0 * l) +
  476. 1626 * Math.sin(lprime) -
  477. 1370 * Math.sin(sixD - threel);
  478. longitudeOfNodeSecPart +=
  479. -5392 * Math.sin(twoD - twoF) -
  480. 540 * Math.sin(lprime) -
  481. 441 * Math.sin(twoD) +
  482. 423 * Math.sin(twoF) -
  483. 288 * Math.sin(twol - twoF);
  484. meanLongitudeSecPart +=
  485. -3332.9 * Math.sin(twoD) +
  486. 1197.4 * Math.sin(twoD - l) -
  487. 662.5 * Math.sin(lprime) +
  488. 396.3 * Math.sin(l) -
  489. 218.0 * Math.sin(twoD - lprime);
  490. // Add terms from Table 5
  491. const twoPsi = 2.0 * psi;
  492. const threePsi = 3.0 * psi;
  493. inclinationSecPart +=
  494. 46.997 * Math.cos(psi) * t -
  495. 0.614 * Math.cos(twoD - twoF + psi) * t +
  496. 0.614 * Math.cos(twoD - twoF - psi) * t -
  497. 0.0297 * Math.cos(twoPsi) * t2 -
  498. 0.0335 * Math.cos(psi) * t2 +
  499. 0.0012 * Math.cos(twoD - twoF + twoPsi) * t2 -
  500. 0.00016 * Math.cos(psi) * t3 +
  501. 0.00004 * Math.cos(threePsi) * t3 +
  502. 0.00004 * Math.cos(twoPsi) * t3;
  503. const perigeeAndMean =
  504. 2.116 * Math.sin(psi) * t -
  505. 0.111 * Math.sin(twoD - twoF - psi) * t -
  506. 0.0015 * Math.sin(psi) * t2;
  507. longitudeOfPerigeeSecPart += perigeeAndMean;
  508. meanLongitudeSecPart += perigeeAndMean;
  509. longitudeOfNodeSecPart +=
  510. -520.77 * Math.sin(psi) * t +
  511. 13.66 * Math.sin(twoD - twoF + psi) * t +
  512. 1.12 * Math.sin(twoD - psi) * t -
  513. 1.06 * Math.sin(twoF - psi) * t +
  514. 0.66 * Math.sin(twoPsi) * t2 +
  515. 0.371 * Math.sin(psi) * t2 -
  516. 0.035 * Math.sin(twoD - twoF + twoPsi) * t2 -
  517. 0.015 * Math.sin(twoD - twoF + psi) * t2 +
  518. 0.0014 * Math.sin(psi) * t3 -
  519. 0.0011 * Math.sin(threePsi) * t3 -
  520. 0.0009 * Math.sin(twoPsi) * t3;
  521. // Add constants and convert units
  522. semimajorAxis *= MetersPerKilometer;
  523. const inclination =
  524. inclinationConstant + inclinationSecPart * RadiansPerArcSecond;
  525. const longitudeOfPerigee =
  526. longitudeOfPerigeeConstant +
  527. longitudeOfPerigeeSecPart * RadiansPerArcSecond;
  528. const meanLongitude =
  529. meanLongitudeConstant + meanLongitudeSecPart * RadiansPerArcSecond;
  530. const longitudeOfNode =
  531. longitudeOfNodeConstant + longitudeOfNodeSecPart * RadiansPerArcSecond;
  532. return elementsToCartesian(
  533. semimajorAxis,
  534. eccentricity,
  535. inclination,
  536. longitudeOfPerigee,
  537. longitudeOfNode,
  538. meanLongitude,
  539. result
  540. );
  541. }
  542. // Gets a point describing the motion of the Earth. This point uses the Moon point and
  543. // the 1992 mu value (ratio between Moon and Earth masses) in Table 2 of the paper in order
  544. // to determine the position of the Earth relative to the Earth-Moon barycenter.
  545. const moonEarthMassRatio = 0.012300034; // From 1992 mu value in Table 2
  546. const factor = (moonEarthMassRatio / (moonEarthMassRatio + 1.0)) * -1;
  547. function computeSimonEarth(date, result) {
  548. result = computeSimonMoon(date, result);
  549. return Cartesian3.multiplyByScalar(result, factor, result);
  550. }
  551. // Values for the <code>axesTransformation</code> needed for the rotation were found using the STK Components
  552. // GreographicTransformer on the position of the sun center of mass point and the earth J2000 frame.
  553. const axesTransformation = new Matrix3(
  554. 1.0000000000000002,
  555. 5.619723173785822e-16,
  556. 4.690511510146299e-19,
  557. -5.154129427414611e-16,
  558. 0.9174820620691819,
  559. -0.39777715593191376,
  560. -2.23970096136568e-16,
  561. 0.39777715593191376,
  562. 0.9174820620691819
  563. );
  564. let translation = new Cartesian3();
  565. /**
  566. * Computes the position of the Sun in the Earth-centered inertial frame
  567. *
  568. * @param {JulianDate} [julianDate] The time at which to compute the Sun's position, if not provided the current system time is used.
  569. * @param {Cartesian3} [result] The object onto which to store the result.
  570. * @returns {Cartesian3} Calculated sun position
  571. */
  572. Simon1994PlanetaryPositions.computeSunPositionInEarthInertialFrame = function (
  573. julianDate,
  574. result
  575. ) {
  576. if (!defined(julianDate)) {
  577. julianDate = JulianDate.now();
  578. }
  579. if (!defined(result)) {
  580. result = new Cartesian3();
  581. }
  582. //first forward transformation
  583. translation = computeSimonEarthMoonBarycenter(julianDate, translation);
  584. result = Cartesian3.negate(translation, result);
  585. //second forward transformation
  586. computeSimonEarth(julianDate, translation);
  587. Cartesian3.subtract(result, translation, result);
  588. Matrix3.multiplyByVector(axesTransformation, result, result);
  589. return result;
  590. };
  591. /**
  592. * Computes the position of the Moon in the Earth-centered inertial frame
  593. *
  594. * @param {JulianDate} [julianDate] The time at which to compute the Sun's position, if not provided the current system time is used.
  595. * @param {Cartesian3} [result] The object onto which to store the result.
  596. * @returns {Cartesian3} Calculated moon position
  597. */
  598. Simon1994PlanetaryPositions.computeMoonPositionInEarthInertialFrame = function (
  599. julianDate,
  600. result
  601. ) {
  602. if (!defined(julianDate)) {
  603. julianDate = JulianDate.now();
  604. }
  605. result = computeSimonMoon(julianDate, result);
  606. Matrix3.multiplyByVector(axesTransformation, result, result);
  607. return result;
  608. };
  609. export default Simon1994PlanetaryPositions;