From f579853ad50670ef5bff2006fcb5b54fa253aee0 Mon Sep 17 00:00:00 2001 From: Abhishek Agrawal Date: Wed, 13 Apr 2016 14:30:36 +0200 Subject: [PATCH 1/3] Create new header file for computing change in orbital elements due to J2 perturbation. --- include/Astro/astro.hpp | 2 ++ include/Astro/j2Gravity.hpp | 71 +++++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+) create mode 100644 include/Astro/j2Gravity.hpp diff --git a/include/Astro/astro.hpp b/include/Astro/astro.hpp index e1ce7df..fee3565 100644 --- a/include/Astro/astro.hpp +++ b/include/Astro/astro.hpp @@ -8,8 +8,10 @@ #define ASTRO_HPP #include "Astro/constants.hpp" +#include "Astro/j2Gravity.hpp" #include "Astro/orbitalElementConversions.hpp" #include "Astro/twoBodyMethods.hpp" #include "Astro/solarRadiationPressureAccelerationModel.hpp" +#include "Astro/stateVectorIndices.hpp" #endif // ASTRO_HPP diff --git a/include/Astro/j2Gravity.hpp b/include/Astro/j2Gravity.hpp new file mode 100644 index 0000000..c0a794c --- /dev/null +++ b/include/Astro/j2Gravity.hpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2014-2016 Kartik Kumar, Dinamica Srl (me@kartikkumar.com) + * Copyright (c) 2014-2016 Abhishek Agrawal, Delft University of Technology + * (abhishek.agrawal@protonmail.com) + * Distributed under the MIT License. + * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT + */ + +#ifndef J2_GRAVITY_HPP +#define J2_GRAVITY_HPP + +#include + +#include + +namespace astro +{ + +//! Compute orbit-averaged rate of change in the orbital elements due to J2 perturbation. +/*! + * Computes the first order, orbit-averaged rate of change in longitude of ascending node and + * argument of periapsis due to the J2 perturbation. + * + * @tparam Real Real type + * @tparam Vector6 Vector of 6 elements + * + * @param[in] keplerianElements Vector containing Keplerian elements + * N.B.: Order of elements and units is important! + * keplerianElements( 0 ) = semiMajorAxis [km]
+ * keplerianElements( 1 ) = eccentricity [-]
+ * keplerianElements( 2 ) = inclination [rad]
+ * keplerianElements( 3 ) = argument of periapsis [rad]
+ * keplerianElements( 4 ) = longitude of ascending node [rad]
+ * keplerianElements( 5 ) = true anomaly [rad] + * @param[in] meanMotion meanMotion of the orbiting object [deg/day] + * @param[in] earthMeanRadius Earth mean radius [km] + * + * @param[out] longitudeAscendingNodeDot Stores rate of change in longitude of ascending node + * due to J2 perturbation [deg/day] + * @param[out] argumentOfPeriapsisDot Stores rate of change in argument of periapsis + * due to J2 perturbation [deg/day] + */ + template< typename Real, typename Vector6 > + void computeFirstOrderAveragedEffectJ2Perturbation( + const Vector6& keplerianElements, + const Real meanMotion, + const Real earthMeanRadius, + const Real& longitudeAscendingNodeDot, + const Real& argumentOfPeriapsisDot ) + { + const Real J2 = 0.00108263; + const Real semiMajorAxis = keplerianElements[ astro::semiMajorAxisIndiex ]; + const Real inclination = keplerianElements[ astro::inclinationIndiex ]; + const Real eccentricity = keplerianElements[ astro::eccentricityIndiex ]; + + longitudeAscendingNodeDot + = -1.5 * meanMotion * J2 + * ( earthMeanRadius / semiMajorAxis ) * ( earthMeanRadius / semiMajorAxis ) + * std::cos( inclination ) + / ( ( 1 - eccentricity * eccentricity ) * ( 1 - eccentricity * eccentricity ) ); + + argumentOfPeriapsisDot + = 0.75 * meanMotion * J2 + * ( earthMeanRadius / semiMajorAxis ) * ( earthMeanRadius / semiMajorAxis ) + * ( 4 - 5 * std::sin( inclination ) * std::sin( inclination ) ) + / ( ( 1 - eccentricity * eccentricity ) * ( 1 - eccentricity * eccentricity ) ); + } + +} // namespace_astro + +#endif // J2_GRAVITY_HPP From 771494f5c9026196a865197e4704a2fc0242ce54 Mon Sep 17 00:00:00 2001 From: Abhishek Agrawal Date: Wed, 13 Apr 2016 15:23:48 +0200 Subject: [PATCH 2/3] Add new test file for j2Gravity.hpp --- include/Astro/j2Gravity.hpp | 6 +- test/testJ2Gravity.cpp | 156 ++++++++++++++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 test/testJ2Gravity.cpp diff --git a/include/Astro/j2Gravity.hpp b/include/Astro/j2Gravity.hpp index c0a794c..3f608a9 100644 --- a/include/Astro/j2Gravity.hpp +++ b/include/Astro/j2Gravity.hpp @@ -49,9 +49,9 @@ namespace astro const Real& argumentOfPeriapsisDot ) { const Real J2 = 0.00108263; - const Real semiMajorAxis = keplerianElements[ astro::semiMajorAxisIndiex ]; - const Real inclination = keplerianElements[ astro::inclinationIndiex ]; - const Real eccentricity = keplerianElements[ astro::eccentricityIndiex ]; + const Real semiMajorAxis = keplerianElements[ astro::semiMajorAxisIndex ]; + const Real inclination = keplerianElements[ astro::inclinationIndex ]; + const Real eccentricity = keplerianElements[ astro::eccentricityIndex ]; longitudeAscendingNodeDot = -1.5 * meanMotion * J2 diff --git a/test/testJ2Gravity.cpp b/test/testJ2Gravity.cpp new file mode 100644 index 0000000..52c7773 --- /dev/null +++ b/test/testJ2Gravity.cpp @@ -0,0 +1,156 @@ +/* + * Copyright (c) 2014-2016 Kartik Kumar, Dinamica Srl (me@kartikkumar.com) + * Copyright (c) 2014-2016 Abhishek Agrawal, Delft University of Technology + * (abhishek.agrawal@protonmail.com) + * Distributed under the MIT License. + * See accompanying file LICENSE.md or copy at http://opensource.org/licenses/MIT + */ + +#include +#include + +#include + +#include "Astro/j2Gravity.hpp" +#include "Astro/twoBodyMethods.hpp" + +namespace astro +{ +namespace tests +{ + +typedef double Real; +typedef std::vector< Real > Vector; + +TEST_CASE( "First order, orbit-averaged Keplerian element rate of change due to J2 perturbation", + "[first-order-orbit-averaged-j2]" ) +{ + const Real pi = 3.14159265358979323846; + // Earth's mean radius in [km]. + const Real earthMeanRadius = 6371.003; + // Earth's gravitational parameter [km^3 s^-2]. + const Real earthGravitationalParameter = 398600.4418; + + SECTION( "Test for Sun-Synchronous orbit" ) + { + const Vector keplerianElements( 6 ); + keplerianElements[ 0 ] = 6728.0; + keplerianElements[ 1 ] = 0.0; + keplerianElements[ 2 ] = 96.85 * pi / 180.0 ; + keplerianElements[ 3 ] = 0.0; + keplerianElements[ 4 ] = 0.0; + keplerianElements[ 5 ] = 0.0; + + // Mean motion or orbiting object in radians per second. + const Real semiMajorAxis = keplerianElements[ 0 ]; + const Real massOrbitingBody = 0.0; + const Real meanMotion = astro::computeKeplerMeanMotion( semiMajorAxis, + earthGravitationalParameter, + massOrbitingBody ); + // Mean motion in degrees per day. + const Real meanMotionDegreesPerDay = ( meanMotion * 86400.0 ) * ( 180.0 / pi ); + + const Real longitudeAscendingNodeDot = 0.0; + const Real argumentOfPeriapsisDot = 0.0; + + const Real expectedLongitudeAscendingNodeDot = 0.986; + const Real expectedArgumentOfPeriapsisDot = -4.890; + + computeFirstOrderAveragedEffectJ2Perturbation( + keplerianElements, + meanMotionDegreesPerDay, + earthMeanRadius, + longitudeAscendingNodeDot, + argumentOfPeriapsisDot ); + + REQUIRE( expectedLongitudeAscendingNodeDot + == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-10 ) ); + REQUIRE( expectedArgumentOfPeriapsisDot + == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-10 ) ); + } + + SECTION( "Test for Molniya orbit" ) + { + const Vector keplerianElements( 6 ); + keplerianElements[ 0 ] = 26600.0; + keplerianElements[ 1 ] = 0.75; + keplerianElements[ 2 ] = 63.4 * pi / 180.0 ; + keplerianElements[ 3 ] = 0.0; + keplerianElements[ 4 ] = 0.0; + keplerianElements[ 5 ] = 0.0; + + // Mean motion or orbiting object in radians per second. + const Real semiMajorAxis = keplerianElements[ 0 ]; + const Real massOrbitingBody = 0.0; + const Real meanMotion = astro::computeKeplerMeanMotion( semiMajorAxis, + earthGravitationalParameter, + massOrbitingBody ); + // Mean motion in degrees per day. + const Real meanMotionDegreesPerDay = ( meanMotion * 86400.0 ) * ( 180.0 / pi ); + + const Real longitudeAscendingNodeDot = 0.0; + const Real argumentOfPeriapsisDot = 0.0; + + const Real expectedLongitudeAscendingNodeDot = -0.30; + const Real expectedArgumentOfPeriapsisDot = 0.0; + + computeFirstOrderAveragedEffectJ2Perturbation( + keplerianElements, + meanMotionDegreesPerDay, + earthMeanRadius, + longitudeAscendingNodeDot, + argumentOfPeriapsisDot ); + + REQUIRE( expectedLongitudeAscendingNodeDot + == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-10 ) ); + REQUIRE( expectedArgumentOfPeriapsisDot + == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-10 ) ); + } + + SECTION( "Test for Geo-Stationary orbit" ) + { + const Vector keplerianElements( 6 ); + keplerianElements[ 0 ] = 42160.0; + keplerianElements[ 1 ] = 0.0; + keplerianElements[ 2 ] = 0.0; + keplerianElements[ 3 ] = 0.0; + keplerianElements[ 4 ] = 0.0; + keplerianElements[ 5 ] = 0.0; + + // Mean motion or orbiting object in radians per second. + const Real semiMajorAxis = keplerianElements[ 0 ]; + const Real massOrbitingBody = 0.0; + const Real meanMotion = astro::computeKeplerMeanMotion( semiMajorAxis, + earthGravitationalParameter, + massOrbitingBody ); + // Mean motion in degrees per day. + const Real meanMotionDegreesPerDay = ( meanMotion * 86400.0 ) * ( 180.0 / pi ); + + const Real longitudeAscendingNodeDot = 0.0; + const Real argumentOfPeriapsisDot = 0.0; + + const Real expectedLongitudeAscendingNodeDot = -0.013; + const Real expectedArgumentOfPeriapsisDot = 0.025; + + computeFirstOrderAveragedEffectJ2Perturbation( + keplerianElements, + meanMotionDegreesPerDay, + earthMeanRadius, + longitudeAscendingNodeDot, + argumentOfPeriapsisDot ); + + REQUIRE( expectedLongitudeAscendingNodeDot + == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-10 ) ); + REQUIRE( expectedArgumentOfPeriapsisDot + == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-10 ) ); + } +} + +} // namespace tests +} // namespace astro + +/*! + * References + * Wertz, J.R., et al. Space mission analysis and design, Third Edition, + * ISBN 1-881883-10-8, Space Technology Library. + */ From 3136a68ef9f0081cfd8d95319f9c1023da7e3354 Mon Sep 17 00:00:00 2001 From: Abhishek Agrawal Date: Wed, 13 Apr 2016 16:07:36 +0200 Subject: [PATCH 3/3] Modify tolerances for tests in testJ2Gravity.cpp --- ProjectFiles.cmake | 3 +- include/Astro/j2Gravity.hpp | 12 +++---- test/testJ2Gravity.cpp | 66 ++++++++++++++++++------------------- 3 files changed, 41 insertions(+), 40 deletions(-) diff --git a/ProjectFiles.cmake b/ProjectFiles.cmake index ce50e5d..ed6874a 100644 --- a/ProjectFiles.cmake +++ b/ProjectFiles.cmake @@ -6,8 +6,9 @@ set(TEST_SRC "${TEST_SRC_PATH}/testAstro.cpp" "${TEST_SRC_PATH}/testConstants.cpp" + "${TEST_SRC_PATH}/testJ2Gravity.cpp" "${TEST_SRC_PATH}/testOrbitalElementConversions.cpp" "${TEST_SRC_PATH}/testStateVectorIndices.cpp" "${TEST_SRC_PATH}/testSolarRadiationPressureAccelerationModel.cpp" "${TEST_SRC_PATH}/testTwoBodyMethods.cpp" -) \ No newline at end of file +) diff --git a/include/Astro/j2Gravity.hpp b/include/Astro/j2Gravity.hpp index 3f608a9..45aa5f5 100644 --- a/include/Astro/j2Gravity.hpp +++ b/include/Astro/j2Gravity.hpp @@ -33,7 +33,7 @@ namespace astro * keplerianElements( 4 ) = longitude of ascending node [rad]
* keplerianElements( 5 ) = true anomaly [rad] * @param[in] meanMotion meanMotion of the orbiting object [deg/day] - * @param[in] earthMeanRadius Earth mean radius [km] + * @param[in] earthEquatorialRadius Earth equatorial radius [km] * * @param[out] longitudeAscendingNodeDot Stores rate of change in longitude of ascending node * due to J2 perturbation [deg/day] @@ -44,9 +44,9 @@ namespace astro void computeFirstOrderAveragedEffectJ2Perturbation( const Vector6& keplerianElements, const Real meanMotion, - const Real earthMeanRadius, - const Real& longitudeAscendingNodeDot, - const Real& argumentOfPeriapsisDot ) + const Real earthEquatorialRadius, + Real& longitudeAscendingNodeDot, + Real& argumentOfPeriapsisDot ) { const Real J2 = 0.00108263; const Real semiMajorAxis = keplerianElements[ astro::semiMajorAxisIndex ]; @@ -55,13 +55,13 @@ namespace astro longitudeAscendingNodeDot = -1.5 * meanMotion * J2 - * ( earthMeanRadius / semiMajorAxis ) * ( earthMeanRadius / semiMajorAxis ) + * ( earthEquatorialRadius / semiMajorAxis ) * ( earthEquatorialRadius / semiMajorAxis ) * std::cos( inclination ) / ( ( 1 - eccentricity * eccentricity ) * ( 1 - eccentricity * eccentricity ) ); argumentOfPeriapsisDot = 0.75 * meanMotion * J2 - * ( earthMeanRadius / semiMajorAxis ) * ( earthMeanRadius / semiMajorAxis ) + * ( earthEquatorialRadius / semiMajorAxis ) * ( earthEquatorialRadius / semiMajorAxis ) * ( 4 - 5 * std::sin( inclination ) * std::sin( inclination ) ) / ( ( 1 - eccentricity * eccentricity ) * ( 1 - eccentricity * eccentricity ) ); } diff --git a/test/testJ2Gravity.cpp b/test/testJ2Gravity.cpp index 52c7773..b436dea 100644 --- a/test/testJ2Gravity.cpp +++ b/test/testJ2Gravity.cpp @@ -23,20 +23,20 @@ typedef double Real; typedef std::vector< Real > Vector; TEST_CASE( "First order, orbit-averaged Keplerian element rate of change due to J2 perturbation", - "[first-order-orbit-averaged-j2]" ) + "[first-order-orbit-averaged-j2]" ) { const Real pi = 3.14159265358979323846; - // Earth's mean radius in [km]. - const Real earthMeanRadius = 6371.003; + // Earth's equatorial radius in [km]. + const Real earthEquatorialRadius = 6378.13649; // Earth's gravitational parameter [km^3 s^-2]. const Real earthGravitationalParameter = 398600.4418; - SECTION( "Test for Sun-Synchronous orbit" ) + SECTION( "Test for Shuttle (LEO) orbit" ) { - const Vector keplerianElements( 6 ); - keplerianElements[ 0 ] = 6728.0; + Vector keplerianElements( 6 ); + keplerianElements[ 0 ] = 6700.0; keplerianElements[ 1 ] = 0.0; - keplerianElements[ 2 ] = 96.85 * pi / 180.0 ; + keplerianElements[ 2 ] = 28.0 * pi / 180.0 ; keplerianElements[ 3 ] = 0.0; keplerianElements[ 4 ] = 0.0; keplerianElements[ 5 ] = 0.0; @@ -50,31 +50,31 @@ TEST_CASE( "First order, orbit-averaged Keplerian element rate of change due to // Mean motion in degrees per day. const Real meanMotionDegreesPerDay = ( meanMotion * 86400.0 ) * ( 180.0 / pi ); - const Real longitudeAscendingNodeDot = 0.0; - const Real argumentOfPeriapsisDot = 0.0; + Real longitudeAscendingNodeDot = 0.0; + Real argumentOfPeriapsisDot = 0.0; - const Real expectedLongitudeAscendingNodeDot = 0.986; - const Real expectedArgumentOfPeriapsisDot = -4.890; + const Real expectedLongitudeAscendingNodeDot = -7.35; + const Real expectedArgumentOfPeriapsisDot = 12.05; computeFirstOrderAveragedEffectJ2Perturbation( keplerianElements, meanMotionDegreesPerDay, - earthMeanRadius, + earthEquatorialRadius, longitudeAscendingNodeDot, argumentOfPeriapsisDot ); REQUIRE( expectedLongitudeAscendingNodeDot - == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-10 ) ); + == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-2 ) ); REQUIRE( expectedArgumentOfPeriapsisDot - == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-10 ) ); + == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-2 ) ); } - SECTION( "Test for Molniya orbit" ) + SECTION( "Test for GPS (HEO) orbit" ) { - const Vector keplerianElements( 6 ); + Vector keplerianElements( 6 ); keplerianElements[ 0 ] = 26600.0; - keplerianElements[ 1 ] = 0.75; - keplerianElements[ 2 ] = 63.4 * pi / 180.0 ; + keplerianElements[ 1 ] = 0.0; + keplerianElements[ 2 ] = 60.0 * pi / 180.0 ; keplerianElements[ 3 ] = 0.0; keplerianElements[ 4 ] = 0.0; keplerianElements[ 5 ] = 0.0; @@ -88,28 +88,28 @@ TEST_CASE( "First order, orbit-averaged Keplerian element rate of change due to // Mean motion in degrees per day. const Real meanMotionDegreesPerDay = ( meanMotion * 86400.0 ) * ( 180.0 / pi ); - const Real longitudeAscendingNodeDot = 0.0; - const Real argumentOfPeriapsisDot = 0.0; + Real longitudeAscendingNodeDot = 0.0; + Real argumentOfPeriapsisDot = 0.0; - const Real expectedLongitudeAscendingNodeDot = -0.30; - const Real expectedArgumentOfPeriapsisDot = 0.0; + const Real expectedLongitudeAscendingNodeDot = -0.033; + const Real expectedArgumentOfPeriapsisDot = 0.008; computeFirstOrderAveragedEffectJ2Perturbation( keplerianElements, meanMotionDegreesPerDay, - earthMeanRadius, + earthEquatorialRadius, longitudeAscendingNodeDot, argumentOfPeriapsisDot ); REQUIRE( expectedLongitudeAscendingNodeDot - == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-10 ) ); + == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-3 ) ); REQUIRE( expectedArgumentOfPeriapsisDot - == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-10 ) ); + == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-3 ) ); } - SECTION( "Test for Geo-Stationary orbit" ) + SECTION( "Test for Geo-Stationary (GEO) orbit" ) { - const Vector keplerianElements( 6 ); + Vector keplerianElements( 6 ); keplerianElements[ 0 ] = 42160.0; keplerianElements[ 1 ] = 0.0; keplerianElements[ 2 ] = 0.0; @@ -126,23 +126,23 @@ TEST_CASE( "First order, orbit-averaged Keplerian element rate of change due to // Mean motion in degrees per day. const Real meanMotionDegreesPerDay = ( meanMotion * 86400.0 ) * ( 180.0 / pi ); - const Real longitudeAscendingNodeDot = 0.0; - const Real argumentOfPeriapsisDot = 0.0; + Real longitudeAscendingNodeDot = 0.0; + Real argumentOfPeriapsisDot = 0.0; const Real expectedLongitudeAscendingNodeDot = -0.013; - const Real expectedArgumentOfPeriapsisDot = 0.025; + const Real expectedArgumentOfPeriapsisDot = 0.026; computeFirstOrderAveragedEffectJ2Perturbation( keplerianElements, meanMotionDegreesPerDay, - earthMeanRadius, + earthEquatorialRadius, longitudeAscendingNodeDot, argumentOfPeriapsisDot ); REQUIRE( expectedLongitudeAscendingNodeDot - == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-10 ) ); + == Approx( longitudeAscendingNodeDot ).epsilon( 1.0e-3 ) ); REQUIRE( expectedArgumentOfPeriapsisDot - == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-10 ) ); + == Approx( argumentOfPeriapsisDot ).epsilon( 1.0e-3 ) ); } }