181 lines
6.2 KiB
C
181 lines
6.2 KiB
C
|
#ifndef FRAMEWORK_COORDINATES_JGM3MODEL_H_
|
||
|
#define FRAMEWORK_COORDINATES_JGM3MODEL_H_
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include "CoordinateTransformations.h"
|
||
|
#include "../globalfunctions/math/VectorOperations.h"
|
||
|
#include "../globalfunctions/timevalOperations.h"
|
||
|
#include "../globalfunctions/constants.h"
|
||
|
#include <memory.h>
|
||
|
|
||
|
|
||
|
template<uint8_t DEGREE,uint8_t ORDER>
|
||
|
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<double>::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<double>(factorialLookupTable[n-m+2]) / static_cast<double>(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<DEGREE;n++)
|
||
|
}//End of uint8_t m=0;m<ORDER;m++
|
||
|
}
|
||
|
|
||
|
void initializeNavOrbit(const double position[3],const double velocity[3], timeval timeUTC){
|
||
|
CoordinateTransformations::positionEcfToEci(position,&y0[0],&timeUTC);
|
||
|
CoordinateTransformations::velocityEcfToEci(velocity,position,&y0[3],&timeUTC);
|
||
|
lastExecutionTime = timeUTC;
|
||
|
}
|
||
|
|
||
|
|
||
|
void acsNavOrbit(timeval timeUTC, const double S[ORDER+1][DEGREE+1],const double C[ORDER+1][DEGREE+1], double outputPos[3],double outputVel[3]){
|
||
|
|
||
|
//RK4 Integration for this timestamp
|
||
|
double deltaT = timevalOperations::toDouble(timeUTC-lastExecutionTime);
|
||
|
|
||
|
double y0dot[6] = {0,0,0,0,0,0};
|
||
|
double yA[6] = {0,0,0,0,0,0};
|
||
|
double yAdot[6] = {0,0,0,0,0,0};
|
||
|
double yB[6] = {0,0,0,0,0,0};
|
||
|
double yBdot[6] = {0,0,0,0,0,0};
|
||
|
double yC[6] = {0,0,0,0,0,0};
|
||
|
double yCdot[6] = {0,0,0,0,0,0};
|
||
|
|
||
|
//Step One
|
||
|
rungeKuttaStep(y0,y0dot,lastExecutionTime,S,C);
|
||
|
|
||
|
//Step Two
|
||
|
VectorOperations<double>::mulScalar(y0dot,deltaT/2,yA,6);
|
||
|
VectorOperations<double>::add(y0,yA,yA,6);
|
||
|
rungeKuttaStep(yA,yAdot,lastExecutionTime,S,C);
|
||
|
|
||
|
//Step Three
|
||
|
VectorOperations<double>::mulScalar(yAdot,deltaT/2,yB,6);
|
||
|
VectorOperations<double>::add(y0,yB,yB,6);
|
||
|
rungeKuttaStep(yB,yBdot,lastExecutionTime,S,C);
|
||
|
|
||
|
//Step Four
|
||
|
VectorOperations<double>::mulScalar(yBdot,deltaT,yC,6);
|
||
|
VectorOperations<double>::add(y0,yC,yC,6);
|
||
|
rungeKuttaStep(yC,yCdot,lastExecutionTime,S,C);
|
||
|
|
||
|
//Calc new State
|
||
|
VectorOperations<double>::mulScalar(yAdot,2,yAdot,6);
|
||
|
VectorOperations<double>::mulScalar(yBdot,2,yBdot,6);
|
||
|
VectorOperations<double>::add(y0dot,yAdot,y0dot,6);
|
||
|
VectorOperations<double>::add(y0dot,yBdot,y0dot,6);
|
||
|
VectorOperations<double>::add(y0dot,yCdot,y0dot,6);
|
||
|
VectorOperations<double>::mulScalar(y0dot,1./6.*deltaT,y0dot,6);
|
||
|
VectorOperations<double>::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_ */
|