├── Config └── ISS.ini ├── DynamicsFunctionPassive.asv ├── DynamicsFunctionPassive.m ├── Euler_Inertia_to_Body.m ├── ExternalPerturbations.m ├── Field_Vector.m ├── GUI.fig ├── GUI.m ├── GUI_Override.m ├── Harrisons_Dynamics.asv ├── Harrisons_Dynamics.m ├── Hysteresis_Rods.m ├── IGRF Model ├── Archive │ ├── ECI2ECEF.m │ ├── Field_Vector.m │ ├── Magnetic Field with Earth2.jpg │ ├── Main.asv │ ├── Orbital ECEF 1000 orbits e=0.2.jpg │ ├── OrbitalTesting.m │ ├── OrbitalTesting_True_Anomaly.m │ ├── Orbital_Model.m │ ├── SchmidtCoefficients.m │ └── untitled.jpg ├── Attitude-Control-Model │ ├── Field_Vector.m │ ├── GUI.fig │ ├── GUI.m │ ├── GUI_Override.m │ ├── IGRF12coeffs.xls │ ├── IGRF2015.txt │ ├── IGRF_Model.m │ ├── Model_Executor.m │ ├── Orbital_Model_Function.m │ ├── igrfSg2015.txt │ └── igrfSh2015.txt ├── Orbital_Model.asv └── Orbital_Model.m ├── IGRF12coeffs.xls ├── IGRF2015.txt ├── IGRF_Model.asv ├── IGRF_Model.m ├── IniConfig.m ├── Model_Executor.m ├── Mu_body_rotate.m ├── Mu_rotate.m ├── Orbital_Model_Function.m ├── Passive_Magnetic_Dynamics_Simulation.m ├── Permanent_Magnet.m ├── README.md ├── Shadow_Detection.m ├── Suns_Orbit.m ├── igrfSg2015.txt └── igrfSh2015.txt /Config/ISS.ini: -------------------------------------------------------------------------------- 1 | [Model] 2 | Orbit_Interval = 100 3 | Num_Orbits = 2 4 | 5 | [Orbit] 6 | Eccentricity = 0.0007373 7 | Inclination = 0.9013 8 | Semimajor_Axis = 6775200 9 | RAAN = 2.1078 10 | Arg_of_Perigee = 5.4950 -------------------------------------------------------------------------------- /DynamicsFunctionPassive.asv: -------------------------------------------------------------------------------- 1 | function[Outputs] = DynamicsFunctionPassive(Ts, bx_new, by_new, bz_new, x_old, y_old, z_old, wx_old, wy_old, wz_old, mu_x_body 2 | 3 | 4 | , mu_y, mu_z) 5 | %% 6 | %Definitions 7 | 8 | %Inertia Matrix 9 | 10 | Jb = [0.0333333333333333 0 0 11 | 0 0.0333333333333333 0 12 | 0 0 0.00666666666666667]; 13 | 14 | % -- Respective input definitions -- 15 | 16 | % B_new - Earths Magnetic Field in the bodyframe 17 | % Mu - Magnetic Moment of the Bar Magnet in the body frame 18 | % T_new - Direction of Bar Magnet Applied Torque 19 | % O_old - Satellite Orientation from previous timestep 20 | % W_old - Satellite angular velocity from previous timestep 21 | % H_old - Satellite momentum from the previous timestep 22 | 23 | 24 | %convert mu vector into angular displacements (ie angles) about the x y and 25 | %z axes 26 | 27 | B_new = [bx_new; by_new; bz_new]; 28 | Mu = [mu_x, mu_y, mu_z]; 29 | O_old = [x_old; y_old; z_old]; 30 | W_old = [wx_old; wy_old; wz_old]; 31 | H_old = Jb*W_old; 32 | %Mu_body = Mu_body_rotate(O_old(1), O_old(2), O_old(3)); 33 | 34 | % Output variable initialization 35 | wx_new = 0; 36 | wy_new = 0; 37 | wz_new = 0; 38 | ox_new = 0; 39 | oy_new = 0; 40 | oz_new = 0; 41 | 42 | %% 43 | % Calculations 44 | 45 | % Step 1 - Find the total torque 46 | T_mag = cross(Mu, B_new); 47 | 48 | % Step 1 - Calculate the new satellite angular velocity 49 | W_dot = inv(Jb)*(-T_mag - cross(W_old, H_old)); 50 | W_new = W_old + Ts*W_dot; 51 | 52 | % Step 2 - Calculate the new satellite orientation 53 | O_dot = -[ 0, wz_old, -wy_old 54 | -wz_old, 0, wx_old 55 | wy_old, -wx_old, 0]*O_old; 56 | 57 | 58 | O_new = O_old + Ts*O_dot; 59 | 60 | % Step 3 - Assign calculated values to the output variables 61 | Outputs = [O_new(1), O_new(2), O_new(3), W_new(1), W_new(2), W_new(3)]; 62 | 63 | end -------------------------------------------------------------------------------- /DynamicsFunctionPassive.m: -------------------------------------------------------------------------------- 1 | function[Outputs] = DynamicsFunctionPassive(Ts, MagneticFieldVectorECEF_x, MagneticFieldVectorECEF_y, MagneticFieldVectorECEF_z, Roll_Old, Pitch_Old, Yaw_Old, AngularVelocityRoll_Old, AngularVelocityPitch_Old, AngularVelocityYaw_Old, MagneticMomentPermanentMagnet, MagneticMomentHysteresisRods) 2 | 3 | %% 4 | 5 | % Definitions 6 | 7 | Inertial_Tensor = [0.0333333333333333 0 0 8 | 0 0.0333333333333333 0 9 | 0 0 0.00666666666666667]; 10 | 11 | % ^^ The inertial Tensor should be passed in as a parameter (eventually) 12 | 13 | % -- Respective input definitions -- 14 | 15 | % B_ECI - Earths Magnetic Field Vector WRT ECI (Teslas) 16 | 17 | % B_Body - Earths Magnetic Field Vector WRT BodyFrame (Teslas) 18 | 19 | % Mu - Magnetic Moment Vector (which includes the permanent magnet as 20 | % well as both sets of hysteresis rods) (A*m^2 or Nm/Tesla) 21 | 22 | % T_new - Direction of the applied torque, due to the magnet, hyst rods, 23 | % and external torques (Nm) 24 | 25 | % O_old - Satellite Orientation from previous timestep (rad) 26 | 27 | % O_dot - The descretized change in satellite orientation (aka angular 28 | % velocity) between the last timestep and the current timestep (rad/s) 29 | 30 | % O_new - Newly calculated satellite orientation (rad) 31 | 32 | % W_old - Satellite angular velocity from previous timestep (rad/s) 33 | 34 | % W_dot - The descetized change in satellite angular velocity (aka angular 35 | % acceleration) between the last timestep and the current timestep (rad/s) 36 | 37 | % W_new - Newly calculated satellite angular velocity (rad) 38 | 39 | % H_old - Satellite angular momentum from the previous timestep (kg*m^2/s) 40 | 41 | 42 | %Define the DCMs that describe the orientation of the satellite with 43 | %respect to the ECI frame of reference 44 | DCMroll = [1, 0, 0; 0, cos(Roll_Old), sin(Roll_Old); 0, -sin(Roll_Old), cos(Roll_Old)]; 45 | DCMpitch = [cos(Pitch_Old), 0, -sin(Pitch_Old); 0, 1, 0; sin(Pitch_Old), 0, cos(Pitch_Old)]; 46 | DCMyaw = [cos(Yaw_Old), sin(Yaw_Old), 0; -sin(Yaw_Old), cos(Yaw_Old), 0; 0, 0, 1]; 47 | 48 | %convert the magnetic field vector from ECEF into ECI 49 | MagneticFieldVectorECEFtoECI_DCM = dcmeci2ecef('IAU-2000/2006', datevec(SystemTimeObj.dateAndTime)); 50 | B_ECI = transpose(MagneticFieldVectorECEFtoECI_DCM)*[MagneticFieldVectorECEF_x; MagneticFieldVectorECEF_y; MagneticFieldVectorECEF_z]; 51 | 52 | %convert the magnetic field vector B from ECEF into Body Frame 53 | B_Body = (Ryaw*(Rpitch*(Rroll*[bx_new; by_new; bz_new]))); 54 | 55 | Mu = [2*MagneticMomentHysteresisRods, 2*MagneticMomentHysteresisRods, MagneticMomentPermanentMagnet]; 56 | O_old = [Roll_Old; Pitch_Old; Yaw_Old]; 57 | W_old = [AngularVelocityRoll_Old; AngularVelocityPitch_Old; AngularVelocityYaw_Old]; 58 | H_old = Inertial_Tensor*W_old; 59 | 60 | %Mu_body = Mu_body_rotate(O_old(1), O_old(2), O_old(3)); 61 | 62 | % Output variable initialization 63 | Roll_new = 0; 64 | Pitch_new = 0; 65 | Yaw_new = 0; 66 | AngularVelocity_Roll_New = 0; 67 | AngularVelocity_Pitch_New = 0; 68 | AngularVelocity_Yaw_New = 0; 69 | 70 | %% 71 | % Calculations 72 | % Step 1 - Find the new applied torque to the body 73 | T_new = cross(Mu, B_Body); 74 | 75 | % Step 2 - Calculate the new satellite angular velocity using the new torque 76 | % (this equation accounts for the systems non-linearity aka gyroscopic forces 77 | % aka precessive forces) 78 | W_dot = transpose(Inertia_Tensor)*(-T_new - cross(W_old, H_old)); 79 | W_new = W_old + Ts*W_dot; 80 | 81 | % Step 3 - Calculate the new satellite orientation 82 | O_dot = [ 0, wz_old, -wy_old 83 | -wz_old, 0, wx_old 84 | wy_old, -wx_old, 0] * O_old; 85 | 86 | 87 | O_new = O_old + Ts*O_dot; 88 | 89 | % Step 3 - Assign calculated values to the output variables 90 | Outputs = [O_new(1), O_new(2), O_new(3), W_new(1), W_new(2), W_new(3)]; 91 | 92 | end -------------------------------------------------------------------------------- /Euler_Inertia_to_Body.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/Euler_Inertia_to_Body.m -------------------------------------------------------------------------------- /ExternalPerturbations.m: -------------------------------------------------------------------------------- 1 | %% 2 | %------------------------------------------------- 3 | % EXTERNAL TORQUES (Given in Nm) 4 | %------------------------------------------------- 5 | 6 | % AERODYNAMIC DRAG TORQUE 7 | 8 | % d_atmos - is the atmospheric density (dependent on altitude) 9 | % v_sat - is the orbital velocity of the cubesat 10 | % Cd - is the drag coefficient 11 | % A - is the area facing the velocity vector (can be calculated if the 12 | % orientation is known) 13 | % uv - is the unit velocity vector 14 | % scp - is the vector from the center of pressure to the center of mass 15 | 16 | % T_aero = (1/2)*d_atmos*(v_sat^2)*Cd*A*(cross(uv,scp)); 17 | 18 | % GRAVITY GRADIENT TORQUE 19 | 20 | % mu - geocentric gravitational constant 21 | % ue - unit vector towards nadir 22 | % Ro - distance from the center of Earth to the satellite 23 | % J - cubesat inertia matrix 24 | 25 | %T_grav = (3*mu*cross(ue,J*ue))/(Ro^3) 26 | 27 | % SOLAR RADIATION TORQUE 28 | 29 | % Fs - solar constant (1367 W/m^2) 30 | % c - speed of light (m/s) 31 | % As - surface area (m^2) -- external 32 | % q - reflectance factor (either 0 or 1) -- external 33 | % beta - angle of incidence of the sun -- external 34 | % cp - center of pressure -- calculate in shadow detection 35 | % cg - center of gravity 36 | 37 | %Fs = 1367; 38 | %c = 2.998e+8; 39 | 40 | %F = (Fs/c)*As*(1+q)*cos(beta) 41 | %T_sol = F*abs(cp-cg); -------------------------------------------------------------------------------- /Field_Vector.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/Field_Vector.m -------------------------------------------------------------------------------- /GUI.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/GUI.fig -------------------------------------------------------------------------------- /GUI.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/GUI.m -------------------------------------------------------------------------------- /GUI_Override.m: -------------------------------------------------------------------------------- 1 | %Main Operation with GUI Inputs 2 | % Output Format: [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z, Earth_B_x_ECEF, Earth_B_y_ECEF, Earth_B_z_ECEF] 3 | 4 | %% 5 | % GUI Replacement 6 | tic; 7 | 8 | Launch_Date = datetime(); 9 | % Orbital Properties 10 | Eccentricity = 0.0007373; 11 | Inclination = 0.9013; %[rad] 12 | Semimajor_Axis = 6775200; %[m] 13 | Orbital_Interval = 1000; 14 | RAAN = 2.1078; %[rad] 15 | Arg_of_Perigee = 5.95; %[rad] 16 | Num_of_Orbits = 5; 17 | Magnetic_Moment = [ 0.5; 0.1; 0.1]; 18 | 19 | % Dynamic Properties 20 | Inertia_Tensor = [0.0267, 0.03, 0.1; 0.03, 0.1333, 0.01; 0.03, 0.01, 0.1333]; % x in long direction [kg*m2] 21 | Results = Model_Executor(Launch_Date, Eccentricity, Inclination, Semimajor_Axis, Orbital_Interval, RAAN, Arg_of_Perigee, Num_of_Orbits, Magnetic_Moment); 22 | Column_Header = {'True Anomaly [rad]', 'Altitude [m]', 'Satellite Orbital Number', 'Time (s)', 'Sat ECI_x [rad]', 'Sat ECI_y [rad]', 'Sat ECI_z [rad]', 'Sat ECEF_x [m]', 'Sat ECEF_y [m]', 'Sat ECEF_z [m]', 'Bx_ECEF [T]', 'By_ECEF [T]', 'Bz_ECEF [T]', 'Sat x_Orientation_ECI', 'Sat y_Orientation_ECI', 'Sat z_Orientation_ECI', 'Sat x_Angular_Velocity_ECI [rad/s]', 'Sat y_Angular_Velocity_ECI [rad/s]', 'Sat z_Angular_Velocity_ECI [rad/s]', 'Magnetic Moment_x', 'Magnetic Moment_y', 'Magnetic Moment_z', 'Sun x_ECI [m]', 'Sun y_ECI [m]', 'Sun z_ECI [m]', 'Sun x_ECEF [m]', 'Sun y_ECEF [m]', 'Sun z_ECEF [m]', 'Shadow [T or F]'}; 23 | Final_Results = [Column_Header; num2cell(Results)]; 24 | % Model Operation 25 | toc; 26 | %% Orbital Propagation Model - Harrison Handley 27 | % Orbit Propagation - Defines Result_Matrix as 28 | % [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z] 29 | % Results = Orbital_Model_Function(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits); 30 | 31 | %% Magnetic Field Model - Harrison Handley 32 | % Earth Magnetic Field Model 33 | % Add to Results three vectors for Earths magnetic field x, y and z components in ECEF for that rows satellite CM ECEF position 34 | % Results = horzcat(Results, zeros(size(Results, 1), 3 )); 35 | 36 | % Find magnetic field of earth at each position in Teslas 37 | % for row = 1:size(Results, 1) 38 | % % r = vector length of xyz 39 | % % theta Latitude measured in degrees positive from equator 40 | % % phi Longitude measured in degrees positive east from Greenwich 41 | % % days Decimal days since January 1, 2015 42 | % r = sqrt(Results(row,8)^2 + Results(row,9)^2 + Results(row,10)^2); 43 | % theta = acosd(sqrt(Results(row,8)^2 + Results(row,9)^2)/r); 44 | % phi = atand(Results(row,9)/Results(row,8)); 45 | % Days_since_Jan_1st_2015 = daysact('1-Jan-2015 00:00:00', (Launch_Time + seconds(Results(row, 4)))); 46 | % [Br ,Bt, Bp] = IGRF_Model(r, theta, phi,Days_since_Jan_1st_2015); 47 | % [Bx, By, Bz] = sph2cart(Bp, Bt, Br); 48 | % Results(row, 11) = Bx; 49 | % Results(row, 12) = By; 50 | % Results(row, 13) = Bz; 51 | % end 52 | 53 | %% Dynamic Model 54 | 55 | -------------------------------------------------------------------------------- /Harrisons_Dynamics.asv: -------------------------------------------------------------------------------- 1 | %function [ output_args ] = Harrisons_Dynamics( Inertia_Tensor_BodyFrame, Magnetic_Moment_BodyFrame, Bx_Earth, By_Earth, Bz_Earth, Pitch_Orientation, Roll_Orientation, Yaw_Orientation, Pitch_AngVel, Roll_AngVel, Yaw_AngVel, Time_step, Current_Time ) 2 | % Inertia_Tensor_BodyFrame - Satellites Inertia Matrix in Body Reference Frame 3 | % Magnetic_Moment_BodyFrame - Satellites Magnetic Moment (Pitch, Roll and Yaw axis) in Body Reference Frame 4 | % Bx_Earth, By_Earth, Bz_Earth - Earths Magnetic Field in ECEF from CM of satellite in Teslas 5 | % Pitch_Orientation - Pitch Orientation from ECI CM to Body Frame 6 | % Roll_Orientation - Roll Orientation from ECI CM to Body Frame 7 | % Yaw_Orientation - Yaw Orientation from ECI CM to Body Frame 8 | % Pitch_AngVel - Angular Velocity of satellite around the pitch axis 9 | % Roll_AngVel - Angular Velocity of satellite around the roll axis 10 | % Yaw_AngVel - Angular Velocity of satellite around the yaw axis 11 | % Time_step - Time Step between iterations 12 | 13 | Inertia_Tensor_BodyFrame = [0.0267, 0.03, 0.1; 0.03, 0.1333, 0.01; 0.03, 0.01, 0.1333]; 14 | Magnetic_Moment_BodyFrame = [0.1, 0.5, 0.3]; 15 | Bx_Earth = 0.05; 16 | By_Earth = 0.0001; 17 | Bz_Earth = 0.003; 18 | Pitch_Orientation = 0; 19 | Roll_Orientation = 0; 20 | Yaw_Orientation = 0; 21 | Pitch_AngVel = 0; 22 | Roll_AngVel = 0; 23 | Yaw_AngVel = 0; 24 | Time_step = 10; 25 | Current_Time = datetime(); 26 | 27 | % Convert Earth Magnetic field frame to Body Reference 28 | % Convert from ECEF to ECI 29 | Date_Array = [year(Current_Time), month(Current_Time), day(Current_Time), hour(Current_Time), minute(Current_Time), second(Current_Time)]; 30 | ECI2ECEF_Matrix = dcmeci2ecef('IAU-2000/2006', Date_Array); 31 | %ECI2ECEF_Matrix = eye(3); For Testing 32 | Earth_Magnetic_Field_ECI = [Bx_Earth, By_Earth, Bz_Earth]*inv(ECI2ECEF_Matrix) 33 | Rz_ECI2BodyRefFrame = [cos(Yaw_Orientation), -sin(Yaw_Orientation), 0;... 34 | sin(Yaw_Orientation), cos(Yaw_Orientation), 0;... 35 | 0, 0, 1]; 36 | Ry_ECI2BodyRefFrame = [cos(Pitch_Orientation), 0, sin(Pitch_Orientation);... 37 | 0, 1, 0;... 38 | -sin(Pitch_Orientation), 0, cos(Pitch_Orientation)]; 39 | Rx_ECI2BodyRefFrame = [1, 0, 0;... 40 | 0, cos(Roll_Orientation), -sin(Roll_Orientation);... 41 | 0, sin(Roll_Orientation), cos(Roll_Orientation)]; 42 | RzRyRx = Rz_ECI2BodyRefFrame*Ry_ECI2BodyRefFrame*Rx_ECI2BodyRefFrame 43 | Earth_Magnetic_Field_BodyRefFrame = Earth_Magnetic_Field_ECI*RzRyRx 44 | Magnetic_Torque_BodyRefFrame = cross(Magnetic_Moment_BodyFrame, Earth_Magnetic_Field_BodyRefFrame) 45 | Total_Torque = Magnetic_Torque_BodyRefFrame 46 | %end 47 | 48 | -------------------------------------------------------------------------------- /Harrisons_Dynamics.m: -------------------------------------------------------------------------------- 1 | %function [ output_args ] = Harrisons_Dynamics( Inertia_Tensor_BodyFrame, Magnetic_Moment_BodyFrame, Bx_Earth, By_Earth, Bz_Earth, Pitch_Orientation, Roll_Orientation, Yaw_Orientation, Pitch_AngVel, Roll_AngVel, Yaw_AngVel, Time_step, Current_Time ) 2 | % Inertia_Tensor_BodyFrame - Satellites Inertia Matrix in Body Reference Frame 3 | % Magnetic_Moment_BodyFrame - Satellites Magnetic Moment (Pitch, Roll and Yaw axis) in Body Reference Frame 4 | % Bx_Earth, By_Earth, Bz_Earth - Earths Magnetic Field in ECEF from CM of satellite in Teslas 5 | % Pitch_Orientation - Pitch Orientation from ECI CM to Body Frame 6 | % Roll_Orientation - Roll Orientation from ECI CM to Body Frame 7 | % Yaw_Orientation - Yaw Orientation from ECI CM to Body Frame 8 | % Pitch_AngVel - Angular Velocity of satellite around the pitch axis 9 | % Roll_AngVel - Angular Velocity of satellite around the roll axis 10 | % Yaw_AngVel - Angular Velocity of satellite around the yaw axis 11 | % Time_step - Time Step between iterations 12 | 13 | Inertia_Tensor_BodyFrame = [0.0267, 0.03, 0.1; 0.03, 0.1333, 0.01; 0.03, 0.01, 0.1333]; 14 | Magnetic_Moment_BodyFrame = [0.1, 0.5, 0.3]; 15 | Bx_Earth = 0.05; 16 | By_Earth = 0.0001; 17 | Bz_Earth = 0.003; 18 | Pitch_Orientation = 0; 19 | Roll_Orientation = 0; 20 | Yaw_Orientation = 0; 21 | Pitch_AngVel = 0; 22 | Roll_AngVel = 0; 23 | Yaw_AngVel = 0; 24 | Time_step = 10; 25 | Current_Time = datetime(); 26 | 27 | % Convert Earth Magnetic field frame to Body Reference 28 | % Convert from ECEF to ECI 29 | Date_Array = [year(Current_Time), month(Current_Time), day(Current_Time), hour(Current_Time), minute(Current_Time), second(Current_Time)]; 30 | %ECI2ECEF_Matrix = dcmeci2ecef('IAU-2000/2006', Date_Array); 31 | %ECI2ECEF_Matrix = eye(3); For Testing 32 | Earth_Magnetic_Field_ECI = [Bx_Earth, By_Earth, Bz_Earth]*inv(ECI2ECEF_Matrix) 33 | Rz_ECI2BodyRefFrame = [cos(Yaw_Orientation), -sin(Yaw_Orientation), 0;... 34 | sin(Yaw_Orientation), cos(Yaw_Orientation), 0;... 35 | 0, 0, 1]; 36 | Ry_ECI2BodyRefFrame = [cos(Pitch_Orientation), 0, sin(Pitch_Orientation);... 37 | 0, 1, 0;... 38 | -sin(Pitch_Orientation), 0, cos(Pitch_Orientation)]; 39 | Rx_ECI2BodyRefFrame = [1, 0, 0;... 40 | 0, cos(Roll_Orientation), -sin(Roll_Orientation);... 41 | 0, sin(Roll_Orientation), cos(Roll_Orientation)]; 42 | RzRyRx = Rz_ECI2BodyRefFrame*Ry_ECI2BodyRefFrame*Rx_ECI2BodyRefFrame 43 | Earth_Magnetic_Field_BodyRefFrame = Earth_Magnetic_Field_ECI*RzRyRx 44 | Magnetic_Torque_BodyRefFrame = cross(Magnetic_Moment_BodyFrame, Earth_Magnetic_Field_BodyRefFrame) 45 | Total_Torque = Magnetic_Torque_BodyRefFrame 46 | %end 47 | 48 | -------------------------------------------------------------------------------- /Hysteresis_Rods.m: -------------------------------------------------------------------------------- 1 | % Hysteresis rod design: BY CAMERON JINKS 2 | 3 | % Definitions 4 | 5 | % m_hyst = magnetic moment of the hysteresis rod aligned with its long axis 6 | % B_hyst = the magnetic flux induced in the rod 7 | % V_hyst = the volume of the rod 8 | % mu_o = the permiability of free space 9 | % H = the magnetic field strength 10 | % mu_prime_hyst(H) = the apparent relative permiability of the rod 11 | % N = demagnetizing factor 12 | % mu_hyst(H) = true relative permiability of the rod (which varies with H) 13 | % Bs_prime = apparent saturation induction 14 | % Hs = magnetic field strength at saturation (aka H when B = Bs) 15 | % L/D = ratio of length to diameter 16 | % Hs = Material saturation field strength of HyMu-80 17 | 18 | % Assume material is HyMu-80 19 | 20 | L = 95; % in mm 21 | D = 1; % in mm 22 | Hc = 0.96; % A/m 23 | Br = 0.35; % Tesla 24 | Bs = 0.74; % Tesla 25 | Hc_prime = 12; % A/m 26 | Br_prime = 0.004; % Tesla 27 | Bs_prime = 0.025; % Tesla 28 | 29 | % 30 | % Equations 31 | 32 | % m_hyst = ([B_hyst]*[V_hyst])/[mu_o]; 33 | 34 | % H = the magnetic field strength of earth 35 | % mu_prime_hyst is the apparent relative permiability of the rod (which changes depending on the stregth of the magnetic field of earth) 36 | 37 | % Bhyst = [mu_o]*[mu_prime_hyst]*[H]; 38 | 39 | % N = demagnetizing factor 40 | 41 | % We need the hysteresis curve of the rods in order to calculate the 42 | % following. Max/min values for the magnetic field strength of earth should 43 | % be roughly +or- 30 A*m^2 44 | 45 | % 46 | 47 | N = [(L/D)*(4/sqrt(PI)+2)]^-1; 48 | mu_prime_hyst = [mu_hyst]/(1+N*[mu_hyst]); 49 | Bs_prime = [mu_o]*(mu_hyst/mu_prime_hyst)*Hs; 50 | -------------------------------------------------------------------------------- /IGRF Model/Archive/ECI2ECEF.m: -------------------------------------------------------------------------------- 1 | %-------------------------------------------------------------------------- 2 | % 3 | % ECI2ECEF: Transforms Earth Centered Inertial (ECI) coordinates to Earth 4 | % Centered Earth Fixed (ECEF) coordinates 5 | % 6 | % Last modified: 2015/08/12 M. Mahooti 7 | % 8 | %-------------------------------------------------------------------------- 9 | function Y = ECI2ECEF(MJD_UTC, Y0) 10 | 11 | global eopdata 12 | 13 | SAT_Const 14 | 15 | [UT1_UTC,TAI_UTC,x_pole,y_pole,ddpsi,ddeps] = IERS(eopdata,MJD_UTC,'l'); 16 | [UT1_TAI,UTC_GPS,UT1_GPS,TT_UTC,GPS_UTC] = timediff(UT1_UTC,TAI_UTC); 17 | 18 | MJD_UT1 = MJD_UTC + UT1_UTC/86400; 19 | MJD_TT = MJD_UTC + TT_UTC/86400; 20 | 21 | % ICRS to ITRS transformation matrix and derivative 22 | P = PrecMatrix(MJD_J2000,MJD_TT); % IAU 1976 Precession 23 | N = NutMatrix(MJD_TT); % IAU 1980 Nutation 24 | Theta = GHAMatrix(MJD_UT1); % Earth rotation 25 | Pi = PoleMatrix(x_pole,y_pole); % Polar motion 26 | 27 | S = zeros(3); 28 | S(1,2) = 1; S(2,1) = -1; % Derivative of Earth rotation 29 | Omega = 7292115.8553e-11+4.3e-15*( (MJD_UTC-MJD_J2000)/36525 ); 30 | dTheta = Omega*S*Theta; % matrix [1/s] 31 | 32 | U = Pi*Theta*N*P; % ICRS to ITRS transformation 33 | dU = Pi*dTheta*N*P; % Derivative [1/s] 34 | 35 | % Transformation from ICRS to WGS 36 | r = U*Y0(1:3)'; 37 | v = U*Y0(4:6)' + dU*Y0(1:3)'; 38 | Y = [r;v]; 39 | 40 | -------------------------------------------------------------------------------- /IGRF Model/Archive/Field_Vector.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Archive/Field_Vector.m -------------------------------------------------------------------------------- /IGRF Model/Archive/Magnetic Field with Earth2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Archive/Magnetic Field with Earth2.jpg -------------------------------------------------------------------------------- /IGRF Model/Archive/Main.asv: -------------------------------------------------------------------------------- 1 | %Main Operation with GUI Inputs 2 | % Output Format: [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z, Earth_B_x_ECEF, Earth_B_x_ECEF, Earth_B_z_ECEF] 3 | % GUI Replacement 4 | Launch_Time = datetime(); 5 | % Orbital Properties 6 | Orbital_Eccentricity = 0.2; 7 | Orbital_Inclination = pi/2; %[rad] 8 | Orbital_Semimajor_Axis = 1000000; %[m] 9 | Orbital_Mesh = 100; 10 | Orbital_RAAN = 0.3; %[rad] 11 | Orbital_Arg_of_Perigee = pi/4; %[rad] 12 | Orbital_Num_of_Orbits = 5; 13 | 14 | % Dynamic Properties 15 | Inertia_Tensor = [0.0267, 0.03, 0.1; 0.03, 0.1333, 0.01; 0.03, 0.01, 0.1333]; % x in long direction [kg*m2] 16 | 17 | % Model Operation 18 | 19 | % Orbit Propogation - Defines Result_Matrix as 20 | % [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z] 21 | Results = Orbital_Model_Function(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits); 22 | 23 | % Earth Magnetic Field Model 24 | % Add to Results three vectors for Earths magnetic field x, y and z components in ECEF for that rows satellite CM ECEF position 25 | Results = horzcat(Results, zeros(size(Results, 1), 3 )); 26 | 27 | % Find magnetic field of earth at each position in nT 28 | for row = 1:size(Results, 1) 29 | % r = vector length of xyz 30 | % theta Latitude measured in degrees positive from equator 31 | % phi Longitude measured in degrees positive east from Greenwich 32 | % days Decimal days since January 1, 2015 33 | r = sqrt(Results(row,8)^2 + Results(row,9)^2 + Results(row,10)^2); 34 | theta = acosd(sqrt(Results(row,8)^2 + Results(row,9)^2)/r); 35 | phi = atand(Results(row,9)/Results(row,8)); 36 | Days_since_Jan_1st_2015 = daysact('1-Jan-2015 00:00:00', (Launch_Time + seconds(Results(row, 4)))); 37 | [Br ,Bt, Bp] = IGRF_Model(r, theta, phi,Days_since_Jan_1st_2015); 38 | [Bx, By, Bz] = sph2cart(Bp, Bt, Br); 39 | Results(row, 11) = Bx; 40 | Results(row, 12) = By; 41 | Results(row, 13) = Bz; 42 | end -------------------------------------------------------------------------------- /IGRF Model/Archive/Orbital ECEF 1000 orbits e=0.2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Archive/Orbital ECEF 1000 orbits e=0.2.jpg -------------------------------------------------------------------------------- /IGRF Model/Archive/OrbitalTesting.m: -------------------------------------------------------------------------------- 1 | % Orbital Model Summary 2 | % The orbit of the satellite is defined in Earth-Centered Inertial 3 | % Reference Frame and requires converting into ECEF to provide 4 | % positioning information. 5 | % All orbits are assumed to start at the ascending node for prograde 6 | % orbits and at the descending node for retrograde orbits 7 | % The IC of the orbit is assumed to be at the intercept of the Equinox 8 | % and the equator 9 | % The position of the satellite is reference to Right acension node 10 | % called the Arguement_of_Latitude 11 | % Eccentricity of the Arguement_of_Latitude is when the orbit is changed 12 | % to an eccentricity of 0 for easier calculations 13 | % The model currently does not account for inclinations of 0 or 180 14 | % degrees. Nor does it consider any perturbations such as 15 | % radiation pressure 16 | % aerodynamic drag 17 | % Orbital precession 18 | 19 | % Constants 20 | GM = 3.986005*10^14; 21 | 22 | % Year, Month, Day, Hour, Minutes, Seconds, eccentricity, inclination, semimajor_axis, Argument_of_Latitude, Interval, RAAN 23 | Year = 2015; 24 | Month = 1; 25 | Day = 1; 26 | Hour = 0; 27 | Minutes = 0; 28 | Seconds = 0; 29 | eccentricity = 0.5; 30 | inclination = 45; 31 | semimajor_axis = 6800000; 32 | Argument_of_Latitude = pi %radians 33 | Argument_of_Perigee = 0.5; %radians only for eccentricity != 0 34 | Time_Interval = 10; 35 | RAAN = 0; 36 | 37 | % Find semiminor axis, total area of the ellipse/circle and the orbital 38 | % period 39 | semiminor_axis = sqrt((semimajor_axis^2)-(eccentricity*semimajor_axis)^2); 40 | Total_Area = pi*semiminor_axis*semimajor_axis; 41 | Orbital_Period=sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)); 42 | 43 | % Find area per second of the orbit 44 | Area_per_second_travelled = Total_Area/Orbital_Period; 45 | 46 | % Find Area of the orbit so far from current True Anomaly by 47 | % making the orbit into a circle (Eccentricity = 0) 48 | 49 | % Keep True Anomaly within 0 to 2pi 50 | Current_True_Anomaly = Argument_of_Latitude - Argument_of_Perigee; 51 | if Current_True_Anomaly < 0 52 | Current_True_Anomaly = Current_True_Anomaly + 2*pi; 53 | end 54 | 55 | % Find the Eccentricity_True_Anomaly and area covered by True_Anomaly so 56 | % far in the orbit 57 | Current_Eccentricity_True_Anomaly = 2*atan(sqrt((1-eccentricity)/(1+eccentricity))*tan(Current_True_Anomaly/2)); 58 | Current_True_Anomaly_Area = 0.5*semimajor_axis*semiminor_axis*(Current_Eccentricity_True_Anomaly-eccentricity*sin(Current_Eccentricity_True_Anomaly)); 59 | 60 | % Find new area and subsequently new True_Anomaly 61 | New_Area = Current_True_Anomaly_Area + Area_per_second_travelled*Time_Interval; 62 | if New_Area > Total_Area 63 | New_Area = New_Area - Total_Area; 64 | end 65 | 66 | % Find the new True_Anomaly that correlates with the New Area covered by the 67 | % orbit 68 | 69 | fun = @(variable1) variable1*(1-eccentricity*sin(variable1))-(2*New_Area/(semimajor_axis*semiminor_axis)); 70 | New_Eccentric_True_Anomaly = fzero(fun, Current_Eccentricity_True_Anomaly); 71 | if eccentricity == 0 || New_Eccentric_True_Anomaly == pi% Skip secondary iterative solution if eccentricity is already a circle 72 | New_True_Anomaly = New_Eccentric_True_Anomaly; 73 | else 74 | fun2 = @(variable2) 2*atan((sqrt(((1-eccentricity)/(1+eccentricity)))*tan(variable2/2)))-New_Eccentric_True_Anomaly; 75 | New_True_Anomaly = fzero(fun2, Current_True_Anomaly) 76 | end 77 | New_Argument_of_Latitude = New_True_Anomaly + Argument_of_Perigee 78 | if New_Argument_of_Latitude > 2*pi 79 | New_Argument_of_Latitude = New_Argument_of_Latitude - 2*pi 80 | end 81 | % Calculate the transformation matrix for ECI to ECEF using IAU-76/FK5 as 82 | % reduction methodology 83 | 84 | % ECI2ECEF_Transformation_Matrix = dcmeci2ecef('IAU-76/FK5',[Year Month Day Hour Minutes Seconds]); 85 | 86 | % Calculate ECI coordinates 87 | 88 | 89 | -------------------------------------------------------------------------------- /IGRF Model/Archive/OrbitalTesting_True_Anomaly.m: -------------------------------------------------------------------------------- 1 | % Orbital Model Summary 2 | % The orbit of the satellite is defined in Earth-Centered Inertial 3 | % Reference Frame and requires converting into ECEF to provide 4 | % positioning information. 5 | % All orbits are assumed to start at the ascending node for prograde 6 | % orbits and at the descending node for retrograde orbits 7 | % The IC of the orbit is assumed to be at the intercept of the Equinox 8 | % and the equator 9 | % The position of the satellite is reference to Right acension node 10 | % called the Arguement_of_Latitude 11 | % Eccentricity of the Arguement_of_Latitude is when the orbit is changed 12 | % to an eccentricity of 0 for easier calculations 13 | % The model currently does not account for inclinations of 0 or 180 14 | % degrees. Nor does it consider any perturbations such as 15 | % radiation pressure 16 | % aerodynamic drag 17 | % Orbital precession 18 | 19 | 20 | GM = 3.986005*10^14; 21 | 22 | % Year, Month, Day, Hour, Minutes, Seconds, eccentricity, inclination, semimajor_axis, Argument_of_Latitude, Interval, RAAN 23 | Year = 2015; 24 | Month = 1; 25 | Day = 1; 26 | Hour = 0; 27 | Minutes = 0; 28 | Seconds = 0; 29 | eccentricity = 0.5; 30 | inclination = 45; 31 | semimajor_axis = 6800000; 32 | Argument_of_Latitude = 0 %radians 33 | Argument_of_Perigee = 0; %radians only for eccentricity != 0 34 | Time_Interval = 10; 35 | RAAN = 0; 36 | 37 | Result_Vector = [0, 0]; 38 | for Argument_of_Latitude = 0:0.01:2*pi 39 | % Find semiminor axis, total area of the ellipse/circle and the orbital 40 | % period 41 | semiminor_axis = sqrt((semimajor_axis^2)-(eccentricity*semimajor_axis)^2); 42 | Total_Area = pi*semiminor_axis*semimajor_axis; 43 | Orbital_Period=sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)); 44 | 45 | % Find area per second of the orbit 46 | Area_per_second_travelled = Total_Area/Orbital_Period; 47 | 48 | % Find Area of the orbit so far from current True Anomaly by 49 | % making the orbit into a circle (Eccentricity = 0) 50 | 51 | % Keep True Anomaly within 0 to 2pi 52 | Current_True_Anomaly = Argument_of_Latitude - Argument_of_Perigee; 53 | if Current_True_Anomaly < 0 54 | Current_True_Anomaly = Current_True_Anomaly + 2*pi; 55 | end 56 | 57 | % Find the Eccentricity_True_Anomaly and area covered by True_Anomaly so 58 | % far in the orbit 59 | Current_Eccentricity_True_Anomaly = 2*atan(sqrt((1-eccentricity)/(1+eccentricity))*tan(Current_True_Anomaly/2)); 60 | Current_True_Anomaly_Area = 0.5*semimajor_axis*semiminor_axis*(Current_Eccentricity_True_Anomaly-eccentricity*sin(Current_Eccentricity_True_Anomaly)); 61 | 62 | % Find new area and subsequently new True_Anomaly 63 | New_Area = Current_True_Anomaly_Area + Area_per_second_travelled*Time_Interval; 64 | if New_Area > Total_Area 65 | New_Area = New_Area - Total_Area; 66 | end 67 | 68 | % Find the new True_Anomaly that correlates with the New Area covered by the 69 | % orbit 70 | 71 | % Solve for New True Anomaly when ellipse is as a circle 72 | fun = @(variable1) variable1*(1-eccentricity*sin(variable1))-(2*New_Area/(semimajor_axis*semiminor_axis)); 73 | New_Eccentricity_True_Anomaly = fzero(fun, Current_Eccentricity_True_Anomaly); 74 | if eccentricity == 0 || New_Eccentricity_True_Anomaly == pi% Skip secondary iterative solution if eccentricity is already a circle 75 | New_True_Anomaly = New_Eccentricity_True_Anomaly; 76 | else 77 | % Solve for True Anomaly after converting the circle back into 78 | % ellipse. Has a singularity at variable2 = pi 79 | TestMethod = 2*atan(tan(New_Eccentricity_True_Anomaly/2)*sqrt((1+eccentricity)/(1-eccentricity))); 80 | fun2 = @(variable2) 2*atan(sqrt((1-eccentricity)/(1+eccentricity))*tan(variable2/2))-New_Eccentricity_True_Anomaly; 81 | New_True_Anomaly = fzero(fun2, Current_True_Anomaly); 82 | end 83 | % Establish New_Argument_of_Latitude (Easier for converting to ECEF?) 84 | New_Argument_of_Latitude = New_True_Anomaly + Argument_of_Perigee; 85 | if New_Argument_of_Latitude > 2*pi 86 | New_Argument_of_Latitude = New_Argument_of_Latitude - 2*pi; 87 | end 88 | 89 | Error = New_Area - 0.5*semimajor_axis*semiminor_axis*(New_Eccentricity_True_Anomaly-eccentricity*sin(New_Eccentricity_True_Anomaly)); 90 | Result_Vector = [Result_Vector; Argument_of_Latitude, Error]; 91 | end 92 | 93 | % Troubleshooting 94 | 95 | 96 | % Calculate the transformation matrix for ECI to ECEF using IAU-76/FK5 as 97 | % reduction methodology 98 | 99 | % ECI2ECEF_Transformation_Matrix = dcmeci2ecef('IAU-76/FK5',[Year Month Day Hour Minutes Seconds]); 100 | 101 | % Calculate ECI coordinates 102 | 103 | 104 | -------------------------------------------------------------------------------- /IGRF Model/Archive/Orbital_Model.m: -------------------------------------------------------------------------------- 1 | function [ x_ECI, y_ECI, z_ECI, x_ECEF, y_ECEF, z_ECEF ] = Orbital_Model( Year, Month, Day, Hour, Minutes, Seconds, eccentricity, inclination, semimajor_axis, Arguement_of_Latitude, Interval, RAAN) 2 | % Orbital Model Summary 3 | % The orbit of the satellite is defined in Earth-Centered Inertial 4 | % Reference Frame and requires converting into ECEF to provide 5 | % positioning information. 6 | % All orbits are assumed to start at the ascending node for prograde 7 | % orbits and at the descending node for retrograde orbits 8 | % The IC of the orbit is assumed to be at the intercept of the Equinox 9 | % and the equator 10 | % The position of the satellite is reference to Right acension node 11 | % called the Arguement_of_Latitude 12 | % Eccentricity of the Arguement_of_Latitude is when the orbit is changed 13 | % to an eccentricity of 0 for easier calculations 14 | % The model currently does not account for inclinations of 0 or 180 15 | % degrees. Nor does it consider any perturbations such as 16 | % radiation pressure 17 | % aerodynamic drag 18 | % Orbital precession 19 | 20 | % Constants 21 | GM = 3.986005*10^14; 22 | 23 | semiminor_axis = sqrt((semimajor_axis^2)-(eccentricity*semimajor_axis)^2); 24 | Total_Area = pi*semiminor_axis*semimajor_axis; 25 | Orbital_Period=sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)); 26 | 27 | Area_per_second_travelled = Total_Area/Orbital_Period; 28 | 29 | % Find Area of the orbit so far from current Arguement of Latitude by 30 | % making the orbit into a circle (Eccentricity = 0) 31 | Current_Eccentricity_Arguement_of_Latitude = 2*atan(sqrt((1-eccentricity)/(1+eccentricity))*tan(Arguement_of_Latitude/2)); 32 | Arguement_of_Latitude_Area = 0.5*semimajor_axis*semiminor_axis*(Current_Eccentricity_Anamoaly-eccentricity*sin(Current_Eccentricity_Arguement_of_Latitude)); 33 | 34 | % Find new area and subsequently new Arguement of Latitude 35 | New_Area = Arguement_of_Latitude_Area + Area_per_second*interval; 36 | if New_Area > Total_Area 37 | New_Area = New_Area - Total_Area; 38 | end 39 | 40 | % Find the new Arguement of Latitude that correlates with the New Area covered by the 41 | % orbit 42 | fun = x*(1-eccentricity*sin(x))-(2*New_Area/(semimajor_axis*semiminor_axis)); 43 | New_Eccentric_Arguement_of_Latitude = fzero(fun, Current_Eccentricity_Arguement_of_Latitude); 44 | fun2 = 2*atan((sqrt((1-eccentricity)/(1+eccentricity))*tan(x/2)))-New_Eccentric_Arguement_of_Latitude; 45 | New_Arguement_of_Latitude = fzero(fun2, Arguement_of_Latitude); 46 | 47 | % Calculate the transformation matrix for ECI to ECEF using IAU-76/FK5 as 48 | % reduction methodology 49 | 50 | % ECI2ECEF_Transformation_Matrix = dcmeci2ecef('IAU-76/FK5',[Year Month Day Hour Minutes Seconds]); 51 | 52 | % Calculate ECI coordinates 53 | end 54 | 55 | -------------------------------------------------------------------------------- /IGRF Model/Archive/SchmidtCoefficients.m: -------------------------------------------------------------------------------- 1 | 2 | [gh, n, m, val, sv] = textread('igrf2015.txt','%s %f %f %f %f'); 3 | N=max(n); 4 | g=zeros(N,N+1); 5 | h=zeros(N,N+1); 6 | hsv=zeros(N,N+1); 7 | gsv=zeros(N,N+1); 8 | for x=1:length(gh) 9 | if strcmp(gh(x),'g') 10 | g(n(x),m(x)+1) = val(x); 11 | gsv(n(x),m(x)+1) = sv(x); 12 | else 13 | h(n(x),m(x)+1) = val(x); 14 | hsv(n(x),m(x)+1) = sv(x); 15 | end 16 | end 17 | count=1; 18 | S = zeros(N,N+1); 19 | for n=1:N 20 | for m=0:n 21 | if m>1 22 | S(n,m+1) = S(n,m)*((n-m+1)/(n+m))^0.5; 23 | elseif m>0 24 | S(n,m+1) = S(n,m)*(2*(n-m+1)/(n+m))^0.5; 25 | elseif n==1 26 | S(n,1) = 1; 27 | else 28 | S(n,1) = S(n-1,1)*(2*n-1)/(n); 29 | end 30 | gS(count,1) = n; gS(count,2)=m; 31 | gS(count,3)=g(n,m+1)*S(n,m+1); gS(count,4)=gsv(n,m+1)*S(n,m+1); 32 | hS(count,1) = n; hS(count,2)=m; 33 | hS(count,3)=h(n,m+1)*S(n,m+1); hS(count,4)=hsv(n,m+1)*S(n,m+1); 34 | count=count+1; 35 | end 36 | end 37 | 38 | %Split into g and h coefficients with format of m 2015 SV in order of n 39 | %value 40 | dlmwrite('igrfSg2015.txt',gS,'\t') 41 | dlmwrite('igrfSh2015.txt',hS,'\t') 42 | -------------------------------------------------------------------------------- /IGRF Model/Archive/untitled.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Archive/untitled.jpg -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/Field_Vector.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Attitude-Control-Model/Field_Vector.m -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/GUI.fig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Attitude-Control-Model/GUI.fig -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/GUI.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Attitude-Control-Model/GUI.m -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/GUI_Override.m: -------------------------------------------------------------------------------- 1 | %Main Operation with GUI Inputs 2 | % Output Format: [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z, Earth_B_x_ECEF, Earth_B_y_ECEF, Earth_B_z_ECEF] 3 | 4 | %% 5 | % GUI Replacement 6 | Launch_Time = datetime(); 7 | % Orbital Properties 8 | Orbital_Eccentricity = 0.2; 9 | Orbital_Inclination = pi/2; %[rad] 10 | Orbital_Semimajor_Axis = 6871000; %[m] 11 | Orbital_Mesh = 100; 12 | Orbital_RAAN = 0.3; %[rad] 13 | Orbital_Arg_of_Perigee = pi/4; %[rad] 14 | Orbital_Num_of_Orbits = 5; 15 | 16 | % Dynamic Properties 17 | Inertia_Tensor = [0.0267, 0.03, 0.1; 0.03, 0.1333, 0.01; 0.03, 0.01, 0.1333]; % x in long direction [kg*m2] 18 | 19 | % Model Operation 20 | 21 | %% Orbital Propagation Model - Harrison Handley 22 | % Orbit Propagation - Defines Result_Matrix as 23 | % [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z] 24 | Results = Orbital_Model_Function(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits); 25 | 26 | %% Magnetic Field Model - Harrison Handley 27 | % Earth Magnetic Field Model 28 | % Add to Results three vectors for Earths magnetic field x, y and z components in ECEF for that rows satellite CM ECEF position 29 | Results = horzcat(Results, zeros(size(Results, 1), 3 )); 30 | 31 | % Find magnetic field of earth at each position in Teslas 32 | for row = 1:size(Results, 1) 33 | % r = vector length of xyz 34 | % theta Latitude measured in degrees positive from equator 35 | % phi Longitude measured in degrees positive east from Greenwich 36 | % days Decimal days since January 1, 2015 37 | r = sqrt(Results(row,8)^2 + Results(row,9)^2 + Results(row,10)^2); 38 | theta = acosd(sqrt(Results(row,8)^2 + Results(row,9)^2)/r); 39 | phi = atand(Results(row,9)/Results(row,8)); 40 | Days_since_Jan_1st_2015 = daysact('1-Jan-2015 00:00:00', (Launch_Time + seconds(Results(row, 4)))); 41 | [Br ,Bt, Bp] = IGRF_Model(r, theta, phi,Days_since_Jan_1st_2015); 42 | [Bx, By, Bz] = sph2cart(Bp, Bt, Br); 43 | Results(row, 11) = Bx; 44 | Results(row, 12) = By; 45 | Results(row, 13) = Bz; 46 | end 47 | 48 | %% Dynamic Model 49 | 50 | -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/IGRF12coeffs.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF Model/Attitude-Control-Model/IGRF12coeffs.xls -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/IGRF2015.txt: -------------------------------------------------------------------------------- 1 | g 1 0 -29442.0 10.3 2 | g 1 1 -1501.0 18.1 3 | h 1 1 4797.1 -26.6 4 | g 2 0 -2445.1 -8.7 5 | g 2 1 3012.9 -3.3 6 | h 2 1 -2845.6 -27.4 7 | g 2 2 1676.7 2.1 8 | h 2 2 -641.9 -14.1 9 | g 3 0 1350.7 3.4 10 | g 3 1 -2352.3 -5.5 11 | h 3 1 -115.3 8.2 12 | g 3 2 1225.6 -0.7 13 | h 3 2 244.9 -0.4 14 | g 3 3 582.0 -10.1 15 | h 3 3 -538.4 1.8 16 | g 4 0 907.6 -0.7 17 | g 4 1 813.7 0.2 18 | h 4 1 283.3 -1.3 19 | g 4 2 120.4 -9.1 20 | h 4 2 -188.7 5.3 21 | g 4 3 -334.9 4.1 22 | h 4 3 180.9 2.9 23 | g 4 4 70.4 -4.3 24 | h 4 4 -329.5 -5.2 25 | g 5 0 -232.6 -0.2 26 | g 5 1 360.1 0.5 27 | h 5 1 47.3 0.6 28 | g 5 2 192.4 -1.3 29 | h 5 2 197.0 1.7 30 | g 5 3 -140.9 -0.1 31 | h 5 3 -119.3 -1.2 32 | g 5 4 -157.5 1.4 33 | h 5 4 16.0 3.4 34 | g 5 5 4.1 3.9 35 | h 5 5 100.2 0.0 36 | g 6 0 70.0 -0.3 37 | g 6 1 67.7 -0.1 38 | h 6 1 -20.8 0.0 39 | g 6 2 72.7 -0.7 40 | h 6 2 33.2 -2.1 41 | g 6 3 -129.9 2.1 42 | h 6 3 58.9 -0.7 43 | g 6 4 -28.9 -1.2 44 | h 6 4 -66.7 0.2 45 | g 6 5 13.2 0.3 46 | h 6 5 7.3 0.9 47 | g 6 6 -70.9 1.6 48 | h 6 6 62.6 1.0 49 | g 7 0 81.6 0.3 50 | g 7 1 -76.1 -0.2 51 | h 7 1 -54.1 0.8 52 | g 7 2 -6.8 -0.5 53 | h 7 2 -19.5 0.4 54 | g 7 3 51.8 1.3 55 | h 7 3 5.7 -0.2 56 | g 7 4 15.0 0.1 57 | h 7 4 24.4 -0.3 58 | g 7 5 9.4 -0.6 59 | h 7 5 3.4 -0.6 60 | g 7 6 -2.8 -0.8 61 | h 7 6 -27.4 0.1 62 | g 7 7 6.8 0.2 63 | h 7 7 -2.2 -0.2 64 | g 8 0 24.2 0.2 65 | g 8 1 8.8 0.0 66 | h 8 1 10.1 -0.3 67 | g 8 2 -16.9 -0.6 68 | h 8 2 -18.3 0.3 69 | g 8 3 -3.2 0.5 70 | h 8 3 13.3 0.1 71 | g 8 4 -20.6 -0.2 72 | h 8 4 -14.6 0.5 73 | g 8 5 13.4 0.4 74 | h 8 5 16.2 -0.2 75 | g 8 6 11.7 0.1 76 | h 8 6 5.7 -0.3 77 | g 8 7 -15.9 -0.4 78 | h 8 7 -9.1 0.3 79 | g 8 8 -2.0 0.3 80 | h 8 8 2.1 0.0 81 | g 9 0 5.4 0.0 82 | g 9 1 8.8 0.0 83 | h 9 1 -21.6 0.0 84 | g 9 2 3.1 0.0 85 | h 9 2 10.8 0.0 86 | g 9 3 -3.3 0.0 87 | h 9 3 11.8 0.0 88 | g 9 4 0.7 0.0 89 | h 9 4 -6.8 0.0 90 | g 9 5 -13.3 0.0 91 | h 9 5 -6.9 0.0 92 | g 9 6 -0.1 0.0 93 | h 9 6 7.8 0.0 94 | g 9 7 8.7 0.0 95 | h 9 7 1.0 0.0 96 | g 9 8 -9.1 0.0 97 | h 9 8 -4.0 0.0 98 | g 9 9 -10.5 0.0 99 | h 9 9 8.4 0.0 100 | g 10 0 -1.9 0.0 101 | g 10 1 -6.3 0.0 102 | h 10 1 3.2 0.0 103 | g 10 2 0.1 0.0 104 | h 10 2 -0.4 0.0 105 | g 10 3 0.5 0.0 106 | h 10 3 4.6 0.0 107 | g 10 4 -0.5 0.0 108 | h 10 4 4.4 0.0 109 | g 10 5 1.8 0.0 110 | h 10 5 -7.9 0.0 111 | g 10 6 -0.7 0.0 112 | h 10 6 -0.6 0.0 113 | g 10 7 2.1 0.0 114 | h 10 7 -4.2 0.0 115 | g 10 8 2.4 0.0 116 | h 10 8 -2.8 0.0 117 | g 10 9 -1.8 0.0 118 | h 10 9 -1.2 0.0 119 | g 10 10 -3.6 0.0 120 | h 10 10 -8.7 0.0 121 | g 11 0 3.1 0.0 122 | g 11 1 -1.5 0.0 123 | h 11 1 -0.1 0.0 124 | g 11 2 -2.3 0.0 125 | h 11 2 2.0 0.0 126 | g 11 3 2.0 0.0 127 | h 11 3 -0.7 0.0 128 | g 11 4 -0.8 0.0 129 | h 11 4 -1.1 0.0 130 | g 11 5 0.6 0.0 131 | h 11 5 0.8 0.0 132 | g 11 6 -0.7 0.0 133 | h 11 6 -0.2 0.0 134 | g 11 7 0.2 0.0 135 | h 11 7 -2.2 0.0 136 | g 11 8 1.7 0.0 137 | h 11 8 -1.4 0.0 138 | g 11 9 -0.2 0.0 139 | h 11 9 -2.5 0.0 140 | g 11 10 0.4 0.0 141 | h 11 10 -2.0 0.0 142 | g 11 11 3.5 0.0 143 | h 11 11 -2.4 0.0 144 | g 12 0 -1.9 0.0 145 | g 12 1 -0.2 0.0 146 | h 12 1 -1.1 0.0 147 | g 12 2 0.4 0.0 148 | h 12 2 0.4 0.0 149 | g 12 3 1.2 0.0 150 | h 12 3 1.9 0.0 151 | g 12 4 -0.8 0.0 152 | h 12 4 -2.2 0.0 153 | g 12 5 0.9 0.0 154 | h 12 5 0.3 0.0 155 | g 12 6 0.1 0.0 156 | h 12 6 0.7 0.0 157 | g 12 7 0.5 0.0 158 | h 12 7 -0.1 0.0 159 | g 12 8 -0.3 0.0 160 | h 12 8 0.3 0.0 161 | g 12 9 -0.4 0.0 162 | h 12 9 0.2 0.0 163 | g 12 10 0.2 0.0 164 | h 12 10 -0.9 0.0 165 | g 12 11 -0.9 0.0 166 | h 12 11 -0.1 0.0 167 | g 12 12 0.0 0.0 168 | h 12 12 0.7 0.0 169 | g 13 0 0.0 0.0 170 | g 13 1 -0.9 0.0 171 | h 13 1 -0.9 0.0 172 | g 13 2 0.4 0.0 173 | h 13 2 0.4 0.0 174 | g 13 3 0.5 0.0 175 | h 13 3 1.6 0.0 176 | g 13 4 -0.5 0.0 177 | h 13 4 -0.5 0.0 178 | g 13 5 1.0 0.0 179 | h 13 5 -1.2 0.0 180 | g 13 6 -0.2 0.0 181 | h 13 6 -0.1 0.0 182 | g 13 7 0.8 0.0 183 | h 13 7 0.4 0.0 184 | g 13 8 -0.1 0.0 185 | h 13 8 -0.1 0.0 186 | g 13 9 0.3 0.0 187 | h 13 9 0.4 0.0 188 | g 13 10 0.1 0.0 189 | h 13 10 0.5 0.0 190 | g 13 11 0.5 0.0 191 | h 13 11 -0.3 0.0 192 | g 13 12 -0.4 0.0 193 | h 13 12 -0.4 0.0 194 | g 13 13 -0.3 0.0 195 | h 13 13 -0.8 0.0 196 | -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/IGRF_Model.m: -------------------------------------------------------------------------------- 1 | 2 | function [Br,Bt,Bp] = IGRF_Model(r,theta,phi,days) 3 | % Output is Spherical ECEF 4 | % Inputs 5 | % r Geocentric radius 6 | % theta Latitude measured in degrees positive from equator 7 | % phi Longitude measured in degrees positive east from Greenwich 8 | % days Decimal days since January 1, 2015 9 | % 10 | % Outputs - magnetic field strength in local tangential coordinates 11 | % Br B in radial direction 12 | % Bt B in theta direction 13 | % Bp B in phi direction 14 | 15 | % Checks to see if located at either pole to avoid singularities 16 | if (theta>-0.00000001 & theta<0.00000001) 17 | theta=0.00000001; 18 | elseif(theta<180.00000001 & theta>179.99999999) 19 | theta=179.99999999; 20 | end 21 | 22 | % The angles must be converted from degrees into radians 23 | theta=(90-theta)*pi/180; 24 | phi = phi*pi/180; 25 | 26 | a=6371.2; % Reference radius used in IGRF 27 | 28 | % This section of the code simply reads in the g and h Schmidt 29 | % quasi-normalized coefficients 30 | [gn, gm, gvali, gsvi] = textread('igrfSg2015.txt','%f %f %f %f'); 31 | [hn, hm, hvali, hsvi] = textread('igrfSh2015.txt','%f %f %f %f'); 32 | N=max(gn); 33 | g=zeros(N,N+1); 34 | h=zeros(N,N+1); 35 | for x=1:length(gn) 36 | g(gn(x),gm(x)+1) = gvali(x) + gsvi(x)*days/365; 37 | h(hn(x),hm(x)+1) = hvali(x) + hsvi(x)*days/365; 38 | end 39 | 40 | % Initialize each of the variables 41 | % Br B in the radial driection 42 | % Bt B in the theta direction 43 | % Bp B in the phi direction 44 | % P The associated Legendre polynomial evaluated at cos(theta) 45 | % The nomenclature for the recursive values generally follows 46 | % the form P10 = P(n-1,m-0) 47 | % dP The partial derivative of P with respect to theta 48 | 49 | Br=0; Bt=0; Bp=0; 50 | P11=1; P10=P11; 51 | dP11=0; dP10=dP11; 52 | 53 | for m=0:N 54 | for n=1:N 55 | if m<=n 56 | % Calculate Legendre polynomials and derivatives recursively 57 | if n==m 58 | P2 = sin(theta)*P11; 59 | dP2 = sin(theta)*dP11 + cos(theta)*P11; 60 | P11=P2; P10=P11; P20=0; 61 | dP11=dP2; dP10=dP11; dP20=0; 62 | elseif n==1 63 | P2 = cos(theta)*P10; 64 | dP2 = cos(theta)*dP10 - sin(theta)*P10; 65 | P20=P10; P10=P2; 66 | dP20=dP10; dP10=dP2; 67 | else 68 | K = ((n-1)^2-m^2)/((2*n-1)*(2*n-3)); 69 | P2 = cos(theta)*P10 - K*P20; 70 | dP2 = cos(theta)*dP10 - sin(theta)*P10 - K*dP20; 71 | P20=P10; P10=P2; 72 | dP20=dP10; dP10=dP2; 73 | end 74 | 75 | % Calculate Br, Bt, and Bp 76 | Br = Br + (a/r)^(n+2)*(n+1)*... 77 | ((g(n,m+1)*cos(m*phi) + h(n,m+1)*sin(m*phi))*P2); 78 | Bt = Bt + (a/r)^(n+2)*... 79 | ((g(n,m+1)*cos(m*phi) + h(n,m+1)*sin(m*phi))*dP2); 80 | Bp = Bp + (a/r)^(n+2)*... 81 | (m*(-g(n,m+1)*sin(m*phi) + h(n,m+1)*cos(m*phi))* P2); 82 | end 83 | end 84 | end 85 | end 86 | 87 | -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/Model_Executor.m: -------------------------------------------------------------------------------- 1 | function [ Results ] = Model_Executor(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits) 2 | %Main Operation with GUI Inputs 3 | % Output Format: [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z, Earth_B_x_ECEF, Earth_B_y_ECEF, Earth_B_z_ECEF] 4 | % 5 | 6 | %% Orbital Propagation Model - Harrison Handley 7 | % Orbit Propagation - Defines Result_Matrix as 8 | % [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z] 9 | Results = Orbital_Model_Function(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits); 10 | 11 | %% Magnetic Field Model - Harrison Handley 12 | % Earth Magnetic Field Model 13 | % Add to Results three vectors for Earths magnetic field x, y and z components in ECEF for that rows satellite CM ECEF position 14 | Results = horzcat(Results, zeros(size(Results, 1), 3 )); 15 | 16 | % Find magnetic field of earth at each position in Teslas 17 | for row = 1:size(Results, 1) 18 | % r = vector length of xyz 19 | % theta Latitude measured in degrees positive from equator 20 | % phi Longitude measured in degrees positive east from Greenwich 21 | % days Decimal days since January 1, 2015 22 | r = sqrt(Results(row,8)^2 + Results(row,9)^2 + Results(row,10)^2); 23 | theta = acosd(sqrt(Results(row,8)^2 + Results(row,9)^2)/r); 24 | phi = atand(Results(row,9)/Results(row,8)); 25 | Days_since_Jan_1st_2015 = daysact('1-Jan-2015 00:00:00', (Launch_Time + seconds(Results(row, 4)))); 26 | [Br ,Bt, Bp] = IGRF_Model(r, theta, phi,Days_since_Jan_1st_2015); 27 | [Bx, By, Bz] = sph2cart(Bp, Bt, Br); 28 | Results(row, 11) = Bx; 29 | Results(row, 12) = By; 30 | Results(row, 13) = Bz; 31 | end 32 | 33 | %% Dynamic Model 34 | 35 | 36 | 37 | %% End of Simulation 38 | 39 | end 40 | 41 | -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/Orbital_Model_Function.m: -------------------------------------------------------------------------------- 1 | function [ Output_Matrix ] = Orbital_Model_Function( Start_Datetime, eccentricity, inclination, semimajor_axis, Num_Intervals, RAAN, argument_of_perigee, num_of_orbits) 2 | % Keplerian Orbital Model 3 | 4 | % eccentricity is the eccentricity of the orbit specified by GUI 5 | % inclination is the incliation of the orbit specified by GUI 6 | % semimajor_axis is half the length of the elliptical orbit specified by 7 | % GUI in [meters] 8 | % Num_Intervals is the number of intervals one orbit is split into 9 | % RAAN is the right ascension of ascending node 10 | % argument_of_perigee is the the polar angle on the orbital plane from 11 | % RAAN to the closest point of the orbit to the earth. It is 0 for 12 | % eccentricity of 0. [Radians] 13 | % Time values are with respect to the starting time values of the orbit 14 | % Stuff 15 | Num_of_Terms_in_infinite_Series = 10; 16 | GM = 3.986005*10^14; 17 | % [Sat_True_Anomaly, Altitude, Orbit #, Time, 18 | % ECI_x, ECI_y, ECI_z, ECEF_x, ECEF_y, ECEF_z] 19 | 20 | % Orbital_Matrix = zeros(Num_Intervals, 3) + repmat(datetime, Num_Intervals, 1) + zeros(Num_Intervals, 6); 21 | Orbital_Matrix = zeros(Num_Intervals, 10 ); 22 | 23 | E = zeros(1,Num_Intervals); % Mean Anomaly 24 | % Provides the angle vector for which the orbit is divided up into when 25 | % considering the same orbit with e = 0 26 | M = linspace(0,2*pi,Num_Intervals); % Mean Anomaly 27 | 28 | % Calculate true anomaly at each point 29 | for j = 1:Num_Intervals 30 | E(j) = M(j); 31 | for n = 1:Num_of_Terms_in_infinite_Series 32 | E(j) = E(j) + 2/n * besselj(n,n*eccentricity).*sin(n*M(j)); 33 | end 34 | end 35 | 36 | % calculate polar coordinates where theta = 0 is perigee 37 | Orbital_Matrix (:,1) = 2 .* atan(sqrt((1+eccentricity)/(1-eccentricity)) .* tan(E/2)); 38 | Orbital_Matrix (:,2) = semimajor_axis * (1-eccentricity^2)./ (1 + eccentricity.*cos(Orbital_Matrix(:,1))); 39 | Orbital_Matrix (:,3) = 1; 40 | Orbital_Matrix (:,4) = sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)).*(M./(2*pi)); 41 | Output_Matrix = Orbital_Matrix; 42 | 43 | % Add in additional orbits 44 | for k = 2:num_of_orbits 45 | Temp_Matrix = Orbital_Matrix; 46 | Temp_Matrix (:,3) = k; 47 | Temp_Matrix (:,4) = Orbital_Matrix(:,4) + sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM))* (k-1); 48 | Output_Matrix = vertcat(Output_Matrix, Temp_Matrix); 49 | end 50 | % Euler Transformation Matrix 51 | B = [cos(argument_of_perigee), sin(argument_of_perigee), 0; -sin(argument_of_perigee), cos(argument_of_perigee), 0; 0, 0, 1]; 52 | C = [1, 0, 0; 0, cos(inclination), sin(inclination); 0, -sin(inclination), cos(inclination)]; 53 | D = [cos(RAAN), sin(RAAN), 0; -sin(RAAN), cos(RAAN), 0; 0, 0, 1]; 54 | Euler_Transformation_Matrix = B*C*D; 55 | 56 | % ECI Coordinates 57 | for k = 1:length(Output_Matrix) 58 | Temp_Array = [Output_Matrix(k,2).*cos(Output_Matrix(k,1)), Output_Matrix(k,2).*sin(Output_Matrix(k,1)), 0]*Euler_Transformation_Matrix; 59 | Output_Matrix(k, 5) = Temp_Array(1); 60 | Output_Matrix(k, 6) = Temp_Array(2); 61 | Output_Matrix(k, 7) = Temp_Array(3); 62 | end 63 | % ECI to ECEF Coordinates 64 | for k = 1:length(Output_Matrix) 65 | Temp_Date = Start_Datetime + seconds(Output_Matrix(k, 4)); 66 | Data_Array = [year(Temp_Date), month(Temp_Date), day(Temp_Date), hour(Temp_Date), minute(Temp_Date), second(Temp_Date)]; 67 | ECI2ECEF_Matrix = dcmeci2ecef('IAU-2000/2006', Data_Array); 68 | Temp_Array = [Output_Matrix(k,5), Output_Matrix(k,6), Output_Matrix(k,7)]*ECI2ECEF_Matrix; 69 | Output_Matrix(k, 8) = Temp_Array(1); 70 | Output_Matrix(k, 9) = Temp_Array(2); 71 | Output_Matrix(k, 10) = Temp_Array(3); 72 | end 73 | Output_Matrix; 74 | end 75 | 76 | -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/igrfSg2015.txt: -------------------------------------------------------------------------------- 1 | 1 0 -29442 10.3 2 | 1 1 -1501 18.1 3 | 2 0 -3667.6 -13.05 4 | 2 1 5218.5 -5.7158 5 | 2 2 1452.1 1.8187 6 | 3 0 3376.8 8.5 7 | 3 1 -7202.4 -16.84 8 | 3 2 2373.4 -1.3555 9 | 3 3 460.11 -7.9848 10 | 4 0 3970.8 -3.0625 11 | 4 1 4503 1.1068 12 | 4 2 471.14 -35.609 13 | 4 3 -700.49 8.5758 14 | 4 4 52.062 -3.1799 15 | 5 0 -1831.7 -1.575 16 | 5 1 3661 5.0833 17 | 5 2 1478.6 -9.9908 18 | 5 3 -663.11 -0.47062 19 | 5 4 -349.42 3.1059 20 | 5 5 2.8764 2.7361 21 | 6 0 1010.6 -4.3312 22 | 6 1 1279.7 -1.8903 23 | 6 2 1086.4 -10.461 24 | 6 3 -1294.2 20.922 25 | 6 4 -157.7 -6.5482 26 | 6 5 30.714 0.69804 27 | 6 6 -47.623 1.0747 28 | 7 0 2187.9 8.0437 29 | 7 1 -2699.2 -7.0939 30 | 7 2 -196.93 -14.48 31 | 7 3 1060.8 26.622 32 | 7 4 185.23 1.2349 33 | 7 5 58.04 -3.7047 34 | 7 6 -6.7811 -1.9375 35 | 7 7 4.4014 0.12945 36 | 8 0 1216.6 10.055 37 | 8 1 589.88 0 38 | 8 2 -947.79 -33.649 39 | 8 3 -132.54 20.71 40 | 8 4 -550.77 -5.3472 41 | 8 5 198.73 5.9322 42 | 8 6 80.323 0.68652 43 | 8 7 -39.859 -1.0027 44 | 8 8 -1.2534 0.18801 45 | 9 0 512.79 0 46 | 9 1 1121.2 0 47 | 9 2 336.82 0 48 | 9 3 -273.84 0 49 | 9 4 39.463 0 50 | 9 5 -448.09 0 51 | 9 6 -1.7398 0 52 | 9 7 65.542 0 53 | 9 8 -23.514 0 54 | 9 9 -6.395 0 55 | 10 0 -342.81 0 56 | 10 1 -1532.7 0 57 | 10 2 21.069 0 58 | 10 3 82.64 0 59 | 10 4 -58.435 0 60 | 10 5 133.05 0 61 | 10 6 -28.924 0 62 | 10 7 42.091 0 63 | 10 8 19.638 0 64 | 10 9 -4.7786 0 65 | 10 10 -2.1371 0 66 | 11 0 1067.8 0 67 | 11 1 -699.58 0 68 | 11 2 -940.81 0 69 | 11 3 655.94 0 70 | 11 4 -191.61 0 71 | 11 5 95.054 0 72 | 11 6 -65.882 0 73 | 11 7 9.9209 0 74 | 11 8 38.692 0 75 | 11 9 -1.763 0 76 | 11 10 1.0881 0 77 | 11 11 2.0299 0 78 | 12 0 -1254.4 0 79 | 12 1 -179.41 0 80 | 12 2 318.05 0 81 | 12 3 779.06 0 82 | 12 4 -389.53 0 83 | 12 5 300.62 0 84 | 12 6 20.83 0 85 | 12 7 58.527 0 86 | 12 8 -17.558 0 87 | 12 9 -10.217 0 88 | 12 10 1.8865 0 89 | 12 11 -2.5033 0 90 | 12 12 0 0 91 | 13 0 0 0 92 | 13 1 -1557.2 0 93 | 13 2 619.01 0 94 | 13 3 641.57 0 95 | 13 4 -492.06 0 96 | 13 5 695.88 0 97 | 13 6 -90.309 0 98 | 13 7 213.71 0 99 | 13 8 -14.279 0 100 | 13 9 20.422 0 101 | 13 10 2.8388 0 102 | 13 11 5.0184 0 103 | 13 12 -1.1355 0 104 | 13 13 -0.16702 0 105 | -------------------------------------------------------------------------------- /IGRF Model/Attitude-Control-Model/igrfSh2015.txt: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 1 1 4797.1 -26.6 3 | 2 0 0 0 4 | 2 1 -4928.7 -47.458 5 | 2 2 -555.9 -12.211 6 | 3 0 0 0 7 | 3 1 -353.03 25.107 8 | 3 2 474.25 -0.7746 9 | 3 3 -425.64 1.423 10 | 4 0 0 0 11 | 4 1 1567.8 -7.1942 12 | 4 2 -738.41 20.74 13 | 4 3 378.38 6.0658 14 | 4 4 -243.67 -3.8455 15 | 5 0 0 0 16 | 5 1 480.88 6.0999 17 | 5 2 1514 13.065 18 | 5 3 -561.45 -5.6475 19 | 5 4 35.496 7.543 20 | 5 5 70.296 0 21 | 6 0 0 0 22 | 6 1 -393.18 0 23 | 6 2 496.15 -31.383 24 | 6 3 586.81 -6.974 25 | 6 4 -363.97 1.0914 26 | 6 5 16.986 2.0941 27 | 6 6 42.048 0.67169 28 | 7 0 0 0 29 | 7 1 -1918.9 28.376 30 | 7 2 -564.74 11.584 31 | 7 3 116.73 -4.0957 32 | 7 4 301.31 -3.7047 33 | 7 5 20.993 -3.7047 34 | 7 6 -66.358 0.24218 35 | 7 7 -1.424 -0.12945 36 | 8 0 0 0 37 | 8 1 677.02 -20.109 38 | 8 2 -1026.3 16.825 39 | 8 3 550.88 4.142 40 | 8 4 -390.35 13.368 41 | 8 5 240.26 -2.9661 42 | 8 6 39.132 -2.0596 43 | 8 7 -22.812 0.75205 44 | 8 8 1.3161 0 45 | 9 0 0 0 46 | 9 1 -2751.9 0 47 | 9 2 1173.4 0 48 | 9 3 979.2 0 49 | 9 4 -383.36 0 50 | 9 5 -232.47 0 51 | 9 6 135.7 0 52 | 9 7 7.5335 0 53 | 9 8 -10.336 0 54 | 9 9 5.116 0 55 | 10 0 0 0 56 | 10 1 778.52 0 57 | 10 2 -84.277 0 58 | 10 3 760.29 0 59 | 10 4 514.23 0 60 | 10 5 -583.93 0 61 | 10 6 -24.792 0 62 | 10 7 -84.181 0 63 | 10 8 -22.911 0 64 | 10 9 -3.1857 0 65 | 10 10 -5.1646 0 66 | 11 0 0 0 67 | 11 1 -46.639 0 68 | 11 2 818.1 0 69 | 11 3 -229.58 0 70 | 11 4 -263.47 0 71 | 11 5 126.74 0 72 | 11 6 -18.824 0 73 | 11 7 -109.13 0 74 | 11 8 -31.864 0 75 | 11 9 -22.037 0 76 | 11 10 -5.4407 0 77 | 11 11 -1.392 0 78 | 12 0 0 0 79 | 12 1 -986.73 0 80 | 12 2 318.05 0 81 | 12 3 1233.5 0 82 | 12 4 -1071.2 0 83 | 12 5 100.21 0 84 | 12 6 145.81 0 85 | 12 7 -11.705 0 86 | 12 8 17.558 0 87 | 12 9 5.1087 0 88 | 12 10 -8.4892 0 89 | 12 11 -0.27815 0 90 | 12 12 0.39744 0 91 | 13 0 0 0 92 | 13 1 -1557.2 0 93 | 13 2 619.01 0 94 | 13 3 2053 0 95 | 13 4 -492.06 0 96 | 13 5 -835.05 0 97 | 13 6 -45.155 0 98 | 13 7 106.86 0 99 | 13 8 -14.279 0 100 | 13 9 27.229 0 101 | 13 10 14.194 0 102 | 13 11 -3.011 0 103 | 13 12 -1.1355 0 104 | 13 13 -0.44539 0 105 | -------------------------------------------------------------------------------- /IGRF Model/Orbital_Model.asv: -------------------------------------------------------------------------------- 1 | function [ output_args ] = Orbital_Model( Time, eccentricity, inclination, semimajor_axis, True_Anomaly, Interval) 2 | % Orbital Model Summary 3 | % The orbit of the satellite is defined in Earth-Centered Inertial 4 | % Reference Frame and requires converting into ECEF to provide 5 | % positioning information. 6 | % All orbits are assumed to start at the ascending node for prograde 7 | % orbits and at the descending node for retrograde orbits 8 | % The IC of the orbit is assumed to be at the intercept of the Equinox 9 | % and the equator 10 | % An eccentricity of 0 has the true anomaly referenced from the 11 | % ascending node. 12 | % For all other eccentricities, it is referenced to the perigee 13 | % The model currently does not account for inclinations of 0 or 180 14 | % degrees. Nor does it consider any perturbations such as 15 | % radiation pressure 16 | % aerodynamic drag 17 | % Orbital precession 18 | 19 | % Constants 20 | GM = 3.986005*10^14; 21 | 22 | 23 | semiminor_axis = sqrt(semimajor_axis^2-(eccentricity*semimajor_axis)^2); 24 | Total_Area = pi*semiminor_axis*semimajor_axis; 25 | Orbital_Period=sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)); 26 | 27 | Area_per_second_travelled = Total_Area/Orbital_Period; 28 | 29 | % Find A 30 | Current_Eccentric_Anomaly = 2*arctan(sqrt((1-eccentricity)/(1+eccentricity))*tan(True_anaomaly/2)); 31 | True_Anamoly_Area = 0.5*semimajor_axis*semiminor_axis*(Current_Eccentricity_Anamoaly-eccentricity*sin(Current_Eccentricity_Anamoly)); 32 | 33 | New_Area = True_Anamoaly_Area + Area_per_second*interval; 34 | fun = x*(1-eccentricity*sin(x))-(2*New_Area/(semimajor_axis*semiminor_axis)); 35 | New_Eccentric_Anomaly = fzero(fun, x0); 36 | 37 | 38 | end 39 | 40 | -------------------------------------------------------------------------------- /IGRF Model/Orbital_Model.m: -------------------------------------------------------------------------------- 1 | function [ output_args ] = Orbital_Model( Time, eccentricity, inclination, semimajor_axis, True_Anomaly, Interval) 2 | % Orbital Model Summary 3 | % The orbit of the satellite is defined in Earth-Centered Inertial 4 | % Reference Frame and requires converting into ECEF to provide 5 | % positioning information. 6 | % All orbits are assumed to start at the ascending node for prograde 7 | % orbits and at the descending node for retrograde orbits 8 | % The IC of the orbit is assumed to be at the intercept of the Equinox 9 | % and the equator 10 | % An eccentricity of 0 has the true anomaly referenced from the 11 | % ascending node. 12 | % For all other eccentricities, it is referenced to the perigee 13 | % The model currently does not account for inclinations of 0 or 180 14 | % degrees. Nor does it consider any perturbations such as 15 | % radiation pressure 16 | % aerodynamic drag 17 | % Orbital precession 18 | 19 | % Constants 20 | GM = 3.986005*10^14; 21 | 22 | 23 | semiminor_axis = sqrt(semimajor_axis^2-(eccentricity*semimajor_axis)^2); 24 | Total_Area = pi*semiminor_axis*semimajor_axis; 25 | Orbital_Period=sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)); 26 | 27 | Area_per_second_travelled = Total_Area/Orbital_Period; 28 | 29 | % Find Area of the orbit so far from current true anamoaly 30 | Current_Eccentric_Anomaly = 2*arctan(sqrt((1-eccentricity)/(1+eccentricity))*tan(True_anaomaly/2)); 31 | True_Anamoly_Area = 0.5*semimajor_axis*semiminor_axis*(Current_Eccentricity_Anamoaly-eccentricity*sin(Current_Eccentricity_Anamoly)); 32 | 33 | % Find new area and subsequently new true anamoaly 34 | New_Area = True_Anamoaly_Area + Area_per_second*interval; 35 | if New_Area > Total_Area 36 | New_Area = New_Area - Total_Area; 37 | end 38 | 39 | fun = x*(1-eccentricity*sin(x))-(2*New_Area/(semimajor_axis*semiminor_axis)); 40 | New_Eccentric_Anomaly = fzero(fun, x0); 41 | 42 | 43 | end 44 | 45 | -------------------------------------------------------------------------------- /IGRF12coeffs.xls: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IGRF12coeffs.xls -------------------------------------------------------------------------------- /IGRF2015.txt: -------------------------------------------------------------------------------- 1 | g 1 0 -29442.0 10.3 2 | g 1 1 -1501.0 18.1 3 | h 1 1 4797.1 -26.6 4 | g 2 0 -2445.1 -8.7 5 | g 2 1 3012.9 -3.3 6 | h 2 1 -2845.6 -27.4 7 | g 2 2 1676.7 2.1 8 | h 2 2 -641.9 -14.1 9 | g 3 0 1350.7 3.4 10 | g 3 1 -2352.3 -5.5 11 | h 3 1 -115.3 8.2 12 | g 3 2 1225.6 -0.7 13 | h 3 2 244.9 -0.4 14 | g 3 3 582.0 -10.1 15 | h 3 3 -538.4 1.8 16 | g 4 0 907.6 -0.7 17 | g 4 1 813.7 0.2 18 | h 4 1 283.3 -1.3 19 | g 4 2 120.4 -9.1 20 | h 4 2 -188.7 5.3 21 | g 4 3 -334.9 4.1 22 | h 4 3 180.9 2.9 23 | g 4 4 70.4 -4.3 24 | h 4 4 -329.5 -5.2 25 | g 5 0 -232.6 -0.2 26 | g 5 1 360.1 0.5 27 | h 5 1 47.3 0.6 28 | g 5 2 192.4 -1.3 29 | h 5 2 197.0 1.7 30 | g 5 3 -140.9 -0.1 31 | h 5 3 -119.3 -1.2 32 | g 5 4 -157.5 1.4 33 | h 5 4 16.0 3.4 34 | g 5 5 4.1 3.9 35 | h 5 5 100.2 0.0 36 | g 6 0 70.0 -0.3 37 | g 6 1 67.7 -0.1 38 | h 6 1 -20.8 0.0 39 | g 6 2 72.7 -0.7 40 | h 6 2 33.2 -2.1 41 | g 6 3 -129.9 2.1 42 | h 6 3 58.9 -0.7 43 | g 6 4 -28.9 -1.2 44 | h 6 4 -66.7 0.2 45 | g 6 5 13.2 0.3 46 | h 6 5 7.3 0.9 47 | g 6 6 -70.9 1.6 48 | h 6 6 62.6 1.0 49 | g 7 0 81.6 0.3 50 | g 7 1 -76.1 -0.2 51 | h 7 1 -54.1 0.8 52 | g 7 2 -6.8 -0.5 53 | h 7 2 -19.5 0.4 54 | g 7 3 51.8 1.3 55 | h 7 3 5.7 -0.2 56 | g 7 4 15.0 0.1 57 | h 7 4 24.4 -0.3 58 | g 7 5 9.4 -0.6 59 | h 7 5 3.4 -0.6 60 | g 7 6 -2.8 -0.8 61 | h 7 6 -27.4 0.1 62 | g 7 7 6.8 0.2 63 | h 7 7 -2.2 -0.2 64 | g 8 0 24.2 0.2 65 | g 8 1 8.8 0.0 66 | h 8 1 10.1 -0.3 67 | g 8 2 -16.9 -0.6 68 | h 8 2 -18.3 0.3 69 | g 8 3 -3.2 0.5 70 | h 8 3 13.3 0.1 71 | g 8 4 -20.6 -0.2 72 | h 8 4 -14.6 0.5 73 | g 8 5 13.4 0.4 74 | h 8 5 16.2 -0.2 75 | g 8 6 11.7 0.1 76 | h 8 6 5.7 -0.3 77 | g 8 7 -15.9 -0.4 78 | h 8 7 -9.1 0.3 79 | g 8 8 -2.0 0.3 80 | h 8 8 2.1 0.0 81 | g 9 0 5.4 0.0 82 | g 9 1 8.8 0.0 83 | h 9 1 -21.6 0.0 84 | g 9 2 3.1 0.0 85 | h 9 2 10.8 0.0 86 | g 9 3 -3.3 0.0 87 | h 9 3 11.8 0.0 88 | g 9 4 0.7 0.0 89 | h 9 4 -6.8 0.0 90 | g 9 5 -13.3 0.0 91 | h 9 5 -6.9 0.0 92 | g 9 6 -0.1 0.0 93 | h 9 6 7.8 0.0 94 | g 9 7 8.7 0.0 95 | h 9 7 1.0 0.0 96 | g 9 8 -9.1 0.0 97 | h 9 8 -4.0 0.0 98 | g 9 9 -10.5 0.0 99 | h 9 9 8.4 0.0 100 | g 10 0 -1.9 0.0 101 | g 10 1 -6.3 0.0 102 | h 10 1 3.2 0.0 103 | g 10 2 0.1 0.0 104 | h 10 2 -0.4 0.0 105 | g 10 3 0.5 0.0 106 | h 10 3 4.6 0.0 107 | g 10 4 -0.5 0.0 108 | h 10 4 4.4 0.0 109 | g 10 5 1.8 0.0 110 | h 10 5 -7.9 0.0 111 | g 10 6 -0.7 0.0 112 | h 10 6 -0.6 0.0 113 | g 10 7 2.1 0.0 114 | h 10 7 -4.2 0.0 115 | g 10 8 2.4 0.0 116 | h 10 8 -2.8 0.0 117 | g 10 9 -1.8 0.0 118 | h 10 9 -1.2 0.0 119 | g 10 10 -3.6 0.0 120 | h 10 10 -8.7 0.0 121 | g 11 0 3.1 0.0 122 | g 11 1 -1.5 0.0 123 | h 11 1 -0.1 0.0 124 | g 11 2 -2.3 0.0 125 | h 11 2 2.0 0.0 126 | g 11 3 2.0 0.0 127 | h 11 3 -0.7 0.0 128 | g 11 4 -0.8 0.0 129 | h 11 4 -1.1 0.0 130 | g 11 5 0.6 0.0 131 | h 11 5 0.8 0.0 132 | g 11 6 -0.7 0.0 133 | h 11 6 -0.2 0.0 134 | g 11 7 0.2 0.0 135 | h 11 7 -2.2 0.0 136 | g 11 8 1.7 0.0 137 | h 11 8 -1.4 0.0 138 | g 11 9 -0.2 0.0 139 | h 11 9 -2.5 0.0 140 | g 11 10 0.4 0.0 141 | h 11 10 -2.0 0.0 142 | g 11 11 3.5 0.0 143 | h 11 11 -2.4 0.0 144 | g 12 0 -1.9 0.0 145 | g 12 1 -0.2 0.0 146 | h 12 1 -1.1 0.0 147 | g 12 2 0.4 0.0 148 | h 12 2 0.4 0.0 149 | g 12 3 1.2 0.0 150 | h 12 3 1.9 0.0 151 | g 12 4 -0.8 0.0 152 | h 12 4 -2.2 0.0 153 | g 12 5 0.9 0.0 154 | h 12 5 0.3 0.0 155 | g 12 6 0.1 0.0 156 | h 12 6 0.7 0.0 157 | g 12 7 0.5 0.0 158 | h 12 7 -0.1 0.0 159 | g 12 8 -0.3 0.0 160 | h 12 8 0.3 0.0 161 | g 12 9 -0.4 0.0 162 | h 12 9 0.2 0.0 163 | g 12 10 0.2 0.0 164 | h 12 10 -0.9 0.0 165 | g 12 11 -0.9 0.0 166 | h 12 11 -0.1 0.0 167 | g 12 12 0.0 0.0 168 | h 12 12 0.7 0.0 169 | g 13 0 0.0 0.0 170 | g 13 1 -0.9 0.0 171 | h 13 1 -0.9 0.0 172 | g 13 2 0.4 0.0 173 | h 13 2 0.4 0.0 174 | g 13 3 0.5 0.0 175 | h 13 3 1.6 0.0 176 | g 13 4 -0.5 0.0 177 | h 13 4 -0.5 0.0 178 | g 13 5 1.0 0.0 179 | h 13 5 -1.2 0.0 180 | g 13 6 -0.2 0.0 181 | h 13 6 -0.1 0.0 182 | g 13 7 0.8 0.0 183 | h 13 7 0.4 0.0 184 | g 13 8 -0.1 0.0 185 | h 13 8 -0.1 0.0 186 | g 13 9 0.3 0.0 187 | h 13 9 0.4 0.0 188 | g 13 10 0.1 0.0 189 | h 13 10 0.5 0.0 190 | g 13 11 0.5 0.0 191 | h 13 11 -0.3 0.0 192 | g 13 12 -0.4 0.0 193 | h 13 12 -0.4 0.0 194 | g 13 13 -0.3 0.0 195 | h 13 13 -0.8 0.0 196 | -------------------------------------------------------------------------------- /IGRF_Model.asv: -------------------------------------------------------------------------------- 1 | function [Br,Bt,Bp] = IGRF_Model(r,theta,phi,days) 2 | % Output is Spherical ECEF 3 | % Inputs r Geocentric radius 4 | % theta Latitude measured in degrees positive from equator 5 | % phi Longitude measured in degrees positive east from Greenwich 6 | % days Decimal days since January 1, 2015 7 | % Outputs - magnetic field strength in local tangential coordinates 8 | % Br B in radial direction 9 | % Bt B in theta direction 10 | % Bp B in phi direction 11 | % Checks to see if located at either pole to avoid singularities 12 | if (theta>-0.00000001 & theta<0.00000001) 13 | theta=0.00000001; 14 | elseif(theta<180.00000001 & theta>179.99999999) 15 | theta=179.99999999; 16 | end 17 | 18 | % The angles must be converted from degrees into radians 19 | theta=(90-theta)*pi/180; 20 | phi = phi*pi/180; 21 | 22 | a=6371.2; % Reference radius used in IGRF 23 | 24 | % This section of the code simply reads in the g and h Schmidt 25 | % quasi-normalized coefficients 26 | [gn, gm, gvali, gsvi] = textread('igrfSg2015.txt','%f %f %f %f'); 27 | [hn, hm, hvali, hsvi] = textread('igrfSh2015.txt','%f %f %f %f'); 28 | N=max(gn); 29 | g=zeros(N,N+1); 30 | h=zeros(N,N+1); 31 | for x=1:length(gn) 32 | g(gn(x),gm(x)+1) = gvali(x) + gsvi(x)*days/365; 33 | h(hn(x),hm(x)+1) = hvali(x) + hsvi(x)*days/365; 34 | end 35 | 36 | % Initialize each of the variables 37 | % Br B in the radial driection 38 | % Bt B in the theta direction 39 | % Bp B in the phi direction 40 | % P The associated Legendre polynomial evaluated at cos(theta) 41 | % The nomenclature for the recursive values generally follows 42 | % the form P10 = P(n-1,m-0) 43 | % dP The partial derivative of P with respect to theta 44 | 45 | Br=0; Bt=0; Bp=0; 46 | P11=1; P10=P11; 47 | dP11=0; dP10=dP11; 48 | 49 | for m=0:N 50 | for n=1:N 51 | if m<=n 52 | % Calculate Legendre polynomials and derivatives recursively 53 | if n==m 54 | P2 = sin(theta)*P11; 55 | dP2 = sin(theta)*dP11 + cos(theta)*P11; 56 | P11=P2; P10=P11; P20=0; 57 | dP11=dP2; dP10=dP11; dP20=0; 58 | elseif n==1 59 | P2 = cos(theta)*P10; 60 | dP2 = cos(theta)*dP10 - sin(theta)*P10; 61 | P20=P10; P10=P2; 62 | dP20=dP10; dP10=dP2; 63 | else 64 | K = ((n-1)^2-m^2)/((2*n-1)*(2*n-3)); 65 | P2 = cos(theta)*P10 - K*P20; 66 | dP2 = cos(theta)*dP10 - sin(theta)*P10 - K*dP20; 67 | P20=P10; P10=P2; 68 | dP20=dP10; dP10=dP2; 69 | end 70 | 71 | % Calculate Br, Bt, and Bp 72 | Br = Br + (a/r)^(n+2)*(n+1)*... 73 | ((g(n,m+1)*cos(m*phi) + h(n,m+1)*sin(m*phi))*P2); 74 | Bt = Bt + (a/r)^(n+2)*... 75 | ((g(n,m+1)*cos(m*phi) + h(n,m+1)*sin(m*phi))*dP2); 76 | Bp = Bp + (a/r)^(n+2)*... 77 | (m*(-g(n,m+1)*sin(m*phi) + h(n,m+1)*cos(m*phi))* P2); 78 | end 79 | end 80 | end 81 | end 82 | 83 | -------------------------------------------------------------------------------- /IGRF_Model.m: -------------------------------------------------------------------------------- 1 | function [Br,Bt,Bp] = IGRF_Model(r,theta,phi,days) 2 | % Output is Spherical ECEF 3 | % Inputs r Geocentric radius 4 | % theta Latitude measured in degrees positive from equator 5 | % phi Longitude measured in degrees positive east from Greenwich 6 | % days Decimal days since January 1, 2015 7 | % Outputs - magnetic field strength in local tangential coordinates 8 | % Br B in radial direction 9 | % Bt B in theta direction 10 | % Bp B in phi direction 11 | % Checks to see if located at either pole to avoid singularities 12 | if (theta>-0.00000001 & theta<0.00000001) 13 | theta=0.00000001; 14 | elseif(theta<180.00000001 & theta>179.99999999) 15 | theta=179.99999999; 16 | end 17 | 18 | % The angles must be converted from degrees into radians 19 | theta=(90-theta)*pi/180; 20 | phi = phi*pi/180; 21 | 22 | a=6371.2; % Reference radius used in IGRF 23 | 24 | % This section of the code simply reads in the g and h Schmidt 25 | % quasi-normalized coefficients 26 | [gn, gm, gvali, gsvi] = textread('igrfSg2015.txt','%f %f %f %f'); 27 | [hn, hm, hvali, hsvi] = textread('igrfSh2015.txt','%f %f %f %f'); 28 | N=max(gn); 29 | g=zeros(N,N+1); 30 | h=zeros(N,N+1); 31 | for x=1:length(gn) 32 | g(gn(x),gm(x)+1) = gvali(x) + gsvi(x)*days/365; 33 | h(hn(x),hm(x)+1) = hvali(x) + hsvi(x)*days/365; 34 | end 35 | 36 | % Initialize each of the variables 37 | % Br B in the radial driection 38 | % Bt B in the theta direction 39 | % Bp B in the phi direction 40 | % P The associated Legendre polynomial evaluated at cos(theta) 41 | % The nomenclature for the recursive values generally follows 42 | % the form P10 = P(n-1,m-0) 43 | % dP The partial derivative of P with respect to theta 44 | 45 | Br=0; Bt=0; Bp=0; 46 | P11=1; P10=P11; 47 | dP11=0; dP10=dP11; 48 | 49 | for m=0:N 50 | for n=1:N 51 | if m<=n 52 | % Calculate Legendre polynomials and derivatives recursively 53 | if n==m 54 | P2 = sin(theta)*P11; 55 | dP2 = sin(theta)*dP11 + cos(theta)*P11; 56 | P11=P2; P10=P11; P20=0; 57 | dP11=dP2; dP10=dP11; dP20=0; 58 | elseif n==1 59 | P2 = cos(theta)*P10; 60 | dP2 = cos(theta)*dP10 - sin(theta)*P10; 61 | P20=P10; P10=P2; 62 | dP20=dP10; dP10=dP2; 63 | else 64 | K = ((n-1)^2-m^2)/((2*n-1)*(2*n-3)); 65 | P2 = cos(theta)*P10 - K*P20; 66 | dP2 = cos(theta)*dP10 - sin(theta)*P10 - K*dP20; 67 | P20=P10; P10=P2; 68 | dP20=dP10; dP10=dP2; 69 | end 70 | 71 | % Calculate Br, Bt, and Bp 72 | Br = Br + (a/r)^(n+2)*(n+1)*... 73 | ((g(n,m+1)*cos(m*phi) + h(n,m+1)*sin(m*phi))*P2); 74 | Bt = Bt + (a/r)^(n+2)*... 75 | ((g(n,m+1)*cos(m*phi) + h(n,m+1)*sin(m*phi))*dP2); 76 | Bp = Bp + (a/r)^(n+2)*... 77 | (m*(-g(n,m+1)*sin(m*phi) + h(n,m+1)*cos(m*phi))* P2); 78 | end 79 | end 80 | end 81 | end 82 | 83 | -------------------------------------------------------------------------------- /IniConfig.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/IniConfig.m -------------------------------------------------------------------------------- /Model_Executor.m: -------------------------------------------------------------------------------- 1 | function [ Results ] = Model_Executor(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits, Magnetic_Moment, Spacecraft_Config) 2 | %Main Operation with GUI Inputs 3 | % Output Format: [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z, Earth_B_x_ECEF, Earth_B_y_ECEF, Earth_B_z_ECEF, Cubesat_Orientation_x, Cubesat_Orientation_y, Cubesat_Orientation_z, Cubesat_Rotational_Velocity_x, Cubesat_Rotational_Velocity_y, Cubesat_Rotational_Velocity_z, Magnet_moment_x, Magnet_moment_y, Magnet_moment_z, Sun_x_ECI, Sun_y_ECI, Sun_z_ECI, Sun_x_ECEF, Sun_y_ECEF, Sun_z_ECEF] 4 | % 5 | %% Orbital Propagation Model - Harrison Handley 6 | % Orbit Propagation - Defines Result_Matrix as 7 | % [True_Anomaly, Altitude, Orbital_Number, Time_since_launch, CM_ECI_x, CM_ECI_y, CM_ECI_z, CM_ECEF_x, CM_ECEF_y, CM_ECEF_z] 8 | Results = Orbital_Model_Function(Launch_Time, Orbital_Eccentricity, Orbital_Inclination, Orbital_Semimajor_Axis, Orbital_Mesh, Orbital_RAAN, Orbital_Arg_of_Perigee, Orbital_Num_of_Orbits); 9 | Results = vertcat(Results, zeros(1, 10)); 10 | %% Magnetic Field Model - Harrison Handley 11 | % Earth Magnetic Field Model 12 | % Add to Results three vectors for Earths magnetic field x, y and z components in ECEF for that rows satellite CM ECEF position 13 | Results = horzcat(Results, zeros(size(Results, 1), 19 )); 14 | Results(:, 20) = Magnetic_Moment(1); 15 | Results(:, 21) = Magnetic_Moment(2); 16 | Results(:, 22) = Magnetic_Moment(3); 17 | 18 | % Find magnetic field of earth at each position in Teslas 19 | for row = 1:(size(Results, 1) - 1) 20 | % r = vector length of xyz 21 | % theta Latitude measured in degrees positive from equator 22 | % phi Longitude measured in degrees positive east from Greenwich 23 | % days Decimal days since January 1, 2015 24 | r = sqrt(Results(row,8)^2 + Results(row,9)^2 + Results(row,10)^2); 25 | theta = acosd(sqrt(Results(row,8)^2 + Results(row,9)^2)/r); 26 | phi = atand(Results(row,9)/Results(row,8)); 27 | Days_since_Jan_1st_2015 = daysact('1-Jan-2015 00:00:00', (Launch_Time + seconds(Results(row, 4)))); 28 | [Br ,Bt, Bp] = IGRF_Model(r, theta, phi,Days_since_Jan_1st_2015); 29 | [Bx, By, Bz] = sph2cart(Bp, Bt, Br); 30 | Results(row, 11) = Bx; 31 | Results(row, 12) = By; 32 | Results(row, 13) = Bz; 33 | 34 | 35 | Dynamics_Outputs = DynamicsFunctionPassive( Results(row+1, 4) - Results(row, 4), Results(row , 11), Results(row , 12), Results(row , 13), Results(row , 14), Results(row , 15), Results(row , 16), Results(row, 17), Results(row, 18), Results(row, 19), Results(row, 20), Results(row, 21), Results(row, 22)); 36 | Results(row + 1, 14) = Dynamics_Outputs(1); 37 | Results(row + 1, 15) = Dynamics_Outputs(2); 38 | Results(row + 1, 16) = Dynamics_Outputs(3); 39 | Results(row + 1, 17) = Dynamics_Outputs(4); 40 | Results(row + 1, 18) = Dynamics_Outputs(5); 41 | Results(row + 1, 19) = Dynamics_Outputs(6); 42 | 43 | Sun_Position_Output = Suns_Orbit(Launch_Time, Results(row, 4)); 44 | Results(row, 23) = Sun_Position_Output(1); 45 | Results(row, 24) = Sun_Position_Output(2); 46 | Results(row, 25) = Sun_Position_Output(3); 47 | Results(row, 26) = Sun_Position_Output(4); 48 | Results(row, 27) = Sun_Position_Output(5); 49 | Results(row, 28) = Sun_Position_Output(6); 50 | 51 | Results(row, 29) = Shadow_Detection(Results(row, 23), Results(row, 24), Results(row, 25), Results(row, 5), Results(row, 6), Results(row, 7)); 52 | end 53 | 54 | %% Dynamic Model 55 | 56 | 57 | 58 | %% End of Simulation 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /Mu_body_rotate.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/Mu_body_rotate.m -------------------------------------------------------------------------------- /Mu_rotate.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SFUSatClub/Attitude-Control-Model/09b8fbe14880b2fa1c17cb580924a41f3f05917f/Mu_rotate.m -------------------------------------------------------------------------------- /Orbital_Model_Function.m: -------------------------------------------------------------------------------- 1 | function [ Output_Matrix ] = Orbital_Model_Function( Start_Datetime, eccentricity, inclination, semimajor_axis, Num_Intervals, RAAN, argument_of_perigee, num_of_orbits) 2 | 3 | % Keplerian Orbital Model 4 | % eccentricity is the eccentricity of the orbit specified by GUI 5 | % inclination is the incliation of the orbit specified by GUI 6 | % semimajor_axis is half the length of the elliptical orbit specified by 7 | % GUI in [meters] 8 | % Num_Intervals is the number of intervals one orbit is split into 9 | % RAAN is the right ascension of ascending node 10 | % argument_of_perigee is the the polar angle on the orbital plane from 11 | % RAAN to the closest point of the orbit to the earth. It is 0 for 12 | % eccentricity of 0. [Radians] 13 | % Time values are with respect to the starting time values of the orbit 14 | % Stuff 15 | 16 | Num_of_Terms_in_infinite_Series = 10; 17 | GM = 3.986005*10^14; 18 | 19 | % [Sat_True_Anomaly, Altitude, Orbit #, Time, 20 | % ECI_x, ECI_y, ECI_z, ECEF_x, ECEF_y, ECEF_z] 21 | 22 | % Orbital_Matrix = zeros(Num_Intervals, 3) + repmat(datetime, Num_Intervals, 1) + zeros(Num_Intervals, 6); 23 | Orbital_Matrix = zeros(Num_Intervals, 10 ); 24 | 25 | E = zeros(1, Num_Intervals); % Mean Anomaly 26 | 27 | % Provides the angle vector for which the orbit is divided up into when 28 | % considering the same orbit with e = 0 29 | 30 | M = linspace(0, 2*pi, Num_Intervals); % Mean Anomaly 31 | 32 | % Calculate true anomaly at each point 33 | 34 | for j = 1:Num_Intervals 35 | E(j) = M(j); 36 | for n = 1:Num_of_Terms_in_infinite_Series 37 | E(j) = E(j) + 2/n * besselj(n,n*eccentricity).*sin(n*M(j)); 38 | end 39 | end 40 | 41 | % calculate polar coordinates where theta = 0 is perigee 42 | 43 | Orbital_Matrix (:,1) = 2 .* atan(sqrt((1+eccentricity)/(1-eccentricity)) .* tan(E/2)); 44 | Orbital_Matrix (:,2) = semimajor_axis * (1-eccentricity^2)./ (1 + eccentricity.*cos(Orbital_Matrix(:,1))); 45 | Orbital_Matrix (:,3) = 1; 46 | Orbital_Matrix (:,4) = sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM)).*(M./(2*pi)); 47 | Output_Matrix = Orbital_Matrix; 48 | 49 | % Add in additional orbits 50 | 51 | for k = 2:num_of_orbits 52 | Temp_Matrix = Orbital_Matrix; 53 | Temp_Matrix (:,3) = k; 54 | Temp_Matrix (:,4) = Orbital_Matrix(:,4) + sqrt((4*(pi^2)*(semimajor_axis)^3)/(GM))* (k-1); 55 | Output_Matrix = vertcat(Output_Matrix, Temp_Matrix); 56 | end 57 | 58 | % Euler Transformation Matrix 59 | 60 | B = [cos(argument_of_perigee), sin(argument_of_perigee), 0; -sin(argument_of_perigee), cos(argument_of_perigee), 0; 0, 0, 1]; 61 | C = [1, 0, 0; 0, cos(inclination), sin(inclination); 0, -sin(inclination), cos(inclination)]; 62 | D = [cos(RAAN), sin(RAAN), 0; -sin(RAAN), cos(RAAN), 0; 0, 0, 1]; 63 | Euler_Transformation_Matrix = B*C*D; 64 | 65 | % ECI Coordinates 66 | 67 | for k = 1:length(Output_Matrix) 68 | Temp_Array = [Output_Matrix(k,2).*cos(Output_Matrix(k,1)), Output_Matrix(k,2).*sin(Output_Matrix(k,1)), 0]*Euler_Transformation_Matrix; 69 | Output_Matrix(k, 5) = Temp_Array(1); 70 | Output_Matrix(k, 6) = Temp_Array(2); 71 | Output_Matrix(k, 7) = Temp_Array(3); 72 | end 73 | 74 | % ECI to ECEF Coordinates 75 | 76 | for k = 1:length(Output_Matrix) 77 | Temp_Date = Start_Datetime + seconds(Output_Matrix(k, 4)); 78 | Date_Array = [year(Temp_Date), month(Temp_Date), day(Temp_Date), hour(Temp_Date), minute(Temp_Date), second(Temp_Date)]; 79 | %ECI2ECEF_Matrix = dcmeci2ecef('IAU-2000/2006', Date_Array); 80 | %Temp_Array = [Output_Matrix(k,5), Output_Matrix(k,6), Output_Matrix(k,7)]*ECI2ECEF_Matrix; 81 | Output_Matrix(k, 8) = Temp_Array(1); 82 | Output_Matrix(k, 9) = Temp_Array(2); 83 | Output_Matrix(k, 10) = Temp_Array(3); 84 | end 85 | Output_Matrix; 86 | end 87 | 88 | -------------------------------------------------------------------------------- /Passive_Magnetic_Dynamics_Simulation.m: -------------------------------------------------------------------------------- 1 | %definitions 2 | % 3 | % theta_1 = euler angle 1 4 | % theta_2 = euler angle 2 5 | % theta_3 = euler angle 3 6 | 7 | % theta_dot_1 = euler angle rate of change 1 8 | % theta_dot_2 = euler angle rate of change 2 9 | % theta_dot_3 = euler angle rate of change 3 10 | 11 | % omega_dot_x = body fixed change in angular velocity x 12 | % omega_dot_y = body fixed change in angular velocity y 13 | % omega_dot_z = body fixed change in angular velocity z 14 | 15 | % omega_x = body fixed angular velocity x 16 | % omega_y = body fixed angular velocity y 17 | % omega_z = body fixed angular velocity z 18 | 19 | % Ixx = Cubesat inertia x 20 | % Iyy = Cubesat inertia y 21 | % Izz = Cubesat inertia x 22 | 23 | % Equations of Motion 24 | 25 | %[theta_dot_1; theta_dot_2; theta_dot_3] = (1/cos(theta_2))*[ 0, sin(theta_3), cos(theta_3) 26 | % 0, cos(theta_3)*cos(theta_2), -sin(theta_3)*cos(theta_2) 27 | % cos(theta_2), sin(theta_3)*sin(theta_2), cos(theta_3)*sin(theta_2) ] * (omega_x; omega_y; omega_z); 28 | 29 | % Ixx*omega_dot_x = -(Izz-Iyy)*omega_y*omega_z + Lz; 30 | % Iyy*omega_dot_y = -(Ixx-Izz)*omega_z*omega_x + Ly; 31 | % Izz*omega_dot_z = -(Ixx-Izz)*omega_z*omega_x + Ly; 32 | 33 | % DCM 34 | 35 | % [ cos(theta_2)*cos(theta_1), cos(theta_2)*sin(theta_1), -sin(theta_2) 36 | % (sin(theta_3)*sin(theta_2)*cos(theta_1)-cos(theta_3)*sin(theta_1)), ((sin(theta_3)*sin(theta_2)*sin(theta_1))+cos((theta_3)*cos(theta_1))), sin(theta_3)*cos(theta_2) 37 | % ((cos(theta_3)*sin(theta_2)*cos(theta_1))+(sin(theta_3)*sin(theta_1))), ((cos(theta_3)*sin(theta_2)*sin(theta_1))-sin(theta_3)*cos(theta_1)), (cos(theta_3)*cos(theta_2))]; 38 | 39 | % H1 = 3*Heq*sin(i)*cos(i)*sin^2(u); 40 | % H2 = -3*Heq*sin(i)*sin(u)*cos(u); 41 | % H3 = Heq(1-(3*sin(i)^2*sin(u)^2)); -------------------------------------------------------------------------------- /Permanent_Magnet.m: -------------------------------------------------------------------------------- 1 | % Permanent magnet design 2 | % Variable Initializations 3 | A=0; % Aerodynamic drag torque (Nm) 4 | G=0; % Gravity gradient torque (Nm) 5 | R=0; % Radiometric torque (Nm) 6 | T_rms=0; % Root mean squared sum of the external perturbation torques (Nm) 7 | m_mag=0; % Bar magnetic flux density (A*m^2) 8 | beta_max=0; % Desired pointing accuracy (degrees) 9 | B_min=0; % Minimum flux density at 600km (Tesla or Webber/m^2 OR Nm/A) 10 | eta=0; % Related to resonance frequencies we want to avoid 11 | eta_prl=0; % Related to resonance frequencies we want to avoid 12 | m_res_old=0; % Parametric resonance flux density (A*m^2) 13 | m_res_new=0; % Parametric resonance flux density (A*m^2) 14 | m_res_prl_old=0; % Parametric resonance flux density (A*m^2) 15 | m_res_prl_new=0; % Parametric resonance flux density (A*m^2) 16 | no=0; % Orbit mean motion (angular speed required to stay in orbit) 17 | B_eq=0; % Magnetic flux density at the equator (Tesla or Webber/m^2 OR Nm/A) 18 | Ixx=0; % Major axis moment of inertia (kg*m^2) 19 | Iyy=0; % Major axis moment of inertia (kg*m^2) 20 | Izz=0; % Minor axis moment of inertia (kg*m^2) 21 | 22 | % STEP 1 - Calculate the appropriate flux density for the magnet 23 | 24 | A = 8*(10^-8); 25 | G = 6*(10^-8); 26 | R = 1*(10^-8); 27 | T_rms = sqrt((A^2)+(G^2)+(R^2)); 28 | B_min = 2.0*10^-5; 29 | beta_max = 15; 30 | 31 | m_mag=(10*T_rms)/(B_min*sin(beta_max)); 32 | 33 | % STEP 2 - Re-adjust the magnets flux density to account for the 34 | % parametric resonances you want to avoid for polar orbits 35 | 36 | B_eq = 2.3*10^-5; 37 | 38 | for k=1:50 39 | eta = (2.63*(k^2))-0.49+(0.51*(Izz/Iyy)); 40 | eta_prl = (2.63*(k^2))-0.49+0.51*(Izz/Ixx); 41 | m_res_new = (Iyy*(no^2)*eta)/B_eq; 42 | m_res_prl_new = (Iyy*(no^2)*eta_prl)/B_eq; 43 | if(m_mag < m_res_new) 44 | m_mag = (m_res_new+m_res_old)/2; 45 | break; 46 | end 47 | if(m_mag < m_res_prl_new) 48 | m_mag = (m_res_prl_new+m_res_prl_old)/2; 49 | break; 50 | end 51 | m_res_new = m_res_old; 52 | m_res_prl_new = m_res_prl_old; 53 | end 54 | 55 | % output m_mag 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Configuration File 2 | All model configuration can be defined in an .ini file. [Model] and [Orbit] sections are required. Additional section can be added for defining spacecraft properties, mission properties, etc. The path to the configuration file is passed to the Model_Executor. Properties can be assed by: 3 | ''' 4 | ini = IniConfig(); 5 | ini.ReadFile(Spacecraft_Config); 6 | ini.GetValues(Section Name, Key Name) 7 | ''' 8 | and the config file has the format: 9 | ''' 10 | [Section Name] 11 | Key Name = value 12 | Key Name = value 13 | 14 | [Section Name] 15 | Key Name = value 16 | ''' 17 | . -------------------------------------------------------------------------------- /Shadow_Detection.m: -------------------------------------------------------------------------------- 1 | function [ In_Shadow_Bool ] = Shadow_Detection( Sun_ECI_x, Sun_ECI_y, Sun_ECI_z, Sat_ECI_x, Sat_ECI_y, Sat_ECI_z ) 2 | %UNTITLED Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | % Earths radius is 6371.2km 6 | 7 | % Default value is the satellite has direct line of sight with the sun 8 | In_Shadow_Bool = 0; 9 | 10 | % Determine the vector for the sun to earth, sat to earth and sun to sat 11 | Sun_to_Earth_Vector = [Sun_ECI_x; Sun_ECI_y; Sun_ECI_z]; 12 | Sat_to_Earth_Vector = [Sat_ECI_x; Sat_ECI_y; Sat_ECI_z]; 13 | Sun_to_Sat_Vector = Sun_to_Earth_Vector + Sat_to_Earth_Vector; 14 | 15 | Sun_to_Earth_Edge_Angle = atan(6371200/norm(Sun_to_Earth_Vector)); 16 | Sun_to_Sat_Angle = acos(norm(Sun_to_Sat_Vector)/norm(Sun_to_Earth_Vector)); 17 | 18 | if Sun_to_Sat_Angle < Sun_to_Earth_Edge_Angle 19 | if norm(Sun_to_Sat_Vector) > norm(Sun_to_Earth_Vector) 20 | In_Shadow_Bool = 1; 21 | end 22 | end 23 | 24 | -------------------------------------------------------------------------------- /Suns_Orbit.m: -------------------------------------------------------------------------------- 1 | function [ Sun_Position ] = Suns_Orbit( Launch_Time, Time_After_Launch ) 2 | 3 | % Satellite: SUN 4 | % Catalog: 0 5 | % Epoch Time: 15001.00000000000 (year 2015, day 1.00000) 6 | % Inclination: 23.4406 deg (Earth's axis tilted 23 deg from ecliptic) 7 | % RA of Node: 0.0000 deg (definition of Right Ascension) 8 | % Eccentricity: 0.0167133 9 | % Arg of Perigee: 282.7685 deg (perihelion in early January) 10 | % Mean Anomaly: 357.6205 deg (The Earth is quite close to perihelion on Jan 1) 11 | % Mean Motion: 0.002737778522 Rev/day (one revolution per year) 12 | % Decay rate: 0.00000 Rev/day^2 13 | % Epoch rev: 2017 (orbit number equals the year) 14 | % Semimajor Axis: 149597870 km 15 | 16 | Inclination = 23.4406*pi/180; 17 | RAAN = 0; 18 | Eccentricity = 0.0167133; 19 | Arg_of_Perigee = (282.7685*pi/180); 20 | Mean_Anomaly = (357.6205*pi/180); 21 | Semimajor_Axis = 149597870*1000; 22 | 23 | Num_of_Terms_in_infinite_Series = 10; 24 | GM = 3.986005*10^14; 25 | 26 | % [ECI_x, ECI_y, ECI_z, ECEF_x, ECEF_y, ECEF_z] 27 | Sun_Position = zeros(1, 6); 28 | Total_Time = Launch_Time + second(Time_After_Launch); 29 | Time_Since_Perigee = second(Total_Time - year(Total_Time)); 30 | Orbital_Period = 365*24*3600; 31 | 32 | M = 2*pi*(Time_Since_Perigee/Orbital_Period); % Mean Anomaly 33 | 34 | % Calculate true anomaly at each point 35 | E = M; 36 | for n = 1:Num_of_Terms_in_infinite_Series 37 | E = E + 2/n * besselj(n,n*Eccentricity).*sin(n*M); 38 | end 39 | 40 | % calculate polar coordinates where theta = 0 is perigee 41 | Sun_Position_True_Anomaly = 2 .* atan(sqrt((1+Eccentricity)/(1-Eccentricity)) .* tan(E/2)); 42 | Sun_Position_Altitude = Semimajor_Axis * (1-Eccentricity^2)./ (1 + Eccentricity.*cos(Sun_Position_True_Anomaly)); 43 | 44 | 45 | % Euler Transformation Matrix 46 | B = [cos(Arg_of_Perigee), sin(Arg_of_Perigee), 0; -sin(Arg_of_Perigee), cos(Arg_of_Perigee), 0; 0, 0, 1]; 47 | C = [1, 0, 0; 0, cos(Inclination), sin(Inclination); 0, -sin(Inclination), cos(Inclination)]; 48 | D = [cos(RAAN), sin(RAAN), 0; -sin(RAAN), cos(RAAN), 0; 0, 0, 1]; 49 | Euler_Transformation_Matrix = B*C*D; 50 | 51 | % ECI Coordinates 52 | Temp_Array = [Sun_Position_Altitude.*cos(Sun_Position_True_Anomaly), Sun_Position_Altitude.*sin(Sun_Position_True_Anomaly), 0]*Euler_Transformation_Matrix; 53 | Sun_Position(1) = Temp_Array(1); 54 | Sun_Position(2) = Temp_Array(2); 55 | Sun_Position(3) = Temp_Array(3); 56 | 57 | % ECI to ECEF Coordinates 58 | Data_Array = [year(Total_Time), month(Total_Time), day(Total_Time), hour(Total_Time), minute(Total_Time), second(Total_Time)]; 59 | ECI2ECEF_Matrix = dcmeci2ecef('IAU-2000/2006', Data_Array); 60 | Temp_Array = [Sun_Position(1), Sun_Position(2), Sun_Position(3)]*ECI2ECEF_Matrix; 61 | Sun_Position(4) = Temp_Array(1); 62 | Sun_Position(5) = Temp_Array(2); 63 | Sun_Position(6) = Temp_Array(3); 64 | 65 | end 66 | 67 | -------------------------------------------------------------------------------- /igrfSg2015.txt: -------------------------------------------------------------------------------- 1 | 1 0 -29442 10.3 2 | 1 1 -1501 18.1 3 | 2 0 -3667.6 -13.05 4 | 2 1 5218.5 -5.7158 5 | 2 2 1452.1 1.8187 6 | 3 0 3376.8 8.5 7 | 3 1 -7202.4 -16.84 8 | 3 2 2373.4 -1.3555 9 | 3 3 460.11 -7.9848 10 | 4 0 3970.8 -3.0625 11 | 4 1 4503 1.1068 12 | 4 2 471.14 -35.609 13 | 4 3 -700.49 8.5758 14 | 4 4 52.062 -3.1799 15 | 5 0 -1831.7 -1.575 16 | 5 1 3661 5.0833 17 | 5 2 1478.6 -9.9908 18 | 5 3 -663.11 -0.47062 19 | 5 4 -349.42 3.1059 20 | 5 5 2.8764 2.7361 21 | 6 0 1010.6 -4.3312 22 | 6 1 1279.7 -1.8903 23 | 6 2 1086.4 -10.461 24 | 6 3 -1294.2 20.922 25 | 6 4 -157.7 -6.5482 26 | 6 5 30.714 0.69804 27 | 6 6 -47.623 1.0747 28 | 7 0 2187.9 8.0437 29 | 7 1 -2699.2 -7.0939 30 | 7 2 -196.93 -14.48 31 | 7 3 1060.8 26.622 32 | 7 4 185.23 1.2349 33 | 7 5 58.04 -3.7047 34 | 7 6 -6.7811 -1.9375 35 | 7 7 4.4014 0.12945 36 | 8 0 1216.6 10.055 37 | 8 1 589.88 0 38 | 8 2 -947.79 -33.649 39 | 8 3 -132.54 20.71 40 | 8 4 -550.77 -5.3472 41 | 8 5 198.73 5.9322 42 | 8 6 80.323 0.68652 43 | 8 7 -39.859 -1.0027 44 | 8 8 -1.2534 0.18801 45 | 9 0 512.79 0 46 | 9 1 1121.2 0 47 | 9 2 336.82 0 48 | 9 3 -273.84 0 49 | 9 4 39.463 0 50 | 9 5 -448.09 0 51 | 9 6 -1.7398 0 52 | 9 7 65.542 0 53 | 9 8 -23.514 0 54 | 9 9 -6.395 0 55 | 10 0 -342.81 0 56 | 10 1 -1532.7 0 57 | 10 2 21.069 0 58 | 10 3 82.64 0 59 | 10 4 -58.435 0 60 | 10 5 133.05 0 61 | 10 6 -28.924 0 62 | 10 7 42.091 0 63 | 10 8 19.638 0 64 | 10 9 -4.7786 0 65 | 10 10 -2.1371 0 66 | 11 0 1067.8 0 67 | 11 1 -699.58 0 68 | 11 2 -940.81 0 69 | 11 3 655.94 0 70 | 11 4 -191.61 0 71 | 11 5 95.054 0 72 | 11 6 -65.882 0 73 | 11 7 9.9209 0 74 | 11 8 38.692 0 75 | 11 9 -1.763 0 76 | 11 10 1.0881 0 77 | 11 11 2.0299 0 78 | 12 0 -1254.4 0 79 | 12 1 -179.41 0 80 | 12 2 318.05 0 81 | 12 3 779.06 0 82 | 12 4 -389.53 0 83 | 12 5 300.62 0 84 | 12 6 20.83 0 85 | 12 7 58.527 0 86 | 12 8 -17.558 0 87 | 12 9 -10.217 0 88 | 12 10 1.8865 0 89 | 12 11 -2.5033 0 90 | 12 12 0 0 91 | 13 0 0 0 92 | 13 1 -1557.2 0 93 | 13 2 619.01 0 94 | 13 3 641.57 0 95 | 13 4 -492.06 0 96 | 13 5 695.88 0 97 | 13 6 -90.309 0 98 | 13 7 213.71 0 99 | 13 8 -14.279 0 100 | 13 9 20.422 0 101 | 13 10 2.8388 0 102 | 13 11 5.0184 0 103 | 13 12 -1.1355 0 104 | 13 13 -0.16702 0 105 | -------------------------------------------------------------------------------- /igrfSh2015.txt: -------------------------------------------------------------------------------- 1 | 1 0 0 0 2 | 1 1 4797.1 -26.6 3 | 2 0 0 0 4 | 2 1 -4928.7 -47.458 5 | 2 2 -555.9 -12.211 6 | 3 0 0 0 7 | 3 1 -353.03 25.107 8 | 3 2 474.25 -0.7746 9 | 3 3 -425.64 1.423 10 | 4 0 0 0 11 | 4 1 1567.8 -7.1942 12 | 4 2 -738.41 20.74 13 | 4 3 378.38 6.0658 14 | 4 4 -243.67 -3.8455 15 | 5 0 0 0 16 | 5 1 480.88 6.0999 17 | 5 2 1514 13.065 18 | 5 3 -561.45 -5.6475 19 | 5 4 35.496 7.543 20 | 5 5 70.296 0 21 | 6 0 0 0 22 | 6 1 -393.18 0 23 | 6 2 496.15 -31.383 24 | 6 3 586.81 -6.974 25 | 6 4 -363.97 1.0914 26 | 6 5 16.986 2.0941 27 | 6 6 42.048 0.67169 28 | 7 0 0 0 29 | 7 1 -1918.9 28.376 30 | 7 2 -564.74 11.584 31 | 7 3 116.73 -4.0957 32 | 7 4 301.31 -3.7047 33 | 7 5 20.993 -3.7047 34 | 7 6 -66.358 0.24218 35 | 7 7 -1.424 -0.12945 36 | 8 0 0 0 37 | 8 1 677.02 -20.109 38 | 8 2 -1026.3 16.825 39 | 8 3 550.88 4.142 40 | 8 4 -390.35 13.368 41 | 8 5 240.26 -2.9661 42 | 8 6 39.132 -2.0596 43 | 8 7 -22.812 0.75205 44 | 8 8 1.3161 0 45 | 9 0 0 0 46 | 9 1 -2751.9 0 47 | 9 2 1173.4 0 48 | 9 3 979.2 0 49 | 9 4 -383.36 0 50 | 9 5 -232.47 0 51 | 9 6 135.7 0 52 | 9 7 7.5335 0 53 | 9 8 -10.336 0 54 | 9 9 5.116 0 55 | 10 0 0 0 56 | 10 1 778.52 0 57 | 10 2 -84.277 0 58 | 10 3 760.29 0 59 | 10 4 514.23 0 60 | 10 5 -583.93 0 61 | 10 6 -24.792 0 62 | 10 7 -84.181 0 63 | 10 8 -22.911 0 64 | 10 9 -3.1857 0 65 | 10 10 -5.1646 0 66 | 11 0 0 0 67 | 11 1 -46.639 0 68 | 11 2 818.1 0 69 | 11 3 -229.58 0 70 | 11 4 -263.47 0 71 | 11 5 126.74 0 72 | 11 6 -18.824 0 73 | 11 7 -109.13 0 74 | 11 8 -31.864 0 75 | 11 9 -22.037 0 76 | 11 10 -5.4407 0 77 | 11 11 -1.392 0 78 | 12 0 0 0 79 | 12 1 -986.73 0 80 | 12 2 318.05 0 81 | 12 3 1233.5 0 82 | 12 4 -1071.2 0 83 | 12 5 100.21 0 84 | 12 6 145.81 0 85 | 12 7 -11.705 0 86 | 12 8 17.558 0 87 | 12 9 5.1087 0 88 | 12 10 -8.4892 0 89 | 12 11 -0.27815 0 90 | 12 12 0.39744 0 91 | 13 0 0 0 92 | 13 1 -1557.2 0 93 | 13 2 619.01 0 94 | 13 3 2053 0 95 | 13 4 -492.06 0 96 | 13 5 -835.05 0 97 | 13 6 -45.155 0 98 | 13 7 106.86 0 99 | 13 8 -14.279 0 100 | 13 9 27.229 0 101 | 13 10 14.194 0 102 | 13 11 -3.011 0 103 | 13 12 -1.1355 0 104 | 13 13 -0.44539 0 105 | --------------------------------------------------------------------------------