/** * Simple constructor. * * <p>The {@code applyBefore} parameter is mainly used when the differential effect is associated * with a maneuver. In this case, the parameter must be set to {@code false}. * * @param orbit0 original orbit at reference date * @param orbit1 shifted orbit at reference date * @param applyBefore if true, effect is applied both before and after reference date, if false it * is only applied after reference date * @param gravityField gravity field to use * @exception OrekitException if gravity field does not contain J2 coefficient */ public J2DifferentialEffect( final Orbit orbit0, final Orbit orbit1, final boolean applyBefore, final UnnormalizedSphericalHarmonicsProvider gravityField) throws OrekitException { this( orbit0, orbit1, applyBefore, gravityField.getAe(), gravityField.getMu(), -gravityField.onDate(orbit0.getDate()).getUnnormalizedCnm(2, 0)); }
/** * Simple constructor. * * <p>The {@code applyBefore} parameter is mainly used when the differential effect is associated * with a maneuver. In this case, the parameter must be set to {@code false}. * * @param original original state at reference date * @param directEffect direct effect changing the orbit * @param applyBefore if true, effect is applied both before and after reference date, if false it * is only applied after reference date * @param gravityField gravity field to use * @exception OrekitException if gravity field does not contain J2 coefficient */ public J2DifferentialEffect( final SpacecraftState original, final AdapterPropagator.DifferentialEffect directEffect, final boolean applyBefore, final UnnormalizedSphericalHarmonicsProvider gravityField) throws OrekitException { this( original, directEffect, applyBefore, gravityField.getAe(), gravityField.getMu(), -gravityField.onDate(original.getDate()).getUnnormalizedCnm(2, 0)); }
/** * Single constructor. * * @param centralBodyFrame rotating body frame * @param centralBodyRotationRate central body rotation rate (rad/s) * @param provider provider for spherical harmonics * @param mDailiesOnly if true only M-dailies tesseral harmonics are taken into account for short * periodics */ TesseralContribution( final Frame centralBodyFrame, final double centralBodyRotationRate, final UnnormalizedSphericalHarmonicsProvider provider, final boolean mDailiesOnly) { // Central body rotating frame this.bodyFrame = centralBodyFrame; // Save the rotation rate this.centralBodyRotationRate = centralBodyRotationRate; // Central body rotation period in seconds this.bodyPeriod = MathUtils.TWO_PI / centralBodyRotationRate; // Provider for spherical harmonics this.provider = provider; this.maxDegree = provider.getMaxDegree(); this.maxOrder = provider.getMaxOrder(); // set the maximum degree order for short periodics this.maxDegreeTesseralSP = FastMath.min(maxDegree, MAX_DEGREE_TESSERAL_SP); this.maxDegreeMdailyTesseralSP = FastMath.min(maxDegree, MAX_DEGREE_MDAILY_TESSERAL_SP); this.maxOrderTesseralSP = FastMath.min(maxOrder, MAX_ORDER_TESSERAL_SP); this.maxOrderMdailyTesseralSP = FastMath.min(maxOrder, MAX_ORDER_MDAILY_TESSERAL_SP); // set the maximum value for eccentricity power this.maxEccPowTesseralSP = MAX_ECCPOWER_SP; this.maxEccPowMdailyTesseralSP = FastMath.min(maxDegreeMdailyTesseralSP - 2, MAX_ECCPOWER_SP); this.jMax = FastMath.min(MAXJ, maxDegreeTesseralSP + maxEccPowTesseralSP); // m-daylies only this.mDailiesOnly = mDailiesOnly; // Initialize default values this.resOrders = new ArrayList<Integer>(); this.nonResOrders = new TreeMap<Integer, List<Integer>>(); this.maxEccPow = 0; this.maxHansen = 0; // Factorials computation final int maxFact = 2 * maxDegree + 1; this.fact = new double[maxFact]; fact[0] = 1; for (int i = 1; i < maxFact; i++) { fact[i] = i * fact[i - 1]; } }
/** * Compute the n-SUM for potential derivatives components. * * @param date current date * @param j resonant index <i>j</i> * @param m resonant order <i>m</i> * @param s d'Alembert characteristic <i>s</i> * @param maxN maximum possible value for <i>n</i> index * @param roaPow powers of R/a up to degree <i>n</i> * @param ghMSJ G<sup>j</sup><sub>m,s</sub> and H<sup>j</sup><sub>m,s</sub> polynomials * @param gammaMNS Γ<sup>m</sup><sub>n,s</sub>(γ) function * @return Components of U<sub>n</sub> derivatives for fixed j, m, s * @throws OrekitException if some error occurred */ private double[][] computeNSum( final AbsoluteDate date, final int j, final int m, final int s, final int maxN, final double[] roaPow, final GHmsjPolynomials ghMSJ, final GammaMnsFunction gammaMNS) throws OrekitException { // spherical harmonics final UnnormalizedSphericalHarmonics harmonics = provider.onDate(date); // Potential derivatives components double dUdaCos = 0.; double dUdaSin = 0.; double dUdhCos = 0.; double dUdhSin = 0.; double dUdkCos = 0.; double dUdkSin = 0.; double dUdlCos = 0.; double dUdlSin = 0.; double dUdAlCos = 0.; double dUdAlSin = 0.; double dUdBeCos = 0.; double dUdBeSin = 0.; double dUdGaCos = 0.; double dUdGaSin = 0.; // I^m final int Im = I > 0 ? 1 : (m % 2 == 0 ? 1 : -1); // jacobi v, w, indices from 2.7.1-(15) final int v = FastMath.abs(m - s); final int w = FastMath.abs(m + s); // Initialise lower degree nmin = (Max(2, m, |s|)) for summation over n final int nmin = FastMath.max(FastMath.max(2, m), FastMath.abs(s)); // Get the corresponding Hansen object final int sIndex = maxDegree + (j < 0 ? -s : s); final int jIndex = FastMath.abs(j); final HansenTesseralLinear hans = this.hansenObjects[sIndex][jIndex]; // n-SUM from nmin to N for (int n = nmin; n <= maxN; n++) { // If (n - s) is odd, the contribution is null because of Vmns if ((n - s) % 2 == 0) { // Vmns coefficient final double fns = fact[n + FastMath.abs(s)]; final double vMNS = CoefficientsFactory.getVmns(m, n, s, fns, fact[n - m]); // Inclination function Gamma and derivative final double gaMNS = gammaMNS.getValue(m, n, s); final double dGaMNS = gammaMNS.getDerivative(m, n, s); // Hansen kernel value and derivative final double kJNS = hans.getValue(-n - 1, chi); final double dkJNS = hans.getDerivative(-n - 1, chi); // Gjms, Hjms polynomials and derivatives final double gMSJ = ghMSJ.getGmsj(m, s, j); final double hMSJ = ghMSJ.getHmsj(m, s, j); final double dGdh = ghMSJ.getdGmsdh(m, s, j); final double dGdk = ghMSJ.getdGmsdk(m, s, j); final double dGdA = ghMSJ.getdGmsdAlpha(m, s, j); final double dGdB = ghMSJ.getdGmsdBeta(m, s, j); final double dHdh = ghMSJ.getdHmsdh(m, s, j); final double dHdk = ghMSJ.getdHmsdk(m, s, j); final double dHdA = ghMSJ.getdHmsdAlpha(m, s, j); final double dHdB = ghMSJ.getdHmsdBeta(m, s, j); // Jacobi l-index from 2.7.1-(15) final int l = FastMath.min(n - m, n - FastMath.abs(s)); // Jacobi polynomial and derivative final DerivativeStructure jacobi = JacobiPolynomials.getValue(l, v, w, new DerivativeStructure(1, 1, 0, gamma)); // Geopotential coefficients final double cnm = harmonics.getUnnormalizedCnm(n, m); final double snm = harmonics.getUnnormalizedSnm(n, m); // Common factors from expansion of equations 3.3-4 final double cf_0 = roaPow[n] * Im * vMNS; final double cf_1 = cf_0 * gaMNS * jacobi.getValue(); final double cf_2 = cf_1 * kJNS; final double gcPhs = gMSJ * cnm + hMSJ * snm; final double gsMhc = gMSJ * snm - hMSJ * cnm; final double dKgcPhsx2 = 2. * dkJNS * gcPhs; final double dKgsMhcx2 = 2. * dkJNS * gsMhc; final double dUdaCoef = (n + 1) * cf_2; final double dUdlCoef = j * cf_2; final double dUdGaCoef = cf_0 * kJNS * (jacobi.getValue() * dGaMNS + gaMNS * jacobi.getPartialDerivative(1)); // dU / da components dUdaCos += dUdaCoef * gcPhs; dUdaSin += dUdaCoef * gsMhc; // dU / dh components dUdhCos += cf_1 * (kJNS * (cnm * dGdh + snm * dHdh) + h * dKgcPhsx2); dUdhSin += cf_1 * (kJNS * (snm * dGdh - cnm * dHdh) + h * dKgsMhcx2); // dU / dk components dUdkCos += cf_1 * (kJNS * (cnm * dGdk + snm * dHdk) + k * dKgcPhsx2); dUdkSin += cf_1 * (kJNS * (snm * dGdk - cnm * dHdk) + k * dKgsMhcx2); // dU / dLambda components dUdlCos += dUdlCoef * gsMhc; dUdlSin += -dUdlCoef * gcPhs; // dU / alpha components dUdAlCos += cf_2 * (dGdA * cnm + dHdA * snm); dUdAlSin += cf_2 * (dGdA * snm - dHdA * cnm); // dU / dBeta components dUdBeCos += cf_2 * (dGdB * cnm + dHdB * snm); dUdBeSin += cf_2 * (dGdB * snm - dHdB * cnm); // dU / dGamma components dUdGaCos += dUdGaCoef * gcPhs; dUdGaSin += dUdGaCoef * gsMhc; } } return new double[][] { {dUdaCos, dUdaSin}, {dUdhCos, dUdhSin}, {dUdkCos, dUdkSin}, {dUdlCos, dUdlSin}, {dUdAlCos, dUdAlSin}, {dUdBeCos, dUdBeSin}, {dUdGaCos, dUdGaSin} }; }
/** {@inheritDoc} */ @Override public double[] getShortPeriodicVariations(final AbsoluteDate date, final double[] meanElements) throws OrekitException { // Initialise the short periodic variations final double[] shortPeriodicVariation = new double[] {0., 0., 0., 0., 0., 0.}; // Compute only if there is at least one non-resonant tesseral or // only the m-daily tesseral should be taken into account if (!nonResOrders.isEmpty() || mDailiesOnly) { // Build an Orbit object from the mean elements final Orbit meanOrbit = OrbitType.EQUINOCTIAL.mapArrayToOrbit( meanElements, PositionAngle.MEAN, date, provider.getMu(), this.frame); // Build an auxiliary object final AuxiliaryElements aux = new AuxiliaryElements(meanOrbit, I); // Central body rotation angle from equation 2.7.1-(3)(4). final Transform t = bodyFrame.getTransformTo(aux.getFrame(), aux.getDate()); final Vector3D xB = t.transformVector(Vector3D.PLUS_I); final Vector3D yB = t.transformVector(Vector3D.PLUS_J); final double currentTheta = FastMath.atan2( -f.dotProduct(yB) + I * g.dotProduct(xB), f.dotProduct(xB) + I * g.dotProduct(yB)); // Add the m-daily contribution for (int m = 1; m <= maxOrderMdailyTesseralSP; m++) { // Phase angle final double jlMmt = -m * currentTheta; final double sinPhi = FastMath.sin(jlMmt); final double cosPhi = FastMath.cos(jlMmt); // compute contribution for each element for (int i = 0; i < 6; i++) { shortPeriodicVariation[i] += tesseralSPCoefs.getCijm(i, 0, m, date) * cosPhi + tesseralSPCoefs.getSijm(i, 0, m, date) * sinPhi; } } // loop through all non-resonant (j,m) pairs for (final Map.Entry<Integer, List<Integer>> entry : nonResOrders.entrySet()) { final int m = entry.getKey(); final List<Integer> listJ = entry.getValue(); for (int j : listJ) { // Phase angle final double jlMmt = j * meanElements[5] - m * currentTheta; final double sinPhi = FastMath.sin(jlMmt); final double cosPhi = FastMath.cos(jlMmt); // compute contribution for each element for (int i = 0; i < 6; i++) { shortPeriodicVariation[i] += tesseralSPCoefs.getCijm(i, j, m, date) * cosPhi + tesseralSPCoefs.getSijm(i, j, m, date) * sinPhi; } } } } return shortPeriodicVariation; }
/** {@inheritDoc} */ @Override public void initializeStep(final AuxiliaryElements aux) throws OrekitException { // Equinoctial elements a = aux.getSma(); k = aux.getK(); h = aux.getH(); q = aux.getQ(); p = aux.getP(); lm = aux.getLM(); // Eccentricity ecc = aux.getEcc(); e2 = ecc * ecc; // Retrograde factor I = aux.getRetrogradeFactor(); // Equinoctial frame vectors f = aux.getVectorF(); g = aux.getVectorG(); // Central body rotation angle from equation 2.7.1-(3)(4). final Transform t = bodyFrame.getTransformTo(aux.getFrame(), aux.getDate()); final Vector3D xB = t.transformVector(Vector3D.PLUS_I); final Vector3D yB = t.transformVector(Vector3D.PLUS_J); theta = FastMath.atan2( -f.dotProduct(yB) + I * g.dotProduct(xB), f.dotProduct(xB) + I * g.dotProduct(yB)); // Direction cosines alpha = aux.getAlpha(); beta = aux.getBeta(); gamma = aux.getGamma(); // Equinoctial coefficients // A = sqrt(μ * a) final double A = aux.getA(); // B = sqrt(1 - h² - k²) final double B = aux.getB(); // C = 1 + p² + q² final double C = aux.getC(); // Common factors from equinoctial coefficients // 2 * a / A ax2oA = 2. * a / A; // B / A BoA = B / A; // 1 / AB ooAB = 1. / (A * B); // C / 2AB Co2AB = C * ooAB / 2.; // B / (A * (1 + B)) BoABpo = BoA / (1. + B); // &mu / a moa = provider.getMu() / a; // R / a roa = provider.getAe() / a; // Χ = 1 / B chi = 1. / B; chi2 = chi * chi; // mean motion n meanMotion = aux.getMeanMotion(); }