// Copyright (c) CNES 2008
//
// This software is part of CelestLab, a CNES toolbox for Scilab
//
// This software is governed by the CeCILL license under French law and
// abiding by the rules of distribution of free software. You can use,
// modify and/ or redistribute the software under the terms of the CeCILL
// license as circulated by CEA, CNRS and INRIA at the following URL
// 'http://www.cecill.info'.
function [cir,jacob] = CL_oe_car2cir(pos,vel, mu)
// Cartesian to circular orbital elements
//
// Calling Sequence
// [cir,jacob] = CL_oe_car2cir(pos,vel [,mu])
//
// Description
//
//
Converts cartesian orbital elements to orbital elements adapted to near-circular orbits.
//
The transformation jacobian is optionally computed.
//
See Orbital elements for more details.
//
//
//
// Parameters
// pos: Position vector [x;y;z] [m] (3xN)
// vel: Velocity vector [vx;vy;vz] [m/s] (3xN)
// mu : (optional) Gravitational constant. [m^3/s^2] (default value is %CL_mu)
// cir: Orbital elements adapted to near-circular orbits [sma;ex;ey;inc;gom;pso] [m,rad] (6xN)
// jacob: (optional) Transformation jacobian (See Orbital elements for more details) (6x6xN)
//
// Authors
// CNES - DCT/SB
//
// See also
// CL_oe_cir2car
// CL_oe_car2kep
//
// Examples
// // Example 1
// pos = [7000.e3; 1000.e3; -500.e3];
// vel = [1.e3; 2.e3; 7e3];
// cir = CL_oe_car2cir(pos, vel);
//
// // Example 2
// pos = [7000.e3; 1000.e3; -500.e3];
// vel = [1.e3; 2.e3; 7e3];
// [cir, jacob1] = CL_oe_car2cir(pos, vel);
// [pos2, vel2, jacob2] = CL_oe_cir2car(cir);
// pos2 - pos // => zero
// vel2 - vel // => zero
// jacob2 * jacob1 // => identity
// Declarations:
EPS_ORB = CL__dataGetEnv("epsOrb", internal=%t);
// Code:
if (~exists("mu", "local")); mu = CL__dataGetEnv("mu"); end
// Handle [] cases
if (pos == [] | vel == [])
cir = [];
jacob = [];
return;
end
// Check input sizes
[pos,vel,N] = CL__checkInputs(pos,3, vel,3);
// Check validity of inputs
[isvalid,orbit_type] = CL__oe_isValid("car",[pos;vel],mu);
if (~isvalid); CL__error("Invalid position velocity (zero norm or colinear)"); end;
if (find(orbit_type <> 1) <> []); CL__error("Invalid position velocity (parabolic or hyperbolic orbit)"); end;
// Semi major axis
r = CL_norm(pos);
V = CL_norm(vel);
W = CL_cross(pos,vel);
[Wu,normW] = CL_unitVector(W);
a = r ./ (2 - r .* V.^2/mu);
esinE = CL_dot(pos,vel) ./ sqrt(mu.*a);
// ecosE = r .* V.^2/mu - 1
// Inclination (=atan(sqrt(W(1)+W(2)),W(3)))
inc = CL_vectAngle(W, [0;0;1]);
// Raan
gom = atan(W(1,:), -W(2,:));
// NB: if W(1)==0 and W(2)==0 --> gom = 0
Ieq = find(sin(inc) < EPS_ORB.equa); // equatorial orbit
gom(Ieq) = 0;
// Eccentricity vector
// Coordinates in the "natural frame"
// P = first column of matrix R
// Q = second column of matrix R
P = [cos(gom);sin(gom);zeros(gom)];
Q = [-cos(inc).*sin(gom);cos(inc).*cos(gom);sin(inc)];
X = CL_dot(pos, P);
Y = CL_dot(pos, Q);
VX = CL_dot(vel, P);
VY = CL_dot(vel, Q);
ex = normW .* VY ./ mu - X ./ r;
ey = -normW .* VX ./ mu - Y ./ r;
// Alpha (mean argument of latitude)
nu = 1 ./ (1 + sqrt(1 - ex.^2 - ey.^2));
cosF = X ./ a + ex - esinE .* nu .* ey;
sinF = Y ./ a + ey + esinE .* nu .* ex;
alpha = atan(sinF,cosF) - ex .* sinF + ey .* cosF;
// Reduce gom,alpha to [0,2pi[
cir = [a;ex;ey;inc;CL_rMod([gom;alpha],2*%pi)];
// Jacobian computation (dcir/dcar)
jacob = [];
if (argn(1) == 2)
// jacob(i,j) = d(cir_i)/d(car_j)
jacob = zeros(6,6,N);
// Partial derivatives of W(1,:), W(2,:) and W(3,:) with respect to (x,y,z) and (vx,vy,vz)
dW1dr = [ zeros(a) ; vel(3,:) ; -vel(2,:)];
dW2dr = [-vel(3,:) ; zeros(a) ; vel(1,:)];
dW3dr = [ vel(2,:) ; -vel(1,:); zeros(a)];
dW1dv = [ zeros(a) ; -pos(3,:); pos(2,:)];
dW2dv = [ pos(3,:) ; zeros(a) ; -pos(1,:)];
dW3dv = [-pos(2,:) ; pos(1,:) ; zeros(a)];
// Useful values:
s = sqrt(W(1,:).^2+W(2,:).^2);
// s, set to %nan if equatorial orbit
s(Ieq) = %nan;
ci = W(3,:) ./ normW; // cos(inc)
si = s ./ normW; // sin(inc)
cg = -W(2,:) ./ s; // cos(gom)
sg = W(1,:) ./ s; // sin(gom)
// Partial derivatives of the norm of W with respect to (x,y,z) and (vx,vy,vz)
dnormWdr = CL_dMult(CL_cross(vel, W), 1 ./ normW);
dnormWdv = -CL_dMult(CL_cross(pos, W), 1 ./ normW);
for j = 1 : 3
// da/d(x,y,z):
dadr = 2 * a.^2 ./ r.^3 .* pos(j,:);
// da/d(vx,vy,vz):
dadv = 2 * a.^2 ./ mu .* vel(j,:);
// Partial derivative of s = sqrt(W(1)^2+W(2)^2)
dsdr = (W(1,:).*dW1dr(j,:) + W(2,:).*dW2dr(j,:)) ./ s;
dsdv = (W(1,:).*dW1dv(j,:) + W(2,:).*dW2dv(j,:)) ./ s;
// Partial derivatives of cos(inc) with respect to (x,y,z) and (vx,vy,vz)
dcidr = dW3dr(j,:) ./ normW - W(3,:) .* dnormWdr(j,:) ./ normW.^2;
dcidv = dW3dv(j,:) ./ normW - W(3,:) .* dnormWdv(j,:) ./ normW.^2;
// Partial derivatives of sin(inc) with respect to (x,y,z) and (vx,vy,vz)
dsidr = dsdr ./ normW - s .* dnormWdr(j,:) ./ normW.^2;
dsidv = dsdv ./ normW - s .* dnormWdv(j,:) ./ normW.^2;
// Partial derivatives of cos(gom) with respect to (x,y,z) and (vx,vy,vz)
dcgdr = -dW2dr(j,:) ./ s + W(2,:) .* dsdr ./ s.^2;
dcgdv = -dW2dv(j,:) ./ s + W(2,:) .* dsdv ./ s.^2;
// Partial derivatives of sin(gom) with respect to (x,y,z) and (vx,vy,vz)
dsgdr = dW1dr(j,:) ./ s - W(1,:) .* dsdr ./ s.^2;
dsgdv = dW1dv(j,:) ./ s - W(1,:) .* dsdv ./ s.^2;
// Partial derivatives of VX = cos(gom)*vx + sin(gom)*vy
dVXdr = dcgdr.*vel(1,:) + dsgdr.*vel(2,:);
dVXdv = dcgdv.*vel(1,:) + cg * (j==1) + dsgdv.*vel(2,:) + sg * (j==2);
// Partial derivatives of VY = -sin(gom)*cos(i)*vx + cos(gom)*cos(i)*vy + sin(i)*vz
dVYdr = -dsgdr.*ci.*vel(1,:) -sg.*dcidr.*vel(1,:) + dcgdr.*ci.*vel(2,:) + cg.*dcidr.*vel(2,:) + dsidr.*vel(3,:);
dVYdv = -dsgdv.*ci.*vel(1,:) -sg.*dcidv.*vel(1,:) - sg.*ci*(j==1) + ...
dcgdv.*ci.*vel(2,:) + cg.*dcidv.*vel(2,:) + cg.*ci*(j==2) + dsidv.*vel(3,:) + si*(j==3);
// Partial derivatives of X = cos(gom)*x + sin(gom)*y
dXdr = dcgdr.*pos(1,:) + cg*(j==1) + dsgdr.*pos(2,:) + sg*(j==2);
dXdv = dcgdv.*pos(1,:) + dsgdv.*pos(2,:);
// Partial derivatives of Y = -sin(gom)*cos(i)*x + cos(gom)*cos(i)*y + sin(i)*z
dYdr = -dsgdr.*ci.*pos(1,:) -sg.*dcidr.*pos(1,:) - sg.*ci*(j==1) + ...
dcgdr.*ci.*pos(2,:) + cg.*dcidr.*pos(2,:) + cg.*ci*(j==2) + dsidr.*pos(3,:) + si*(j==3);
dYdv = -dsgdv.*ci.*pos(1,:) -sg.*dcidv.*pos(1,:) + dcgdv.*ci.*pos(2,:) + cg.*dcidv.*pos(2,:) + dsidv.*pos(3,:);
// Partial derivatives of ex = normW*VY/mu -X/r
dexdr = dnormWdr(j,:) .* VY ./ mu + normW .* dVYdr ./ mu - dXdr ./ r + X .* pos(j,:) ./ r.^3;
dexdv = dnormWdv(j,:) .* VY ./ mu + normW .* dVYdv ./ mu - dXdv ./ r;
// Partial derivatives of ey = -normW*VX/mu -Y/r
deydr = -dnormWdr(j,:) .* VX ./ mu - normW .* dVXdr ./ mu - dYdr ./ r + Y .* pos(j,:) ./ r.^3;
deydv = -dnormWdv(j,:) .* VX ./ mu - normW .* dVXdv ./ mu - dYdv ./ r;
// Partial derivatives of i = atan(s/W3)
didr = (W(3,:) .* dsdr - dW3dr(j,:) .* s) ./ (W(3,:).^2 + s.^2);
didv = (W(3,:) .* dsdv - dW3dv(j,:) .* s) ./ (W(3,:).^2 + s.^2);
// Partial derivatives of gom = atan(W(1)/-W(2))
dgdr = -(W(2,:) .* dW1dr(j,:) - dW2dr(j,:) .* W(1,:)) ./ s.^2;
dgdv = -(W(2,:) .* dW1dv(j,:) - dW2dv(j,:) .* W(1,:)) ./ s.^2;
// Partial derivatives of alpha:
// d(esinE)/d(x,y,z)
desinEdr = vel(j,:) ./ (sqrt(mu.*a)) - a .* esinE ./ r.^3 .* pos(j,:);
desinEdv = pos(j,:) ./ (sqrt(mu.*a)) - a .* esinE ./ mu .* vel(j,:);
// Partial derivatives of nu
dnudr = (ex.*dexdr + ey.*deydr) ./ sqrt(1 - ex.^2 - ey.^2) .* nu.^2;
dnudv = (ex.*dexdv + ey.*deydv) ./ sqrt(1 - ex.^2 - ey.^2) .* nu.^2;
dcosFdr = dXdr ./ a - X .* dadr ./ a.^2 + dexdr - (desinEdr .* nu .* ey + esinE .* dnudr .* ey + esinE .* nu .* deydr);
dsinFdr = dYdr ./ a - Y .* dadr ./ a.^2 + deydr + (desinEdr .* nu .* ex + esinE .* dnudr .* ex + esinE .* nu .* dexdr);
dFdr = (cosF .* dsinFdr - dcosFdr .* sinF) ./ (cosF.^2 + sinF.^2);
dalphadr = dFdr - dexdr .* sinF - ex .* dsinFdr + deydr .* cosF + ey .* dcosFdr;
dcosFdv = dXdv ./ a - X .* dadv ./ a.^2 + dexdv - (desinEdv .* nu .* ey + esinE .* dnudv .* ey + esinE .* nu .* deydv);
dsinFdv = dYdv ./ a - Y .* dadv ./ a.^2 + deydv + (desinEdv .* nu .* ex + esinE .* dnudv .* ex + esinE .* nu .* dexdv);
dFdv = (cosF .* dsinFdv - dcosFdv .* sinF) ./ (cosF.^2 + sinF.^2);
dalphadv = dFdv - dexdv .* sinF - ex .* dsinFdv + deydv .* cosF + ey .* dcosFdv;
// Assign results to the output jacobian:
jacob(1,j,:) = dadr;
jacob(2,j,:) = dexdr;
jacob(3,j,:) = deydr;
jacob(4,j,:) = didr;
jacob(5,j,:) = dgdr;
jacob(6,j,:) = dalphadr;
jacob(1,j+3,:) = dadv;
jacob(2,j+3,:) = dexdv;
jacob(3,j+3,:) = deydv;
jacob(4,j+3,:) = didv;
jacob(5,j+3,:) = dgdv;
jacob(6,j+3,:) = dalphadv;
end
end
endfunction