├── 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 --------------------------------------------------------------------------------