Verbesserungen am Skript für die Finite Burn Trajectory Optimization mit MATLAB

Ich habe ein MATLAB-Skript geschrieben, um den Zweipunkt-Grenzgleichungslöser bvp4c zu verwenden, um eine Trajektorienoptimierung des Calculus of Variations des Problems einer einzelnen endlichen Verbrennung mit einer freien Küste zu implementieren, um den optimalen Zündpunkt auszuwählen. Ich hätte gerne Beiträge zu Fehlern, die ich gemacht habe, oder Möglichkeiten, den Code zu verbessern. Was es tut, ist die optimale endliche Verbrennung von einer Umlaufbahn von 185 x 185 km auf eine Umlaufbahn von 185 x 1000 km mit einer optionalen Neigungsänderung. Es stellt ein Mehrpunkt-Grenzwertproblem auf, um ein Burn-Coast-Problem unter Verwendung der Primer-Vektorgleichung zu lösen.

Der Code basiert auf MATLAB-Code in den Anhängen von Optimal Control with Aerospace Applications von Longuski, Guzman und Prussing. Die Auslaufzeit und Brennzeiten wurden als freie Parameter implementiert und das Grenzwertproblem verwendet eine normalisierte Zeit (Tau), sodass [0,1] die Auslaufzeit und [1,2] die Brenndauer ist.

Die ODE implementiert die Bewegungsgleichungen und die Grundvektorgleichung für die Zentralkraftbewegung in kartesischen 3D-Koordinaten. Ich glaube, ich habe diese richtig verstanden, könnte aber jemanden gebrauchen, der meine Arbeit noch einmal überprüft. Die Multiplikation mit den Küsten- oder Brennzeiten in den Rückgabewert der ODE ist notwendig, um die Ableitung umzuwandeln d d t zu d d τ .

Die Randbedingungen sind etwas, zu dem ich eine Frage habe, ob ich es richtig gemacht habe. Anfangslage, Geschwindigkeit und Masse sind triviale Bedingungen. Es gibt auch 14 Bedingungen, die allen Variablen auf der linken und rechten Seite zwischen der Küste und dem Brand (Tau = 1) Kontinuität auferlegen.

Die verbleibenden Bedingungen sind die 5 Beschränkungen für die Endbedingungen der Umlaufbahn und dann die 3 Transversalitätsbedingungen, um die wahre Anomalie zu berücksichtigen, dass der Befestigungspunkt frei ist, und die Zeiten der Küste und der Verbrennung, die frei sind. Für die Endbahnbedingungen verwende ich den Drehimpulsvektor und die ersten beiden Komponenten des Exzentrizitätsvektors sind gleich der Zielbahn. Was ich für Transveralitätsbedingungen verwende, ist das, wenn der Hamiltonian zerlegt wird H = H 0 + T S wobei T die Schubkraft und S die Schaltfunktion ist, dann stelle ich ein H 0 ( t 2 ) = 0 , H 0 ( t 0 ) = 0 und dann mit S = ( | p v | 1 ) einstellen | p v ( t 1 ) | = 1 . Mir fehlt etwas Selbstvertrauen, dass ich das ganz richtig verstanden habe.

Die Ergebnisse scheinen ziemlich anständig zu sein, aber ich bin ein wenig überrascht, dass ich es nicht sehe | p v ( t 2 ) | = 1 . Ich sehe auch Konvergenzprobleme bei Problemen mit einer Neigung über etwa 25 Grad (aber das geht in 300 Sekunden / 3000 dV-Verbrennungen).

Ich habe die Einheiten für Position und Geschwindigkeit noch nicht normalisiert, also sind sie noch drin m und m / s .

Für mäßigere Verbrennungen scheint es ziemlich gut zu funktionieren und liefert Brennzeiten innerhalb von etwa einer Sekunde des impulsiven Verbrennungsmodells und sieht so aus, als ob es die Verbrennung mit einer negativen Küste von ungefähr der Hälfte der Brennzeit korrekt anführt.

Ich würde mich jedoch über jede Hilfe freuen, um Fehler zu finden, die ich gemacht habe, oder Möglichkeiten, diesen Code zu verbessern, um ihn robuster zu machen.

close all; clear all; clc;

global r0 v0 m0 rT vT g0
global MU Thrust Mdot

MU = 3.9860044189e+14;  % earth
Thrust = 232.7 * 1000;  % N; LR-91 232.7 kN
m0 = 32.74 * 1000;      % kg; 32.74t - 1g start accel
isp = 316;              % sec; LR-91
g0 = 9.80665;           % m/s; standard gravity
ve = isp * g0;          % m/s
a0 = Thrust / m0        % m/s^2; initial accel
tau = ve / a0           % s; time to burn rocket to zero
Mdot = Thrust / ve;     % kg/sec

rearth = 6.371e+6;      % m; earth radius
r185 = rearth + 0.185e+6;
r1000 = rearth + 1.000e+6;

% initial position (185x185)
r0 = [ r185, 0, 0 ];
v185 = sqrt(MU/r185);
v0 = [ 0, v185, 0 ];

% target orbital parameters (185x1000)
rT = [ r185, 0, 0 ];
smaT = ( r185 + r1000 ) / 2;
inc = 10;  % degrees
vTm = sqrt(MU * (2/r185 - 1/smaT) );
vT = [ 0, vTm * cosd(inc), vTm * sind(inc)];

vBurn = vT - v0;
dV = norm(vBurn)

% list initial conds
yinit = [r0 v0 vBurn/norm(vBurn) 0 0 0 m0 ];  % initial state and costate
tb_guess = tau * (1 - exp(-dV/ve) )
tc_guess = - tb_guess / 2

% sanity checks on the impulsive burn model
mf_impulsive = m0 - tb_guess * Mdot
af_impulsive = Thrust / mf_impulsive / g0

% parameters
parameters = [ tc_guess, tb_guess ];

% number of timeslices
Nt = 41;
tau = [
  linspace(0,1,Nt)'
  linspace(1,2,Nt)'
];

% initial guess
solinit = bvpinit(tau, yinit, parameters);

% bump up the mesh by a bit
option=bvpset('Nmax',50000);

% solve
sol = bvp4c(@Burn_odes, @Burn_bcs, solinit, option);

% extract times
tc = sol.parameters(1)
tb = sol.parameters(2)

% pull out values for times
Z = deval(sol, tau);

% convert taus to times
for i=1:length(tau)
  if tau(i) <= 1
    time(i) = tau(i) * tc;
  else
    time(i) = tc + ( tau(i) - 1 ) * tb;
  end
end

% extract solution vars
x_sol = Z(1,:);
y_sol = Z(2,:);
z_sol = Z(3,:);
r_sol = sqrt( x_sol.^2 + y_sol.^2 + z_sol.^2 );
vx_sol = Z(4,:);
vy_sol = Z(5,:);
vz_sol = Z(6,:);
v_sol = sqrt( vx_sol.^2 + vy_sol.^2 + vz_sol.^2 );
pvx_sol = Z(7,:);
pvy_sol = Z(8,:);
pvz_sol = Z(9,:);
pv_sol = sqrt( pvx_sol.^2 + pvy_sol.^2 + pvz_sol.^2 );
m_sol = Z(13,:);

for i = 1:length(tau)
  r = Z(1:3, i);
  v = Z(4:6, i);
  h(i) = norm(cross(r,v));
end

% plots

figure;
subplot(3,2,1);
plot(time,m_sol/1000);
ylabel('mass, tons', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

subplot(3,2,2);
plot(time,r_sol/1000);
ylabel('radius, km', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

subplot(3,2,3);
plot(time,v_sol/1000);
ylabel('velocity, km/s', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

subplot(3,2,4);
plot(time,h);
ylabel('h', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

subplot(3,2,5);
plot(time,pv_sol);
ylabel('pv magnitude', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

figure;
plot(x_sol/1000, y_sol/1000);
grid on;
axis equal
xlabel('x, km', 'fontsize', 14);
ylabel('y, km', 'fontsize', 14);


%
% Boundary conditions
%

function PSI = Burn_bcs(yleft, yright, parameters)

Y0 = yleft(:,1);
Y1 = yleft(:,2);  % == yright(:,1)
Y2 = yright(:,2);

global r0 v0 m0 rT vT MU g0 Thrust

ri = Y0(1:3);
vi = Y0(4:6);
pvi = Y0(7:9);
pri = Y0(10:12);
mi = Y0(13);
ri3 = norm(ri)^3;

rf = Y2(1:3);
vf = Y2(4:6);
pvf = Y2(7:9);
prf = Y2(10:12);
mf = Y2(13);
rf3 = norm(rf)^3;

r1 = Y1(1:3);
v1 = Y1(4:6);
pv1 = Y1(7:9);
pr1 = Y1(10:12);
r13 = norm(r1)^3;

hT = cross(rT, vT);
hf = cross(rf, vf);

eT = - (rT/norm(rT) + cross(hT,vT)/MU);
ef = - (rf/norm(rf) + cross(hf,vf)/MU);

emiss = ef - eT';

uf = pvf / norm(pvf);

H0ti = dot(pri, vi) - MU * dot(pvi, ri) / ri3;
H0t1 = dot(pr1, v1) - MU * dot(pv1, r1) / r13;
H0tf = dot(prf, vf) - MU * dot(pvf, rf) / rf3;
Htf = H0tf - Thrust * ( norm(pvf) - 1 );

PSI = [
    Y0(1:3) - r0'                       % 3 - initial position
    Y0(4:6) - v0'                       % 3 - initial velocity
    Y0(13) - m0                         % 1 - initial mass
    norm(Y1(7:9)) - 1                   % 1 - norm(pv1) = 1 (so H(t1) = 0 on both sides of t1)
    hf - hT'                            % 3 - terminal constraint on angular momentum
    emiss(1:2)                          % 2 - terminal constraint on ecc vector
    H0ti                                % 1 - H0(t0) = 0
    H0tf                                % 1 - H0(tf) = 0
    yleft(:,2) - yright(:,1)            % 14 - values at t1 are continuous
    ];

end

%
% Equations of motion
%

function dX_dtau = Burn_odes(tau, X, k, parameters)

global MU Thrust Mdot

if k == 1
  thr = 0;
  md = 0;
  tinterval = parameters(1);  % tc
else
  thr = Thrust;
  md = Mdot;
  tinterval = parameters(2);  % tb
end

r = X(1:3);
v = X(4:6);
pv = X(7:9);
pr = X(10:12);
m = X(13);

u = pv / norm(pv);

Fm = thr / m;
r3 = norm(r)^3;
r2 = dot(r,r);
r5 = norm(r)^5;

rdot  = v;
vdot  = - MU * r / r3 + Fm * u;
pvdot = pr;
prdot = - MU / r5 * ( 3 * r' * r - r2 * eye(3,3) ) * pv;

dX_dtau = tinterval*[rdot', vdot', pvdot', prdot', -md ];

end
Ich gebe zu, dass ich mit Longuskis Arbeit nicht sehr vertraut bin (obwohl ich das tun sollte, da ich an Finite-Burn-Optimierung und suboptimalen Lösungen arbeite), also entschuldigen Sie bitte die uninformierten Fragen. Können Sie uns erklären, warum die ersten drei Elemente des Co-Zustands die Norm des Geschwindigkeitsvektors sind (wenn ich richtig gelesen habe)? Gibt es außerdem einen bestimmten Grund, warum Sie alles in Metern statt in Kilometern kodiert haben? Sind Sie außerdem sicher, dass dieser TPBVP-Algorithmus mit großen Neigungsänderungen funktioniert? Viele Optimierungsalgorithmen brechen bei großen OE-Änderungen zusammen oder sobald einige Störungen aktiviert werden.
Wenn Sie sich auf Yinit beziehen, ist dies nur die anfängliche Vermutung des Primervektors costate, der ein Einheitsvektor in der progressiven Richtung ist. Die Primer-Vektorgleichung für die Küstenlinie befindet sich fast am Ende des Skripts.
Kein Grund von Metern statt km, und ich glaube, es sollte auf etwas normalisiert werden, das näher am Radius der Anfangs- oder Zielumlaufbahnen liegt. Es gibt ein zusätzliches Beispiel in dem Buch, das darauf eingeht, und es ist nur ein TODO, zu dem ich noch nicht gekommen bin.
Und dies ist mein erster Versuch mit richtigen Optimierungsproblemen (jeglicher Art), daher habe ich keine Ahnung, ob der TPBVP-Algorithmus mit großen Neigungsänderungen funktionieren sollte oder nicht. Wenn erwartet wird, dass Optimierer Schwierigkeiten mit diesem Problem haben, dann macht das Sinn (ich habe keine Ahnung, wie der bvp4c-Optimierer für diese Art von Problem geeignet ist, ich benutze ihn hauptsächlich, um mir selbst beizubringen, wie man diese Probleme in der erster Platz).
Ich weiß nicht genug über Variationsrechnung, um zu wissen, ob sie zusammenbricht: Ich werde einige Kollegen fragen, die hoffentlich eine Antwort für Sie haben werden. Was ich jedoch behaupten kann, ist, dass ein Lambert-Löser eine Möglichkeit ist, das TPBVP zu lösen, und es funktioniert definitiv für kleine Neigungsänderungen. Und ich sehe auch nicht ein, warum es selbst bei sehr großen Neigungsänderungen versagen sollte ... Das ist rätselhaft! Tolle Frage! :-D
Ich habe heute Morgen eine kleine Änderung vorgenommen, um die Schätzung für die anfängliche Costat in Richtung der impulsiven Verbrennungslösung und nicht nur in die prograde Richtung zu ändern, aber es scheint sich nicht viel zu ändern.
Möglicherweise kann ich dies erheblich umgestalten, um die Funktion ode45() in Matlab zusammen mit ein paar beliebten und robust aussehenden jacobianest()- und newtonraphson()-Routinen für den Mathworks-Dateiaustausch zu verwenden (und letztere scheint ein Quasi-Newton zu sein Ansatz, der sich zu einem Gradientenanstieg verschlechtert und daher für diese Art von Anwendung geeignet sein kann). Das Ergebnis sollte weitgehend allen CoV-Ansätzen in der Literatur entsprechen (analytische Behandlung der Küstenperiode und Normalisierung der Einheiten würden es abrunden).
Auch beim Lesen von Mehrpunkt-Grenzproblemen war mir nicht bewusst, dass Sie nicht nur über die Grenzpunkte integrieren, sondern (z. B.) Newton-Raphson an Ihren Grenzpunkten ausführen, was die Stabilität erhöht (anscheinend einige der Vorteile von Finite-Elemente-Methoden bei geringeren Kosten?). Ich denke also, dass das Zerhacken des Burn-Ups in 200-300s-Schritten die Stabilität erhöhen würde. Was mit dem übereinstimmt, was ich in der Literatur über die Trajektorienoptimierung von Aufstiegen gelesen habe.
Das Hinzufügen eines festen 200-Sekunden-Zusatzpunkts in der Verbrennung brachte mich zu einer stabilen Neigungsänderung von 30 Grad (was die Ausrollzeit auf 200 Sekunden erhöht). Ich werde versuchen, das Problem sowohl an der Küste als auch an der Küste dynamisch in 100-Sekunden-Intervalle aufzuteilen und zu sehen, wie das geht.
Bin auf dieses Papier gestoßen researchgate.net/publication/… das meiner Meinung nach alle Fragen abdeckt, die ich habe. Es sieht so aus, als müsste ich mich wirklich darauf konzentrieren, das Problem zu konditionieren, damit der Zustand und der Küstenzustand nahe Null normalisiert werden, und ich glaube, ich habe zumindest meine durcheinander gebracht H 0 ( t f ) = 0 Zustand, der sein sollte H ( t f ) = 0 und ich muss die Skalierungsprobleme mit dieser Bedingung ansprechen, die das Papier behandelt.
"... normalisiert nahe eins "
Ein großer Fehler, den ich gerade in der Costate / Primer-Vektorgleichung gefunden habe, ist, dass r' * res sich nur um das innere Punktprodukt handelt, während Sie r * r'dort das äußere Produkt benötigen (ich wusste, dass ich brauchte, dass ich nur einen Tippfehler hatte und es nie verifiziert habe).
Ich stimme dafür, diese Frage als nicht zum Thema gehörend zu schließen, da es darum geht, Gleichungen mit Matlab zu lösen. Die Gleichungen selbst sind relevant, aber die Frage dreht sich nicht um sie oder wie sie angewendet wurden.
Die Fragen zu den Randbedingungen gelten hier als Frage zur Orbitalmechanik, ich würde sagen, sie werden weder in der Frage noch in der Selbstantwort ausreichend hervorgehoben. Angesichts der Upvotes und der Kommentare, bevor die knappen Abstimmungen Monate später auftauchten, stimme ich dafür, es offen zu lassen.
@ErinAnne, die Grenzbedingungsfrage mag anwendbar sein, aber die Frage müsste stark bearbeitet werden, um sie zu behandeln - andernfalls sollte die Frage als zu weit gefasst werden.
Ich kann die Frage wahrscheinlich jetzt besser schreiben, obwohl ich nicht glaube, dass ich jetzt die Zeit habe, sie zu bearbeiten. Die Absicht der Frage ist jedoch "Ich versuche, einen Raketenflugbahnoptimierer (in Matlab) zu schreiben, und ich weiß nicht, was ich tue, Hilfe."
Und es geht über die Grenzwert-/Transversalitätsfragen hinaus. Ich begann mit dem Versuch, den bpv4c TPBPV-Solver von Matlab zu verwenden, als die von mir gewählte CoV/indirekte Methode ein TPBPV bereits in ein Integrations- und Root-Suchproblem verwandelte, sodass die Verwendung von ode45+fsolve() erheblich besser funktionierte. Ich weiß nicht, was ich mit bpv4c gemacht habe, aber es hat definitiv nicht funktioniert. Möglicherweise gibt es auch bessere Möglichkeiten, das ursprüngliche Problem der Trajektorienoptimierung mit Matlabs bpv4c zu lösen, und ich würde es trotzdem schätzen, wenn mir jemand zeigt, wie.
(Außerdem suchte ich speziell nach Beiträgen von Leuten, die Studenten oder darüber hinaus sein könnten und Raketenflugbahnoptimierung durchführen, nicht durchschnittliche Matlab-Benutzer - die Problemdomäne ist viel wichtiger als das Tool.)

Antworten (1)

Ich erkannte schließlich, dass ich durch den Versuch, das zu verwenden bvp4c, das ganze Problem schwieriger machte als nötig. Durch die Verwendung von CoV habe ich das Problem bereits von einem TPBVP in ein Wurzelfindungsproblem umgewandelt. Der standardmäßige Root-Finder fsolvein Matlab ist quasi-Newtonsch mit einer Dogleg-Vertrauensregion und unterstützt die Berechnung numerischer Jacobi. Das erfüllt alle Kriterien.

Also habe ich das obige Skript aktualisiert, um fsolve zu verwenden. Ich habe auch die numerische Konditionierung angewendet, die Ping Lu verwendet.

Es scheint den Fall einer Verbrennung zu bewältigen, um von einer äquatorialen Umlaufbahn von 185 x 185 km auf eine Umlaufbahn von 185 x 1000 mit einer Neigungsänderung von 89 Grad zu gelangen, und liefert plausibel aussehende Ergebnisse. Dauert auf meinem Desktop nur 0,4 Sekunden, wenn ich mit der anfänglichen Vermutung füttere, die dem impulsiven Brennen entspricht. Das ist eine Verbrennung von 11.089 dV, was in Bezug auf die Realität ziemlich albern wird, aber der Solver handhabt es.

Dieses Skript hat eine Besonderheit in den Randbedingungen, wenn es auf polare Umlaufbahnen zielt (die Referenz, von der ich die Randbedingungen erhalten habe, schlägt vor, die Vektoren durch eine Änderung des Koordinatensystems zu verschieben, um dies zu beheben). Deshalb habe ich eine 89-Grad-Änderung anstelle von 90 Grad verwendet.

Ich glaube, der größte numerische Mangel besteht hier darin, dass dies ein Single-Shooting-Ansatz ist und dass das Problem für mehrere Burn-Coast-Phasen einen Multiple-Shooting - Ansatz für zusätzliche Stabilität (oder für lange Burn- oder Coast-Arcs) verwenden sollte.

Ich werfe auch nur ODE45 auf die Integration der Lösung. Es wäre besser, die analytische Lösung von Goodyear für Küstenbögen zu verwenden. Ping Lu hat eine Reihe von Artikeln über verschiedene Ansätze zur analytischen Annäherung an die Burn Arcs veröffentlicht.

Ich bin mir auch immer noch nicht sicher, ob ich die 3 Randbedingungen für die freie Befestigung und Optimierung der Küsten- und Brennzeiten richtig habe - ich muss jetzt einfach zu denen zurückkehren, da ich eine stabilere Optimierungslösung habe.

Ich muss mich auch ein wenig mit der Bereinigung der Variablen im Code für die Normalisierung befassen - ich bin mir ziemlich sicher, dass my mu_barimmer algebraisch identisch ist 1.000..und vollständig gelöscht werden kann usw.

Um diesen Code auszuführen, ist Matlab R2017b erforderlich (für vecnorm) und die Funktion rv2orb() konvertiert Zustandsvektoren in keplersche Elemente und ist hier .

close all; clear all; clc;
format shortG;

mu = 3.9860044189e+14;  % m^3/s^2; earth
thrust = 232.7 * 1000;  % N; kg m / s^2; LR-91 232.7 kN
m0 = 32.74 * 1000;      % kg; 32.74t - 1g start accel
isp = 316;              % sec; LR-91
g0 = 9.80665;           % m/s; standard gravity
ve = isp * g0;          % m/s
a0 = thrust / m0;       % m/s^2; initial accel
tau = ve / a0;          % s; time to burn rocket to zero
mdot = thrust / ve;     % kg/sec

rearth = 6.371e+6;      % m; earth radius
r185   = rearth + 0.185e+6;
r1000  = rearth + 1.000e+6;
v185   = sqrt(mu/r185); % 185x185 velocity

% initial conditions
r0 = [ r185, 0, 0 ];
v0 = [ 0, v185, 0 ];

% target conditions
rT = [ r185, 0, 0 ];
smaT = ( r185 + r1000 ) / 2;
inc = 89; % degrees
vTm = sqrt(mu * (2/r185 - 1/smaT) );
vT = [ 0, vTm * cosd(inc), vTm * sind(inc)];

% impulsive burn approximation
dV = vT - v0;
dVm = norm(dV)
burnTime = tau * (1 - exp(-dVm/ve) )

% scaling factors
g_bar = mu / norm(r0)^2;
r_scale = norm(r0);
v_scale = sqrt( norm(r0) * g_bar );
t_scale = sqrt( norm(r0) / g_bar );

% applying scaling
tb_bar     = burnTime / t_scale;
tc_bar     = - burnTime / t_scale / 2;
r0_bar     = r0 / r_scale;
rT_bar     = rT / r_scale;
v0_bar     = v0 / v_scale;
vT_bar     = vT / v_scale;
mu_bar     = mu / r_scale^3 * t_scale^2;    % this is just always == 1.000 tho right?
thrust_bar = thrust / r_scale * t_scale^2;  % can these two...
mdot_bar   = mdot * t_scale;                % ...get simplified?

% solve the problem
fun = @(x) coastBurn5constraintFun(r0_bar, v0_bar, x(1:3), x(4:6), m0, x(7), x(8), mu_bar, thrust_bar, mdot_bar, rT_bar, vT_bar);

tic
[x, z, exitflag, output, jacobian] = fsolve(fun, [ dV/norm(dV) zeros(1,3) tc_bar tb_bar ]);
toc

disp(z');

disp(output);

% use the solution to pull data out of the IVP again
xinit = [ r0_bar v0_bar x(1:3) x(4:6) m0 ];
tc_bar = x(7);
tb_bar = x(8);
[x, tfull, xfull] = coastBurnIVP(xinit, tc_bar, tb_bar, mu_bar, thrust_bar, mdot_bar);

% reverse scaling
tfull = tfull * t_scale;
xfull(:,1:3) = xfull(:,1:3) * r_scale;
xfull(:,4:6) = xfull(:,4:6) * v_scale;

% print some output
rf = xfull(end, 1:3)
vf = xfull(end, 4:6)

tc = tc_bar * t_scale
tb = tb_bar * t_scale

[a,eMag,i,O,o,nu,truLon,argLat,lonPer,p] = rv2orb(rf', vf', mu);

inc = rad2deg(i)

PeR = (1 - eMag) * a
ApR = (1 + eMag) * a

PeA = PeR - rearth
ApA = ApR - rearth

% plots

figure;
subplot(3,2,1);
plot(tfull,xfull(:,13)/1000);
ylabel('mass, tons', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

subplot(3,2,2);
plot(tfull,vecnorm(xfull(:,1:3)')'/1000);
ylabel('radius, km', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

subplot(3,2,3);
plot(tfull,vecnorm(xfull(:,4:6)')'/1000);
ylabel('velocity, km/s', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

%subplot(3,2,4);
%plot(time,h);
%ylabel('h', 'fontsize', 14);
%xlabel('Time, sec', 'fontsize', 14);
%hold on;
%grid on;

subplot(3,2,5);
plot(tfull,vecnorm(xfull(:,7:9)')');
ylabel('pv magnitude', 'fontsize', 14);
xlabel('Time, sec', 'fontsize', 14);
hold on;
grid on;

%figure;
%plot(x_sol/1000, y_sol/1000);
%grid on;
%axis equal
%xlabel('x, km', 'fontsize', 14);
%ylabel('y, km', 'fontsize', 14);


% IVP function returning the 5-constraint BC miss
%
function z = coastBurn5constraintFun(r0_bar, v0_bar, pv, pr, m0, tc_bar, tb_bar, mu_bar, thrust_bar, mdot_bar, rT_bar, vT_bar)
  xinit = [ r0_bar v0_bar pv pr m0 ];
  [x, tfull, xfull] = coastBurnIVP(xinit, tc_bar, tb_bar, mu_bar, thrust_bar, mdot_bar);
  z = coastBurn5constraintBC(x, mu_bar, rT_bar, vT_bar);
end

% 5 orbital constraint Boundary Conditions for Coast-Burn with free times
%
function z = coastBurn5constraintBC(x, mu_bar, rT, vT)
  x0 = x(1,:);
  x1 = x(2,:);
  x2 = x(3,:);

  r0 = x0(1:3);
  v0 = x0(4:6);
  pv0 = x0(7:9);
  pr0 = x0(10:12);

  r1 = x1(1:3);
  v1 = x1(4:6);
  pv1 = x1(7:9);
  pr1 = x1(10:12);

  r2 = x2(1:3);
  v2 = x2(4:6);
  pv2 = x2(7:9);
  pr2 = x2(10:12);

  hT = cross(rT, vT);
  h2 = cross(r2, v2);

  hmiss = h2 - hT;

  eT = - (rT/norm(rT) + cross(hT, vT)/mu_bar);
  e2 = - (r2/norm(r2) + cross(h2, v2)/mu_bar);

  emiss = e2 - eT;

  H0t1 = dot(pr1, v1) - mu_bar * dot(pv1, r1) / norm(r1)^3;
  H0t2 = dot(pr2, v2) - mu_bar * dot(pv2, r2) / norm(r2)^3;

  z = [
    hmiss'          % 3 constraints
    emiss(1:2)'     % 2 constraints
    H0t1
    H0t2
    norm(pv0) - 1
  ];
end

% Multi step integration of the IVP
%
function [x, tfull, xfull] = coastBurnIVP(x0, tc, tb, mu, thrust, mdot)
  coastfun = @(t,x) centralForceThrustEOM(t, x, mu, 0, 0);  % FIXME: Use Goodyear instead of ODE45
  [t1, x1] = ode45(coastfun, [0 tc], x0);

  burnfun = @(t,x) centralForceThrustEOM(t, x, mu, thrust, mdot);
  [t2, x2] = ode45(burnfun, [tc tc+tb], x1(end,:));

  % x values at the boundaries
  x = [
    x1(1,:)
    x2(1,:)
    x2(end,:)
  ];

  % all the t's for graphing
  tfull = [
    t1
    t2
  ];

  % all the x's for graphing
  xfull = [
    x1
    x2
  ];
end

% Equations of Motion
%
function dX_dt = centralForceThrustEOM(t, X, mu, thrust, mdot)
  r  = X(1:3);
  v  = X(4:6);
  pv = X(7:9);
  pr = X(10:12);
  m  = X(13);

  u = pv/norm(pv);
  Fm = thrust / m;

  r3 = norm(r)^3;
  r2 = dot(r,r);
  r5 = r2 * r3;

  rdot  = v;
  vdot  = - mu * r / r3 + Fm * u;
  pvdot = pr;
  prdot = - mu / r5 * ( 3 * r * r' - r2 * eye(3,3) ) * pv;

  dX_dt = [ rdot' , vdot', pvdot', prdot', -mdot ]';
end
Tagge @ChrisR
Ich habe das obige Skript konvertiert, um eine Multipoint-Root-Suche durchzuführen, was sich als konzeptionell einfacher herausstellte, als ich erwartet hatte. Obwohl ich die festen Variablen (r0, v0 und m) herausgenommen habe, erhöht sich die Anzahl der Gleichungen immer noch von 8 auf 20 und die Zeit zum Lösen geht von 0,4 s auf 1,4 s.
Das Entfernen der Variablen scheint eine unnötige Mikrooptimierung zu sein. Das Erweitern auf ein 28-dimensionales Wurzellösungsproblem scheint nicht viel zu kosten (da die Anfangsbedingungen des Jacobian trival sind und die anfängliche Vermutung genau ist). Das beginnt, den Code zu vereinfachen. Die Implementierung von Levenburg-Marquardt fsolve() scheint ebenfalls geeignet zu sein, um diese Art von Problem zu lösen.