#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_ #define FRAMEWORK_COORDINATES_JGM3MODEL_H_ #include #include #include "CoordinateTransformations.h" #include "coordinatesConf.h" #include "fsfw/globalfunctions/constants.h" #include "fsfw/globalfunctions/math/VectorOperations.h" #include "fsfw/globalfunctions/timevalOperations.h" template class Jgm3Model { public: static const uint32_t factorialLookupTable[DEGREE + 3]; // This table is used instead of factorial calculation, // must be increased if order or degree is higher Jgm3Model() { y0[0] = 0; y0[1] = 0; y0[2] = 0; y0[3] = 0; y0[4] = 0; y0[5] = 0; lastExecutionTime.tv_sec = 0; lastExecutionTime.tv_usec = 0; } virtual ~Jgm3Model(){}; // double acsNavOrbit(double posECF[3],double velECF[3],timeval gpsTime); double y0[6]; // position and velocity at beginning of RK step in EC timeval lastExecutionTime; // Time of last execution void accelDegOrd(const double pos[3], const double S[ORDER + 1][DEGREE + 1], const double C[ORDER + 1][DEGREE + 1], double* accel) { // Get radius of this position double r = VectorOperations::norm(pos, 3); // Initialize the V and W matrix double V[DEGREE + 2][ORDER + 2] = {{0}}; double W[DEGREE + 2][ORDER + 2] = {{0}}; for (uint8_t m = 0; m < (ORDER + 2); m++) { for (uint8_t n = m; n < (DEGREE + 2); n++) { if ((n == 0) && (m == 0)) { // Montenbruck "Satellite Orbits Eq.3.31" V[0][0] = Earth::MEAN_RADIUS / r; W[0][0] = 0; } else { if (n == m) { // Montenbruck "Satellite Orbits Eq.3.29" V[m][m] = (2 * m - 1) * (pos[0] * Earth::MEAN_RADIUS / pow(r, 2) * V[m - 1][m - 1] - pos[1] * Earth::MEAN_RADIUS / pow(r, 2) * W[m - 1][m - 1]); W[m][m] = (2 * m - 1) * (pos[0] * Earth::MEAN_RADIUS / pow(r, 2) * W[m - 1][m - 1] + pos[1] * Earth::MEAN_RADIUS / pow(r, 2) * V[m - 1][m - 1]); } else { // Montenbruck "Satellite Orbits Eq.3.30" V[n][m] = ((2 * n - 1) / (double)(n - m)) * pos[2] * Earth::MEAN_RADIUS / pow(r, 2) * V[n - 1][m]; W[n][m] = ((2 * n - 1) / (double)(n - m)) * pos[2] * Earth::MEAN_RADIUS / pow(r, 2) * W[n - 1][m]; if (n != (m + 1)) { V[n][m] = V[n][m] - (((n + m - 1) / (double)(n - m)) * (pow(Earth::MEAN_RADIUS, 2) / pow(r, 2)) * V[n - 2][m]); W[n][m] = W[n][m] - (((n + m - 1) / (double)(n - m)) * (pow(Earth::MEAN_RADIUS, 2) / pow(r, 2)) * W[n - 2][m]); } // End of if(n!=(m+1)) } // End of if(n==m){ } // End of if(n==0 and m==0) } // End of for(uint8_t n=0;n<(DEGREE+1);n++) } // End of for(uint8_t m=0;m<(ORDER+1);m++) // overwrite accel if not properly initialized accel[0] = 0; accel[1] = 0; accel[2] = 0; for (uint8_t m = 0; m < (ORDER + 1); m++) { for (uint8_t n = m; n < (DEGREE + 1); n++) { // Use table lookup to get factorial double partAccel[3] = {0}; double factor = Earth::STANDARD_GRAVITATIONAL_PARAMETER / pow(Earth::MEAN_RADIUS, 2); if (m == 0) { // Montenbruck "Satellite Orbits Eq.3.33" partAccel[0] = factor * (-C[n][0] * V[n + 1][1]); partAccel[1] = factor * (-C[n][0] * W[n + 1][1]); } else { double factMN = static_cast(factorialLookupTable[n - m + 2]) / static_cast(factorialLookupTable[n - m]); partAccel[0] = factor * 0.5 * ((-C[n][m] * V[n + 1][m + 1] - S[n][m] * W[n + 1][m + 1]) + factMN * (C[n][m] * V[n + 1][m - 1] + S[n][m] * W[n + 1][m - 1])); partAccel[1] = factor * 0.5 * ((-C[n][m] * W[n + 1][m + 1] + S[n][m] * V[n + 1][m + 1]) + factMN * (-C[n][m] * W[n + 1][m - 1] + S[n][m] * V[n + 1][m - 1])); } partAccel[2] = factor * ((n - m + 1) * (-C[n][m] * V[n + 1][m] - S[n][m] * W[n + 1][m])); accel[0] += partAccel[0]; accel[1] += partAccel[1]; accel[2] += partAccel[2]; } // End of for(uint8_t n=0;n::mulScalar(y0dot, deltaT / 2, yA, 6); VectorOperations::add(y0, yA, yA, 6); rungeKuttaStep(yA, yAdot, lastExecutionTime, S, C); // Step Three VectorOperations::mulScalar(yAdot, deltaT / 2, yB, 6); VectorOperations::add(y0, yB, yB, 6); rungeKuttaStep(yB, yBdot, lastExecutionTime, S, C); // Step Four VectorOperations::mulScalar(yBdot, deltaT, yC, 6); VectorOperations::add(y0, yC, yC, 6); rungeKuttaStep(yC, yCdot, lastExecutionTime, S, C); // Calc new State VectorOperations::mulScalar(yAdot, 2, yAdot, 6); VectorOperations::mulScalar(yBdot, 2, yBdot, 6); VectorOperations::add(y0dot, yAdot, y0dot, 6); VectorOperations::add(y0dot, yBdot, y0dot, 6); VectorOperations::add(y0dot, yCdot, y0dot, 6); VectorOperations::mulScalar(y0dot, 1. / 6. * deltaT, y0dot, 6); VectorOperations::add(y0, y0dot, y0, 6); CoordinateTransformations::positionEciToEcf(&y0[0], outputPos, &timeUTC); CoordinateTransformations::velocityEciToEcf(&y0[3], &y0[0], outputVel, &timeUTC); lastExecutionTime = timeUTC; } void rungeKuttaStep(const double* yIn, double* yOut, timeval time, const double S[ORDER + 1][DEGREE + 1], const double C[ORDER + 1][DEGREE + 1]) { double rECF[3] = {0, 0, 0}; double rDotECF[3] = {0, 0, 0}; double accelECF[3] = {0, 0, 0}; double accelECI[3] = {0, 0, 0}; CoordinateTransformations::positionEciToEcf(&yIn[0], rECF, &time); CoordinateTransformations::velocityEciToEcf(&yIn[3], &yIn[0], rDotECF, &time); accelDegOrd(rECF, S, C, accelECF); // This is not correct, as the acceleration would have derived terms but we don't know the // velocity and position at that time Tests showed that a wrong velocity does make the equation // worse than neglecting it CoordinateTransformations::positionEcfToEci(accelECF, accelECI, &time); memcpy(&yOut[0], &yIn[3], sizeof(yOut[0]) * 3); memcpy(&yOut[3], accelECI, sizeof(yOut[0]) * 3); } }; #endif /* FRAMEWORK_COORDINATES_JGM3MODEL_H_ */