Computes all repeat (also called "phased") orbits for a given range of semi major axis and number of planet revolutions per cycle.
//An orbit is considered as "phased" if the ground tracks (with respect to the rotating planet) repeat exactly, // which means that after a certain whole number of orbits, the planet must has rotated a whole number of revolutions with respect to the orbit's node.
//Let Tc be the duration of the repeat cycle. There must exist 2 integers M and Q such that:
//Tc = M * T = Q * Tr
//where T is the orbit period (more exactly the mean nodal period), and Tr is the revolution period of the planet // with respect to the orbit's (ascending or descending) node (Tr is called "orbital day" in the following).
//If M is expressed as: M=N*Q+P (with P < Q), the problem comes down to determining the 3 integers N,P,Q such that:
//Tc = (N*Q+P)*T = Q * Tr (with P < Q))
//Then:
//Q (=Tc/Tr) is the number of planet revolutions per repeat cycle.
//N+P/Q (=Tr/T) is the number of orbits per planet revolutions with respect to the orbit's (ascending or descending) node.
//N*Q+P (= Tc/T) is the (whole) number of orbits per repeat cycle.
//Note that Tr depends on the orbit parameters because the node drifts under the effect of J2.
//Two orbit cases are handled:
//- Orbits with a fixed inclination (incInput). There is only one unknown (sma), // which is determined using the equation: (N*Q+P)*T(sma) = Q * Tr(sma)
//- Sun-synchronous orbits: the inclination is computed in the process. // There are 2 unknowns (sma and inc). Two equations are then used: (N*Q+P)*T(sma) = Q * Tr(sma), and sun-sync(sma,inc) (condition for Sun-synchronicity). // For a Sun-synchronous orbit, an orbital day is the same as a usual day (86400 s).
//Also note that the computation uses the mean drifts, so that the true ground tracks may not repeat exactly if the argument of perigee drifts.
//params is a 11-column matrix with as many rows as there are solutions.
//- params(:,1): Semi major axis [m]
//- params(:,2): Eccentricity
//- params(:,3): Inclination [rad]
//- params(:,4:6): N, P, Q
//- params(:,7): Number of orbits per cycle (=N*Q+P)
//- params(:,8): (mean) Nodal period [s]
//- params(:,9): Cycle duration [days]
//- params(:,10): Longitude gap between 2 closest ascending ground tracks at the equator [rad] = 2*pi/(N*Q+P)
//- params(:,11): Gap in longitude after one cycle modulo 2*pi [rad] (for checking purposes)
//// Cette fonction renvoie toutes les combinaisons de N, P et Q qui respectent les conditions : // // // Authors // A. LAMY - CNES - DCT/SB/MS // G. AZEMA - Thales Services pour le CNES - DCT/SB/MS // // See also // // Examples // xNmin = 14.25; // xNmax = 15.75; // QMin = 3; // QMax = 6; // [N,P,Q]=CL__findNPQ(xNmin,xNmax,QMin,QMax) Nmin = floor(xNmin); Nmax = ceil(xNmax); // Recherche des couples P,Q tels que P et Q soient premiers entre eux : P1=[]; Q1=[]; for iQ = QMin:QMax tabP = 1:iQ-1; I = find(CL_gcd(iQ*ones(tabP),tabP) <= 1); tabP = tabP(I); if (iQ == 1); tabP = [0, tabP]; end // add P=0 if Q == 1 P1 = [P1, tabP]; Q1 = [Q1, iQ * ones(tabP)]; end N=[]; P=[]; Q=[]; for iN = Nmin:Nmax N=[N, iN * ones(P1)]; P=[P, P1]; // NB : P1 and Q1: same size Q=[Q, Q1]; end // Keep N,P,Q if N+P/Q in [xNmin, xNmax] I = find(N+P./Q >= xNmin & N+P./Q <= xNmax); N = N(I); P = P(I); Q = Q(I); endfunction // Declarations: // Code: if (~exists("er", "local")); er = CL__dataGetEnv("eqRad"); end if (~exists("mu", "local")); mu = CL__dataGetEnv("mu"); end if (~exists("j2", "local")); j2 = CL__dataGetEnv("j1jn", 2); end if (~exists("rotr_pla", "local")); rotr_pla = CL__dataGetEnv("rotrBody"); end if (~exists("rotr_pla_sun", "local")); rotr_pla_sun = CL__dataGetEnv("rotrBodySun"); end // Verification des entrees if (smaMin < 0); CL__error("smaMin out of range"); end if (smaMax <= smaMin); CL__error("smaMax out of range"); end if (ecc < 0 | ecc >= 1); CL__error("eccentricity out of range"); end if (QMin < 1); CL__error("QMin out of range"); end if (QMax < QMin); CL__error("QMax out of range"); end if (sso <> 0 & sso <> 1); CL__error("sso: wrong value"); end if (sso == 0) if ~exists('incInput','local') then CL__error('You must give incInput when sso = 0'); end I = find(incInput < 0 | incInput > %pi+%eps); if ~isempty(I); CL__error("inclination out of range"); end else incInput = 0; // not used ! end // computes xNmin, xNmax (range of number of orbits per planet rev) // NOTE : // it is assumed that : // - the number of orbit / planet rev is a // monotonous function of the semi major axis (for sso == 0 or 1) // - max sma of a sun-synchronous orbit corresponds to inc= %pi tabsma = [smaMin,smaMax]; if (sso == 1) smaMax_sso = CL_op_ssoJ2('a', ecc, %pi); tabsma(2) = min(smaMax, smaMax_sso) tabinc = CL_op_ssoJ2('i', tabsma, ecc); else tabinc = [incInput, incInput]; end [tabpomp, tabgomp, tabanmp] = CL_op_driftJ2(tabsma,ecc,tabinc,er,mu,j2); tabTnod = 2*%pi ./ (tabpomp + tabanmp); // nodal period tabTrev = 2*%pi ./ (rotr_pla - tabgomp); // planet rev. period / node tabxN = tabTrev ./ tabTnod; xNmin = min(tabxN); xNmax = max(tabxN); // (N,P,Q) such that N+P/Q in [xNmin, xNmax] [N,P,Q] = CL__findNPQ(xNmin,xNmax,QMin,QMax); params = []; if (and([N <> [], P <> [], Q <> []])) // computed sma and inc for each (N,P,Q) [sma,inc] = CL_op_repeat2smaInc(N,P,Q,ecc,sso,incInput,er,mu,j2,rotr_pla,rotr_pla_sun); // final results ecc = ecc .* ones(sma); [pomp, gomp, anmp] = CL_op_driftJ2(sma,ecc,inc,er,mu,j2); nbOrbCycle = N.*Q + P; maille = 2*%pi ./ nbOrbCycle; periodeNodale = 2*%pi ./ (pomp + anmp); dureeCycle = nbOrbCycle .* periodeNodale; ecartLongitudeCycle = CL_rMod(dureeCycle .* (rotr_pla - gomp), -%pi, %pi); params = [sma; ecc; inc; N; P; Q; nbOrbCycle; periodeNodale; dureeCycle/86400.0; maille ; ecartLongitudeCycle]'; // %nan removed if any I = find(isnan(params(:,1)) | isnan(params(:,3))); // sma or inc is %nan if (~isempty(I)); CL__warning("%nan found in result: removed"); end params(I,:) = []; end endfunctionxNmin <= N+P/Q <= xNmax
//QMin <= Q <= QMax
//P et Q premiers entre eux
//0<=P
//Note : la taille des vecteurs N,P,Q en sortie n'est pas connue a l'avance.
//