├── earth.png
├── cw_rr.m
├── cw_vr.m
├── ta_from_E.m
├── cw_vv.m
├── cw_rv.m
├── ecc_anomaly_from_ta.m
├── delta_m.m
├── rocket_equation.m
├── README.md
├── rot2.m
├── rot3.m
├── rot1.m
├── time_of_transfer.m
├── hyp_anomaly.m
├── stumpff.m
├── ecc_anomaly_from_M.m
├── ra_and_dec_from_r.m
├── fDot_and_gDot_ta.m
├── f_and_g_ta.m
├── ecc_anomaly.m
├── f_and_g.m
├── fdot_and_gdot.m
├── rv_from_r0v0_ta.m
├── sidereal.m
├── topo_to_geo.m
├── wait_time.m
├── atmosphere.m
├── trajectory.m
├── rotation.m
├── planetary_departure.m
├── rv_from_coe.m
├── binary_trajectory.m
├── ground_track_from_rv.m
├── lvlh_from_sv.m
├── hohmann.m
├── kepler_convert.m
├── planet_select.m
├── universal_lagrange.m
├── two_impulse_rend.m
├── time_to_transfer_window.m
├── phasing_maneuver.m
├── coe_from_rv.m
├── gibbs.m
├── runge_kutta_fehlberg.m
├── date_after_transfer.m
├── non_impulse_thrust.m
├── rv_from_obs.m
├── lambert.m
├── binary_plot.m
├── geocentric_track.m
├── rkf45.m
├── twobody.m
├── ground_track_from_coe.m
├── planet_sv.m
├── iss_tracking.m
├── euler_rotation.m
├── orbit.m
├── iss_current_track.m
├── interplanetary_trajectory.m
└── rocket_launch.m
/earth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/jeremy-penn/Orbital_Mechanics/HEAD/earth.png
--------------------------------------------------------------------------------
/cw_rr.m:
--------------------------------------------------------------------------------
1 | function phi_rr = cw_rr(t,n)
2 |
3 | phi_rr = [4-3*cos(n*t), 0, 0
4 | 6*(sin(n*t) - n*t) 1 0
5 | 0 0 cos(n*t)];
6 | end
--------------------------------------------------------------------------------
/cw_vr.m:
--------------------------------------------------------------------------------
1 | function phi_vr = cw_vr(t,n)
2 |
3 | phi_vr = [3*n*sin(n*t), 0, 0
4 | 6*n*(cos(n*t)-1), 0, 0
5 | 0, 0, -n*sin(n*t)];
6 |
7 | end
--------------------------------------------------------------------------------
/ta_from_E.m:
--------------------------------------------------------------------------------
1 | function th = ta_from_E(E, e)
2 | %% Calculates the true anomaly [rad] from the eccentric anomaly [rad]
3 |
4 | th = 2*atan( sqrt( (1+e)/(1-e) )*tan(E/2) );
5 | end
--------------------------------------------------------------------------------
/cw_vv.m:
--------------------------------------------------------------------------------
1 | function phi_vv = cw_vv(t,n)
2 |
3 | phi_vv = [cos(n*t), 2*sin(n*t), 0
4 | -2*sin(n*t), 4*cos(n*t)-3, 0
5 | 0, 0, cos(n*t)];
6 |
7 | end
--------------------------------------------------------------------------------
/cw_rv.m:
--------------------------------------------------------------------------------
1 | function phi_rv = cw_rv(t,n)
2 |
3 | phi_rv = [(1/n)*sin(n*t), (2/n)*(1-cos(n*t)), 0
4 | (2/n)*(cos(n*t)-1), (1/n)*(4*sin(n*t)-3*n*t), 0
5 | 0, 0, (1/n)*sin(n*t)];
6 |
7 | end
--------------------------------------------------------------------------------
/ecc_anomaly_from_ta.m:
--------------------------------------------------------------------------------
1 | function E = ecc_anomaly_from_ta(th,e)
2 | %% Calculates the eccentric anomaly [rad] from the true anomaly [deg]
3 | th1 = mod(th, 360);
4 |
5 | th2 = th1 * pi/180;
6 |
7 | E = 2*atan( sqrt( ((1-e)/(1+e)) )*tan(th2/2) );
8 | end
--------------------------------------------------------------------------------
/delta_m.m:
--------------------------------------------------------------------------------
1 | function delta_m(m, isp, g0, v)
2 | clc;
3 |
4 | %% calculating the mass of propellant burned for a maneuver
5 | dm = m * ( 1 - exp( - v/(isp*g0) ) );
6 |
7 | %% print the results
8 | fprintf('The final mass of the spacecraft is %.2f [kg]\n',m - dm)
9 | end
--------------------------------------------------------------------------------
/rocket_equation.m:
--------------------------------------------------------------------------------
1 | function dv = rocket_equation(isp, m0, mf, g)
2 | if nargin == 0
3 | isp = input('Input specific impulse of the rocket engine (s): \n');
4 | m0 = input('Input the initial mass of the rocket (kg):\n');
5 | mf = input('Input the final mass of the rocket (kg):\n');
6 | g = input('Input magnitude of surface gravity (m/s^2):\n');
7 | end
8 |
9 | dv = g*isp*log(m0/mf);
10 | end
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Orbital_Mechanics
2 |
3 | This is a repository of useful orbital dynamics programs. All equations are taken from Orbital Mechanics for Engineering Students by Howard D. Curtis
4 |
5 | ## Citations:
6 |
7 | - rkf45.m, Howard D. Curtis, Orbital Mechanics for Engineering Students, Third Edition, 2010
8 |
9 | - atmosphere.m, Howard D. Curtis, Orbital Mechanics for Engineering Students, Third Edition, 2010
10 |
--------------------------------------------------------------------------------
/rot2.m:
--------------------------------------------------------------------------------
1 | function rot2 = rot2(th)
2 | %% Create the rotation matrix about the y-axis
3 | %
4 | % Jeremy Penn
5 | % 18 October 2017
6 | %
7 | % Revision 22/09/17
8 | %
9 | % function rot2 = rot2(th)
10 | %
11 | % Purpose: This function calculates the rotation matrix about the
12 | % y-axis
13 | %
14 | % Inputs: o th - The rotation angle.
15 | %
16 | % Output: o rot2 - Rotation matrix about the y-axis.
17 | %
18 |
19 | %% Create the matrix
20 |
21 | rot2 = [cos(th),0,-sin(th);0,1,0;sin(th),0,cos(th)];
22 | end
--------------------------------------------------------------------------------
/rot3.m:
--------------------------------------------------------------------------------
1 | function rot3 = rot3(th)
2 | %% Create the rotation matrix about the y-axis
3 | %
4 | % Jeremy Penn
5 | % 18 October 2017
6 | %
7 | % Revision 22/09/17
8 | %
9 | % function rot3 = rot3(th)
10 | %
11 | % Purpose: This function calculates the rotation matrix about the
12 | % z-axis
13 | %
14 | % Inputs: o th - The rotation angle.
15 | %
16 | % Output: o rot3 - Rotation matrix about the x-axis.
17 | %
18 |
19 | %% Create the matrix
20 |
21 | rot3 = [cos(th),sin(th),0;-sin(th),cos(th),0;0,0,1];
22 | end
--------------------------------------------------------------------------------
/rot1.m:
--------------------------------------------------------------------------------
1 | function rot1 = rot1(th)
2 | %% Create the rotation matrix about the x-axis
3 | %
4 | % Jeremy Penn
5 | % 18 October 2017
6 | %
7 | % Revision 22/09/17
8 | %
9 | % function rot1 = rot1(th)
10 | %
11 | % Purpose: This function calculates the rotation matrix about the
12 | % x-axis
13 | %
14 | % Inputs: o th - The rotation angle. [rad]
15 | %
16 | % Output: o rot1 - Rotation matrix about the x-axis.
17 | %
18 |
19 | %% Create the matrix
20 |
21 | rot1 = [1,0,0;0,cos(th),sin(th);0,-sin(th),cos(th)];
22 | end
--------------------------------------------------------------------------------
/time_of_transfer.m:
--------------------------------------------------------------------------------
1 | function time = time_of_transfer(R1, R2, mu)
2 | %% Calculate the time of interplanetary transfer
3 | %
4 | % Jeremy Penn
5 | % 06/11/17
6 | %
7 | % Input: o R1 - The orbital semimajor axis of the departing planet
8 | % o R2 - The orbital semimajor axis of the arrival planet
9 | % o mu - grav parameter [OPTIONAL]
10 | %
11 | % Output: o time - transfer flight time [s]
12 | %
13 | clc;
14 |
15 | %% constants
16 | if nargin == 2
17 | mu = 132.71e9; % [km^3/s^2]
18 | end
19 |
20 | %% calculate the transfer time
21 | time = (pi/sqrt(mu)) * ( (R1 + R2)/2 )^1.5; %[s]
22 |
23 | end
--------------------------------------------------------------------------------
/hyp_anomaly.m:
--------------------------------------------------------------------------------
1 | function F = hyp_anomaly(e, M)
2 | %% Calculates the hyperbolic anomaly
3 | %
4 | % Jeremy Penn
5 | % 22 October 2017
6 | %
7 | % Revision 22/10/17
8 | %
9 | % function F = hyp_anomaly(e, M)
10 | %
11 | % Purpose: This function calculates the hyperbolic anomaly given the
12 | % eccentricity and hyperbolic mean anomaly.
13 | %
14 | % Inputs: o e - Eccentricity
15 | % o M - Mean anomaly [radians]
16 | %
17 | % Outputs: o F - Hyperbolic anomaly [radians]
18 | %
19 |
20 | %% Initial guess
21 | F = M;
22 |
23 | %% Calculate F until within desired tolerance
24 | tol = 1e-08;
25 | ratio = 1;
26 |
27 | while abs(ratio) > tol
28 | ratio = (e*sinh(F) - F - M) / (e*cosh(F) - 1);
29 | F = F - ratio;
30 | end
--------------------------------------------------------------------------------
/stumpff.m:
--------------------------------------------------------------------------------
1 | function [Cz, Sz] = stumpff(z)
2 | %% Stumpff Functions
3 | %
4 | % Jeremy Penn
5 | % 22 September 2017
6 | %
7 | % Revision:19/10/17
8 | %
9 | % function [Cz, Sz] = Stumpff(z)
10 | %
11 | % Purpose: This function calculates the given Stumpff functions.
12 | %
13 | % Inputs: o z - The argument of the Stumpff function.
14 | %
15 | % Outputs: o Cz - The cosine Stumpff function.
16 | % o Sz - The sine Stumpff function.
17 | %
18 |
19 | if (z > 0)
20 | Sz = (z^0.5 -sin(z^0.5))/z^1.5; %C3 Stumpff
21 | Cz = (1 - cos(z^0.5))/z; %C2 Stumpff
22 | elseif (z < 0)
23 | Sz = (sinh(-z^0.5) - (-z)^0.5)/((-z)^1.5); %C3 Stumpff (negative argument)
24 | Cz = (cosh(-z^0.5) - 1)/(-z); %C2 Stumpff (negative argument)
25 | else
26 | Sz = 1/6;
27 | Cz = 0.5;
28 | end
29 | end
30 |
31 |
--------------------------------------------------------------------------------
/ecc_anomaly_from_M.m:
--------------------------------------------------------------------------------
1 | function E = ecc_anomaly_from_M(e, M)
2 | %% Calculates the eccentric anomaly
3 | %
4 | % Jeremy Penn
5 | % 22 October 2017
6 | %
7 | % Revision 22/10/17
8 | %
9 | % function E = ecc_anomaly(e, M)
10 | %
11 | % Purpose: This function calculates the eccentric anomaly given the
12 | % eccentricity and mean anomaly.
13 | %
14 | % Inputs: o e - Eccentricity
15 | % o M - Mean anomaly [radians]
16 | %
17 | % Outputs: o E - Eccentric anomaly [radians]
18 | %
19 |
20 | %% Choose initial estimate for E
21 | if M < pi
22 | E = M + e/2;
23 | else
24 | E = M - e/2;
25 | end
26 |
27 | %% Calculate the ratio to given tolerance
28 | tol = 1e-08;
29 | ratio = 1;
30 |
31 | while abs(ratio) > tol
32 | ratio = (E - e*sin(E) - M)/(1 - e*cos(E));
33 | E = E - ratio;
34 | end
35 | end
--------------------------------------------------------------------------------
/ra_and_dec_from_r.m:
--------------------------------------------------------------------------------
1 | function [RA , dec] = ra_and_dec_from_r(r)
2 | %% Convert Cartesian Coordinates to Right Ascension and Declination
3 | %
4 | % Jeremy Penn
5 | % 22 September 2017
6 | %
7 | % Revision 22/09/17
8 | %
9 | % function [RA , dec] = R2RA_Dec(r)
10 | %
11 | % Purpose: This function converts the position vector, r, into the
12 | % Right Acension and Declination.
13 | %
14 | % Inputs: o r - a 1x3 vector of the x, y and z positions of the
15 | % satellite.
16 | %
17 | % Output: o RA - The Right Ascension [deg]
18 | % o dec - The Declination [deg]
19 | %
20 | l = r(1)/norm(r);
21 | m = r(2)/norm(r);
22 | n = r(3)/norm(r);
23 |
24 | dec = asin(n);
25 |
26 | if m > 0
27 | RA = acos(l/cos(dec))*180/pi;
28 | else
29 | RA = 360 - acos(l/cos(dec))*180/pi;
30 | end
31 |
32 | dec = dec*180/pi;
33 | end
--------------------------------------------------------------------------------
/fDot_and_gDot_ta.m:
--------------------------------------------------------------------------------
1 | function [fdot, gdot] = fDot_and_gDot_ta(r0, v0, dt, mu)
2 | %% This function calculates the Lagrange fdot and gdot coefficients from the
3 | % change in true anomaly since time t0
4 | %
5 | % Jeremy Penn
6 | % 19/11/2017
7 | %
8 | % function [fdot, gdot] = fDot_and_gDot_ta(r0, v0, dt, mu)
9 | %
10 | % Inputs: o mu - gravitational parameter (km^3/s^2)
11 | % o dt - change in true anomaly (degrees)
12 | % o r0 - position vector at time t0 (km)
13 | % o v0 - velocity vector at time t0 (km/s)
14 | %
15 | % Outputs: o fdot - the Lagrange f coefficient (dimensionless)
16 | % o gdot - the Lagrange g coefficient (s)
17 | %
18 |
19 | h = norm(cross(r0,v0));
20 | vr0 = dot(v0,r0)/norm(r0);
21 | r0 = norm(r0);
22 | c = cosd(dt);
23 | s = sind(dt);
24 |
25 | %...Equations 2.158c & d:
26 | fdot = mu/h*(vr0/h*(1 - c) - s/r0);
27 | gdot = 1 - mu*r0/h^2*(1 - c);
28 |
29 | end
--------------------------------------------------------------------------------
/f_and_g_ta.m:
--------------------------------------------------------------------------------
1 | function [f, g] = f_and_g_ta(r0, v0, dt, mu)
2 | %% This function calculates the Lagrange f and g coefficients from the
3 | % change in true anomaly since time t0
4 | %
5 | % Jeremy Penn
6 | % 19/11/2017
7 | %
8 | % function [f, g] = f_and_g_ta(r0, v0, dt, mu)
9 | %
10 | % Inputs: o mu - gravitational parameter (km^3/s^2)
11 | % o dt - change in true anomaly (degrees)
12 | % o r0 - position vector at time t0 (km)
13 | % o v0 - velocity vector at time t0 (km/s)
14 | %
15 | % Outputs: o f - the Lagrange f coefficient (dimensionless)
16 | % o g - the Lagrange g coefficient (s)
17 | %
18 |
19 | h = norm(cross(r0,v0));
20 | vr0 = dot(v0,r0)/norm(r0);
21 | r0 = norm(r0);
22 | s = sind(dt);
23 | c = cosd(dt);
24 |
25 | %...Equation 2.152:
26 | r = h^2/mu/(1 + (h^2/mu/r0 - 1)*c - h*vr0*s/mu);
27 |
28 | %...Equations 2.158a & b:
29 | f = 1 - mu*r*(1 - c)/h^2;
30 | g = r*r0*s/h;
31 |
32 | end
--------------------------------------------------------------------------------
/ecc_anomaly.m:
--------------------------------------------------------------------------------
1 | function E = ecc_anomaly(e, M)
2 | %% Calculates the eccentric anomaly
3 | %
4 | % Jeremy Penn
5 | % 22 October 2017
6 | %
7 | % Revision 22/10/17
8 | %
9 | % function E = ecc_anomaly(e, M)
10 | %
11 | % Purpose: This function calculates the eccentric anomaly given the
12 | % eccentricity and mean anomaly.
13 | %
14 | % Inputs: o e - Eccentricity
15 | % o M - Mean anomaly [radians]
16 | %
17 | % Outputs: o E - Eccentric anomaly [radians]
18 | %
19 | clc; clear E;
20 |
21 | %% Choose initial estimate for E
22 | if M < pi
23 | E = M + e/2;
24 | else
25 | E = M - e/2;
26 | end
27 |
28 | %% Calculate the ratio to given tolerance
29 | tol = 1e-08;
30 | ratio = 1;
31 |
32 | while abs(ratio) > tol
33 | ratio = (E - e*sin(E) - M)/(1 - e*cos(E));
34 | E = E - ratio;
35 | end
36 |
37 | fprintf('The Eccentric Anomaly is %4.4f [rad]\n', E)
38 |
39 |
40 | end
--------------------------------------------------------------------------------
/f_and_g.m:
--------------------------------------------------------------------------------
1 | function [f,g] = f_and_g(x, R0, dt, a, mu)
2 | %% f and g functions
3 | %
4 | % Jeremy Penn
5 | % 25 October 2017
6 | %
7 | % Revision 25/10/17
8 | %
9 | % function [f,g] = f_and_g(x, R0, dt, a, mu)
10 | %
11 | % Purpose: This function calculates the f and g functions from the
12 | % universal anomaly.
13 | %
14 | % Inputs: o x - The universal anomaly [km^0.5].
15 | % o R0 - The position vector at time dt [km].
16 | % o dt - The change in time since perigee [s].
17 | % o a - The reciprical of the semi-major axis [km^-1].
18 | % o mu - The Standard Grav Para [km^3/s^2] [OPTIONAL].
19 | %
20 | % Outputs: o f - The f function.
21 | % o g - The g function.
22 | %
23 | % Requires: stumpff.m
24 | %
25 |
26 | if nargin == 4
27 | mu = 398600;
28 | end
29 |
30 | r0 = norm(R0);
31 | z = a*x^2;
32 | [Cz,Sz] = stumpff(z);
33 |
34 | f = 1 - x^2/r0 * Cz;
35 | g = dt - ( 1/sqrt(mu) )* x^3 * Sz;
36 |
37 | end
--------------------------------------------------------------------------------
/fdot_and_gdot.m:
--------------------------------------------------------------------------------
1 | function [fdot,gdot] = fdot_and_gdot(x, R0, r, a, mu)
2 | %% f and g functions
3 | %
4 | % Jeremy Penn
5 | % 25 October 2017
6 | %
7 | % Revision 25/10/17
8 | %
9 | % function [fdot,gdot] = fdot_and_gdot(x, R0, r, a, mu)
10 | %
11 | % Purpose: This function calculates the f and g functions from the
12 | % universal anomaly.
13 | %
14 | % Inputs: o x - The universal anomaly [km^0.5].
15 | % o R0 - The position vector at time dt [km].
16 | % o r - The magnitude of the new position [km].
17 | % o a - The reciprical of the semi-major axis [km^-1].
18 | % o mu - The Standard Grav Para [km^3/s^2] [OPTIONAL].
19 | %
20 | % Outputs: o fdot - The fdot function.
21 | % o gdot - The gdot function.
22 | %
23 | % Requires: stumpff.m
24 | %
25 | if nargin == 4
26 | mu = 398600;
27 | end
28 |
29 | r0 = norm(R0);
30 | z = a*x^2;
31 | [Cz,Sz] = stumpff(z);
32 |
33 | fdot = (sqrt(mu)/(r*r0)) * ( a*x^3*Sz - x );
34 | gdot = 1 - (x^2/r) *Cz;
35 | end
--------------------------------------------------------------------------------
/rv_from_r0v0_ta.m:
--------------------------------------------------------------------------------
1 | function [r,v] = rv_from_r0v0_ta(r0, v0, dt, mu)
2 | %% This function computes the state vector (r,v) from the
3 | % initial state vector (r0,v0) and the change in true anomaly.
4 | %
5 | % Jeremy Penn
6 | % 19/11/2017
7 | %
8 | % function [r,v] = rv_from_r0v0_ta(r0, v0, dt, mu)
9 | %
10 | % Inputs: o mu - gravitational parameter (km^3/s^2)
11 | % o r0 - initial position vector (km)
12 | % o v0 - initial velocity vector (km/s)
13 | % o dt - change in true anomaly (degrees)
14 | % o r - final position vector (km)
15 | % o v - final velocity vector (km/s)
16 | %
17 | % Output: o r - new position vector (km)
18 | % o v - new velocity vector (km/s)
19 | %
20 | % Required: f_and_g_ta, fDot_and_gDot_ta
21 | %
22 |
23 | %...Compute the f and g functions and their derivatives:
24 | [f, g] = f_and_g_ta(r0, v0, dt, mu);
25 | [fdot, gdot] = fDot_and_gDot_ta(r0, v0, dt, mu);
26 |
27 | %...Compute the final position and velocity vectors:
28 | r = f*r0 + g*v0;
29 | v = fdot*r0 + gdot*v0;
30 |
31 | end
--------------------------------------------------------------------------------
/sidereal.m:
--------------------------------------------------------------------------------
1 | function stime = sidereal(y, m, d,h, min, sec,gam)
2 | %% Calculate the sidereal time from the given date and UT time
3 | %{
4 | Jeremy Penn
5 | 21 October 2017
6 |
7 | Revision: 21/10/17
8 | 09/11/17 - replaced while loops with mod to keep ang
9 | between 0 and 360
10 |
11 | function stime = sidereal(y, m, d,h, min, sec)
12 |
13 | Purpose: This function calculates the sidereal time.
14 |
15 | Inputs: o y - The year
16 | o m - The month
17 | o d - The day
18 | o h - The hour
19 | o min - The minutes
20 | o sec - The seconds
21 | o gam - The eastward longitude
22 |
23 | Outputs: o stime - The sidereal time
24 | %}
25 |
26 | j0 = 367*y - fix(7*(y + fix((m + 9)/12))/4) + fix((275*m)/9) + d + 1721013.5;
27 | T0 = (j0 - 2451545) / 36525;
28 |
29 | thg0 = 100.4606184 + 36000.77004*T0 + 0.000387933*T0^2 - 2.583e-08*T0^3;
30 |
31 | thg0 = mod(thg0, 360);
32 |
33 | UT = h + min/60 + sec/3600;
34 | thg = thg0 + 360.98564724*(UT/24);
35 | th = thg + gam;
36 |
37 | th = mod(th, 360);
38 |
39 | stime = th;
40 | end
--------------------------------------------------------------------------------
/topo_to_geo.m:
--------------------------------------------------------------------------------
1 | function topo_to_geo(th, phi, A, a)
2 | %% Coverts from topocentric to geocentric coordinates
3 | %
4 | % Jeremy Penn
5 | % 22/10/2017
6 | %
7 | % Revision: 22/10/2017
8 | %
9 | % function topo_to_geo(Del, th, phi, A, a)
10 | %
11 | % Input: o th - The local sidereal time [deg]
12 | % o phi - The latitude of the observer [deg]
13 | % o A - The azimuth angle of the target [deg]
14 | % o a - The angular elevation of the object [deg]
15 | %
16 | % Requires: ra_and_dec_from_r.m
17 | %
18 |
19 | clc;
20 |
21 | %% Convert from degrees to radians
22 | th = th * pi/180;
23 | phi = phi * pi/180;
24 | A = A * pi/180;
25 | a = a * pi/180;
26 |
27 | %% Set up the rotation matrix
28 | Q = [-sin(th), -sin(phi)*cos(th), cos(phi)*cos(th); cos(th), -sin(phi)*sin(th), cos(phi)*sin(th); 0, cos(phi), sin(phi)];
29 |
30 | %% Calculate the position in topo coordinates, rho
31 | rho = [cos(a)*sin(A); cos(a)*cos(A); sin(a)];
32 |
33 | %% Convert coordinates
34 | r = Q*rho;
35 |
36 | %% Calculate the RA and Dec
37 | [RA,Dec] = ra_and_dec_from_r(r);
38 |
39 | fprintf('The RA of the object in the Geocentric frame is %5.2f [deg]\n',RA)
40 | fprintf('The Dec of the object in the Geocentric frame is %5.2f [deg]\n',Dec)
41 | end
--------------------------------------------------------------------------------
/wait_time.m:
--------------------------------------------------------------------------------
1 | function wait_time()
2 | %% Calculate the wait time after Hohmann transfer for return transfer
3 | %
4 | % Jeremy Penn
5 | % 06/11/17
6 | %
7 | % Required: planet_select.m, time_of_transfer.m
8 | %
9 | clc;
10 |
11 | %% inputs
12 | planet1 = input('Input the departure planet:\n','s');
13 | planet2 = input('Input the target planet:\n','s');
14 |
15 | planet1 = lower(planet1);
16 | planet2 = lower(planet2);
17 |
18 | dp = planet_select(planet1);
19 | da = planet_select(planet2);
20 |
21 | n1 = 2*pi/dp(8);
22 | n2 = 2*pi/da(8);
23 |
24 | t12 = time_of_transfer(dp(5),da(5)) / 86400;
25 |
26 | %% calculate the phase angle after transfer
27 | phif = pi - n1*t12;
28 |
29 | %% calculate the wait time
30 | if n1 > n2
31 | N = 0;
32 | twait = (-2*phif - 2*pi*N) / (n2 - n1);
33 |
34 | while twait < 0
35 | N = N + 1;
36 | twait = (-2*phif - 2*pi*N) / (n2 - n1);
37 | end
38 |
39 | elseif n2 > n1
40 | N = 0;
41 | twait = (-2*phif + 2*pi*N) / (n2 - n1);
42 |
43 | while twait < 0
44 | N = N + 1;
45 | twait = (-2*phif + 2*pi*N) / (n2 - n1);
46 | end
47 |
48 | else
49 | error('Error: n1 and n2 can not be equal')
50 | end
51 |
52 | fprintf('The wait time is %.2f days\n',twait)
53 | end
--------------------------------------------------------------------------------
/atmosphere.m:
--------------------------------------------------------------------------------
1 | function density = atmosphere(z)
2 | %
3 | % ATMOSPHERE calculates density for altitudes from sea level
4 | % through 1000 km using exponential interpolation.
5 | %
6 |
7 | %...Geometric altitudes (km):
8 | h = ...
9 | [ 0 25 30 40 50 60 70 ...
10 | 80 90 100 110 120 130 140 ...
11 | 150 180 200 250 300 350 400 ...
12 | 450 500 600 700 800 900 1000];
13 |
14 | %...Corresponding densities (kg/m^3) from USSA76:
15 | r = ...
16 | [1.225 4.008e-2 1.841e-2 3.996e-3 1.027e-3 3.097e-4 8.283e-5 ...
17 | 1.846e-5 3.416e-6 5.606e-7 9.708e-8 2.222e-8 8.152e-9 3.831e-9 ...
18 | 2.076e-9 5.194e-10 2.541e-10 6.073e-11 1.916e-11 7.014e-12 2.803e-12 ...
19 | 1.184e-12 5.215e-13 1.137e-13 3.070e-14 1.136e-14 5.759e-15 3.561e-15];
20 |
21 | %...Scale heights (km):
22 | H = ...
23 | [ 7.310 6.427 6.546 7.360 8.342 7.583 6.661 ...
24 | 5.927 5.533 5.703 6.782 9.973 13.243 16.322 ...
25 | 21.652 27.974 34.934 43.342 49.755 54.513 58.019 ...
26 | 60.980 65.654 76.377 100.587 147.203 208.020];
27 |
28 | %...Handle altitudes outside of the range:
29 | if z > 1000
30 | z = 1000;
31 | elseif z < 0
32 | z = 0;
33 | end
34 |
35 | %...Determine the interpolation interval:
36 | for j = 1:27
37 | if z >= h(j) && z < h(j+1)
38 | i = j;
39 | end
40 | end
41 | if z == 1000
42 | i = 27;
43 | end
44 |
45 | %...Exponential interpolation:
46 | density = r(i)*exp(-(z - h(i))/H(i));
47 |
48 | end
--------------------------------------------------------------------------------
/trajectory.m:
--------------------------------------------------------------------------------
1 | function [Ri,Vi] = trajectory(R0,V0,dt,step,mu)
2 | %% Calculate And Plot Trajectory
3 | %
4 | % Jeremy Penn
5 | % 22 September 2017
6 | %
7 | % Revision 22/09/17
8 | %
9 | % function [Ri] = trajectory(R0,V0,mu,dt,step)
10 | %
11 | % Purpose: This function calculates the trajectory of a satellite
12 | % around the Earth over a given time interval.
13 | %
14 | % Inputs: o R0 - A 1x3 vector describing the initial position of the
15 | % satellite.
16 | % o V0 - A 1x3 vector describing the initial velocity of the
17 | % satellite.
18 | % o dt - The total time interval in seconds
19 | % o step - The calculation step size in seconds
20 | % o mu - The Standard Grav Parameter [OPTIONAL]. Defaults
21 | % to Earth [km^3/s^2]
22 | %
23 | % Output: o Ri - A matrix of the calculated positions
24 | % o Vi - A matrix of the calculated velocities
25 | %
26 | % Requires: universal_lagrange.m
27 | %
28 |
29 | clc; clear R V Long Lat t ind Ri;
30 |
31 | if nargin == 4
32 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
33 | end
34 |
35 | t = 0; %[s] Initial time
36 | ind = 1;
37 | N = (dt / step);
38 | Ri = zeros(N,3);
39 | Vi = zeros(N,3);
40 | while (t < dt)
41 | [R, V] = universal_lagrange(R0, V0, t,mu);
42 | Ri(ind,:) = R;
43 | Vi(ind,:) = V;
44 | ind = ind + 1;
45 | t = t + step;
46 | end
47 | %
48 | end
--------------------------------------------------------------------------------
/rotation.m:
--------------------------------------------------------------------------------
1 | function r = rotation(R,th,phi,rho)
2 | %% Coordinate Rotation once about each axis
3 | %
4 | % Jeremy Penn
5 | % 18 October 2017
6 | %
7 | % Revision 22/09/17
8 | %
9 | % function r = rotation(R,th,phi,rho)
10 | %
11 | % Purpose: This program calculates the new position vector after applying
12 | % rotations of th(x-axis), phi(y-axis), and rho(z-axis).
13 | %
14 | % Inputs: o R - A 1x3 vector to be rotated.
15 | % o th - The rotation angle about the x-axis.
16 | % o phi - The rotation angle about the y-axis.
17 | % o rho - The rotation angle about the z-axis.
18 | %
19 | % Outputs: o r - The new vector after rotation.
20 | %
21 | % Requires: rot1.m, rot2.m, rot3.m
22 | %
23 |
24 | clear r; clc;
25 |
26 | %% Make sure angles are between 0 and 360
27 | th = mod(th,360);
28 | phi = mod(phi,360);
29 | rho = mod(rho,360);
30 |
31 | %% Convert degrees to radians
32 | th = th * pi/180;
33 | phi = phi * pi/180;
34 | rho = rho * pi/180;
35 |
36 | %% Check R is a column vector
37 |
38 | if isrow(R)
39 | R = transpose(R);
40 | end
41 |
42 | %% Set up the rotation matrix
43 |
44 | rotx = rot1(th);
45 | roty = rot2(phi);
46 | rotz = rot3(rho);
47 |
48 | %% Perform the rotation
49 |
50 | r = rotx*roty*rotz*R;
51 |
52 | %% Display new vector
53 |
54 | fprintf('The x componant after rotation is %4.2f\n', r(1))
55 | fprintf('The y componant after rotation is %4.2f\n', r(2))
56 | fprintf('The z componant after rotation is %4.2f\n', r(3))
57 | end
58 |
59 |
--------------------------------------------------------------------------------
/planetary_departure.m:
--------------------------------------------------------------------------------
1 | function planetary_departure(R1, R2, r, mu_e, Re)
2 | %% Calculate the deltav and ejection angle for planetary transfer
3 | %
4 | % Jeremy Penn
5 | % 09 November 2017
6 | %
7 | % Revision: 09/11/17
8 | %
9 | % function planetary_departure(R1, R2, r, mu_e)
10 | %
11 | % Input: o R1 - orbital radius of the inital planet
12 | % o R2 - orbital radius of the target planet
13 | % o r - orbital height above the surface of initial
14 | % planet
15 | % o mu_e - standard grav param [OPTIONAL]
16 | % o Re - planetary radius [OPTIONAL]
17 | %
18 | %
19 | clc;
20 |
21 | %% constants
22 | mu_s = 1.327e11; %[km^3 / s^2] gravitational param of the Sun
23 |
24 | if nargin == 3
25 | Re = 6378; %[km] radius of the Earth
26 | mu_e = 398600; %[km^3 / s^2] gravitational param of the Earth
27 | end
28 |
29 | %% calculate the hyperbolic excess velocity
30 | vinf = sqrt( mu_s / R1 ) * ( sqrt(2*R2 / (R1+R2)) -1 );
31 |
32 | %% calculate the speed of the parking orbit
33 | vc = sqrt( mu_e / (Re+r) );
34 |
35 | %% delta-v for the hyperbolic escape trajectory
36 | dv = vc * ( sqrt( 2 + (vinf/vc)^2 ) -1 );
37 | dv = dv * 1000;
38 |
39 | %% calculate the escape angle
40 | e = 1 + ( (Re+r)*vinf^2 ) / mu_e;
41 |
42 | beta = acos(1/e);
43 |
44 | beta = beta * 180/pi;
45 |
46 | beta = mod(beta,360);
47 |
48 | %% print the results
49 | fprintf('The delta-v of the trans-planetary injection burn is %.2f [m/s]\n',dv)
50 | fprintf('The ejection angle is %.2f [deg]\n', beta)
51 | end
--------------------------------------------------------------------------------
/rv_from_coe.m:
--------------------------------------------------------------------------------
1 | function [r , v] = rv_from_coe(h, e, i, omega, w, theta, mu)
2 | %% Calculate the state vector from classical orbital elements
3 | %
4 | % Jeremy Penn
5 | % 28 October 2017
6 | %
7 | % Revision: 28/10/17
8 | %
9 | % function [r , v] = rv_from_coe(h, e, i, omega, w, theta, mu)
10 | %
11 | % Input: o h - Specific angular momentum
12 | % o e - eccentricity
13 | % o i - orbital inclination
14 | % o omega - right ascension of the ascending node
15 | % o w - argument of perigee
16 | % o theta - true anomaly
17 | % o mu - standard grav param [OPTIONAL]
18 | %
19 | % Output: o r - The position vector
20 | % o v - The velocity vector
21 | %
22 | % Requires: rot1.m, rot3.m
23 | %
24 |
25 | if nargin == 6
26 | mu = 398600;
27 | end
28 |
29 | %% Confirm angles are between 0 and 360
30 | i = mod(i, 360);
31 | omega = mod(omega, 360);
32 | w = mod(w, 360);
33 | theta = mod(theta, 360);
34 |
35 | %% Convert deg to rad
36 | dtor = pi/180;
37 | i = i * dtor;
38 | omega = omega * dtor;
39 | w = w * dtor;
40 | theta = theta * dtor;
41 |
42 |
43 | %% Calculate the position vector in the perifocal frame
44 | rp = (h^2/mu) * ( 1/(1+e*cos(theta)) ) * [cos(theta); sin(theta); 0];
45 |
46 | %% Calculate the velocity vector in the perifocal frame
47 | vp = (mu/h) * [-sin(theta); e + cos(theta); 0];
48 |
49 | %% Calculate the transform matrix from perifocal to geocentric
50 | Q = ( rot3(w)*rot1(i)*rot3(omega) )';
51 |
52 | %% Transform from perifocal to geocentric
53 | r = Q * rp;
54 | v = Q * vp;
55 |
56 | end
--------------------------------------------------------------------------------
/binary_trajectory.m:
--------------------------------------------------------------------------------
1 | function [rf1,rf2] = binary_trajectory(R0,V0,m1,m2,dt,step)
2 | %% Calculate the relative tracjectories for two bodies orbiting their center of mass
3 | %
4 | % Jeremy Penn
5 | % 21 September 2017
6 | %
7 | % Revision: 21/09/17
8 | % 21/10/17 - Moved print functionality to binary_plot.
9 | %
10 | % function [rf1,rf2] = binaryTrajectory(R0,V0,m1,m2,dt,step)
11 | %
12 | % Purpose: This function calculates the trajectories of two objects about
13 | % their common center of mass.
14 | %
15 | % Inputs: o R0 - A 1x3 vector of the initial separation vector
16 | % between m1 and m2.
17 | % o V0 - A 1x3 vector of the initial total velocity vector.
18 | % o dt - The time difference (tf - ti).
19 | % o step - The step size for the calculation
20 | % o m1 - Mass of object 1 in solar mass
21 | % o m2 - Mass of object 2 in solar mass
22 | %
23 | % Requires: universal_lagrange.m
24 | %
25 |
26 | clc; clear R V t ind RedMassN rf1 rf2;
27 |
28 | t = 0; %[s] Initial time
29 | ind = 1;
30 | mn1 = m1 * 1.988e+30; %[kg] Convert mass to kg
31 | mn2 = m2 * 1.988e+30; %[kg] Convert mass to kg
32 | RedMass = (mn1*mn2) / (mn1 + mn2); %[kg] Reduced Mass
33 | G = 6.647e-25; %[km^3/kg s^2] Grav Constant
34 | mu = G * (mn1 + mn2);
35 | N = (dt / step);
36 | rf1 = zeros(N,3); %[km] Final Position of m1
37 | rf2 = zeros(N,3); %[km] Final Position of m2
38 | while (t < dt)
39 | [R, V] = universal_lagrange(R0, V0, t, mu);
40 | rf1(ind,:) = (RedMass/m1)*R;
41 | rf2(ind,:) = -(RedMass/m2)*R;
42 | ind = ind + 1;
43 | t = t + step;
44 | end
45 | end
--------------------------------------------------------------------------------
/ground_track_from_rv.m:
--------------------------------------------------------------------------------
1 | function ground_track_from_rv(R0, V0, n, mu, Re, J2, we)
2 | %% Calculate and plot the geocentric orbit of a satellite about the Earth
3 | %
4 | % Jeremy Penn
5 | % 21 October 2017
6 | %
7 | % Revision: 21/10/17
8 | % 29/10/2017 - Changed RA from 0:360 to -180:180
9 | % 30/10/2017 - Changed dependecy to ground_track_from_coe.m
10 | %
11 | % function ground_track(R0, V0, dt, step, mu)
12 | %
13 | % Purpose: This function plots the ground track of a satellite in the
14 | % geocentric frame of reference. Additionally, it creates a
15 | % video of the ground track.
16 | %
17 | % Inputs: o R0 - A 1x3 vector of the satellite's initial position
18 | % o V0 - A 1x3 vector of the satellite's initial velocity
19 | % o n - number of orbits
20 | % o mu - standard grav param [OPTIONAL]
21 | % o Re - central body radius [OPTIONAL]
22 | % o J2 - central body second zonal harmonic [OPTIONAL]
23 | % o we - central body angular speed [OPTIONAL]
24 | %
25 | % Requires: coe_from_rv.m, ground_track_from_coe.m
26 | %
27 |
28 | clc;
29 | if nargin == 2
30 | n = 1;
31 | Re = 6378; % [km] radius of the Earth
32 | we = 7.27e-5; % [rad/s] angular speed of Earth
33 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
34 | J2 = 0.0010836;
35 | end
36 |
37 | if nargin == 3
38 | Re = 6378; % [km] radius of the Earth
39 | we = 7.27e-5; % [rad/s] angular speed of Earth
40 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
41 | J2 = 0.0010836;
42 | end
43 |
44 | %% Calculate classic orbital elements
45 | [h, e, i, omega, w, theta] = coe_from_rv(R0, V0, mu);
46 |
47 | %% Calculate the track
48 | ground_track_from_coe(h,e,i,omega,w,theta,n, mu, Re, J2, we)
49 | end
--------------------------------------------------------------------------------
/lvlh_from_sv.m:
--------------------------------------------------------------------------------
1 | function lvlh_from_sv(Ra, Rb, Va, Vb, mu)
2 | %% Calculate the relative position, velocity, and accel of B wrt A
3 | %
4 | % Jeremy Penn
5 | % 02/11/0217
6 | %
7 | % Revision: 02/11/0217
8 | %
9 | % Purpose: This function calculates the relative position, velocity and
10 | % acceleration of B with respect to A.
11 | %
12 | % function LVLH_from_sv(Ra, Rb, Va, Vb)
13 | %
14 | % Input: o Ra - The position of A in geocentric coordinates
15 | % o Rb - The position of B in geocentric coordinates
16 | % o Va - The velocity of A in geocentric coordinates
17 | % o Vb - The velocity of B in geocentric coordinates
18 | %
19 |
20 | clc;
21 |
22 | %% Constants
23 | if nargin == 4
24 | mu = 398600;
25 | end
26 |
27 | ra = norm(Ra);
28 | rb = norm(Rb);
29 |
30 | %% Calculate the angular momentum of A
31 | Ha = cross(Ra,Va);
32 |
33 | %% Calculate the unit vectors i, j, k (comoving frame)
34 | i = Ra / ra;
35 | k = Ha / norm(Ha);
36 | j = cross(k, i);
37 |
38 | %% Calculate the orthogonal transformation matrix QXx
39 | QXx = [i; j; k];
40 |
41 | %% Calculate W and dW
42 | W = Ha / (ra^2);
43 | dW = -2 * ( dot(Va,Ra) / ra^2 ) * W;
44 |
45 | %% Calculate the absolute accel of A and B
46 | aA = - ( mu/ra^3 ) * Ra;
47 | aB = - ( mu/rb^3 ) * Rb;
48 |
49 | %% Calculate relative R, V, & A in geocentric frame
50 | Rr = Rb - Ra;
51 | Vr = Vb - Va - cross(W, Rr);
52 | Ar = aB - aA - cross(dW, Rr) - cross(W, cross(W,Rr)) - cross(2*W, Vr);
53 |
54 | %% Calculate the relative r, v, & a in the comoving frame
55 | r = QXx * Rr';
56 | v = QXx * Vr';
57 | a = QXx * Ar';
58 |
59 | %% Print the results
60 | fprintf('The relative position in LVLH coordinates is %f *i, %f *j, %f *k [km]\n', r)
61 | fprintf('The relative velocity in LVLH coordinates is %f *i, %f *j, %f *k [km/s]\n', v)
62 | fprintf('The relative acceleration in LVLH coordinates is %f *i, %f *j, %f *k [km/s^2]\n', a)
63 | end
--------------------------------------------------------------------------------
/hohmann.m:
--------------------------------------------------------------------------------
1 | function hohmann(Ria,Rip,Rfa,Rfp,m, isp)
2 | %% Calculates the delta-v to Hohmann transfer from orbit 1 to 2
3 | %
4 | % Jeremy Penn
5 | % 23/10/2017
6 | %
7 | % Revision: 23/10/2017
8 | %
9 | % function hohmann(Ria,Rip,Rfa,Rfp)
10 | %
11 | % Purpose: This function calculates the delta-v necessary to Hohmann
12 | % transfer from orbit 1 to 2. Additionally, it calculates the fuel
13 | % usage.
14 | %
15 | % Input: o Ria - The altitude of the apoapis of the initial orbit [km]
16 | % o Rip - The altitude of the periapis of the initial orbit [km]
17 | % o Rfa - The altitude of the apoapis of the final orbit [km]
18 | % o Rfp - The altitude of the perigee of the final orbit [km]
19 | % o m - The mass of the spacecraft before 1st manuveur [kg]
20 | % o isp - The specific impulse of the engine [s]
21 | %
22 |
23 | clc;
24 | mu = 398600; %[km^3/s^2]
25 | g = 9.807; %[m/s^2]
26 |
27 | %% Cacluate altitude from center of the Earth
28 | Ria = Ria + 6378;
29 | Rip = Rip + 6378;
30 | Rfa = Rfa + 6378;
31 | Rfp = Rfp + 6378;
32 |
33 | %% Calculate the angular momenta
34 | h1 = sqrt(2*mu)*sqrt((Ria*Rip)/(Ria + Rip));
35 | h2 = sqrt(2*mu)*sqrt((Rfa*Rip)/(Rfa + Rip));
36 | h3 = sqrt(2*mu)*sqrt((Rfa*Rfp)/(Rfa + Rfp));
37 |
38 | %% Calculate the speed at each point
39 | va1 = h1 / Rip;
40 | va2 = h2 / Rip;
41 | va = va2 - va1;
42 | va = va*1000; %convert to [m/s]
43 |
44 | vb2 = h2 / Rfa;
45 | vb3 = h3 / Rfa;
46 | vb = vb3 - vb2;
47 | vb = vb*1000; %convert to [m/s]
48 |
49 | deltav = abs(va) + abs(vb);
50 |
51 | %% Calculate mass of propellant expended
52 |
53 | deltam = m*(1 - exp(-(deltav /(isp*g))));
54 | newm = m - deltam;
55 |
56 | fprintf('The delta-v requirement for Hohmann insertion is %.2f [m/s]\n', va)
57 | fprintf('The delta-v requirement for Hohmann breaking is %.2f [m/s]\n', vb)
58 | fprintf('The total delta-v requirement for Hohmann transfer is %.2f [m/s]\n', deltav)
59 | fprintf('The mass of the propellant expended is %.2f [kg]\n', deltam)
60 | fprintf('The new mass of the vessel is %.2f [kg]\n',newm)
61 | end
--------------------------------------------------------------------------------
/kepler_convert.m:
--------------------------------------------------------------------------------
1 | function kepler = kepler_convert(R,V,mu)
2 | %% Calculate all six orbital elements fromega the initial position and velocity
3 | %
4 | % Jeremy Penn
5 | % 15 October 2017
6 | %
7 | % Revision 19/10/17
8 | %
9 | % function kepler = keplerConvert(R,V)
10 | %
11 | % Purpose: This function converts the state vector [R,V] into the six
12 | % keplerian orbital elements.
13 | %
14 | % Inputs: o R - A 1x3 vector of the satellite's initial position
15 | % o V - A 1x3 vector of the satellite's initial velocity
16 | % o mu - The standard Grav Param [OPTIONAL].
17 | %
18 | % Outputs: o kepler - A 1x6 vector containing the orbital elements.
19 | %
20 |
21 | if nargin == 2
22 | mu = 398600;
23 | end
24 |
25 | %% Set up the initial conditions
26 |
27 | r = norm(R);
28 | v = norm(V);
29 | vr = dot(R,V) / r; % If vr > 0 object is moving away fromega perigee
30 |
31 | %% Calculate the specific angular momegaentum
32 |
33 | H = cross(R,V);
34 | h = norm(H);
35 |
36 | %% Calculate the inclination
37 |
38 | i = acos(H(3) / h) * (180/pi);
39 |
40 | %% Calculate node line vector
41 |
42 | k = [0, 0, 1];
43 | N = cross(k,H);
44 | n = norm(N);
45 |
46 | %% Calculate the right ascension of the ascending node
47 |
48 | if N(2) >= 0
49 | omega = acos(N(1) / n) * (180/pi);
50 | else
51 | omega = 360 - acos(N(1) / n) * (180/pi);
52 | end
53 |
54 | %% Calculate the eccentricity
55 |
56 | E = (1 / mu)*((v^2 - (mu / r))*R - vr*V);
57 | e = norm(E);
58 |
59 | %% Calculate the argument of perigee
60 |
61 | if E(3) >= 0
62 | w = acos(dot(N,E)/(n*e)) * (180/pi);
63 | else
64 | w = 360 - acos(dot(N,E)/(n*e)) * (180/pi);
65 | end
66 |
67 | %% Calculate the true anomegaaly
68 |
69 | if vr >= 0
70 | theta = acos(dot(E/e,R/r)) * (180/pi);
71 | else
72 | theta = 360 - acos(dot(E/e,R/r)) * (180/pi);
73 | end
74 |
75 | %% Calculate a
76 |
77 | a = (h^2/mu)*(1/(1-e^2));
78 |
79 | %% Place results into vector
80 |
81 | kepler = [a; e; i; omega; w; theta];
82 | end
83 |
--------------------------------------------------------------------------------
/planet_select.m:
--------------------------------------------------------------------------------
1 | function planet_data = planet_select(planet)
2 | %% provides astronomical data for the solar system
3 | %
4 | % Jeremy Penn
5 | % 13/11/17
6 | %
7 | % function planet_data = planet_select(planet)
8 | %
9 | % Puropose: This function provides the astronomical data of the solar
10 | % system output in vector form.
11 | %
12 | % Output: o planet_data - vector of astro data in the form:
13 | % [Radius (km), Mass(kg), Sidereal Rot Period (d), Inc of Eq to Orbit plane (deg),...
14 | % semimajor axis of orbit (km), eccentricity, Inc of orbit to ecliptic (deg), ...
15 | % Orbit sidereal period (d), Standard Gravitationa Parameter (km^3/s^2)]
16 |
17 | planet = lower(planet);
18 |
19 | switch planet
20 | case 'sun'
21 | planet_data = [696000, 1.989e30, 25.38, 7.25, NaN, NaN, NaN, NaN, 132.7e9];
22 | case 'mercury'
23 | planet_data = [2440, 330.2e21, 58.65, .01, 57.91e6, .2056, 7, 87.97, 22030];
24 | case 'venus'
25 | planet_data = [6052, 4.869e24, 243, 177.4, 108.2e6, .0067, 3.39, 224.7, 324900];
26 | case 'earth'
27 | planet_data = [6371, 5.974e24, 23.9345, 23.45, 149.6e6, .0167, 0, 365.256, 398600];
28 | case 'moon'
29 | planet_data = [1737, 73.48e21, 27.32, 6.68, 384.4e3, .0549, 5.145, 27.322, 4903];
30 | case 'mars'
31 | planet_data = [3396, 641.9e21, 24.62, 25.19, 227.9e6, .0935, 1.85, 1.881*365.256, 42828];
32 | case 'jupiter'
33 | planet_data = [71490, 1.899e27, 9.925, 3.13, 778.6e6, .0489, 1.304, 11.86*365.256, 126686000];
34 | case 'saturn'
35 | planet_data = [60270, 568.5e24, 10.66, 26.73, 1.433e9, .0565, 2.485, 29.46*365.256, 37931000];
36 | case 'uranus'
37 | planet_data = [25560, 86.83e24, 17.24, 97.77, 2.872e9, .0457, .772, 84.01*365.256, 5794000];
38 | case 'neptune'
39 | planet_data = [24760, 102.4e24, 16.11, 28.32, 4.495e9, .0113, 1.769, 164.8*365.256, 6835100];
40 | case 'pluto'
41 | planet_data = [1195, 12.5e21, 6.387, 122.5, 5.870e9, .2444, 17.16, 247.7*365.256, 830];
42 | otherwise
43 | error('Error: selected planet not available. Please try again.')
44 | end
45 | end
--------------------------------------------------------------------------------
/universal_lagrange.m:
--------------------------------------------------------------------------------
1 | function [R , V] = universal_lagrange(R0,V0,dt,mu)
2 | %% Universal Lagrange Function and True Anomoly
3 | %
4 | % Jeremy Penn
5 | % 22 September 2017
6 | %
7 | % Revision: 22/09/2017
8 | % 19/10/2017 - Moved the ploting to outside functions to
9 | % increase encapsulation.
10 | % 30/10/2017 - Moved calculation of lagrange functions to
11 | % outisde functions to increase encapsulation.
12 | %
13 | % function [R , V] = UniversalLagrange(R0,V0,dt)
14 | %
15 | % Purpose: This function calculates the true anomaly to find the f and
16 | % g lagrange functions used to calculate the time-dependent
17 | % position and velocity of a satellite.
18 | %
19 | % Inputs: o R0 - A 1x3 vector of the satellite's initial position
20 | % o V0 - A 1x3 vector of the satellite's initial velocity
21 | % o dt - The final time in seconds [s]
22 | % o mu - The Standard Grav Parameter [OPTIONAL]. Defaults
23 | % to Earth [km^3/s^2]
24 | %
25 | % Outputs: o R - The new position.
26 | % o V - The new velocity.
27 | %
28 | % Requires: f_and_g.m, fdot_and_gdot.m
29 | %
30 |
31 | if nargin == 3
32 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
33 | end
34 |
35 | r0 = norm(R0); % [km] Magnitude of initial position
36 | v0 = norm(V0); % [km/s] Magnitude of initival velocity
37 | vr0 = R0*V0'/r0; % [km/s] Orbital velocity
38 | alpha = 2/r0 - v0^2/mu;
39 |
40 | X0 = mu^0.5*abs(alpha)*dt; %[km^0.5]Initial estimate of Xi
41 | Xi = X0;
42 | tol = 1E-10; % Tolerance
43 | while(1)
44 | zi = alpha*Xi^2;
45 | [ Cz,Sz] = stumpff( zi );
46 | fX = r0*vr0/(mu)^0.5*Xi^2*Cz + (1 - alpha*r0)*Xi^3*Sz + r0*Xi -(mu)^0.5*dt;
47 | fdX = r0*vr0/(mu)^0.5*Xi*(1 - alpha*Xi^2*Sz) + (1 - alpha*r0)*Xi^2*Cz + r0;
48 | eps = fX/fdX;
49 | Xi = Xi - eps;
50 | if(abs(eps) < tol )
51 | break
52 | end
53 | end
54 |
55 | %% Lagrange f and g coefficients in terms of the universal anomaly
56 | [f, g] = f_and_g(Xi,R0, dt, alpha, mu);
57 | R = f*R0 + g*V0;
58 | r = norm(R);
59 | [df, dg] = fdot_and_gdot(Xi, R0, r, alpha, mu);
60 | V = df*R0 + dg*V0;
61 | end
62 |
63 |
--------------------------------------------------------------------------------
/two_impulse_rend.m:
--------------------------------------------------------------------------------
1 | function two_impulse_rend(r0, v0, R0, V0, t)
2 | %% Plot the orbits of small mass orbiting a large central body
3 | %
4 | % Jeremy Penn
5 | % 03 November 2017
6 | %
7 | % Revision: 03/11/17
8 | %
9 | % function two_impulse_rend(r0, v0, R0, V0, t)
10 | %
11 | % Purpose: This function calculates the dv required and trajectory vector
12 | % for a two-impulse rendezvous in LEO. Additionally plots the
13 | % position vector over the time interval.
14 | %
15 | % Input: o r0 - target's geocentric position vector
16 | % o v0 - target's geocentric velocity vector
17 | % o R0 - chaser's geocentric position vector
18 | % o V0 - chaser's geocentric velocity vector
19 | % o t - time to intercept target
20 | %
21 | % Requires: cw_rr.m, cw_rv.m, cw_vr.m, cw_vv.m
22 | %
23 | %
24 | clc;
25 |
26 | %% Calculate the LVLH coordinates
27 | i = r0 / norm(r0);
28 | j = v0 / norm(v0);
29 | k = cross(i,j);
30 |
31 | %% transformation matrix from from geocentric to LVLH
32 | QXx = [i; j; k];
33 |
34 | %% relative vectors in geocentric coords
35 | n = norm(v0) / norm(r0);
36 | Wss = n*k;
37 |
38 | dr = R0 - r0;
39 | dv = V0 - v0 - cross(Wss, dr);
40 |
41 | %% relative position vector in LVLH
42 | dr0 = QXx * dr';
43 | dv0_ = QXx * dv';
44 |
45 | %% CW matrices
46 | phi_rr = cw_rr(t,n);
47 | phi_rv = cw_rv(t,n);
48 | phi_vr = cw_vr(t,n);
49 | phi_vv = cw_vv(t,n);
50 |
51 | %% rel velocity after impulse
52 | dv0p = -inv(phi_rv)*phi_rr*dr0;
53 |
54 | %% rel final velocity before 2nd impulse
55 | dvf_ = phi_vr*dr0 + phi_vv*dv0p;
56 |
57 | %% delta-v
58 | delta_v0 = abs( dv0p - dv0_ );
59 | delta_vf = abs( 0 - dvf_ );
60 |
61 | total_dv = (norm(delta_v0) + norm(delta_vf)) * 1e3;
62 |
63 | %% trajectory angle
64 | r = phi_rr*dr0 + phi_rv*dvf_;
65 |
66 | times = 0:100:t;
67 | pr = zeros(length(times),3);
68 | for lj = 1:length(times)
69 | pr(lj,:) = cw_rr(times(lj),n)*dr0 + cw_rv(times(lj),n)*dvf_;
70 | end
71 |
72 | plot3(pr(:,1),pr(:,2),pr(:,3));
73 |
74 | fprintf('The total delta-v required for the two-impulse rendezvous is %.1f [m/s]\n', total_dv)
75 | fprintf('The trajectory vector is %.2f*i + %.2f*j + %.2f*k [km]\n ', r)
76 |
77 | end
--------------------------------------------------------------------------------
/time_to_transfer_window.m:
--------------------------------------------------------------------------------
1 | function time_to_transfer_window(phi, n1, n2, t12)
2 | %% Calculate the time to transfer window
3 | %
4 | % Jeremy Penn
5 | % 06/11/2017
6 | %
7 | % Revision: 06/11/2017
8 | %
9 | % function time_to_transfer_window(phi, n1, n2, t12)
10 | %
11 | % Purpose: This function calculates the time to an open planetary
12 | % transfer window
13 | %
14 | % Input: o phi - The phase angle between n1 and n2 and t = 0 [deg]
15 | % o n1 - The mean motion of the departing planet [rad/day]
16 | % o n2 - The mean motion of the target planet [rad/day]
17 | % o t12 - The transfer time of the Hohmann transfer to n1 to
18 | % n2 [day]
19 | %
20 | clc;
21 |
22 | %% select the two planets
23 | dep_planet = input('Input the depature planet:\n','s');
24 | arr_planet = input('Input the arrival planet:\n','s');
25 |
26 | dep_planet_data = planet_select(dep_planet);
27 | arr_planet_data = planet_select(arr_planet);
28 |
29 | if nargin == 0
30 | phi = input('Input the current phase angle between the departure and arrival planets (deg):\n');
31 | n1 = (2*pi)/dep_planet_data(8);
32 | n2 = (2*pi)/arr_planet_data(8);
33 | t12 = time_of_transfer(dep_planet_data(5), arr_planet_data(5));
34 | t12 = t12 / 86400; % convert to days
35 | end
36 |
37 | phi = mod(phi, 360);
38 | phi = phi * pi/180;
39 |
40 | %% calculate phase angle for transfer
41 | phi0 = pi - n2*t12;
42 |
43 | %% calculate time to transfer window
44 | if n1 > n2
45 | N = 0;
46 | t = (phi0 - phi - 2*pi*N) / (n2 - n1);
47 |
48 | while t < 0
49 | N = N + 1;
50 | t = (phi0 - phi - 2*pi*N) / (n2 - n1);
51 | end
52 | elseif n2 > n1
53 | N = 0;
54 | t = (phi0 - phi + 2*pi*N) / (n2 - n1);
55 |
56 | while t < 0
57 | N = N + 1;
58 | t = (phi0 - phi + 2*pi*N) / (n2 - n1);
59 | end
60 | else
61 | error('Error: n1 and n2 can not be equal')
62 | end
63 |
64 | %% Calculate the synodic period of the orbit
65 | T1 = (2*pi) / n1;
66 | T2 = (2*pi) / n2;
67 |
68 | Tsyn = (T1*T2) / abs(T1 - T2);
69 |
70 | if abs(t - Tsyn) < 14
71 | fprintf('Transfer window is currently open!\n')
72 | else
73 | fprintf('The transfer window will open in %.2f days\n', t)
74 | end
75 | end
--------------------------------------------------------------------------------
/phasing_maneuver.m:
--------------------------------------------------------------------------------
1 | function phasing_maneuver(Ria,Rip,th,n,mu)
2 | %% Calculates the apogee and delta-v required for a phasing maneuver
3 | %
4 | % Jeremy Penn
5 | % 24 October 2017
6 | %
7 | % Revision: 24/10/17
8 | %
9 | % function phasing_maneuver()
10 | %
11 | % Purpose: This function calculates the phasing orbit and delta-v
12 | % requirement for a phasing maneuver. Burns are assumed at
13 | % perigee.
14 | %
15 | % Inputs: o Ria - The apogee of the initial orbit [km].
16 | % o Rip - The perigee of the initial orbit [km].
17 | % o n - The number of phasing orbits desired [OPTIONAL].
18 | % o th - The true anomaly of the target [deg].
19 | % o mu - The standard grav parameter of the central body
20 | % [OPTIONAL]. Defaults to Earth [km^3/s^2].
21 | %
22 | clc;
23 |
24 | if nargin == 3
25 | n =1;
26 | mu = 398600; %[km^3/s^2]
27 | end
28 |
29 | if nargin == 4
30 | mu = 398600; %[km^3/s^2]
31 | end
32 |
33 | %% Confirm th is between 0 and 360
34 | th = mod(th,360);
35 |
36 | %% Convert deg to rad
37 | th = th * (pi/180);
38 |
39 | %% Calculate the angular momentum of the initial orbit
40 | h1 = sqrt( 2*mu ) * sqrt( (Ria*Rip)/(Ria+Rip) );
41 |
42 | %% Calculate the period of the primary orbit
43 | a1 = (1/2) * (Ria+Rip);
44 | t1 = ( (2*pi)/sqrt(mu) )*( a1^(3/2) );
45 |
46 | %% Calculate the eccentricity of the primary orbit
47 | e = (Ria-Rip) / (Ria+Rip);
48 |
49 | %% Calculate the mean anomaly of the target
50 | Eb = 2 * atan( sqrt( (1-e)/(1+e) ) * tan(th/2) );
51 |
52 | %% Calculate the flight time from A to B
53 | tab = (t1/(2*pi)) * (Eb - e*sin(Eb));
54 |
55 | %% Calculate the phasing orbit period
56 | t2 = t1 - tab/n;
57 |
58 | %% Calculate semi-major axis of phasing orbit
59 | a2 = ( (sqrt(mu)*t2)/(2*pi) )^(2/3);
60 |
61 | %% Calculate apogee of phasing orbit
62 | Rpa = 2*a2 - Rip;
63 |
64 | %% Calculate the angular momentum of the phasing orbit
65 | h2 = sqrt(2*mu) * sqrt( (Rip*Rpa)/(Rip+Rpa) );
66 |
67 | %% Calculate velocities
68 | va1 = h1/Rip;
69 | va2 = h2/Rip;
70 |
71 | dva21 = va2 - va1;
72 | dva12 = va1 - va2;
73 |
74 | % Total delta-v
75 | dv = abs(dva12)+abs(dva21);
76 |
77 | fprintf('The apogee of the phasing obrit is %4.2f [km]\n',Rpa)
78 | fprintf('The total delta-v required is %4.4f [km/s]\n',dv)
79 | end
--------------------------------------------------------------------------------
/coe_from_rv.m:
--------------------------------------------------------------------------------
1 | function [h, e, i, omega, w, theta] = coe_from_rv(R,V,mu)
2 | %% Calculate all six orbital elements fromega the initial position and velocity
3 | %
4 | %
5 | % Jeremy Penn
6 | % 15 October 2017
7 | %
8 | % Revision: 15/10/17
9 | %
10 | % 20/10/17 - Changed notation to conform with "Orbital
11 | % Mechanics for Engineering Students" by Howard D. Curtis.
12 | %
13 | % function orbitElements(R,V,mu)
14 | %
15 | % Purpose: This function calculates the classic orbital elements.
16 | %
17 | % Inputs: o R - A 1x3 vector describing the initial position of the
18 | % satellite.
19 | % o V - A 1x3 vector describing the initial velocity of the
20 | % satellite.
21 | % o mu - Standard gravitationl parameter of the central body
22 | % [OPTIONAL]. Defaults to Earth (398600 [km^3/s^2])
23 | %
24 | % Output: o h - Specific angular momentum
25 | % o e - eccentricity
26 | % o i - orbital inclination
27 | % o omega - right ascension of the ascending node
28 | % o w - argument of perigee
29 | % o theta - true anomaly
30 | %
31 |
32 | clear r v vr H h i k N n E e omega w theta; clc;
33 |
34 | %% Set up the initial conditions
35 | if nargin == 2
36 | mu = 398600;
37 | end
38 |
39 | r = norm(R);
40 | v = norm(V);
41 | vr = dot(R,V) / r; % If vr > 0 object is moving away fromega perigee
42 |
43 | %% Calculate the specific angular momegaentum
44 |
45 | H = cross(R,V);
46 | h = norm(H);
47 |
48 | %% Calculate the inclination
49 |
50 | i = acos(H(3) / h) * (180/pi);
51 |
52 | %% Calculate node line vector
53 |
54 | k = [0, 0, 1];
55 | N = cross(k,H);
56 | n = norm(N);
57 |
58 | %% Calculate the right ascension of the ascending node
59 |
60 | if N(2) >= 0
61 | omega = acos(N(1) / n) * (180/pi);
62 | else
63 | omega = 360 - acos(N(1) / n) * (180/pi);
64 | end
65 |
66 | %% Calculate the eccentricity
67 |
68 | E = (1 / mu)*((v^2 - (mu / r))*R - vr*V);
69 | e = norm(E);
70 |
71 | %% Calculate the argument of perigee
72 |
73 | if E(3) >= 0
74 | w = acos(dot(N,E)/(n*e)) * (180/pi);
75 | else
76 | w = 360 - acos(dot(N,E)/(n*e)) * (180/pi);
77 | end
78 |
79 | %% Calculate the true anomegaaly
80 |
81 | if vr >= 0
82 | theta = acos(dot(E/e,R/r)) * (180/pi);
83 | else
84 | theta = 360 - acos(dot(E/e,R/r)) * (180/pi);
85 | end
86 | end
87 |
--------------------------------------------------------------------------------
/gibbs.m:
--------------------------------------------------------------------------------
1 | function [a,i,e,omega,w,theta] = gibbs(R1,R2,R3,mu)
2 | %% Gibbs method for finding velocities of an orbit
3 | %
4 | % Jeremy Penn
5 | % 20 October 2017
6 | %
7 | % Revision 20/10/17
8 | %
9 | % function [a,i,e,omega,w,theta] = gibbs(R1,R2,R3,mu)
10 | %
11 | % Purpose: This function computes the classical orbital elements by
12 | % means of the Gibbs method.
13 | %
14 | % Inputs: o R1 - A 1x3 vector describing the 1st position of the
15 | % satellite.
16 | % o R2 - A 1x3 vector describing the 2nd position of the
17 | % satellite.
18 | % o R3 - A 1x3 vector describing the 3rd position of the
19 | % satellite.
20 | % o mu - The standard gravitational parameter [OPTIONAL].
21 | % Defaults to Earth.
22 | %
23 | % Output: o a - Semi-major axis
24 | % o i - inclination
25 | % o e - eccintricity
26 | % o omega - right ascension of the ascending node
27 | % o w - argument of perigee
28 | % o theta - true anomaly
29 | %
30 | % Requires: kepler_convert.m
31 | %
32 |
33 |
34 | clc;
35 | if nargin == 3
36 | mu = 398600;
37 | end
38 | tol = 1e4;
39 |
40 | %% Calculate magnitudes of r1,r2, and r3
41 | r1 = norm(R1);
42 | r2 = norm(R2);
43 | r3 = norm(R3);
44 |
45 | %% Confirm they comprise an orbit
46 |
47 | c12 = cross(R1,R2);
48 | c23 = cross(R2,R3);
49 | c31 = cross(R3,R1);
50 |
51 | ur1 = R1/r1;
52 | nc23 = norm(c23);
53 | uc23 = c23/nc23;
54 |
55 | if abs(dot(ur1,uc23)) > tol
56 | error('Error: The given positions do not describe an orbit');
57 | end
58 |
59 | %% Calculate N, D, and S vectors
60 |
61 | N = r1*c23 + r2*c31 + r3*c12;
62 | D = c12 + c23 + c31;
63 | S = R1*(r2-r3) + R2*(r3-r1) + R3*(r1-r2);
64 |
65 | n = norm(N);
66 | d = norm(D);
67 |
68 | %% Compute velocity at r2
69 |
70 | dr2 = cross(D,R2);
71 |
72 | V2 = sqrt(mu/(n*d))*((dr2/r2) + S);
73 |
74 | %% Calculate the orbital elements from r2 and v2
75 |
76 | kepler = kepler_convert(R2,V2);
77 |
78 | a = kepler(1);
79 | e = kepler(2);
80 | i = kepler(3);
81 | omega = kepler(4);
82 | w = kepler(5);
83 | theta = kepler(6);
84 |
85 | fprintf('The semimajor axis is %5f [km]\n', a)
86 | fprintf('The eccentricity is %1.2f [deg]\n', e)
87 | fprintf('The inclination is %3.2f [deg]\n', i)
88 | fprintf('The right ascension of the ascending node is %3.2f [deg]\n', omega)
89 | fprintf('The argument of perigee is %3.2f [deg]\n', w)
90 | fprintf('The true anomaly is %3.2f [deg]\n', theta)
91 | end
--------------------------------------------------------------------------------
/runge_kutta_fehlberg.m:
--------------------------------------------------------------------------------
1 | function [tout, yout] = runge_kutta_fehlberg(ode_function, tspan, y0, tolerance)
2 | %% Runge Kutta Fehlberg Numerical Integration
3 | %
4 | % Jeremy Penn
5 | % 02 November 2017
6 | %
7 | % Revision: 02/11/2017
8 | %
9 | % function [tout, yout] = runge_kutta_fehlberg(ode_function, tspan, y0, tolerance)
10 | %
11 | % Purpose: This function uses the Runge-Kutta-Fehlberg method for
12 | % numerical integration of the given ode.
13 | %
14 | % Input: o ode_function - The function to be integrated
15 | % o tspan - 1x2 vector which gives the initial and
16 | % final time
17 | % o y0 - The inital conditions
18 | % o tolerance - The desired solution tolerance
19 | %
20 | % Output: o tout - The vector of time intervals.
21 | % o yout - The value vector.
22 | %
23 |
24 | a = [0 1/4 3/8 12/13 1 1/2];
25 |
26 | b = [ 0 0 0 0 0
27 | 1/4 0 0 0 0
28 | 3/32 9/32 0 0 0
29 | 1932/2197 -7200/2197 7296/2197 0 0
30 | 439/216 -8 3680/513 -845/4104 0
31 | -8/27 2 -3544/2565 1859/4104 -11/40];
32 |
33 | c4 = [25/216 0 1408/2565 2197/4104 -1/5 0 ];
34 | c5 = [16/135 0 6656/12825 28561/56430 -9/50 2/55];
35 |
36 | if nargin < 4
37 | tol = 1.e-8;
38 | else
39 | tol = tolerance;
40 | end
41 |
42 | t0 = tspan(1);
43 | tf = tspan(2);
44 | t = t0;
45 | y = y0;
46 | tout = t;
47 | yout = y';
48 | h = (tf - t0)/100; % Assumed initial time step.
49 |
50 | while t < tf
51 | hmin = 16*eps(t);
52 | ti = t;
53 | yi = y;
54 | %...Evaluate the time derivative(s) at six points within the current
55 | % interval:
56 | for i = 1:6
57 | t_inner = ti + a(i)*h;
58 | y_inner = yi;
59 | for j = 1:i-1
60 | y_inner = y_inner + h*b(i,j)*f(:,j);
61 | end
62 | f(:,i) = feval(ode_function, t_inner, y_inner);
63 | end
64 |
65 | %...Compute the maximum truncation error:
66 | te = h*f*(c4' - c5'); % Difference between 4th and
67 | % 5th order solutions
68 | te_max = max(abs(te));
69 |
70 | %...Compute the allowable truncation error:
71 | ymax = max(abs(y));
72 | te_allowed = tol*max(ymax,1.0);
73 |
74 | %...Compute the fractional change in step size:
75 | delta = (te_allowed/(te_max + eps))^(1/5);
76 |
77 | %...If the truncation error is in bounds, then update the solution:
78 | if te_max <= te_allowed
79 | h = min(h, tf-t);
80 | t = t + h;
81 | y = yi + h*f*c5';
82 | tout = [tout;t];
83 | yout = [yout;y'];
84 | end
85 |
86 | %...Update the time step:
87 | h = min(delta*h, 4*h);
88 | if h < hmin
89 | fprintf(['\n\n Warning: Step size fell below its minimum\n'...
90 | ' allowable value (%g) at time %g.\n\n'], hmin, t)
91 | return
92 | end
93 | end
--------------------------------------------------------------------------------
/date_after_transfer.m:
--------------------------------------------------------------------------------
1 | function date_vec = date_after_transfer(print_out, d, m, y, in_h, in_m, in_s, days)
2 |
3 | %% calculates the date of arrival after an interplanetary transfer
4 | %
5 | % Jeremy Penn
6 | % 12/11/17
7 | %
8 | % function date_after_transfer()
9 | %
10 | % Input: o print_out - A string to decide whether to print to screen.
11 | % Leave blank to print-to-screen.
12 | %
13 |
14 | if nargin == 0
15 | print_out = 'yes';
16 |
17 | %% Inputs
18 | date = input('Input the departure date (dd/mm/yyyy/):\n','s');
19 | split = strsplit(date, '/');
20 |
21 | d = str2double(split{1});
22 | m = str2double(split{2});
23 | y = str2double(split{3});
24 |
25 | time = input('input the time of departure (HH:MM:SS UT):\n','s');
26 | split_time = strsplit(time, ':');
27 |
28 | in_h = str2double(split_time{1});
29 | in_m = str2double(split_time{2});
30 | in_s = str2double(split_time{3});
31 |
32 | days = input('Length of transfer (days, use fractions of a day):\n');
33 | end
34 |
35 | %% calculate the new date
36 | time_h = in_s/3600 + in_m/60 + in_h;
37 |
38 | % convert to total days
39 | if mod(y, 4) == 0
40 | length_of_month = [31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
41 | else
42 | length_of_month = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
43 | end
44 |
45 | month_d = 0;
46 | for i = 1:m - 1
47 | month_d = month_d + length_of_month(i);
48 | end
49 |
50 | arrive_d = d + month_d + days + time_h/24; % total days
51 |
52 | % back convert to dd/mm/yy from total days
53 | while arrive_d > 365
54 | arrive_d = arrive_d - 365;
55 | y = y + 1;
56 | end
57 |
58 | mm = 0;
59 | for j = 1:12
60 | if arrive_d <= length_of_month(j)
61 | break
62 | end
63 |
64 | arrive_d = arrive_d - length_of_month(j);
65 |
66 | mm = mm + 1;
67 | end
68 |
69 | if arrive_d - round(arrive_d) ~= 0
70 |
71 | remain = arrive_d - floor(arrive_d);
72 | arrive_d = floor(arrive_d);
73 |
74 | hr = remain * 24;
75 |
76 | if hr - round(hr) ~= 0
77 |
78 | h_remain = hr - floor(hr);
79 | hr = floor(hr);
80 | min = h_remain * 60;
81 |
82 | if min - round(min) ~= 0
83 |
84 | m_remain = min - floor(min);
85 | min = floor(min);
86 | sec = m_remain * 60;
87 | end
88 | else
89 | min = 0;
90 | sec = 0;
91 | end
92 | else
93 | hr = 0;
94 | min = 0;
95 | sec = 0;
96 | end
97 |
98 | date_vec = [y, mm, arrive_d, hr, min, sec];
99 |
100 | if strcmp(print_out,'yes')
101 | date_arrive = datestr(date_vec,'dd/mm/yyyy at HH:MM:SS UT');
102 |
103 | da = sprintf('The spacecraft will arrive on %s', date_arrive);
104 |
105 | fprintf(da)
106 | disp(' ')
107 | end
108 | end
--------------------------------------------------------------------------------
/non_impulse_thrust.m:
--------------------------------------------------------------------------------
1 | function non_impulse_thrust()
2 | %% calculates the nonimpulse thrust over the time interval
3 | %
4 | % Jeremy Penn
5 | % 19/11/2017
6 | %
7 | % function non_impulse_thrust()
8 | %
9 | % Required: kepler_convert.m, rfk45.m, rv_from_r0v0_ta.m
10 | %
11 |
12 | %% constants
13 | mu = 398600;
14 | g0 = 9.807;
15 |
16 | %% inputs
17 | alt = input('Input the altitude of perigee [x, y, z] (km):\n');
18 | vel = input('Input the velocity of the orbit [vx, vy, vz] (km/s):\n');
19 | r0 = [alt(1), alt(2), alt(3)];
20 | v0 = [vel(1), vel(2), vel(3)];
21 | t0 = 0;
22 | t_burn = input('Input the total burn time (s): \n');
23 |
24 | m0 = input('Input the mass of the rocket (kg):\n');
25 | T = input('Input the engine thrust (kN):\n');
26 | Isp = input('Input the engine specific impulse (s):\n');
27 |
28 | %% integrate the equations of motion
29 | y0 = [r0 v0 m0]';
30 | [t,y] = rkf45(@rates, [t0 t_burn], y0, 1.e-16);
31 |
32 | %% compute the state vector and mass after burn
33 | r1 = [y(end,1) y(end,2) y(end,3)];
34 | v1 = [y(end,4) y(end,5) y(end,6)];
35 | m1 = y(end,7);
36 | coe = kepler_convert(r1,v1,mu);
37 | e = coe(2);
38 | TA = coe(6);
39 | a = coe(1);
40 |
41 | %% find the state vector at apogee of the post-burn trajectory:
42 | dtheta = mod(TA,360);
43 |
44 | [ra,va] = rv_from_r0v0_ta(r1, v1, dtheta, mu);
45 |
46 | clc;
47 |
48 | fprintf('\n\n--------------------------------------------------------\n')
49 | fprintf('\nBefore ignition:')
50 | fprintf('\n Mass = %g kg', m0)
51 | fprintf('\n State vector:')
52 | fprintf('\n r = [%10g, %10g, %10g] (km)', r0(1), r0(2), r0(3))
53 | fprintf('\n Radius = %g', norm(r0))
54 | fprintf('\n v = [%10g, %10g, %10g] (km/s)', v0(1), v0(2), v0(3))
55 | fprintf('\n Speed = %g\n', norm(v0))
56 | fprintf('\nThrust = %12g kN', T)
57 | fprintf('\nBurn time = %12.6f s', t_burn)
58 | fprintf('\nMass after burn = %12.6E kg\n', m1)
59 | fprintf('\nEnd-of-burn-state vector:')
60 | fprintf('\n r = [%10g, %10g, %10g] (km)', r1(1), r1(2), r1(3))
61 | fprintf('\n Radius = %g', norm(r1))
62 | fprintf('\n v = [%10g, %10g, %10g] (km/s)', v1(1), v1(2), v1(3))
63 | fprintf('\n Speed = %g\n', norm(v1))
64 | fprintf('\nPost-burn trajectory:')
65 | fprintf('\n Eccentricity = %g', e)
66 | fprintf('\n Semimajor axis = %g km', a)
67 | fprintf('\n Apogee state vector:')
68 | fprintf('\n r = [%17.10E, %17.10E, %17.10E] (km)', ra(1), ra(2), ra(3))
69 | fprintf('\n Radius = %g', norm(ra))
70 | fprintf('\n v = [%17.10E, %17.10E, %17.10E] (km/s)', va(1), va(2), va(3))
71 | fprintf('\n Speed = %g', norm(va))
72 | fprintf('\n\n--------------------------------------------------------\n\n')
73 |
74 | %% -----subfunctions----------------------------
75 | function dfdt = rates(t,f) %#ok<*INUSL>
76 |
77 | x = f(1); y = f(2); z = f(3);
78 | vx = f(4); vy = f(5); vz = f(6);
79 | m = f(7);
80 |
81 | r = norm([x y z]);
82 | v = norm([vx vy vz]);
83 | ax = -mu*x/r^3 + T/m*vx/v;
84 | ay = -mu*y/r^3 + T/m*vy/v;
85 | az = -mu*z/r^3 + T/m*vz/v;
86 | mdot = -T*1000/g0/Isp;
87 |
88 | dfdt = [vx vy vz ax ay az mdot]';
89 |
90 | end %rates
91 | end
--------------------------------------------------------------------------------
/rv_from_obs.m:
--------------------------------------------------------------------------------
1 | function [r,v] = rv_from_obs(rho, A, a, drho, dA, da, H, th, phi)
2 | %% Coverts from topocentric to geocentric coordinates
3 | %
4 | % Jeremy Penn
5 | % 22/10/2017
6 | %
7 | % Revision: 22/10/2017
8 | %
9 | % function [r,v] = rv_from_obs(rho, A, a, drho, dA, da, H, th, phi)
10 | %
11 | % Input: o rho - The range from observation [km]
12 | % o A - The azimuth angle of the target [deg]
13 | % o a - The angular elevation of the object [deg]
14 | % o drho - The time rate of change of rho [km]
15 | % o dA - The time rate of change of A [deg]
16 | % o da - The time rate of change of a [deg]
17 | % o H - The height of the observation location [km]
18 | % o th - The local sidereal time [deg]
19 | % o phi - The latitude of the observer [deg]
20 | %
21 | % Output: o r - The geocentric position vector
22 | % o v - The geocentric velocity vector
23 | %
24 | % Requires: kepler_convert.m
25 | %
26 |
27 | %% Convert angles from degrees to radians
28 | A = A * pi/180;
29 | a = a * pi/180;
30 | dA = dA * pi/180;
31 | da = da * pi/180;
32 | th = th * pi/180;
33 | phi = phi * pi/180;
34 |
35 | %% Earth constants
36 | f = .003353;
37 | Re = 6378;
38 | Omega = [0, 0, 72.92e-06]; %[rad/s] Earth's rotational velcoity
39 |
40 | %% Calculate the geocentric position vector of the observer
41 | R = [((Re / sqrt(1 - (2*f - f^2)*sin(phi).^2)) + H)*cos(phi)*cos(th),((Re / sqrt(1 - (2*f - f^2)*sin(phi).^2)) + H)*cos(phi)*sin(th), ((Re*(1 - f)^2 / sqrt(1 - (2*f - f^2)*sin(phi).^2)) + H)*sin(phi)];
42 |
43 | %% Calculate the topocentric RA and dec
44 | del = asin(cos(phi) * cos(A) * cos(a) + sin(phi)*sin(a));
45 |
46 | if A > 0 && A < pi
47 | h = 2*pi - acos((cos(phi) * sin(a) - sin(phi) * cos(A) * cos(a)) / cos(del));
48 | else
49 | h = acos((cos(phi) * sin(a) - sin(phi) * cos(A) * cos(a)) / cos(del));
50 | end
51 |
52 | alpha = th - h;
53 |
54 | %% Calculate the direction cosine vector
55 | rhohat = [cos(del)*cos(alpha), cos(del)*sin(alpha), sin(del)];
56 |
57 | %% Calculate the geocentric position vector
58 | r = R + rho*rhohat;
59 |
60 | %% Calculate the inertial velocity of the observer
61 | Rdot = cross(Omega, R);
62 |
63 | %% Calculate the declination rate
64 | deldot = (1/cos(del)) * (-dA*cos(phi)*sin(A)*cos(a) + da*(sin(phi)*cos(a)-cos(phi)*cos(A)*sin(a)));
65 |
66 | %% Calculate the right ascension rate
67 | hdot = ( (dA*cos(A)*cos(a)) - (da*sin(A)*sin(a)) + (deldot*sin(A)*cos(a)*tan(del)) ) / (cos(phi)*sin(a) - sin(phi)*cos(A)*cos(a));
68 |
69 | aldot = Omega(3) + hdot;
70 |
71 | %% Calculate the direction cosin rate vector
72 | rhohatdot = [(-aldot*sin(alpha)*cos(del) - deldot*cos(alpha)*sin(del)), (aldot*cos(alpha)*cos(del) - deldot*sin(alpha)*sin(del)), deldot*cos(del)];
73 |
74 | v = Rdot + drho*rhohat + rho*rhohatdot;
75 |
76 | %% Calculate the orbital elements
77 | kepler = kepler_convert(r,v);
78 |
79 | a = kepler(1);
80 | e = kepler(2);
81 | i = kepler(3);
82 | omega = kepler(4);
83 | w = kepler(5);
84 | th = kepler(6);
85 |
86 | fprintf('The semi-major axis is %6.2f [km]\n', a);
87 | fprintf('The eccentricity is %6.2f \n', e);
88 | fprintf('The inclination is %6.2f [deg]\n', i);
89 | fprintf('The right ascension of the ascending node is %6.2f [deg]\n', omega);
90 | fprintf('The argument of perigee is %6.2f [deg]\n', w);
91 | fprintf('The true anomaly is %6.2f [deg]\n', th);
92 | end
--------------------------------------------------------------------------------
/lambert.m:
--------------------------------------------------------------------------------
1 | function [v1, v2] = lambert(R1, R2, dt, tolerance, grav)
2 | %% Stumpff Functions
3 | %
4 | % Jeremy Penn
5 | % 04 November 2017
6 | %
7 | % Revision: 04/11/17
8 | % 11/11/2017 - added outputs for both velocities
9 | % - added functionality to find a good guess for
10 | % z
11 | %
12 | % function [v1, v2] = lambert(R1, R2, dt,guess, tolerance, grav)
13 | %
14 | % Purpose: This function calculates the coe of an object using
15 | % Lambert's problem to solve for the velocity.
16 | %
17 | % Inputs: o R1 - The 1st position vector [km]
18 | % o R2 - The position vector after time dt [km]
19 | % o dt - The time interval between R1 and R2 [s]
20 | % o tolerance - The tolderance for the zero of z [OPTIONAL]
21 | % o grav - The standard grav param [km^3/s^2] [OPTIONAL]
22 | %
23 | % Outputs: o v1 - The velocity vector at R1
24 | % o v2 - The velocity vector at R2
25 | %
26 | % Required: coe_from_rv.m, stumpff.m
27 | %
28 | clc;
29 |
30 | %% Constants
31 | if nargin == 3
32 | mu = 398600;
33 | tol = 1e-8;
34 | elseif nargin == 4
35 | mu = 398600;
36 | tol = tolerance;
37 | else
38 | mu = grav;
39 | tol = tolerance;
40 | end
41 |
42 | %% Calculate norm of r1 and r2
43 | r1 = norm(R1);
44 | r2 = norm(R2);
45 | r1xr2 = cross(R1,R2);
46 |
47 | %% Choose either prograde or retrograde orbit
48 | orbit = input('Please choose either prograde or retrograde orbit\n', 's');
49 | orbit = lower(orbit);
50 |
51 | if strcmp(orbit, 'prograde') || strcmp(orbit,'pro')
52 | if r1xr2(3) > 0
53 | dth = acos( dot(R1,R2)/(r1*r2) );
54 | else
55 | dth = 2*pi - acos( dot(R1,R2)/(r1*r2) );
56 | end
57 | elseif strcmp(orbit, 'retrograde') || strcmp(orbit,'retro')
58 | if r1xr2(3) >= 0
59 | dth = 2*pi - acos( dot(R1,R2)/(r1*r2) );
60 | else
61 | dth = acos( dot(R1,R2)/(r1*r2) );
62 | end
63 | else
64 | error('Error: Please input "prograde" or "retrograde"')
65 | end
66 |
67 | %% Calculate A
68 | A = sin(dth)*sqrt( r1*r2/(1-cos(dth)) );
69 |
70 | %% find zero of z
71 | ratio = 1;
72 |
73 | % Determine a good guess by checking where the sign of F changes
74 | z = 0;
75 | while F(z,dt) < 0
76 | z = z + .01;
77 | end
78 |
79 | while abs(ratio) > tol
80 | ratio = F(z,dt)/dF(z);
81 | z = z - ratio;
82 | end
83 |
84 | %% f and g functions
85 | f = 1 - y(z)/r1;
86 | g = A*sqrt(y(z)/mu);
87 | gdot = 1 - y(z)/r2;
88 |
89 | %% Calculate the velocity vector v1
90 | v1 = 1/g * (R2 - f*R1);
91 |
92 | %% calculate the velocity vector v2
93 | v2 = 1/g * (gdot*R2 - R1);
94 |
95 | %% subfunctions
96 | function out = y(z)
97 | [Cz, Sz] = stumpff(z);
98 | out = r1 + r2 + A*(z*Sz-1)/sqrt(Cz);
99 | end %y
100 |
101 | function out = F(z,t)
102 | [Cz, Sz] = stumpff(z);
103 | out = (y(z)/Cz)^1.5 * Sz + A*sqrt(y(z)) - sqrt(mu)*t;
104 | end %F
105 |
106 | function out = dF(z)
107 | [Cz, Sz] = stumpff(z);
108 | if z == 0
109 | out = ( sqrt(2)/40 )*y(0)^1.5 + (A/8)*( sqrt(y(0)) + A*sqrt(1/2*y(0)) );
110 | else
111 | out = ((y(z)/Cz)^1.5) * (1/2*z)*(Cz - 3*Sz/2*Cz)+(3*Sz^2)/4*Cz + (A/8)*( 3*Sz/Cz * sqrt(y(z))+ A*sqrt(Cz/y(z)) );
112 | end
113 | end %dF
114 | end
--------------------------------------------------------------------------------
/binary_plot.m:
--------------------------------------------------------------------------------
1 | function binary_plot(R0,V0,dt,step,m1,m2)
2 | %% Plot the orbits of two objects orbiting their center of mass.
3 | %
4 | % Jeremy Penn
5 | % 21 October 2017
6 | %
7 | % Revision: 21/10/17
8 | %
9 | % function binary_plot(R0,V0,dt,step,m1,m2)
10 | %
11 | % Purpose: This function plots the trajectories of two objects about
12 | % their common center of mass.
13 | %
14 | % Inputs: o R0 - A 1x3 vector of the initial separation vector
15 | % between m1 and m2.
16 | % o V0 - A 1x3 vector of the initial total velocity vector.
17 | % o dt - The time difference (tf - ti).
18 | % o step - The step size for the calculation
19 | % o m1 - Mass of object 1 in solar mass
20 | % o m2 - Mass of object 2 in solar mass
21 | %
22 | % Requires: binary_trajectory.m
23 | %
24 | %% Calculate the trajectories
25 | [rf1,rf2] = binary_trajectory(R0,V0,m1,m2,dt,step);
26 |
27 | %% Plot Orbits
28 |
29 | str = input('Readout plot to video?\n','s');
30 |
31 | switch str
32 | case 'y'
33 | name = input('Please name output animation\n','s');
34 | con = strcat('~/Documents/matlab/animation/',name);
35 | vid = VideoWriter(con);
36 | open(vid);
37 | set(gcf,'color','black');
38 | whitebg('black');
39 | CoM = ((rf1(1,:) * m1) + (rf2(1,:) * m2)) / (m1 * m2);
40 | scatter3(CoM(1),CoM(2),CoM(3),'xwhite');
41 | hold on
42 |
43 | for i = 1:length(rf1)
44 | axis off
45 | grid off
46 | scatter3(rf1(i,1),rf1(i,2),rf1(i,3),'.r');
47 | scatter3(rf2(i,1),rf2(i,2),rf2(i,3),'.g');
48 | frame = getframe(gcf);
49 | writeVideo(vid,frame);
50 | end
51 | hold off;
52 | close(vid);
53 | case 'yes'
54 | name = input('Please name output animation\n','s');
55 | con = strcat('~/Documents/matlab/animation/',name);
56 | vid = VideoWriter(con);
57 | open(vid);
58 | set(gcf,'color','black');
59 | whitebg('black');
60 | CoM = ((rf1(1,:) * m1) + (rf2(1,:) * m2)) / (m1 * m2);
61 | scatter3(CoM(1),CoM(2),CoM(3),'xwhite');
62 | %hold on
63 |
64 | for i = 1:length(rf1)
65 | axis off
66 | grid off
67 | scatter3(rf1(i,1),rf1(i,2),rf1(i,3),'.r');
68 | scatter3(rf2(i,1),rf2(i,2),rf2(i,3),'.g');
69 | frame = getframe(gcf);
70 | writeVideo(vid,frame);
71 | end
72 | %hold off;
73 | close(vid);
74 | case 'n'
75 | set(gcf,'color','black');
76 | whitebg('black');
77 | CoM = ((rf1(1,:) * m1) + (rf2(1,:) * m2)) / (m1 * m2);
78 | scatter3(CoM(1),CoM(2),CoM(3),'xwhite');
79 | hold on
80 |
81 | for i = 1:length(rf1)
82 | axis off
83 | grid off
84 | scatter3(rf1(i,1),rf1(i,2),rf1(i,3),'.r');
85 | scatter3(rf2(i,1),rf2(i,2),rf2(i,3),'.g');
86 | end
87 | hold off
88 | case 'no'
89 | set(gcf,'color','black');
90 | whitebg('black');
91 | CoM = ((rf1(1,:) * m1) + (rf2(1,:) * m2)) / (m1 * m2);
92 | scatter3(CoM(1),CoM(2),CoM(3),'xwhite');
93 | hold on
94 |
95 | for i = 1:length(rf1)
96 | axis off
97 | grid off
98 | scatter3(rf1(i,1),rf1(i,2),rf1(i,3),'.r');
99 | scatter3(rf2(i,1),rf2(i,2),rf2(i,3),'.g');
100 | end
101 | hold off
102 | otherwise
103 | error('Error: Please choose "yes" or "no"')
104 | end
105 | end
--------------------------------------------------------------------------------
/geocentric_track.m:
--------------------------------------------------------------------------------
1 | function geocentric_track(R0, V0, dt, step,mu)
2 | %% Calculate and plot the geocentric orbit of a satellite about the Earth
3 | %
4 | % Jeremy Penn
5 | % 19 October 2017
6 | %
7 | % Revision: 19/10/17
8 | % 28/10/2017 - Added a rotating globe for movie mode.
9 | %
10 | % function GeocentricTrack(R0, V0, dt, step)
11 | %
12 | % Purpose: This function plots the orbit of a satellite as a function of time
13 | % in the geocentric frame of reference. Additionally, it creates a
14 | % video of the orbit.
15 | %
16 | % Inputs: o R0 - A 1x3 vector of the satellite's initial position
17 | % o V0 - A 1x3 vector of the satellite's initial velocity
18 | % o dt - The final time in seconds [s]
19 | % o step - The step sized used to determine how often to
20 | % calculate position and velocity in seconds [s]
21 | %
22 | % Requires: trajectory.m
23 | %
24 |
25 | load topo
26 |
27 | if nargin == 4
28 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
29 | end
30 |
31 | [Ri,Vi] = trajectory(R0,V0,dt,step,mu);
32 |
33 | %% Instantiate Movie Maker
34 | str = input('Would you like an animation?\n','s');
35 |
36 | if strcmpi(str,'y') || strcmpi(str,'yes')
37 | movName = input('Please name the movie\n','s');
38 | con = strcat('~/Documents/matlab/animation/',movName);
39 | vid = VideoWriter(con,'MPEG-4');
40 | open(vid);
41 |
42 | grs80 = referenceEllipsoid('grs80','km');
43 |
44 | figure('Renderer','opengl')
45 | ax = axesm('globe','Geoid',grs80,'Grid','off', ...
46 | 'GLineWidth',1,'GLineStyle','-',...
47 | 'Gcolor',[0.9 0.9 0.1],'Galtitude',100);
48 | ax.Position = [0 0 1 1];
49 | axis equal off
50 |
51 | h1 = geoshow(topo,topolegend,'DisplayType','texturemap');
52 | demcmap(topo)
53 | land = shaperead('landareas','UseGeoCoords',true);
54 | h2 = plotm([land.Lat],[land.Lon],'Color','black');
55 | rivers = shaperead('worldrivers','UseGeoCoords',true);
56 | h3 = plotm([rivers.Lat],[rivers.Lon],'Color','blue');
57 |
58 | n = dt/step;
59 | rate = 360/86164; % Earth's rotation rate [deg/sec]
60 | rotperstep = n*rate;
61 | totalrot = rotperstep*step; % Total degrees of rotation
62 | rotation = 360:-rotperstep:totalrot;
63 | direction = [0, 0, 1];
64 | hold on
65 |
66 | for i = 1:length(Ri)
67 | ax = axesm('globe','Geoid',grs80,'Grid','off', ...
68 | 'GLineWidth',1,'GLineStyle','-',...
69 | 'Gcolor',[0.9 0.9 0.1],'Galtitude',100);
70 | ax.Position = [0 0 1 1];
71 | axis equal off
72 |
73 | %rotate(h1,direction,rotation(i))
74 | %rotate(h2,direction,rotation(i))
75 | %rotate(h3,direction,rotation(i))
76 | view(0,23.5)
77 | scatter3(Ri(i,1),Ri(i,2),Ri(i,3),'.r');
78 | refreshdata
79 | drawnow
80 | frame = getframe;
81 | writeVideo(vid,frame);
82 | end
83 | close(vid);
84 | else
85 |
86 | grs80 = referenceEllipsoid('grs80','km');
87 |
88 | figure('Renderer','opengl')
89 | ax = axesm('globe','Geoid',grs80,'Grid','off', ...
90 | 'GLineWidth',1,'GLineStyle','-',...
91 | 'Gcolor',[0.9 0.9 0.1],'Galtitude',100);
92 | ax.Position = [0 0 1 1];
93 | axis equal off
94 | view(0,23.5)
95 |
96 | geoshow(topo,topolegend,'DisplayType','texturemap')
97 | demcmap(topo)
98 | land = shaperead('landareas','UseGeoCoords',true);
99 | plotm([land.Lat],[land.Lon],'Color','black')
100 | rivers = shaperead('worldrivers','UseGeoCoords',true);
101 | plotm([rivers.Lat],[rivers.Lon],'Color','blue')
102 |
103 | for i = 1:length(Ri)
104 | scatter3(Ri(i,1),Ri(i,2),Ri(i,3),'.r');
105 | end
106 | end
107 | end
--------------------------------------------------------------------------------
/rkf45.m:
--------------------------------------------------------------------------------
1 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 | function [tout, yout] = rkf45(ode_function, tspan, y0, tolerance)
3 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 | %{
5 | This function uses the Runge-Kutta-Fehlberg 4(5) algorithm to
6 | integrate a system of first-order differential equations
7 | dy/dt = f(t,y).
8 |
9 | y - column vector of solutions
10 | f - column vector of the derivatives dy/dt
11 | t - time
12 | a - Fehlberg coefficients for locating the six solution
13 | points (nodes) within each time interval.
14 | b - Fehlberg coupling coefficients for computing the
15 | derivatives at each interior point
16 | c4 - Fehlberg coefficients for the fourth-order solution
17 | c5 - Fehlberg coefficients for the fifth-order solution
18 | tol - allowable truncation error
19 | ode_function - handle for user M-function in which the derivatives f
20 | are computed
21 | tspan - the vector [t0 tf] giving the time interval for the
22 | solution
23 | t0 - initial time
24 | tf - final time
25 | y0 - column vector of initial values of the vector y
26 | tout - column vector of times at which y was evaluated
27 | yout - a matrix, each row of which contains the components of y
28 | evaluated at the correponding time in tout
29 | h - time step
30 | hmin - minimum allowable time step
31 | ti - time at the beginning of a time step
32 | yi - values of y at the beginning of a time step
33 | t_inner - time within a given time step
34 | y_inner - values of y witin a given time step
35 | te - trucation error for each y at a given time step
36 | te_allowed - allowable truncation error
37 | te_max - maximum absolute value of the components of te
38 | ymax - maximum absolute value of the components of y
39 | tol - relative tolerance
40 | delta - fractional change in step size
41 | eps - unit roundoff error (the smallest number for which
42 | 1 + eps > 1)
43 | eps(x) - the smallest number such that x + eps(x) = x
44 |
45 | User M-function required: ode_function
46 | %}
47 | % ---------------------------------------------------------------
48 |
49 | a = [0 1/4 3/8 12/13 1 1/2];
50 |
51 | b = [ 0 0 0 0 0
52 | 1/4 0 0 0 0
53 | 3/32 9/32 0 0 0
54 | 1932/2197 -7200/2197 7296/2197 0 0
55 | 439/216 -8 3680/513 -845/4104 0
56 | -8/27 2 -3544/2565 1859/4104 -11/40];
57 |
58 | c4 = [25/216 0 1408/2565 2197/4104 -1/5 0 ];
59 | c5 = [16/135 0 6656/12825 28561/56430 -9/50 2/55];
60 |
61 | if nargin < 4
62 | tol = 1.e-8;
63 | else
64 | tol = tolerance;
65 | end
66 |
67 | t0 = tspan(1);
68 | tf = tspan(2);
69 | t = t0;
70 | y = y0;
71 | tout = t;
72 | yout = y';
73 | h = (tf - t0)/100; % Assumed initial time step.
74 |
75 | while t < tf
76 | hmin = 16*eps(t);
77 | ti = t;
78 | yi = y;
79 | %...Evaluate the time derivative(s) at six points within the current
80 | % interval:
81 | for i = 1:6
82 | t_inner = ti + a(i)*h;
83 | y_inner = yi;
84 | for j = 1:i-1
85 | y_inner = y_inner + h*b(i,j)*f(:,j);
86 | end
87 | f(:,i) = feval(ode_function, t_inner, y_inner);
88 | end
89 |
90 | %...Compute the maximum truncation error:
91 | te = h*f*(c4' - c5'); % Difference between 4th and
92 | % 5th order solutions
93 | te_max = max(abs(te));
94 |
95 | %...Compute the allowable truncation error:
96 | ymax = max(abs(y));
97 | te_allowed = tol*max(ymax,1.0);
98 |
99 | %...Compute the fractional change in step size:
100 | delta = (te_allowed/(te_max + eps))^(1/5);
101 |
102 | %...If the truncation error is in bounds, then update the solution:
103 | if te_max <= te_allowed
104 | h = min(h, tf-t);
105 | t = t + h;
106 | y = yi + h*f*c5';
107 | tout = [tout;t];
108 | yout = [yout;y'];
109 | end
110 |
111 | %...Update the time step:
112 | h = min(delta*h, 4*h);
113 | if h < hmin
114 | fprintf(['\n\n Warning: Step size fell below its minimum\n'...
115 | ' allowable value (%g) at time %g.\n\n'], hmin, t)
116 | return
117 | end
118 | end
119 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
120 |
--------------------------------------------------------------------------------
/twobody.m:
--------------------------------------------------------------------------------
1 | function twobody()
2 | %% solves the two body problem
3 | %
4 | % Jeremy Penn
5 | % 23/11/17
6 | %
7 | % function twobody()
8 | %
9 | % Required: rkf45.m
10 |
11 | %% constants
12 | G = 6.67408e-20; %[km^3 / kg s^2]
13 |
14 | %% inputs
15 | m1 = input('Input the mass of the first object (kg):\n');
16 | m2 = input('Input the mass of the second object (kg):\n');
17 | t0 = input('Input the initial time (s):\n');
18 | tf = input('Input the final time (s):\n');
19 |
20 | R1_0 = input('Input the initial position vector of the first mass [x, y, z] (km):\n');
21 | R2_0 = input('Input the initial position vector of the second mass [x, y, z] (km):\n');
22 |
23 | V1_0 = input('Input the initial velocity vector of the first mass [x, y, z] (km/s):\n');
24 | V2_0 = input('Input the initial velocity vector of the second mass [x, y, z] (km/s):\n');
25 |
26 | %% make sure all vectors are column vectors
27 | if isrow(R1_0)
28 | R1_0 = R1_0';
29 | end
30 |
31 | if isrow(R2_0)
32 | R2_0 = R2_0';
33 | end
34 |
35 | if isrow(V1_0)
36 | V1_0 = V1_0';
37 | end
38 |
39 | if isrow(V2_0)
40 | V2_0 = V2_0';
41 | end
42 |
43 | %% set initial coniditions
44 | y0 = [R1_0; R2_0; V1_0; V2_0];
45 |
46 | %% integrate the equations of motion
47 | [t,y] = rkf45(@rates, [t0 tf], y0);
48 |
49 | %% output the results
50 | output
51 |
52 | return
53 |
54 | %% ---------subfunctions----------------------------------
55 | function dydt = rates(t,y)
56 |
57 | R1 = [y(1); y(2); y(3)];
58 | R2 = [y(4); y(5); y(6)];
59 |
60 | V1 = [y(7); y(8); y(9)];
61 | V2 = [y(10); y(11); y(12)];
62 |
63 | r = norm(R2 - R1);
64 |
65 | A1 = G*m2*(R2 - R1)/r^3;
66 | A2 = G*m1*(R1 - R2)/r^3;
67 |
68 | dydt = [V1; V2; A1; A2];
69 |
70 | end %rates
71 |
72 | function output
73 | %
74 | % This function calculates the trajectory of the center of mass and
75 | % plots
76 | %
77 | % (a) the motion of m1, m2 and G relative to the inertial frame
78 | % (b) the motion of m2 and G relative to m1
79 | % (c) the motion of m1 and m2 relative to G
80 | %
81 | clc;
82 |
83 | %...Extract the particle trajectories:
84 | X1 = y(:,1); Y1 = y(:,2); Z1 = y(:,3);
85 | X2 = y(:,4); Y2 = y(:,5); Z2 = y(:,6);
86 |
87 | %...Locate the center of mass at each time step:
88 | XG = []; YG = []; ZG = [];
89 | for i = 1:length(t)
90 | XG = [XG; (m1*X1(i) + m2*X2(i))/(m1 + m2)];
91 | YG = [YG; (m1*Y1(i) + m2*Y2(i))/(m1 + m2)];
92 | ZG = [ZG; (m1*Z1(i) + m2*Z2(i))/(m1 + m2)];
93 | end
94 |
95 | %...Plot the trajectories:
96 | figure (1)
97 | title('Motion relative to the inertial frame')
98 | hold on
99 | plot3(X1, Y1, Z1, '-r')
100 | plot3(X2, Y2, Z2, '-g')
101 | plot3(XG, YG, ZG, '-b')
102 |
103 | %comet3(X1, Y1, Z1);
104 | %comet3(X2, Y2, Z2);
105 |
106 |
107 | text(X1(1), Y1(1), Z1(1), '1', 'color', 'r')
108 | text(X2(1), Y2(1), Z2(1), '2', 'color', 'g')
109 | text(XG(1), YG(1), ZG(1), 'G', 'color', 'b')
110 |
111 | common_axis_settings
112 |
113 | figure (2)
114 | title('Motion of m2 and G relative to m1')
115 | hold on
116 | plot3(X2 - X1, Y2 - Y1, Z2 - Z1, '-g')
117 | plot3(XG - X1, YG - Y1, ZG - Z1, '-b')
118 |
119 |
120 | text(X2(1)-X1(1), Y2(1)-Y1(1), Z2(1)-Z1(1), '2', 'color', 'g')
121 | text(XG(1)-X1(1), YG(1)-X1(1), ZG(1)-X1(1), 'G', 'color', 'b')
122 |
123 | common_axis_settings
124 |
125 | figure (3)
126 | title('Motion of m1 and m2 relative to G')
127 | hold on
128 | plot3(X1 - XG, Y1 - YG, Z1 - ZG, '-r')
129 | plot3(X2 - XG, Y2 - YG, Z2 - ZG, '-g')
130 |
131 | text(X1(1)-XG(1), Y1(1)-YG(1), Z1(1)-ZG(1), '1', 'color', 'r')
132 | text(X2(1)-XG(1), Y2(1)-YG(1), Z2(1)-ZG(1), '1', 'color', 'g')
133 |
134 | common_axis_settings
135 |
136 | function common_axis_settings
137 | %
138 | % This function establishes axis properties common to the several plots
139 | %
140 | text(0, 0, 0, 'o')
141 | axis('equal')
142 | view([2,4,1.2])
143 | grid on
144 | axis equal
145 | xlabel('X (km)')
146 | ylabel('Y (km)')
147 | zlabel('Z (km)')
148 | end %common_axis_settings
149 | end %output
150 | end
--------------------------------------------------------------------------------
/ground_track_from_coe.m:
--------------------------------------------------------------------------------
1 | function ground_track_from_coe(h, e, i, omega, w, theta, n, mu, Re, J2, we)
2 | %% Calculate and plot the geocentric orbit of a satellite about the Earth
3 | %
4 | % Jeremy Penn
5 | % 21 October 2017
6 | %
7 | % Revision: 21/10/2017
8 | % 29/10/2017 - Changed RA from 0:360 to -180:180
9 | % 30/10/2017 - Reverted back to 0:360. Changed map to make
10 | % plot lines more readable. Also fixed an issue
11 | % with inverted y-axis from image import.
12 | %
13 | % function ground_track_from_coe(h, e, i, omega, w, theta, n, mu, Re, J2, we)
14 | %
15 | % Purpose: This function plots the ground track of a satellite in the
16 | % geocentric frame of reference.
17 | %
18 | % Input: o h - Specific angular momentum
19 | % o e - eccentricity
20 | % o i - orbital inclination
21 | % o omega - right ascension of the ascending node
22 | % o w - argument of perigee
23 | % o theta - true anomaly
24 | % o n - number of orbits [OPTIONAL]
25 | % o mu - standard grav param [OPTIONAL]
26 | % o Re - central body radius [OPTIONAL]
27 | % o J2 - central body second zonal harmonic [OPTIONAL]
28 | % o we - central body angular speed [OPTIONAL]
29 | %
30 | % Requires: ecc_anomaly_from_ta.m, ecc_anomaly_from_M.m, ta_from_E.m,
31 | % rv_from_coe.m, rot3.m, ra_and_dec_from_r.m, earth.png
32 | %
33 |
34 | clc;
35 | if nargin == 6
36 | n = 1;
37 | Re = 6378; % [km] radius of the Earth
38 | we = 7.27e-5; % [rad/s] angular speed of Earth
39 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
40 | J2 = 0.0010836;
41 | end
42 |
43 | if nargin == 7
44 | Re = 6378; % [km] radius of the Earth
45 | we = 7.27e-5; % [rad/s] angular speed of Earth
46 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
47 | J2 = 0.0010836;
48 | end
49 |
50 | %% Calculate the semi-major axis
51 | a = abs( (h^2/mu) * 1/(e^2 - 1) );
52 |
53 | %% Calculate rate of change omega and w
54 | incl = i*(pi/180);
55 |
56 | fac = -3/2*sqrt(mu)*J2*Re^2/(1-e^2)^2/a^(7/2);
57 |
58 | domega = fac*cos(incl);
59 | dw = fac*(5/2*sin(incl)^2 - 2);
60 |
61 | %% Find time since perigee
62 | E0 = ecc_anomaly_from_ta(theta,e);
63 | M0 = E0 - e*sin(E0);
64 | T = 2*pi/sqrt(mu)*a^(3/2);
65 | t0 = (M0/(2*pi)) * T;
66 | tf = t0 + n*T;
67 |
68 | %% Calculate the RA and dec
69 | timeint = linspace(t0,tf,1000);
70 | ind = 1;
71 |
72 | for j = 1:length(timeint)
73 | Me = (2*pi/T)*timeint(j);
74 | E = ecc_anomaly_from_M(e, Me);
75 | th = ta_from_E(E,e);
76 |
77 | omega = omega + domega * timeint(j);
78 | w = w + dw * timeint(j);
79 |
80 | [r, v] = rv_from_coe(h, e, i, omega, w, th*180/pi);
81 | theta = we * timeint(j);
82 | rprime = rot3(theta)*r;
83 |
84 | [RA(ind), del(ind)] = ra_and_dec_from_r(rprime); %#ok<*NASGU,*SAGROW,*AGROW>
85 |
86 | ind = ind + 1;
87 | end
88 |
89 | %% Separate the data into individual orbit lines
90 | [ra, dec, n_curves] = form_separate_curves(RA, del);
91 |
92 | %% Plot the ground track
93 |
94 | figure('units','normalized','outerposition',[0 0 1 1])
95 | map = imread('~/Documents/earth.png');
96 | image([0 360],[-90 90], flip(map), 'CDataMapping','scaled');
97 |
98 | axis equal % set axis units to be the same size
99 |
100 | ax = gca; % get current axis
101 | ax.XLim = [0 360]; % set x limits
102 | ax.YLim = [-90 90]; % set y limits
103 | ax.XTick = [0 60 120 180 240 300 360]; % define x ticks
104 | ax.YTick = [-90 -60 -30 0 30 60 90]; % define y ticks
105 | ax.YTickLabels = {'\bf 90 S', '\bf 60 S', '\bf 30 S', '\bf 0', '\bf 30 N', '\bf 60 N', '\bf 90 N'};
106 | ax.XTickLabels = {'\bf 0', '\bf 60', '\bf 120','\bf 180', '\bf 240', '\bf 300', '\bf 360'};
107 | set(gca,'FontSize',16,'Ydir','normal')
108 | set(gcf,'color',[.43, .43, .43])
109 | ax.XAxis.Color = 'w';
110 | ax.YAxis.Color = 'w';
111 |
112 | ylabel('Latitude [deg]','FontSize',20,'color','w');
113 | xlabel('Longitude [deg]','FontSize',20,'color','w');
114 | title('Satellite Ground Track','FontSize',24,'color','w');
115 |
116 | ts = text(ra{1}(1), dec{1}(1), 'o Start','color','black','FontWeight','bold');
117 | tf = text(ra{end}(end), dec{end}(end), 'o Finish','color','black','FontWeight','bold');
118 |
119 | ts.FontSize = 14;
120 | tf.FontSize = 14;
121 |
122 | hold on;
123 |
124 | for kk = 1:n_curves
125 | plot(ra{kk}, dec{kk})
126 | end
127 |
128 | function [RA, Dec, n_curves] = form_separate_curves(ra, dec)
129 |
130 | tol = 100;
131 | curve_no = 1;
132 | n_curves = 1;
133 | k = 0;
134 | ra_prev = ra(1);
135 |
136 | for li = 1:length(ra)
137 | if abs(ra(li) - ra_prev) > tol
138 | curve_no = curve_no + 1;
139 | n_curves = n_curves + 1;
140 | k = 0;
141 | end
142 | k = k + 1;
143 | RA{curve_no}(k) = ra(li);
144 | Dec{curve_no}(k) = dec(li);
145 | ra_prev = ra(li);
146 | end
147 | end
148 | end
--------------------------------------------------------------------------------
/planet_sv.m:
--------------------------------------------------------------------------------
1 | function [R, V, jd] = planet_sv(planet_id, d, m, y, UT)
2 | %% Calculate the sidereal time from the given date and UT time
3 | %
4 | % Jeremy Penn
5 | % 09 November 2017
6 | %
7 | % Revision 09/11/17
8 | % 11/11/2017 - Added jd output for use with
9 | % interplanetary_trajectory.m
10 | %
11 | % function [R, V] = planet_sv(planet_id, d, m, y, UT)
12 | %
13 | % Purpose: This function calculates the sidereal time.
14 | %
15 | % Inputs: o planet_id - A string name of the planet
16 | % o d - The day
17 | % o m - The month
18 | % o y - The year
19 | % o UT - The hour
20 | %
21 | % Outputs: o R - The heliocentric position
22 | % o V - The heloiocentric velocity
23 | % o jd - The Julian Day (J2000 epoch)
24 | %
25 | clc;
26 |
27 | %% constants
28 | mu = 1.327e11; %[km^3 / s^2] grav param of the Sun
29 |
30 | %% convert the planet input
31 | planet_id = lower(planet_id);
32 |
33 | switch planet_id
34 | case 'mercury'
35 | planet_id = 1;
36 | case 'venus'
37 | planet_id = 2;
38 | case 'earth'
39 | planet_id = 3;
40 | case 'mars'
41 | planet_id = 4;
42 | case 'jupiter'
43 | planet_id = 5;
44 | case 'saturn'
45 | planet_id = 6;
46 | case 'uranus'
47 | planet_id = 7;
48 | case 'neptune'
49 | planet_id = 8;
50 | case 'pluto'
51 | planet_id = 9;
52 | otherwise
53 | error(strcat(planet_id,' is not a planet'));
54 | end
55 |
56 | %% calculate JD
57 | j0 = 367*y - fix(7*(y + fix((m + 9)/12))/4) + fix((275*m)/9) + d + 1721013.5;
58 | jd = j0 + UT/24;
59 |
60 | %% calculate T0
61 | T0 = (jd - 2451545) / 36525;
62 |
63 | %% search table and adjust orbital elements for JD
64 | [J2000_coe, rates] = planetary_elements(planet_id);
65 |
66 | coe = J2000_coe + rates*T0;
67 |
68 | %% ensure all angles are between 0 and 360
69 | a = coe(1);
70 | e = coe(2);
71 | inc = mod(coe(3), 360);
72 | W = mod(coe(4), 360);
73 | w_hat = mod(coe(5), 360);
74 | L = mod(coe(6), 360);
75 | w = mod(w_hat - W ,360);
76 | M = mod(L - w_hat ,360);
77 |
78 | %% calculate h
79 | h = sqrt( mu*a*(1 - e^2) );
80 |
81 | %% calculate the eccentric anomaly
82 | E = ecc_anomaly_from_M(e, M*pi/180);
83 | E = E * 180/pi;
84 |
85 | %% calculate the true anomaly
86 | th = ta_from_E(E, e);
87 |
88 | %% calculate the state vector from coe
89 | [R,V] = rv_from_coe(h, e, inc, W, w, th, mu);
90 |
91 |
92 | function [J2000_coe, rates] = planetary_elements(planet_id)
93 | %{
94 | This function extracts a planet's J2000 orbital elements and
95 | centennial rates from Table 8.1.
96 |
97 | planet_id - 1 through 9, for Mercury through Pluto
98 |
99 | J2000_elements - 9 by 6 matrix of J2000 orbital elements for the nine
100 | planets Mercury through Pluto. The columns of each
101 | row are:
102 | a = semimajor axis (AU)
103 | e = eccentricity
104 | i = inclination (degrees)
105 | RA = right ascension of the ascending
106 | node (degrees)
107 | w_hat = longitude of perihelion (degrees)
108 | L = mean longitude (degrees)
109 |
110 | cent_rates - 9 by 6 matrix of the rates of change of the
111 | J2000_elements per Julian century (Cy). Using "dot"
112 | for time derivative, the columns of each row are:
113 | a_dot (AU/Cy)
114 | e_dot (1/Cy)
115 | i_dot (deg/Cy)
116 | RA_dot (deg/Cy)
117 | w_hat_dot (deg/Cy)
118 | Ldot (deg/Cy)
119 |
120 | J2000_coe - row vector of J2000_elements corresponding
121 | to "planet_id", with au converted to km
122 | rates - row vector of cent_rates corresponding to
123 | "planet_id", with au converted to km
124 |
125 | au - astronomical unit (149597871 km)
126 | %}
127 | % --------------------------------------------------------------------
128 |
129 | %---- a ----------- e --------- i ---------- RA ------- w_hat ------- L ------
130 |
131 | J2000_elements = ...
132 | [0.38709927 0.20563593 7.00497902 48.33076593 77.45779628 252.25032350
133 | 0.72333566 0.00677672 3.39467605 76.67984255 131.60246718 181.97909950
134 | 1.00000261 0.01671123 -0.00001531 0.0 102.93768193 100.46457166
135 | 1.52371034 0.09339410 1.84969142 49.55953891 -23.94362959 -4.55343205
136 | 5.20288700 0.04838624 1.30439695 100.47390909 14.72847983 34.39644501
137 | 9.53667594 0.05386179 2.48599187 113.66242448 92.59887831 49.95424423
138 | 19.18916464 0.04725744 0.77263783 74.01692503 170.95427630 313.23810451
139 | 30.06992276 0.00859048 1.77004347 131.78422574 44.96476227 -55.12002969
140 | 39.48211675 0.24882730 17.14001206 110.30393684 224.06891629 238.92903833];
141 |
142 | cent_rates = ...
143 | [0.00000037 0.00001906 -0.00594749 -0.12534081 0.16047689 149472.67411175
144 | 0.00000390 -0.00004107 -0.00078890 -0.27769418 0.00268329 58517.81538729
145 | 0.00000562 -0.00004392 -0.01294668 0.0 0.32327364 35999.37244981
146 | 0.0001847 0.00007882 -0.00813131 -0.29257343 0.44441088 19140.30268499
147 | -0.00011607 -0.00013253 -0.00183714 0.20469106 0.21252668 3034.74612775
148 | -0.00125060 -0.00050991 0.00193609 -0.28867794 -0.41897216 1222.49362201
149 | -0.00196176 -0.00004397 -0.00242939 0.04240589 0.40805281 428.48202785
150 | 0.00026291 0.00005105 0.00035372 -0.00508664 -0.32241464 218.45945325
151 | -0.00031596 0.00005170 0.00004818 -0.01183482 -0.04062942 145.20780515];
152 |
153 | J2000_coe = J2000_elements(planet_id,:);
154 | rates = cent_rates(planet_id,:);
155 |
156 | %...Convert from AU to km:
157 | au = 149597871;
158 | J2000_coe(1) = J2000_coe(1)*au;
159 | rates(1) = rates(1)*au;
160 |
161 | end %planetary_elements
162 | end
--------------------------------------------------------------------------------
/iss_tracking.m:
--------------------------------------------------------------------------------
1 | function iss_tracking()
2 | %% pulls current ISS two-line element from NORAD website
3 | %{
4 | Jeremy Penn
5 | 20/11/2017
6 | Updated: 24/06/2018
7 |
8 | function iss_current_track()
9 |
10 | Purpose: This function calculates and plots the ground track and
11 | orbit of the ISS using the TLE from NORAD.
12 |
13 | Requires: ecc_anomaly_from_ta.m, ecc_anomaly_from_M.m, ta_from_E.m,
14 | rv_from_coe.m, rot3.m, ra_and_dec_from_r.m, earth.png
15 | %}
16 |
17 | %% constants
18 | n_orbits = input('Input the number of orbits:\n');
19 | Re = 6378; % [km] radius of the Earth
20 | we = 7.27e-5; % [rad/s] angular speed of Earth
21 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
22 | J2 = 0.0010836;
23 | m_2 = 419455; % [kg] mass of the ISS (approximate)
24 |
25 | %% url to pull data
26 | url = 'http://www.celestrak.com/NORAD/elements/stations.txt';
27 |
28 | %% pull request for orbital data
29 | data = webread(url);
30 |
31 | %% isolate the ISS TLE
32 | sl = strsplit(data,'\n');
33 |
34 | for i = 1:3 % isolate the first 3 lines (ISS)
35 | ss{i} = strsplit(sl{i},' ');
36 | end
37 |
38 | ss{3}{5} = strcat('0.',ss{3}{5});
39 |
40 | for lj = 1:length(ss{3}) - 1
41 | coe(lj) = str2double(ss{3}{lj});
42 | end
43 | coe(8) = str2double( extractBefore(ss{3}{8},12) );
44 |
45 | %% separate coe
46 | inc = coe(3); % orbital inclination [deg]
47 | W = coe(4); % longitude of the ascending node [deg]
48 | e = coe(5); % eccentricity
49 | w = coe(6); % argument of perigee [deg]
50 | M = coe(7) * pi/180; % mean anomaly [rad]
51 | n = coe(8); % mean motion [rev/d]
52 |
53 | %% Calculate the semi-major axis
54 | n = n * pi/43200; % [rad/s] convert from rev/d
55 | a = (mu^(1/3)) / (n^(2/3)); % semi-major axis [km]
56 | h = sqrt( a * mu * (1 - e^2) ); % specific angular momentum [km^2/s]
57 |
58 | % Find time since perigee
59 | T = 2*pi/n;
60 | t0 = (M/(2*pi)) * T;
61 | tf = t0 + n_orbits*T;
62 |
63 | %% calculate the orbit
64 | E_0 = ecc_anomaly_from_M(e, M);
65 | ta = ta_from_E(E_0,e);
66 | [r_0, v_0] = rv_from_coe(h, e, inc, W, w, ta);
67 |
68 | orbit(r_0, v_0, m_2, t0, tf, a)
69 |
70 | %% calculate the ground track
71 | ground_track_from_tle(inc, W, e, w)
72 |
73 | return
74 |
75 | %%-------------subfunctions---------------------------------
76 | function ground_track_from_tle(i, omega, e, w)
77 | % Calculate and plot the geocentric orbit of a satellite about the Earth
78 |
79 | %
80 | % Input: o M - mean anomaly [rad]
81 | % o e - eccentricity
82 | % o i - orbital inclination [deg]
83 | % o omega - right ascension of the ascending node [deg]
84 | % o w - argument of perigee [deg]
85 | % o n - mean motion [rad/s]
86 | %
87 |
88 | % Calculate rate of change omega and w
89 | incl = i*(pi/180);
90 |
91 | fac = -3/2*sqrt(mu)*J2*Re^2/(1-e^2)^2/a^(7/2);
92 |
93 | domega = fac*cos(incl);
94 | dw = fac*(5/2*sin(incl)^2 - 2);
95 |
96 | % Calculate the RA and dec
97 | timeint = linspace(t0,tf,1000);
98 | ind = 1;
99 |
100 | for j = 1:length(timeint)
101 | Me = (2*pi/T)*timeint(j); % mean anomaly at time t
102 | E = ecc_anomaly_from_M(e, Me); % eccentric anomaly at time t
103 | th = ta_from_E(E,e); % true anomaly at time t
104 |
105 | omega = omega + domega * timeint(j);
106 | w = w + dw * timeint(j);
107 |
108 | [r, v] = rv_from_coe(h, e, i, omega, w, th*180/pi);
109 | theta = we * timeint(j);
110 | rprime = rot3(theta)*r;
111 |
112 | [RA(ind), del(ind)] = ra_and_dec_from_r(rprime); %#ok<*NASGU,*SAGROW,*AGROW>
113 |
114 | ind = ind + 1;
115 | end
116 |
117 | % Separate the data into individual orbit lines
118 | [ra, dec, n_curves] = form_separate_curves(RA, del);
119 |
120 | % Plot the ground track
121 | figure('units','normalized','outerposition',[0 0 1 1])
122 | map = imread('~/Documents/earth.png');
123 | image([0 360],[-90 90], flip(map), 'CDataMapping','scaled');
124 |
125 | axis equal % set axis units to be the same size
126 |
127 | ax = gca; % get current axis
128 | ax.XLim = [0 360]; % set x limits
129 | ax.YLim = [-90 90]; % set y limits
130 | ax.XTick = [0 60 120 180 240 300 360]; % define x ticks
131 | ax.YTick = [-90 -60 -30 0 30 60 90]; % define y ticks
132 | ax.YTickLabels = {'\bf 90 S', '\bf 60 S', '\bf 30 S', '\bf 0', '\bf 30 N', '\bf 60 N', '\bf 90 N'};
133 | ax.XTickLabels = {'\bf 0', '\bf 60', '\bf 120','\bf 180', '\bf 240', '\bf 300', '\bf 360'};
134 | set(gca,'FontSize',16,'Ydir','normal')
135 | set(gcf,'color',[.43, .43, .43])
136 | ax.XAxis.Color = 'w';
137 | ax.YAxis.Color = 'w';
138 |
139 | ylabel('Latitude [deg]','FontSize',20,'color','w');
140 | xlabel('Longitude [deg]','FontSize',20,'color','w');
141 | title('Satellite Ground Track','FontSize',24,'color','w');
142 |
143 | ts = text(ra{1}(1), dec{1}(1), 'o Start','color','black','FontWeight','bold');
144 | tf = text(ra{end}(end), dec{end}(end), 'o Finish','color','black','FontWeight','bold');
145 |
146 | ts.FontSize = 14;
147 | tf.FontSize = 14;
148 |
149 | hold on;
150 |
151 | for kk = 1:n_curves
152 | plot(ra{kk}, dec{kk})
153 | end
154 |
155 | function [RA, Dec, n_curves] = form_separate_curves(ra, dec)
156 |
157 | tol = 100;
158 | curve_no = 1;
159 | n_curves = 1;
160 | k = 0;
161 | ra_prev = ra(1);
162 |
163 | for li = 1:length(ra)
164 | if abs(ra(li) - ra_prev) > tol
165 | curve_no = curve_no + 1;
166 | n_curves = n_curves + 1;
167 | k = 0;
168 | end
169 | k = k + 1;
170 | RA{curve_no}(k) = ra(li);
171 | Dec{curve_no}(k) = dec(li);
172 | ra_prev = ra(li);
173 | end
174 | end %form_separate_curves
175 | end %ground_track
176 | end %iss_current_track
--------------------------------------------------------------------------------
/euler_rotation.m:
--------------------------------------------------------------------------------
1 | function euler_rotation(R, alpha, beta, gamma)
2 | %% Computes the "classical" Euler angle sequence
3 | % This program computes the classical Euler angle sequence
4 | %
5 | % Jeremy Penn
6 | % 18 October 2017
7 | %
8 | % Revision 19/10/17
9 | %
10 | % function eulerRotation(R, alpha, beta, gamma)
11 | %
12 | % Purpose: This function computes the Euler angle sequence about any 3
13 | % axis sequence.
14 | %
15 | % Inputs: o R - A 1x3 vector of the satellite's initial position.
16 | % o alpha - The primary Euler angle.
17 | % o beta - The secondary Euler angle.
18 | % o gamma - The tertiary Euler angle.
19 | %
20 | % Requires: rot1.m, rot2.m, rot3.m
21 | %
22 | clc;
23 |
24 | %% Check the angles are between 0 and 360
25 | alpha = mod(alpha, 360);
26 | beta = mod(beta, 360);
27 | gamma = mod(gamma, 360);
28 |
29 | %% Convert to radians
30 |
31 | alpha = alpha * pi/180;
32 | beta = beta * pi/180;
33 | gamma = gamma * pi/180;
34 |
35 | %% Check that R is a column vector
36 |
37 | if isrow(R)
38 | R = transpose(R);
39 | end
40 |
41 | %% Calculate Euler angle sequences
42 | str1 = input('Please choose the primary rotation axis ','s');
43 | str2 = input('Please choose the secondary rotation axis ','s');
44 | str3 = input('Please choose the tertiary rotation axis ','s');
45 |
46 | switch str1
47 | case 'x'
48 | switch str2
49 | case 'x'
50 | switch str3
51 | case 'z'
52 | r = rot1(alpha)*rot1(beta)*rot3(gamma)*R;
53 | case 'y'
54 | r = rot1(alpha)*rot1(beta)*rot2(gamma)*R;
55 | case 'x'
56 | r = rot1(alpha)*rot1(beta)*rot1(gamma)*R;
57 | otherwise
58 | error('Input must be char not a %s',class(str3))
59 | end
60 | case 'y'
61 | switch str3
62 | case 'z'
63 | r = rot1(alpha)*rot2(beta)*rot3(gamma)*R;
64 | case 'y'
65 | r = rot1(alpha)*rot2(beta)*rot2(gamma)*R;
66 | case 'x'
67 | r = rot1(alpha)*rot2(beta)*rot1(gamma)*R;
68 | otherwise
69 | error('Input must be char not a %s',class(str3))
70 | end
71 | case 'z'
72 | switch str3
73 | case 'z'
74 | r = rot1(alpha)*rot3(beta)*rot3(gamma)*R;
75 | case 'y'
76 | r = rot1(alpha)*rot3(beta)*rot2(gamma)*R;
77 | case 'x'
78 | r = rot1(alpha)*rot3(beta)*rot1(gamma)*R;
79 | otherwise
80 | error('Input must be char not a %s',class(str3))
81 | end
82 | otherwise
83 | error('Input must be char not a %s',class(str2))
84 | end
85 | case 'y'
86 | switch str2
87 | case 'x'
88 | switch str3
89 | case 'z'
90 | r = rot2(alpha)*rot1(beta)*rot3(gamma)*R;
91 | case 'y'
92 | r = rot2(alpha)*rot1(beta)*rot2(gamma)*R;
93 | case 'x'
94 | r = rot2(alpha)*rot1(beta)*rot1(gamma)*R;
95 | otherwise
96 | error('Input must be char not a %s',class(str3))
97 | end
98 | case 'y'
99 | switch str3
100 | case 'z'
101 | r = rot2(alpha)*rot2(beta)*rot3(gamma)*R;
102 | case 'y'
103 | r = rot2(alpha)*rot2(beta)*rot2(gamma)*R;
104 | case 'x'
105 | r = rot2(alpha)*rot2(beta)*rot1(gamma)*R;
106 | otherwise
107 | error('Input must be char not a %s',class(str3))
108 | end
109 | case 'z'
110 | switch str3
111 | case 'z'
112 | r = rot2(alpha)*rot3(beta)*rot3(gamma)*R;
113 | case 'y'
114 | r = rot2(alpha)*rot3(beta)*rot2(gamma)*R;
115 | case 'x'
116 | r = rot2(alpha)*rot3(beta)*rot1(gamma)*R;
117 | otherwise
118 | error('Input must be char not a %s',class(str3))
119 | end
120 | otherwise
121 | error('Input must be char not a %s',class(str2))
122 | end
123 | case 'z'
124 | switch str2
125 | case 'x'
126 | switch str3
127 | case 'z'
128 | r = rot3(alpha)*rot1(beta)*rot3(gamma)*R;
129 | case 'y'
130 | r = rot3(alpha)*rot1(beta)*rot2(gamma)*R;
131 | case 'x'
132 | r = rot3(alpha)*rot1(beta)*rot1(gamma)*R;
133 | otherwise
134 | error('Input must be char not a %s',class(str3))
135 | end
136 | case 'y'
137 | switch str3
138 | case 'z'
139 | r = rot3(alpha)*rot2(beta)*rot3(gamma)*R;
140 | case 'y'
141 | r = rot3(alpha)*rot2(beta)*rot2(gamma)*R;
142 | case 'x'
143 | r = rot3(alpha)*rot2(beta)*rot1(gamma)*R;
144 | otherwise
145 | error('Input must be char not a %s',class(str3))
146 | end
147 | case 'z'
148 | switch str3
149 | case 'z'
150 | r = rot3(alpha)*rot3(beta)*rot3(gamma)*R;
151 | case 'y'
152 | r = rot3(alpha)*rot3(beta)*rot2(gamma)*R;
153 | case 'x'
154 | r = rot3(alpha)*rot3(beta)*rot1(gamma)*R;
155 | otherwise
156 | error('Input must be char not a %s',class(str3))
157 | end
158 | otherwise
159 | error('Input must be char not a %s',class(str2))
160 | end
161 | otherwise
162 | error('Input must be char not a %s',class(str1))
163 | end
164 | %% Display the results
165 |
166 | fprintf('The new x-coordinate is %.2f\n',r(1))
167 | fprintf('The new y-coordinate is %.2f\n',r(2))
168 | fprintf('The new z-coordinate is %.2f\n',r(3))
169 | end
170 |
171 |
--------------------------------------------------------------------------------
/orbit.m:
--------------------------------------------------------------------------------
1 | function orbit(r_0, v_0, m_2, t_0, t_f, a)
2 | %% plots the orbit of a small mass around a large central mass
3 | %
4 | % Jeremy Penn
5 | % 22/11/17
6 | %
7 | % function orbit(r_0, v_0, m_2, t_0, t_f)
8 | %
9 | % Inputs: o r_0 - The initial position vector [OPTIONAL]
10 | % o v_0 - The initial velocity vector [OPTIONAL]
11 | % o m_2 - The mass of the orbiting body [OPTIONAL]
12 | % o t_0 - The initial time [OPTIONAL]
13 | % o t_f - The final time [OPTIONAL]
14 | %
15 | % Requires: rkf45.m,
16 | %
17 | S = load('topo');
18 |
19 | %% constants
20 | G = 6.6742e-20; %[km^3/kg s^2] gravitational constant
21 |
22 | %% inputs
23 | m1 = 5.974e24; % mass of the Earth [kg]
24 | R = 6378; % radisu of the Earth[km]
25 |
26 | if nargin < 1
27 | m2 = input('Input the mass of the orbiting body (kg):\n');
28 | r0 = input('Input the initial geocentric position vector of the orbiting body [x, y, z](km):\n');
29 | v0 = input('Input the initial geocentric velocity vector of the orbiting body [vx, vy, vz] (km/s):\n');
30 |
31 | t0 = input('Input the initial time (s):\n');
32 | tf = input('Input the final time (s): \n');
33 | else
34 | r0 = r_0;
35 | v0 = v_0;
36 | m2 = m_2;
37 | t0 = t_0;
38 | tf = t_f;
39 | end
40 |
41 | %% confirm r and v are row vectors
42 |
43 | if iscolumn(r_0)
44 | r0 = r0';
45 | end
46 |
47 | if iscolumn(v_0)
48 | v0 = v0';
49 | end
50 |
51 | %% numerically integrate the orbit
52 | mu = G*(m1 + m2);
53 | y0 = [r0 v0]';
54 | [t,y] = rkf45(@rates, [t0 tf], y0);
55 |
56 | %% plot and print the results
57 | output
58 |
59 | return
60 |
61 | %% -------subfunctions------------------------
62 | function dydt = rates(t,f) %#ok<*INUSL>
63 | % ~~~~~~~~~~~~~~~~~~~~~~~~
64 | %{
65 | This function calculates the acceleration vector using Equation 2.22
66 |
67 | t - time
68 | f - column vector containing the position vector and the
69 | velocity vector at time t
70 | x, y, z - components of the position vector r
71 | r - the magnitude of the the position vector
72 | vx, vy, vz - components of the velocity vector v
73 | ax, ay, az - components of the acceleration vector a
74 | dydt - column vector containing the velocity and acceleration
75 | components
76 | %}
77 | % ------------------------
78 | x = f(1);
79 | y = f(2);
80 | z = f(3);
81 | vx = f(4);
82 | vy = f(5);
83 | vz = f(6);
84 |
85 | r = norm([x y z]);
86 |
87 | ax = -mu*x/r^3;
88 | ay = -mu*y/r^3;
89 | az = -mu*z/r^3;
90 |
91 | dydt = [vx vy vz ax ay az]';
92 | end %rates
93 |
94 | function output
95 | %{
96 | This function computes the maximum and minimum radii, the times they
97 | occur and the speed at those times. It prints those results to
98 | the command window and plots the orbit.
99 |
100 | r - magnitude of the position vector at the times in t
101 | imax - the component of r with the largest value
102 | rmax - the largest value of r
103 | imin - the component of r with the smallest value
104 | rmin - the smallest value of r
105 | v_at_rmax - the speed where r = rmax
106 | v_at_rmin - the speed where r = rmin
107 | %}
108 | % -------------
109 | [h, e, inc, W, w, ta] = coe_from_rv(r0,v0);
110 |
111 | for i = 1:length(t)
112 | r(i) = norm([y(i,1) y(i,2) y(i,3)]); %#ok<*AGROW>
113 | end
114 |
115 | [rmax, imax] = max(r);
116 | [rmin, imin] = min(r);
117 |
118 | v_at_rmax = norm([y(imax,4) y(imax,5) y(imax,6)]);
119 | v_at_rmin = norm([y(imin,4) y(imin,5) y(imin,6)]);
120 |
121 | %...Output to the command window:
122 | clc;
123 | fprintf('\n\n--------------------------------------------------------\n')
124 | fprintf('\n Earth Orbit\n')
125 | fprintf(' %s\n', datestr(now))
126 | fprintf('\n The initial position is [%g, %g, %g] (km).',...
127 | r0(1), r0(2), r0(3))
128 | fprintf('\n\t Magnitude = %g km\n', norm(r0))
129 | fprintf('\n The initial velocity is [%g, %g, %g] (km/s).',...
130 | v0(1), v0(2), v0(3))
131 | fprintf('\n\t Magnitude = %g km/s\n', norm(v0))
132 | fprintf('\n Initial time = %g h.\n Final time = %g h.\n',0,tf/3600)
133 | fprintf('\n The minimum altitude is %g km at time = %g h.',...
134 | rmin-R, t(imin)/3600)
135 | fprintf('\n The speed at that point is %g km/s.\n', v_at_rmin)
136 | fprintf('\n The maximum altitude is %g km at time = %g h.',...
137 | rmax-R, t(imax)/3600)
138 | fprintf('\n The speed at that point is %g km/s\n', v_at_rmax)
139 | fprintf('\n The classic orbital elements:\n')
140 | fprintf('\n\t h = %.2f [km^2/s]',h)
141 | fprintf('\n\t a = %.2f [km]',a)
142 | fprintf('\n\t e = %.5f',e)
143 | fprintf('\n\t i = %.2f [deg]',inc)
144 | fprintf('\n\t W = %.2f [deg]',W)
145 | fprintf('\n\t w = %.2f [deg]',w)
146 | fprintf('\n\t ta = %.2f [deg]',ta)
147 | fprintf('\n\t ep = %.2f [MJ/kg]',-mu / (2*a))
148 | fprintf('\n--------------------------------------------------------\n\n')
149 |
150 | %...Plot the results:
151 | % Draw the planet
152 |
153 | grs80 = referenceEllipsoid('grs80','km');
154 |
155 | figure('Renderer','opengl')
156 | ax = axesm('globe','Geoid',grs80,'Grid','off', ...
157 | 'GLineWidth',1,'GLineStyle','-',...
158 | 'Gcolor',[0.9 0.9 0.1],'Galtitude',100);
159 | ax.Position = [0 0 1 1];
160 | axis equal off
161 | %view(0,23.5)
162 |
163 | geoshow(S.topo,S.topolegend,'DisplayType','texturemap')
164 | demcmap(S.topo)
165 | land = shaperead('landareas','UseGeoCoords',true);
166 | plotm([land.Lat],[land.Lon],'Color','black')
167 | rivers = shaperead('worldrivers','UseGeoCoords',true);
168 | plotm([rivers.Lat],[rivers.Lon],'Color','blue')
169 |
170 | % Draw and label the X, Y and Z axes
171 | line([0 2*R], [0 0], [0 0]); text(2*R, 0, 0, 'X')
172 | line( [0 0], [0 2*R], [0 0]); text( 0, 2*R, 0, 'Y')
173 | line( [0 0], [0 0], [0 2*R]); text( 0, 0, 2*R, 'Z')
174 |
175 | % Plot the orbit, draw a radial to the starting point
176 | % and label the starting point (o) and the final point (f)
177 | hold on
178 | plot3( y(:,1), y(:,2), y(:,3),'r')
179 | line([0 r0(1)], [0 r0(2)], [0 r0(3)])
180 | text( y(1,1), y(1,2), y(1,3), 'o')
181 | text( y(end,1), y(end,2), y(end,3), 'f')
182 |
183 | % Select a view direction (a vector directed outward from the origin)
184 | view([1,1,.4])
185 |
186 | % Specify some properties of the graph
187 | grid on
188 | axis equal
189 | xlabel('km')
190 | ylabel('km')
191 | zlabel('km')
192 |
193 | end %output
194 | end
--------------------------------------------------------------------------------
/iss_current_track.m:
--------------------------------------------------------------------------------
1 | function iss_current_track()
2 | %% pulls current ISS two-line element from NORAD website
3 | %{
4 | Jeremy Penn
5 | 20/11/2017
6 | Updated: 24/06/2018
7 |
8 | function iss_current_track()
9 |
10 | Requires: ecc_anomaly_from_ta.m, ecc_anomaly_from_M.m, ta_from_E.m,
11 | rv_from_coe.m, rot3.m, ra_and_dec_from_r.m, earth.png
12 | %}
13 |
14 | %% constants
15 | n_orbits = input('Input the number of orbits:\n');
16 | Re = 6378; % [km] radius of the Earth
17 | we = 7.27e-5; % [rad/s] angular speed of Earth
18 | mu = 398600; % [km^3/s^2] Standard Gravitational Parameter
19 | J2 = 0.0010836;
20 |
21 | %% url to pull data
22 | url = 'http://www.celestrak.com/NORAD/elements/stations.txt';
23 |
24 | %% pull request for orbital data
25 | data = webread(url);
26 |
27 | %% isolate the ISS TLE
28 | sl = strsplit(data,'\n');
29 |
30 | for i = 1:3 % isolate the first 3 lines (ISS)
31 | ss{i} = strsplit(sl{i},' ');
32 | end
33 |
34 | ss{3}{5} = strcat('0.',ss{3}{5});
35 |
36 | for lj = 1:length(ss{3}) - 1
37 | coe(lj) = str2double(ss{3}{lj});
38 | end
39 | coe(8) = str2double( extractBefore(ss{3}{8},12) );
40 |
41 | %% separate coe
42 | inc = coe(3); % orbital inclination [deg]
43 | W = coe(4); % longitude of the ascending node [deg]
44 | e = coe(5); % eccentricity
45 | w = coe(6); % argument of perigee [deg]
46 | M = coe(7) * pi/180; % mean anomaly [rad]
47 | n = coe(8); % mean motion [rev/d]
48 |
49 | %% Calculate the semi-major axis
50 | n = n * pi/43200; % [rad/s] convert from rev/d
51 | a = (mu^(1/3)) / (n^(2/3)); % semi-major axis [km]
52 | h = sqrt( a * mu * (1 - e^2) ); % specific angular momentum [km^2/s]
53 |
54 | %% calculate the ground track
55 | ground_track_from_tle(inc, W, e, w, M, n)
56 |
57 | %% ouput the results
58 | output
59 |
60 | return
61 |
62 | %%-------------subfunctions---------------------------------
63 | function ground_track_from_tle(i, omega, e, w, M, n)
64 | % Calculate and plot the geocentric orbit of a satellite about the Earth
65 |
66 | %
67 | % Input: o M - mean anomaly [rad]
68 | % o e - eccentricity
69 | % o i - orbital inclination [deg]
70 | % o omega - right ascension of the ascending node [deg]
71 | % o w - argument of perigee [deg]
72 | % o n - mean motion [rad/s]
73 | %
74 |
75 | % Calculate rate of change omega and w
76 | incl = i*(pi/180);
77 |
78 | fac = -3/2*sqrt(mu)*J2*Re^2/(1-e^2)^2/a^(7/2);
79 |
80 | domega = fac*cos(incl);
81 | dw = fac*(5/2*sin(incl)^2 - 2);
82 |
83 | % Find time since perigee
84 | T = 2*pi/n;
85 | t0 = (M/(2*pi)) * T;
86 | tf = t0 + n_orbits*T;
87 |
88 | % Calculate the RA and dec
89 | timeint = linspace(t0,tf,1000);
90 | ind = 1;
91 |
92 | for j = 1:length(timeint)
93 | Me = (2*pi/T)*timeint(j); % mean anomaly at time t
94 | E = ecc_anomaly_from_M(e, Me); % eccentric anomaly at time t
95 | th = ta_from_E(E,e); % true anomaly at time t
96 |
97 | omega = omega + domega * timeint(j);
98 | w = w + dw * timeint(j);
99 |
100 | [r, v] = rv_from_coe(h, e, i, omega, w, th*180/pi);
101 | theta = we * timeint(j);
102 | rprime = rot3(theta)*r;
103 |
104 | [RA(ind), del(ind)] = ra_and_dec_from_r(rprime); %#ok<*NASGU,*SAGROW,*AGROW>
105 |
106 | ind = ind + 1;
107 | end
108 |
109 | % Separate the data into individual orbit lines
110 | [ra, dec, n_curves] = form_separate_curves(RA, del);
111 |
112 | % Plot the ground track
113 | figure('units','normalized','outerposition',[0 0 1 1])
114 | map = imread('~/Documents/earth.png');
115 | image([0 360],[-90 90], flip(map), 'CDataMapping','scaled');
116 |
117 | axis equal % set axis units to be the same size
118 |
119 | ax = gca; % get current axis
120 | ax.XLim = [0 360]; % set x limits
121 | ax.YLim = [-90 90]; % set y limits
122 | ax.XTick = [0 60 120 180 240 300 360]; % define x ticks
123 | ax.YTick = [-90 -60 -30 0 30 60 90]; % define y ticks
124 | ax.YTickLabels = {'\bf 90 S', '\bf 60 S', '\bf 30 S', '\bf 0', '\bf 30 N', '\bf 60 N', '\bf 90 N'};
125 | ax.XTickLabels = {'\bf 0', '\bf 60', '\bf 120','\bf 180', '\bf 240', '\bf 300', '\bf 360'};
126 | set(gca,'FontSize',16,'Ydir','normal')
127 | set(gcf,'color',[.43, .43, .43])
128 | ax.XAxis.Color = 'w';
129 | ax.YAxis.Color = 'w';
130 |
131 | ylabel('Latitude [deg]','FontSize',20,'color','w');
132 | xlabel('Longitude [deg]','FontSize',20,'color','w');
133 | title('Satellite Ground Track','FontSize',24,'color','w');
134 |
135 | ts = text(ra{1}(1), dec{1}(1), 'o Start','color','black','FontWeight','bold');
136 | tf = text(ra{end}(end), dec{end}(end), 'o Finish','color','black','FontWeight','bold');
137 |
138 | ts.FontSize = 14;
139 | tf.FontSize = 14;
140 |
141 | hold on;
142 |
143 | for kk = 1:n_curves
144 | plot(ra{kk}, dec{kk})
145 | end
146 |
147 | function [RA, Dec, n_curves] = form_separate_curves(ra, dec)
148 |
149 | tol = 100;
150 | curve_no = 1;
151 | n_curves = 1;
152 | k = 0;
153 | ra_prev = ra(1);
154 |
155 | for li = 1:length(ra)
156 | if abs(ra(li) - ra_prev) > tol
157 | curve_no = curve_no + 1;
158 | n_curves = n_curves + 1;
159 | k = 0;
160 | end
161 | k = k + 1;
162 | RA{curve_no}(k) = ra(li);
163 | Dec{curve_no}(k) = dec(li);
164 | ra_prev = ra(li);
165 | end
166 | end %form_separate_curves
167 | end %ground_track
168 |
169 | function output
170 | clc;
171 | r_a = (1 + e)*a;
172 | r_p = (1 - e)*a;
173 | v_p = sqrt( ((1+e)*mu)/((1-e)*a) );
174 | v_a = sqrt( ((1-e)*mu)/((1+e)*a) );
175 |
176 | fprintf('----------------------------------------------\n')
177 | fprintf('Current ISS orbital elements: \n')
178 | fprintf('----------------------------------------------\n\n')
179 | fprintf('\t h = %.2f [km^2/s]\n', h)
180 | fprintf('\t a = %.2f [km]\n', a)
181 | fprintf('\t r_a = %.2f [km]\n', r_a)
182 | fprintf('\t r_p = %.2f [km]\n',r_p)
183 | fprintf('\t i = %.2f [deg]\n',inc)
184 | fprintf('\t e = %.4f \n',e)
185 | fprintf('\t W = %.2f [deg]\n',W)
186 | fprintf('\t w = %.2f [deg]\n\n',w)
187 | fprintf('----------------------------------------------\n')
188 | fprintf('Orbital altitude and speed: \n')
189 | fprintf('----------------------------------------------\n\n')
190 | fprintf('Maximum altitude: %.2f [km]\n',r_a - Re)
191 | fprintf('Minimum altitude: %.2f [km]\n',r_p - Re)
192 | fprintf('Maximum speed: %.2f [km/s]\n',v_p)
193 | fprintf('Minimum speed: %.2f [km/s]\n',v_a)
194 | fprintf('Orbital energy: %.2f [MJ/kg]\n',-mu/(2*a))
195 | fprintf('\n\n')
196 | end %output
197 | end %iss_current_track
--------------------------------------------------------------------------------
/interplanetary_trajectory.m:
--------------------------------------------------------------------------------
1 | function interplanetary_trajectory()
2 | %% Calculates the interplanetary COE, ejection angle, & hyperbolic excess velocities
3 | %
4 | % Jeremy Penn
5 | % 11 November 2017
6 | %
7 | % Revision 11/11/2017
8 | % 12/11/2017 - added calculation of dv and beta angles
9 | % 19/11/2017 - improved date functionality
10 | %
11 | % function interplanetary_trajectory()
12 | %
13 | % Purpose: This function calculates the interplanety trajectory orbit
14 | % as well as delta-v and ejection/capture angles.
15 | %
16 | % Required: planet_sv.m, lambert.m, coe_from_rv.m, planet_select.m,
17 | % date_after_transfer.m
18 | %
19 |
20 | %% constants
21 | mu = 132.71e9; % [km^3/s^2]
22 |
23 | %% inputs
24 | planet1 = input('Input the departing planet:\n','s');
25 | planet1 = lower(planet1);
26 |
27 | planet2 = input('Input the target planet:\n','s');
28 | planet2 = lower(planet2);
29 |
30 | date1 = input('Input the departure date (dd/mm/yyyy):\n','s');
31 | time1 = input('Input the departure time (HH:MM:SS):\n','s');
32 | days = input('Input the length of the transfer orbit (days, use fractions if necessary):\n');
33 | split1 = strsplit(date1, '/');
34 |
35 | d1 = str2double(split1{1});
36 | m1 = str2double(split1{2});
37 | y1 = str2double(split1{3});
38 |
39 | split_t1 = strsplit(time1, ':');
40 |
41 | hr1 = str2double(split_t1{1});
42 | min1 = str2double(split_t1{2});
43 | sec1 = str2double(split_t1{3});
44 |
45 | UT1 = hr1 + min1/60 + sec1/3600;
46 |
47 | r_d = input('Input the perigee radius of the parking orbit (km):\n ');
48 | e_d = input('Input the eccentricity of the parking orbit:\n ');
49 |
50 | r_a = input('Input the perigee radius of the capture orbit (km):\n ');
51 | e_a = input('Input the eccentricity of the capture orbit:\n ');
52 |
53 | date_vec_i = date_after_transfer('no', d1, m1, y1, hr1, min1, sec1, days);
54 | UT2 = date_vec_i(4) + date_vec_i(5)/60 + date_vec_i(6)/3600;
55 |
56 | %% calculate the state vector of planet 1 at departure
57 | [R1, V1, jd1] = planet_sv(planet1, d1, m1, y1, UT1);
58 |
59 | %% calculate the state vector of planet 2 at arrival
60 | [R2, V2, jd2] = planet_sv(planet2, date_vec_i(3), date_vec_i(2), date_vec_i(1), UT2);
61 |
62 | %% calculate the flight time
63 | t12 = jd2 - jd1;
64 | t12 = t12 * 86400; %convert days to seconds
65 |
66 | %% solve lambert's problem for the velocities at departure & arrival
67 | [vd, va] = lambert(R1, R2, t12, 1e-8, mu);
68 |
69 | %% calculate the hyperbolic excess velocities at departure & arrival
70 | V_inf_D = vd - V1;
71 | V_inf_A = va - V2;
72 |
73 | speed_inf_D = norm(V_inf_D);
74 | speed_inf_A = norm(V_inf_A);
75 |
76 | %% calculate the coe of the transfer orbit
77 | [h, e, inc, W, w, theta] = coe_from_rv(R1, vd, mu);
78 | a = (h^2/mu)*(1/(1-e^2));
79 |
80 | inc = mod(inc, 360);
81 | W = mod(W, 360);
82 | w = mod(w, 360);
83 | theta = mod(theta, 360);
84 |
85 | %% calculate the ejection angle
86 |
87 | % gather the grav param and radius of the two bodies
88 | data_d = planet_select(planet1);
89 | data_a = planet_select(planet2);
90 |
91 | mu_d = data_d(9);
92 | Rd = data_d(1);
93 |
94 | mu_a = data_a(9);
95 | Ra = data_a(1);
96 |
97 | rd = Rd + r_d;
98 | e_h = 1 + rd*speed_inf_D^2 / mu_d; % ecc of hyperbolic ejection traj
99 |
100 | beta_d = acos(1/e_h)*180/pi;
101 | beta_d = mod(beta_d, 360);
102 |
103 | ra = Ra + r_a;
104 | e_h_a = 1 + ra*speed_inf_A^2 / mu_a; % ecc of hyperbolic capture traj
105 |
106 | beta_a = acos(1/e_h_a)*180/pi;
107 | beta_a = mod(beta_a, 360);
108 |
109 | %% calculate the delta-v of injection and capture
110 | v_d_p = sqrt( speed_inf_D^2 + 2*mu_d/rd );
111 | v_d_c = sqrt( (mu_d/rd) * (1 + e_d));
112 |
113 | delta_vd = v_d_p - v_d_c;
114 |
115 | v_a_p = sqrt( speed_inf_A^2 + 2*mu_a/ra );
116 | v_a_c = sqrt( (mu_a/ra) * (1 + e_a));
117 |
118 | delta_va = v_a_p - v_a_c;
119 |
120 | %% plot the transfer orbit
121 | [ha,ea,ia,Wa,wa,th_a] = coe_from_rv(R2, V2, mu);
122 | theta_plot = linspace(0,th_a*pi/180);
123 | r = h^2/mu .* (1 ./ (1 + e* cos(theta_plot)));
124 |
125 | polarplot(theta_plot,r);
126 | title('Interplanetary Orbital Trajectory')
127 | text(theta_plot(1), r(1), 'o departure','color','black','FontWeight','bold');
128 | text(theta_plot(end), r(end), 'o arrival','color','black','FontWeight','bold');
129 |
130 | %% print the results
131 |
132 | planet_d = replace(planet1,planet1(1),upper(planet1(1)));
133 | planet_a = replace(planet2,planet2(1),upper(planet2(1)));
134 |
135 | date_vec_d = [y1, m1, d1, hr1, min1, sec1];
136 | date_d_str = datestr(date_vec_d,'dd/mm/yyyy at HH:MM:SS UT');
137 | %date_vec = [y2, m2, d2, hr2, min2, sec2];
138 | date_a_str = datestr(date_vec_i,'dd/mm/yyyy at HH:MM:SS UT');
139 |
140 | clc;
141 |
142 | fprintf('\n\n---------------------------------------------------------------\n')
143 | dda = sprintf('The state vector for %s on %s: \n',planet_d, date_d_str);
144 | fprintf(dda)
145 | fprintf('---------------------------------------------------------------\n')
146 | fprintf('\t r_d = %.4e*i + %.4e*j + %.4e*k [km]\n',R1)
147 | fprintf('\t v_d = %.4f*i + %.4f*j + %.4f*k [km/s]\n',V1)
148 |
149 | fprintf('---------------------------------------------------------------\n')
150 | ada = sprintf('The state vector for %s on %s: \n', planet_a,date_a_str);
151 | fprintf(ada)
152 | fprintf('---------------------------------------------------------------\n')
153 | fprintf('\t r_a = %.4e*i + %.4e*j + %.4e*k [km]\n',R2)
154 | fprintf('\t v_a = %.4f*i + %.4f*j + %.4f*k [km/s]\n',V2)
155 |
156 | fprintf('---------------------------------------------------------------\n')
157 | fprintf('The orbital elements of the transfer trajectory: \n')
158 | fprintf('---------------------------------------------------------------\n')
159 | fprintf('\t h = %.4e [km^2/s]\n',h)
160 | fprintf('\t e = %.4f\n',e)
161 | fprintf('\t i = %.4f [deg]\n',inc)
162 | fprintf('\t W = %.4f [deg]\n',W)
163 | fprintf('\t w = %.4f [deg]\n',w)
164 | fprintf('\t th_d = %.4f [deg]\n',theta)
165 | fprintf('\t a = %.4e [km]\n',a)
166 |
167 | fprintf('---------------------------------------------------------------\n')
168 | fprintf('The transfer elements: \n')
169 | fprintf('---------------------------------------------------------------\n')
170 | fprintf('\t t = %.2f [days]\n',t12/86400);
171 | fprintf('\t V_inf_D = %.4f*i + %.4f*j + %.4f*k [km/s]\n',V_inf_D);
172 | fprintf('\t speed_d = %.4f [km/s]\n',speed_inf_D);
173 | fprintf('\t V_inf_A = %.4f*i + %.4f*j + %.4f*k [km/s]\n',V_inf_A);
174 | fprintf('\t speed_a = %.4f [km/s]\n',speed_inf_A);
175 | date_arrive = datestr(date_vec_i,'dd/mm/yyyy at HH:MM:SS UT');
176 | da = sprintf('\t The spacecraft will arrive at %s on %s\n', planet_a, date_arrive);
177 | fprintf(da)
178 |
179 | fprintf('---------------------------------------------------------------\n')
180 | fprintf('The injection elements: \n')
181 | fprintf('---------------------------------------------------------------\n')
182 | fprintf('\t beta = %.4f [deg]\n', beta_d);
183 | fprintf('\t delta-v = %.4f [km/s]\n', delta_vd)
184 |
185 | fprintf('---------------------------------------------------------------\n')
186 | fprintf('The capture elements: \n')
187 | fprintf('---------------------------------------------------------------\n')
188 | fprintf('\t beta = %.4f [deg]\n', beta_a);
189 | fprintf('\t delta-v = %.4f [km/s]\n', delta_va)
190 | end
--------------------------------------------------------------------------------
/rocket_launch.m:
--------------------------------------------------------------------------------
1 | function rocket_launch()
2 | %% calculates the gravity turn trajectory
3 | %
4 | % Requires: rkf45.m
5 | %
6 | clc;
7 |
8 | %% constants
9 | deg = pi/180; % ...Convert degrees to radians
10 | g0 = 9.81; % ...Sea-level acceleration of gravity (m/s)
11 | Re = 6378e3; % ...Radius of the earth (m)
12 | hscale = 7.5e3; % ...Density scale height (m)
13 | rho0 = 1.225; % ...Sea level density of atmosphere (kg/m^3)
14 |
15 | %% inputs
16 | diam = input('Input vehicle diameter (m):\n'); % ...Vehicle diameter (m)
17 | A = pi/4*(diam)^2; % ...Frontal area (m^2)
18 | CD = 0.5; % ...Drag coefficient (assumed constant)
19 | m0 = input('Input Lift-off mass (kg):\n'); % ...Lift-off mass (kg)
20 | n = input('Input mass ratio:\n'); % ...Mass ratio
21 | T2W = input('Input thrust to weight ratio:\n'); % ...Thrust to weight ratio
22 | Isp = input('Input specific inmpulse (s):\n'); % ...Specific impulse (s)
23 |
24 | %% calculate thrust, initial and final mass, and burn time
25 | mfinal = m0/n; % ...Burnout mass (kg)
26 | Thrust = T2W*m0*g0; % ...Rocket thrust (N)
27 | m_dot = Thrust/Isp/g0; % ...Propellant mass flow rate (kg/s)
28 | mprop = m0 - mfinal; % ...Propellant mass (kg)
29 | tburn = mprop/m_dot; % ...Burn time (s)
30 | hturn = input('Input pitchover altitude (m):\n'); % ...Height at which pitchover begins (m)
31 | t0 = 0; % ...Initial time for the numerical integration
32 | tf = tburn; % ...Final time for the numerical integration
33 | tspan = [t0,tf]; % ...Range of integration
34 |
35 | % ...Initial conditions:
36 | v0 = 0; % ...Initial velocity (m/s)
37 | gamma0 = 89.85*deg; % ...Initial flight path angle (rad)
38 | x0 = 0; % ...Initial downrange distance (km)
39 | h0 = 0; % ...Initial altitude (km)
40 | vD0 = 0; % ...Initial value of velocity loss to drag (m/s)
41 | vG0 = 0; % ...Initial value of velocity loss due to gravity (m/s)
42 |
43 | %...Initial conditions vector:
44 | f0 = [v0; gamma0; x0; h0; vD0; vG0];
45 |
46 | %% rkf45 solves the system of equations df/dt = f(t):
47 |
48 | [t,f] = rkf45(@rates, tspan, f0);
49 |
50 | %...t is the vector of times at which the solution is evaluated
51 | %...f is the solution vector f(t)
52 | %...rates is the embedded function containing the df/dt's
53 |
54 | % ...Solution f(t) returned on the time interval [t0 tf]:
55 | v = f(:,1)*1.e-3; % ...Velocity (km/s)
56 | gamma = f(:,2)/deg; % ...Flight path angle (degrees)
57 | x = f(:,3)*1.e-3; % ...Downrange distance (km)
58 | h = f(:,4)*1.e-3; % ...Altitude (km)
59 | vD = -f(:,5)*1.e-3; % ...Velocity loss due to drag (km/s)
60 | vG = -f(:,6)*1.e-3; % ...Velocity loss due to gravity (km/s)
61 |
62 | for i = 1:length(t)
63 | Rho = rho0 * exp(-h(i)*1000/hscale); %...Air density
64 | q(i) = 1/2*Rho*v(i)^2; %...Dynamic pressure
65 | end
66 |
67 | output
68 |
69 | return
70 |
71 | %% ---------- Subfunctions ----------------------------------------
72 | function dydt = rates(t,y)
73 | %-------------------------
74 | % Calculates the time rates df/dt of the variables f(t)
75 | % in the equations of motion of a gravity turn trajectory.
76 | %-------------------------
77 |
78 | %...Initialize dfdt as a column vector:
79 | dfdt = zeros(6,1);
80 |
81 | v = y(1); % ...Velocity
82 | gamma = y(2); % ...Flight path angle
83 | x = y(3); % ...Downrange distance
84 | h = y(4); % ...Altitude
85 | vD = y(5); % ...Velocity loss due to drag
86 | vG = y(6); % ...Velocity loss due to gravity
87 |
88 | %...When time t exceeds the burn time, set the thrust
89 | % and the mass flow rate equal to zero:
90 | if t < tburn
91 | m = m0 - m_dot*t; % ...Current vehicle mass
92 | T = Thrust; % ...Current thrust
93 | else
94 | m = m0 - m_dot*tburn; % ...Current vehicle mass
95 | T = 0; % ...Current thrust
96 | end
97 |
98 | g = g0/(1 + h/Re)^2; % ...Gravitational variation
99 | % with altitude h
100 | rho = rho0 * exp(-h/hscale); % ...Exponential density variation
101 | % with altitude
102 | D = 1/2 * rho*v^2 * A * CD; % ...Drag [Equation 11.1]
103 |
104 | %...Define the first derivatives of v, gamma, x, h, vD and vG
105 | % ("dot" means time derivative):
106 | %v_dot = T/m - D/m - g*sin(gamma); % ...Equation 11.6
107 |
108 | %...Start the gravity turn when h = hturn:
109 | if h <= hturn
110 | gamma_dot = 0;
111 | v_dot = T/m - D/m - g;
112 | x_dot = 0;
113 | h_dot = v;
114 | vG_dot = -g;
115 | else
116 | v_dot = T/m - D/m - g*sin(gamma);
117 | gamma_dot = -1/v*(g - v^2/(Re + h))*cos(gamma);% ...Equation 11.7
118 | x_dot = Re/(Re + h)*v*cos(gamma); % ...Equation 11.8(1)
119 | h_dot = v*sin(gamma); % ...Equation 11.8(2)
120 | vG_dot = -g*sin(gamma); % ...Gravity loss rate
121 | end
122 |
123 | vD_dot = -D/m; % ...Drag loss rate
124 |
125 | %...Load the first derivatives of f(t) into the vector dfdt:
126 | dydt(1) = v_dot;
127 | dydt(2) = gamma_dot;
128 | dydt(3) = x_dot;
129 | dydt(4) = h_dot;
130 | dydt(5) = vD_dot;
131 | dydt(6) = vG_dot;
132 | end %rates
133 |
134 | function output
135 | clc;
136 | fprintf('\n\n -----------------------------------\n')
137 | fprintf('\n Initial flight path angle = %10g [deg] ',gamma0/deg)
138 | fprintf('\n Pitchover altitude = %10g [m] ',hturn)
139 | fprintf('\n Burn time = %10g [s] ',tburn)
140 | fprintf('\n Final speed = %10g [km/s]',v(end))
141 | fprintf('\n Final flight path angle = %10g [deg] ',gamma(end))
142 | fprintf('\n Altitude = %10g [km] ',h(end))
143 | fprintf('\n Downrange distance = %10g [km] ',x(end))
144 | fprintf('\n Drag loss = %10g [km/s]',vD(end))
145 | fprintf('\n Gravity loss = %10g [km/s]',vG(end))
146 | fprintf('\n\n -----------------------------------\n')
147 |
148 | figure(1)
149 | plot(x, h)
150 | title('Altitude and Downrange Launch Distance')
151 | axis equal
152 | xlabel('Downrange Distance (km)')
153 | ylabel('Altitude (km)')
154 | axis([-inf, inf, 0, inf])
155 | grid
156 |
157 | figure(2)
158 | subplot(2,1,1)
159 | plot(h, v)
160 | title('Flight Dynamics')
161 | xlabel('Altitude (km)')
162 | ylabel('Speed (km/s)')
163 | axis([-inf, inf, -inf, inf])
164 | grid
165 |
166 | subplot(2,1,2)
167 | plot(t, gamma)
168 | xlabel('Time (s)')
169 | ylabel('Flight path angle (deg)')
170 | axis([-inf, inf, -inf, inf])
171 | grid
172 |
173 | figure(3)
174 | plot(h, q)
175 | title('Dynamic atmospheric loading')
176 | xlabel('Altitude (km)')
177 | ylabel('Dynamic pressure (N/m^2)')
178 | axis([-inf, inf, -inf, inf])
179 | grid
180 | end %output
181 | end %rocket_launch
--------------------------------------------------------------------------------