Demonstrate the performance of Safe Guidance Mode
A similar version of this safe guidance mode is used onboard the PRISMA formation flying spacecraft, Mango and Tango.
Since version 10. ------------------------------------------------------------------------ See also SafeGuidanceSim, PlotRun3D, DeltaVChart ------------------------------------------------------------------------
Contents
%-------------------------------------------------------------------------- % Copyright (c) 2012 Princeton Satellite Systems, Inc. % All rights reserved. %-------------------------------------------------------------------------- %--- BEGIN USER INPUT ---% % LOAD SIMULATION INPUT DATA setup = SafeGuidanceSimInit('prisma noise'); setup.nSPO = 300; setup.nOrbits = 5; setup.params.minTimeBtwnIPDeltaVs=3600; setup.params.minTimeBtwnDeltaVs=300; setup.params.dTSeparation = 1500; setup.params.margin = 30; setup.params.dMin = 60; setup.noise(3:4) = [.05 .001]; % NUMBER OF SIMULATIONS N = 10; % SELECT ONE TYPE OF INITIAL CONDITIONS: %initCond = 'nominal plus error'; initCond = 'collision course'; %initCond = 'inside avoidance region'; % TO REPRODUCE SAME CONDITIONS EACH TIME, SET RANDN STATE randn('state',0); % OPTIONS FOR "NOMINAL PLUS ERROR" opts.dist = setup.params.dMin+setup.params.margin+10; opts.goals = struct('y0',0,'aE',setup.params.dMin+setup.params.margin+10,'beta',0,'zInc',opts.dist,'zLan',opts.dist); opts.posErrSize = .5; % m opts.velErrSize = 1e-3; % m/s % OPTIONS FOR "COLLISION COURSE" opts.R_init_max = 150; % maximum position boundary (m) opts.R_init_min = 75; % minimum position boundary (m) opts.T_collide = 0.5; % time of collision (orbits) % OPTIONS FOR "INSIDE AVOIDANCE REGION" opts.R_mean = 10; % mean position boundary (m) opts.velScale = 1e-3; % relative velocity scale (m/s) %--- END USER INPUT ---% n = OrbRate(setup.el0(1)); T = 2*pi/n;
Warning: Using 'state' to set RANDN's internal state causes RAND, RANDI, and RANDN to use legacy random number generators. This syntax will be removed in a future release. See <a href="matlab:helpview([docroot '\techdoc\math\math.map'],'update_random_number_generator')">Updating Your Random Number Generator Syntax</a> to use RNG to replace the old syntax.
Print out key settings
%----------------------- disp('**************************************************************') fprintf('Run SafeGuidance %d times. Initial state: %s.\n',N,initCond) fprintf('Safe distance: %3.3g m\n',setup.params.dMin) fprintf('Separation Time: %3.3g s\n',setup.params.dTSeparation) fprintf('Max Drift / Orbit: %3.3g m\n',setup.params.maxDriftPerOrbit) disp('**************************************************************') d1 = setup.params.dMin; d2 = setup.params.dMin + setup.params.margin; [xc,yc]=Circle(setup.params.dMin,0,0,500); [xc2,yc2]=Circle(setup.params.dMin+setup.params.margin,0,0,500);
************************************************************** Run SafeGuidance 10 times. Initial state: collision course. Safe distance: 60 m Separation Time: 1.5e+03 s Max Drift / Orbit: 100 m **************************************************************
RANDOM INITIAL CONDITIONS...
%----------------------------- xH0 = zeros(6,N); switch initCond case 'nominal plus error' % nominal trajectory with random phase and random noise: beta = UnwrapPhase(randn(1,N)*2*pi); % relative ellipse phase xHErr = [opts.posErrSize*randn(3,N); opts.velErrSize*randn(3,N)]; % relative state error for i=1:N opts.goals.beta = beta(i); xH0(:,i) = Goals2Hills( setup.el0, opts.goals ) + xHErr(:,i); end case 'collision course' % generate a random Hills state % - initial position is bounded to be: % + within sphere of radius R_init_max, and % + outside a sphere of R_init_min % - initial velocity is computed to provide a collision at time T_collide collTime = opts.T_collide*T; rH0 = [randn(2,N);zeros(1,N)]*mean([opts.R_init_min,opts.R_init_max]); vH0 = zeros(3,N); % initialize here, computed below dH0 = Mag(rH0); for i=1:N if( dH0(i)<opts.R_init_min ) rH0(:,i) = rH0(:,i)/dH0(i)*opts.R_init_min; elseif( dH0(i)>opts.R_init_max ) rH0(:,i) = rH0(:,i)/dH0(i)*opts.R_init_max; end vH0(:,i) = PositionDeltaV( rH0(:,i), zeros(3,1), zeros(3,1), n, collTime ); end xH0 = [rH0;vH0]; case 'inside avoidance region' % In-plane rH0 = [randn(2,N);zeros(1,N)]*opts.R_mean; vH0 = [randn(2,N);zeros(1,N)]*opts.velScale; xH0 = [rH0;vH0]; % ensure all initial positions are INSIDE region k = find( xH0(2,:).^2+4*xH0(1,:).^2 >= .999*setup.params.dMin^2 ); if( ~isempty(k) ) phase = atan2(xH0(2,k),-xH0(1,k)); xH0(2,k)=0.99*setup.params.dMin*sin(phase); xH0(1,k)=-.5*0.99*setup.params.dMin*cos(phase); end end
Initialize simulation variables
r0 = zeros(3,N); v0 = r0; mD = zeros(1,N); dV = zeros(1,N); xSet = cell(1,N); dVSet = cell(1,N); iSet = cell(1,N); minDist = 1e5; % init to large number maxDV = 0; dT = T/setup.nSPO; vxmod = []; dvtt = []; hw = waitbar(0,sprintf('Running %d simulations...',N)); iMax = [];
Run N cases of FFRelSim with random initial conditions
for i=1:N % compute initial orbital element differences setup.xH0 = xH0(:,i); setup.dEl0 = Hills2DeltaElem( setup.el0, setup.xH0*1e3 ); % run simulation d = SafeGuidanceSim( setup ); % compute min distance mD(i) = min( Mag( d.xH(1:3,:) ) ); % actual min-distance % compute total delta-v dV(i) = sum(Mag(d.aCont(:,2:end)).*diff(d.time)*T); % km/s dV(i) = sum(Mag(d.dVapp)); % km/s % store min dist case if( mD(i) < minDist ) minDist = mD(i); sMin = setup; dMin = d; xHMinUA = HillsEqns( setup.xH0, n, dMin.time*T, 1 ); iMin = i; end % store max dv case if( dV(i) > maxDV ) maxDV = dV(i); sMax = setup; dMax = d; xHMaxUA = HillsEqns( setup.xH0, n, dMax.time*T, 1 ); iMax = i; end % store initial relative position and velocity r0(:,i) = setup.xH0(1:3); v0(:,i) = setup.xH0(4:6); % store entire SLO frame trajectory and controls xSLO = d.xSLO; xSet{i} = xSLO; dVSet{i} = Hills2LVLH(d.aCont)*dT; iSet{i} = d.inside; waitbar(i/N); end close(hw);
Display / plot results
fprintf('\n**************************************************************\n') fprintf('Average Delta-V: %3.3g m/s\n',mean(dV)) fprintf('Highest Delta-V: %3.3g m/s\n',max(dV)) fprintf('Average Min-Distance: %3.3g m\n',mean(mD)) fprintf(' Lowest Min-Distance: %3.3g m\n',min(mD)) disp('**************************************************************') k = find( mD<setup.params.dMin ); [xcmin,zcmin] = Circle(opts.R_init_min,0,0,500); [xcmax,zcmax] = Circle(opts.R_init_max,0,0,500); f=[]; f(end+1) = figure('name','Initial States'); plot(r0(2,:),r0(1,:),'*'), set(gca,'fontsize',14), hold on if( strcmp(initCond,'collision course') ) plot(xcmin,zcmin,'m--',xcmax,zcmax,'m--') end plot(xc,yc/2,'k--') axis equal grid on xlabel('Along-Track [m]') ylabel('Radial [m]') %------------------------------------------ % analysis plots for minimum distance case SafeGuidanceSimPlots(dMin); %------------------------------------------ % MIN DIST CASE fName = sprintf('MIN DISTANCE Case (#%d, %4.1f m)', iMin, minDist ); f(end+1)=PlotRun3D( xSet, dVSet, iSet, iMin, d1, d2 ); set(f(end),'name',fName); %------------------------------------------ % MAX DV CASE if( ~isempty(iMax) ) fName = sprintf('MAX DELTA-V Case (#%d, %1.4f m/s)', iMax, maxDV ); f(end+1)=PlotRun3D( xSet, dVSet, iSet, iMax, d1, d2 ); set(f(end),'name',fName); end %------------------------------------------ % Minimum Distance Bar Chart f(end+1) = figure('name','Minimum Distance'); bar( mD ); set(gca,'fontsize',14), title('Minimum Distance'), xlabel('Case #'), ylabel('Min Dist [m]') %------------------------------------------ % Delta-V Bar Chart f(end+1) = figure('name','Delta-V'); dVstack = zeros(N,3); maxSepBurns = 0; maxNomBurns = 0; maxCTBurns = 0; for i=1:N [kSep,kNom,kCT] = SafeGuidanceBurnData( dVSet{i}, iSet{i} ); dVstack(i,1) = sum(Mag(dVSet{i}(:,kSep))); dVstack(i,2) = sum(Mag(dVSet{i}(:,kNom))) - sum(Mag(dVSet{i}(:,kCT))); dVstack(i,3) = sum(Mag(dVSet{i}(:,kCT))); if( length(kSep) == maxSepBurns && ~isempty(kSep) ) maxSepBurnsCase(end+1) = i; elseif( length(kSep) > maxSepBurns ) maxSepBurnsCase = i; maxSepBurns = length(kSep); end if( length(kNom) == maxNomBurns && ~isempty(kNom) ) maxNomBurnsCase(end+1) = i; elseif( length(kNom) > maxNomBurns ) maxNomBurnsCase = i; maxNomBurns = length(kNom); end if( length(kCT) == maxCTBurns && ~isempty(kCT) ) maxCTBurnsCase(end+1) = i; elseif( length(kCT) > maxCTBurns ) maxCTBurnsCase = i; maxCTBurns = length(kCT); end end bar( dVstack,'stacked' ); grid on set(gca,'fontsize',14) title('Delta-V'), xlabel('Case #'), ylabel('Delta-V [m/s]') legend('Separation','Nominal IP','Nominal CT') % delta-v chart for maximum delta-v case DeltaVChart( d.time, dVSet, iMax ); fprintf('Maximum number of Separation burns: %d\n\tCases: %s\n',maxSepBurns,num2str(maxSepBurnsCase)); fprintf('------------------------------------------------\n') fprintf('Maximum number of Nominal burns: %d\n\tCases: %s\n',maxNomBurns,num2str(maxNomBurnsCase)); fprintf('------------------------------------------------\n') fprintf('Maximum number of Cross-Track burns: %d\n\tCases: %s\n',maxCTBurns,num2str(maxCTBurnsCase)); fprintf('**************************************************************\n') Figui; %-------------------------------------- % PSS internal file version information %--------------------------------------
************************************************************** Average Delta-V: 0.213 m/s Highest Delta-V: 0.26 m/s Average Min-Distance: 40 m Lowest Min-Distance: 34.8 m ************************************************************** Maximum number of Separation burns: 1 Cases: 1 2 3 4 5 6 7 8 9 10 ------------------------------------------------ Maximum number of Nominal burns: 6 Cases: 2 ------------------------------------------------ Maximum number of Cross-Track burns: 5 Cases: 2 **************************************************************