Analyze the performance of relative orbit control in eccentric orbits

This script compares the performance of two different control methods for relative orbit control in a highly eccentric orbit. The two methods compared are: - LPEccentric (relative dynamics expressed in Hills frame) - LPEccentricGVE (relative dynamics expressed with Gauss var. eqs.)

The linearization error is much higher when the relative dynamics is based in Hills frame. This results in noticable error in the controlled trajectory.

In addition, this script also compares the relative trajectories when the maneuver is simulated in different ways. The following types of simulations are compared - Discrete relative dynamics in Hills frame. - Discrete relative dynamics with differential elements using Gauss' variational equations. - Keplerian orbits patched together with impulsive delta-v's - Numerical integration in ECI frame

Since version 7.
------------------------------------------------------------------------
See also Delay, QHills, QTForm, TimeGUI, Mag, RK4TI,
EccGeometry_Structure, DiscreteGVE, FFEccDiscreteHills, LPEccentric,
LPEccentricGVE, ECI2Hills, FFEccDeltaElem2Hills, FFEccGoals2Hills,
FFEccHills2DeltaElem, ApplyDeltaV, RVOrbGenDV, OrbRate, RVOrbGen, El2RV,
M2Nu, M2NuAbs, Period
------------------------------------------------------------------------
%--------------------------------------------------------------------------
%   Copyright (c) 2004 Princeton Satellite Systems, Inc.
%   All rights reserved.
%--------------------------------------------------------------------------



% initial orbit
a = 42095;
i = pi/18;
W = 0;
w = 0;
e = 0.818181000;
M = pi;
el0 = [a,i,W,w,e,M];

% other orbit data
n   = OrbRate(a);
T   = Period(a);
nu0 = M2Nu(e,M);

% initial relative state
dEl0 = [1e-9, 1e-7, 1e-7, 1e-7, 1e-7, 1e-7];
xH0  = FFEccDeltaElem2Hills( el0, dEl0, 2 );

% desired relative state
goals = EccGeometry_Structure;
goals.y0 = 0;
MF  = M + 2*pi;
nuF = M2NuAbs( e, MF );
xHF = FFEccGoals2Hills( e, nuF, goals, n );
dElF = FFEccHills2DeltaElem( el0, xHF, 2 );

fprintf('\nPlanning a maneuver using "LPEccentric" and "LPEccentricGVE"...\n')

% plan a manuever with simplex (Hills)
nS = 2000;
[aC1,t1,flag1] = LPEccentric( e, n, xH0, xHF, nu0, nuF, nS );

% plan a manuever with simplex (GVE)
[aC2,t2,flag2] = LPEccentricGVE( el0, dEl0', zeros(1,6)', MF, nS );


if( norm(t1-t2)>eps )
   warning('Hills-based and GVE-based solutions use different time vectors');
   while 1
      ans = input('continue(c) or quit(q) ?','s');
      switch lower(ans)
         case 'c'
            break;
         case 'q'
            return;
      end
   end
else
   t=t1;
end

% extend time vector to show future orbits
dt   = diff(t);
nOrb = 1;
nSPO = round( nS*2*pi/(MF-el0(6)) );
t    = [t, t(end)+linspace(dt(2),nOrb*T,nOrb*nSPO)];
aC1  = [aC1, zeros(3,nOrb*nSPO)];
aC2  = [aC2, zeros(3,nOrb*nSPO)];
N    = length(t);

fprintf('\nApplying the maneuver and propagating dynamics in relative frames...\n')

% propagate initial state with control using FFEccDiscreteHills
[xHD1,nu] = FFEccDiscreteHills( e, n, xH0, nu0, aC1, t );

% propagate initial state with control using DiscreteGVE
[dEl,M]   = DiscreteGVE( el0, dEl0, aC2, t );

% find delta-v's for Hills solution
k  = find(Mag(aC1));
dV1      = zeros(3,length(k));
dV1(1,:) = aC1(1,k).*dt(k);
dV1(2,:) = aC1(2,k).*dt(k);
dV1(3,:) = aC1(3,k).*dt(k);
dV1Times = t(k)+dt(k)/2;      % apply purely impulsive delta-v at halfway point of burn
dV1Times = t(k)+dt(k);        % apply purely impulsive delta-v at end of burn

% find delta-v's
k = find(Mag(aC2));
dV2      = zeros(3,length(k));
dV2(1,:) = aC2(1,k).*dt(k);
dV2(2,:) = aC2(2,k).*dt(k);
dV2(3,:) = aC2(3,k).*dt(k);
dV2Times = t(k)+dt(k)/2;      % apply purely impulsive delta-v at halfway point of burn
dV2Times = t(k)+dt(k);        % apply purely impulsive delta-v at end of burn

fprintf('\nNow applying impulsive delta-vs to absolute orbit with Keplerian propagation...\n')

% piece together keplerian orbits with purely impulsive delta-v's
[r0,v0]      = RVOrbGen(   el0,      t );
[r1,v1] = RVOrbGenDV( el0+dEl0, t, dV1, dV1Times );
[r2,v2] = RVOrbGenDV( el0+dEl0, t, dV2, dV2Times );
xHK1 = zeros(6,N);
xHK2 = zeros(6,N);

for i=1:N
   xHK1(:,i) = ECI2Hills( [r0(:,i);v0(:,i)], [r1(:,i);v1(:,i) ] );
   xHK2(:,i) = ECI2Hills( [r0(:,i);v0(:,i)], [r2(:,i);v2(:,i)] );
end

% transform element differences from GVE solution to Hills frame
xHD2 = zeros(6,N);
rD2  = zeros(3,N);
vD2  = zeros(3,N);

for i=1:N
   [rD2(:,i),vD2(:,i)] = El2RV( [el0(1:5),M(i)] + dEl(i,:) );
   xHD2(:,i) = ECI2Hills( [r0(:,i);v0(:,i)], [rD2(:,i);vD2(:,i)] );
end


figure('name','Keplerian Orbit Patches with Pure Impulsive Burns')
plot(t/T,xHD1(1:3,:),'linewidth',2), hold on
plot(t/T,xHD2(1:3,:),'--','linewidth',2)
plot(t/T,xHK1(1:3,:),':','linewidth',2)
plot(t/T,xHK2(1:3,:),'-.','linewidth',2)
grid on, zoom on,
xlabel('Time [orbits]')
ylabel('Position [km]')
legend('Hills-Frame Soln - Relative Propagation','GVE-Frame Soln - Relative Propagation',...
    'Hills-Frame Soln - Keplerian Propagation','GVE-Frame Soln - Keplerian Propagation')

fprintf('Position error norm between - Hills prop and GVE prop:  %f km\n',norm(xHD1-xHD2))
fprintf('Position error norm between - Hills prop and Keplerian: %f km\n',norm(xHD1-xHK1))
fprintf('Position error norm between -   GVE prop and Keplerian: %f km\n',norm(xHD2-xHK2))

fprintf('\nNow integrating the reference orbit and two controlled orbits in the ECI frame...\n')

% integrate absolute states in ECI frame
dT  = min(dt)/2;
nSI = round(t(end)/dT)+1;
time = 0:dT:dT*(nSI-1);
xE0 = zeros(6,nSI);  % reference orbit
xE1 = zeros(6,nSI);  % secondary orbit (Hills-based solution)
xE2 = zeros(6,nSI);  % secondary orbit (GVE-vased solution)
xE0(:,1) = [r0(:,1);v0(:,1)];
xE1(:,1) = [r1(:,1);v1(:,1)];
xE2(:,1) = [r2(:,1);v2(:,1)];

% thrust times
k   = find(Mag(aC1)>eps);
t0H = t(k);
tFH = t(k)+dt(k);
aCH = aC1(:,k);
k   = find(Mag(aC2)>eps);
t0G = t(k);
tFG = t(k)+dt(k);
aCG = aC2(:,k);

nBH = length(t0H);
nBG = length(t0G);
tX  = max([tFH,tFG])+dT;

zeroAcc = zeros(3,1);

% initialize time gui
global simulationAction
simulationAction = ' ';
tToGoMem.lastJD        = 0;
tToGoMem.lastStepsDone = 0;
tToGoMem.kAve          = 0;
ratioRealTime          = 0;
[ ratioRealTime, tToGoMem ] =  TimeGUI( nSI, 0, tToGoMem, 0, dT, 'Orbit Simulation' );

xHI1 = zeros(6,nSI);
xHI2 = zeros(6,nSI);
aH1p = zeros(3,nSI);
aH2p = zeros(3,nSI);

xHI1(:,1) = ECI2Hills( xE0(:,1), xE1(:,1) );
xHI2(:,1) = ECI2Hills( xE0(:,1), xE2(:,1) );

delay = 20;
next = delay;

rhs = @(x,a) [x(4:6); a - (3.98600436e5)*x(1:3)/norm(x(1:3))^3];

for i=2:nSI

   % compute thrust
   aH1 = zeroAcc;
   aH2 = zeroAcc;
   if( time(i-1) < tX )
      qEH = QHills( xE0(1:3,i-1), xE0(4:6,i-1) );
      for j=1:nBH
         f = ApplyDeltaV( t0H(j), tFH(j), time(i-1), dT );
         aH1 = aH1 + f*aCH(:,j);
      end
      for j=1:nBG
         f = ApplyDeltaV( t0G(j), tFG(j), time(i-1), dT );
         aH2 = aH2 + f*aCG(:,j);
      end
      a1 = QTForm( qEH, aH1 );
      a2 = QTForm( qEH, aH2 );
   else
      a1 = zeroAcc;
      a2 = zeroAcc;
   end

   % store applied acceleration
   aH1p(:,i-1) = aH1;
   aH2p(:,i-1) = aH2;

   % integrate states
   xE0(:,i) = RK4TI( rhs, xE0(:,i-1), dT, zeroAcc );
   xE1(:,i) = RK4TI( rhs, xE1(:,i-1), dT, a1 );
   xE2(:,i) = RK4TI( rhs, xE2(:,i-1), dT, a2 );

   % transform to Hills frame
   xHI1(:,i) = ECI2Hills( xE0(:,i), xE1(:,i) );
   xHI2(:,i) = ECI2Hills( xE0(:,i), xE2(:,i) );

   % time gui
   if( i > next )
      [ ratioRealTime, tToGoMem ] = TimeGUI( nSI, i, tToGoMem, ratioRealTime, dT );
      next = i + delay;
      switch simulationAction
         case 'pause'
            pause
            simulationAction = ' ';
         case 'stop'
            TimeGUI('close');
            return;
         case 'plot'
            break;
      end
   end

end
TimeGUI('close');

time = time(1:i);
xE0  = xE0(:,1:i);
xE1  = xE1(:,1:i);
xE2  = xE2(:,1:i);
xHI1 = xHI1(:,1:i);
xHI2 = xHI2(:,1:i);

ind = round(linspace(1,length(time),length(t)));

figure('name','Fine Orbit Integration with Matched Duration Burns')
plot(1,0,'k-',1,0,'k--',1,0,'k:',1,0,'k-.','linewidth',2), hold on
legend('Hills-Frame Soln - Relative Propagation','GVE-Frame Soln - Relative Propagation',...
    'Hills-Frame Soln - ECI Integration','GVE-Frame Soln - ECI Integration')
plot(t/T,xHD1(1:3,:),'linewidth',2), hold on
plot(t/T,xHD2(1:3,:),'--','linewidth',2)
plot(time(ind)/T,xHI1(1:3,ind),':','linewidth',2)
plot(time(ind)/T,xHI2(1:3,ind),'-.','linewidth',2)
grid on, zoom on,
xlabel('Time [orbits]')
ylabel('Position [km]')

figure
semilogy(t/T,[Mag(xHD1(1:3,:));Mag(xHD2(1:3,:))],...
   t/T,[Mag(xHK1(1:3,:));Mag(xHK2(1:3,:))],...
   time(ind)/T,[Mag(xHI1(1:3,ind));Mag(xHI2(1:3,ind))])
xlabel('Time [orbits]')
ylabel('|Pos. Error| [km]')

fprintf('Position error norm between - Hills prop and Integrated: %f km\n',...
    norm(interp1(t,xHD1',time(1:end-1))'-xHI1(:,1:end-1)))
fprintf('Position error norm between -   GVE prop and Integrated: %f km\n',...
    norm(interp1(t,xHD2',time(1:end-1))'-xHI2(:,1:end-1)))



%--------------------------------------
Planning a maneuver using "LPEccentric" and "LPEccentricGVE"...

Applying the maneuver and propagating dynamics in relative frames...

Now applying impulsive delta-vs to absolute orbit with Keplerian propagation...
Position error norm between - Hills prop and GVE prop:  0.000553 km
Position error norm between - Hills prop and Keplerian: 0.044794 km
Position error norm between -   GVE prop and Keplerian: 0.008876 km

Now integrating the reference orbit and two controlled orbits in the ECI frame...
Position error norm between - Hills prop and Integrated: 0.297520 km
Position error norm between -   GVE prop and Integrated: 0.031273 km