#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_ #define FRAMEWORK_COORDINATES_JGM3MODEL_H_ #include #include "CoordinateTransformations.h" #include "../globalfunctions/math/VectorOperations.h" #include "../globalfunctions/timevalOperations.h" #include "../globalfunctions/constants.h" #include 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_ */