class TestHNEVector_elliptical_equatorial(): r, v, _, _ = kepler.coe2rv(10000, 0.2, 0, 0, 0, 0, constants.earth.mu) h, n, e = kepler.hne_vec(r, v, constants.earth.mu) def test_h_vec(self): np.testing.assert_allclose(self.h, np.array([0, 0, 1])) def test_n_vec(self): np.testing.assert_allclose(self.n, np.zeros(3)) def test_e_vec(self): np.testing.assert_allclose(self.e, np.array([1, 0, 0]))
def test_coe2rv_polar_circular(): """Test COE to RV for polar circular orbit around Earth""" p = 6378.137 # km ecc = 0.0 inc = np.pi/2 raan = 0.0 arg_p = 0.0 nu = 0.0 mu = 398600.5 # km^3 /sec^2 R_ijk_true = np.array([6378.137,0,0]) V_ijk_true = np.sqrt(mu/p) * np.array([0.0,0.0,1]) R_ijk, V_ijk, R_pqw, V_pqw = kepler.coe2rv(p,ecc,inc,raan,arg_p,nu, mu) np.testing.assert_array_almost_equal(R_ijk_true,R_ijk) np.testing.assert_array_almost_equal(V_ijk_true,V_ijk)
def test_coe2rv_curtis(): """Test COE to RV for Curtis example 4.3""" p_true = 80000**2/398600 ecc_true = 1.4 inc_true = np.deg2rad(30) raan_true = np.deg2rad(40) arg_p_true = np.deg2rad(60) nu_true = np.deg2rad(30) mu = 398600 # km^3 /sec^2 R_ijk_true = np.array([-4040, 4815, 3629]) V_ijk_true = np.array([-10.39, -4.772, 1.744]) R_ijk, V_ijk, R_pqw, V_pqw = kepler.coe2rv(p_true,ecc_true,inc_true,raan_true,arg_p_true,nu_true, mu) np.testing.assert_allclose(R_ijk,R_ijk_true, rtol=1e0) np.testing.assert_allclose(V_ijk,V_ijk_true, rtol=1e0)
def test_coe2rv_vallado(): """Test COE to RV for Vallado example 2-6""" p_true = 1.735272 * constants.earth.radius # km ecc_true = 0.832853 inc_true = np.deg2rad(87.87) raan_true = np.deg2rad(227.89) arg_p_true = np.deg2rad(53.38) nu_true = np.deg2rad(92.336) mu = 398600.5 # km^3 /sec^2 R_ijk_true = np.array([6525.5454,6861.7313, 6449.0585]) V_ijk_true = np.array([4.902227, 5.533085, -1.975757]) R_ijk, V_ijk, R_pqw, V_pqw = kepler.coe2rv(p_true,ecc_true,inc_true,raan_true,arg_p_true,nu_true, mu) np.testing.assert_allclose(R_ijk,R_ijk_true, rtol=1e-4) np.testing.assert_allclose(V_ijk,V_ijk_true, rtol=1e-4)
def roadster_coe(jd): """Output the COES of the roadster at the given JD """ epoch = 2458190.500000000 ecc = 2.560214125839113E-01 # eccentricy per = 9.860631722474498E-01 * au2km # periapsis inc = 1.078548455272089E+00 * deg2rad # inclination raan = 3.171871226218810E+02 * deg2rad # arg_p = 1.774087594994931E+02 * deg2rad jd_per = 2458153.531206728425 mean_motion = 6.459332187157216E-01 * deg2rad * sec2day mean_anom = 2.387937163002724E+01 * deg2rad E, nu, count = kepler.kepler_eq_E(mean_anom, ecc) nu = 4.031991175737090E+01 * deg2rad sma = 1.325391871387247E+00 * au2km apo = 1.664720570527044E+00 * au2km period = 5.573331570030891E+02 * day2sec # compute some other elements p = kepler.semilatus_rectum(sma, ecc) deltat = (jd - epoch) * day2sec # propogate from epoch to JD and find nu Ef, Mf, nuf = kepler.tof_delta_t(p, ecc, constants.sun.mu, nu, deltat) roadster_coe = planets.COE(p=p, ecc=ecc, inc=inc, raan=raan, argp=arg_p, nu=nuf) # compute the vector in J2000 Ecliptic frame r_ecliptic, v_ecliptic, r_pqw, v_pqw = kepler.coe2rv( p, ecc, inc, raan, arg_p, nuf, constants.sun.mu) return roadster_coe, r_ecliptic, v_ecliptic
# initial orbit parameters a_1 =6*re2km ecc_1 = .5 nu_0 = 0 p_1 = a_1*(1-ecc_1**2) # desired orbit altitude - location of manuever r_1 = 7.6*re2km # find intersection of original orbit and desired orbit - true anomaly nu_1 = kepler.nu_solve(p_1, ecc_1, r_1) # conditions of orbit just prior to burn print('Initial Orbit prior to manuever') kepler.orbit_el(p_1, ecc_1, 0, 0, 0, nu_1[0], mu, 'True') _,_, r1_pqw, v1_pqw= kepler.coe2rv(p_1, ecc_1, 0, 0, 0, nu_1[0], mu) fpa1 = kepler.fpa_solve(nu_1[0], ecc_1) # properties of desired orbit at manuever point r_2 = r_1 ecc_2 = 0 _,_, r2_pqw, v2_pqw= kepler.coe2rv(r_2, ecc_2, 0, 0, 0, nu_1[0], mu) delta_v, alpha, beta = manuever.delta_v_solve_planar(np.linalg.norm(v1_pqw), np.linalg.norm(v2_pqw), fpa1, 0) print('Delta V: {} km/sec'.format(delta_v)) print('Alpha: {} deg, Beta: {} deg'.format(np.rad2deg(alpha), np.rad2deg(beta))) # final orbit properties print('Final Orbit after manuever') kepler.orbit_el(r_2, ecc_2, 0, 0, 0, nu_1[0], mu, 'True')
def tle_update(self, jd_span, mu=398600.5): """Update the state of satellite given a JD time span This procedure uses the method of general perturbations to update classical elements from epoch to a future time for inclined elliptical orbits. It includes the effects due to first order secular rates (second order for mean motion) caused by drag and J2. Author: C2C Shankar Kulumani USAFA/CS-19 719-333-4741 Inputs: deltat - elapsed time since epoch (sec) n0 - mean motion at epoch (rad/sec) ndot2 - mean motion rate divided by 2 (rad/sec^2) ecc0 - eccentricity at epoch (unitless) eccdot - eccentricity rate (1/sec) raan0 - RAAN at epoch (rad) raandot - RAAN rate (rad/sec) argp0 - argument of periapsis at epoch (rad) argdot - argument of periapsis rate (rad/sec) mean0 - mean anomaly at epoch Outputs: n - mean motion at epoch + deltat (rad/sec) ecc - eccentricity at epoch + deltat (unitless) raan - RAAN at epoch + deltat (rad) argp - argument of periapsis at epoch + deltat (rad) nu - true anomaly at epoch + deltat (rad) Globals: None Constants: None Coupling: newton.m References: Astro 321 PREDICT LSN 24-25 """ deltat = (jd_span - self.epoch_jd) * day2sec # epoch orbit parameters n0 = self.n0 ecc0 = self.ecc0 ndot2 = self.ndot2 nddot6 = self.nddot6 raan0 = self.raan0 argp0 = self.argp0 mean0 = self.mean0 inc0 = self.inc0 adot = self.adot eccdot = self.eccdot raandot = self.raandot argpdot = self.argpdot _, nu0, _ = kepler.kepler_eq_E(mean0, ecc0) a0 = kepler.n2a(n0, mu) M0, E0 = kepler.nu2anom(nu0, ecc0) # propogated elements a1 = a0 + adot * deltat # either use this or compute a1 from n1 instead ecc1 = ecc0 + eccdot * deltat raan1 = raan0 + raandot * deltat argp1 = argp0 + argpdot * deltat inc1 = inc0 * np.ones_like(ecc1) n1 = n0 + ndot2 * 2 * deltat # a1 = kepler.n2a(n1, mu) p1 = kepler.semilatus_rectum(a1, ecc1) M1 = M0 + n0 * deltat+ ndot2 *deltat**2 + nddot6 *deltat**3 M1 = attitude.normalize(M1, 0, 2 * np.pi) E1, nu1, _ = kepler.kepler_eq_E(M1, ecc1) # convert to vectors r_eci, v_eci, _, _ = kepler.coe2rv(p1, ecc1, inc1, raan1, argp1, nu1, mu) # save all of the variables to the object self.jd_span = jd_span self.coe = COE(n=n1, ecc=ecc1, raan=raan1, argp=argp1, mean=M1, E=E1, nu=nu1, a=a1, p=p1, inc=inc1) self.r_eci = r_eci self.v_eci = v_eci return 0
ecc_i = .4 a_i = 6 * re2km nu_i = 90 * deg2rad p_i = kepler.semilatus_rectum(a_i, ecc_i) inc_i = 0 raan_i = 0 arg_p_i = 0 mag_dv = 0.75 alpha = -60 * deg2rad # calculate orbital elements print('Initial Orbit') kepler.orbit_el(p_i, ecc_i, inc_i, raan_i, arg_p_i, nu_i, mu, 'True') _, _, rpqw_i, vpqw_i = kepler.coe2rv(p_i, ecc_i, inc_i, raan_i, arg_p_i, nu_i, mu) fpa_i = kepler.fpa_solve(nu_i, ecc_i) # convert delta v and alpha into various reference frames (dv_vnc, dv_lvlh) = maneuver.delta_v_vnc(mag_dv, alpha, 0, fpa_i) # transform delta v to pqw frame R_lvlh2pqw = transform.dcm_lvlh2pqw(nu_i) dv_pqw = R_lvlh2pqw.dot(dv_lvlh) print('DV : {} V {} C {} N km/sec'.format(dv_vnc[0], dv_vnc[1], dv_vnc[2])) print('DV : {} R {} T {} H km/sec'.format(dv_lvlh[0], dv_lvlh[1], dv_lvlh[2])) print('DV : {} P {} Q {} W km/sec'.format(dv_pqw[0], dv_pqw[1], dv_pqw[2])) # properties of new orbit rf, vf, fpaf = maneuver.single_impulse(np.linalg.norm(rpqw_i), np.linalg.norm(vpqw_i), fpa_i, mag_dv,
def tle_update(self, jd_span, mu=398600.5): """Update the state of satellite given a JD time span This procedure uses the method of general perturbations to update classical elements from epoch to a future time for inclined elliptical orbits. It includes the effects due to first order secular rates (second order for mean motion) caused by drag and J2. Author: C2C Shankar Kulumani USAFA/CS-19 719-333-4741 Inputs: deltat - elapsed time since epoch (sec) n0 - mean motion at epoch (rad/sec) ndot2 - mean motion rate divided by 2 (rad/sec^2) ecc0 - eccentricity at epoch (unitless) eccdot - eccentricity rate (1/sec) raan0 - RAAN at epoch (rad) raandot - RAAN rate (rad/sec) argp0 - argument of periapsis at epoch (rad) argdot - argument of periapsis rate (rad/sec) mean0 - mean anomaly at epoch Outputs: n - mean motion at epoch + deltat (rad/sec) ecc - eccentricity at epoch + deltat (unitless) raan - RAAN at epoch + deltat (rad) argp - argument of periapsis at epoch + deltat (rad) nu - true anomaly at epoch + deltat (rad) Globals: None Constants: None Coupling: newton.m References: Astro 321 PREDICT LSN 24-25 """ deltat = (jd_span - self.epoch_jd) * day2sec # epoch orbit parameters n0 = self.n0 ecc0 = self.ecc0 ndot2 = self.ndot2 nddot6 = self.nddot6 raan0 = self.raan0 argp0 = self.argp0 mean0 = self.mean0 inc0 = self.inc0 adot = self.adot eccdot = self.eccdot raandot = self.raandot argpdot = self.argpdot _, nu0, _ = kepler.kepler_eq_E(mean0, ecc0) a0 = kepler.n2a(n0, mu) M0, E0 = kepler.nu2anom(nu0, ecc0) # propogated elements a1 = a0 + adot * deltat # either use this or compute a1 from n1 instead ecc1 = ecc0 + eccdot * deltat raan1 = raan0 + raandot * deltat argp1 = argp0 + argpdot * deltat inc1 = inc0 * np.ones_like(ecc1) n1 = n0 + ndot2 * 2 * deltat # a1 = kepler.n2a(n1, mu) p1 = kepler.semilatus_rectum(a1, ecc1) M1 = M0 + n0 * deltat + ndot2 * deltat**2 + nddot6 * deltat**3 M1 = attitude.normalize(M1, 0, 2 * np.pi) E1, nu1, _ = kepler.kepler_eq_E(M1, ecc1) # convert to vectors r_eci, v_eci, _, _ = kepler.coe2rv(p1, ecc1, inc1, raan1, argp1, nu1, mu) # save all of the variables to the object self.jd_span = jd_span self.coe = COE(n=n1, ecc=ecc1, raan=raan1, argp=argp1, mean=M1, E=E1, nu=nu1, a=a1, p=p1, inc=inc1) self.r_eci = r_eci self.v_eci = v_eci return 0
mu = constants.mars.mu deg2rad = constants.deg2rad rad2deg = constants.rad2deg # initial orbit elements a = 5*r_mars ecc =.5 p = kepler.semilatus_rectum(a, ecc) inc = 30*deg2rad raan = 45*deg2rad arg_p = -60*deg2rad nu = 120*deg2rad print('Initial Mars Orbit') kepler.orbit_el(p,ecc,inc,raan,arg_p,nu,mu,'True') r_inertial, v_inertial, _, _ = kepler.coe2rv(p, ecc, inc, raan, arg_p, nu, mu) fpa = kepler.fpa_solve(nu, ecc) # delta v in inertial coordinates dv_inertial = np.array([0.1,-0.25,0.2]) # form rotation matrix to go from mars inertial frame to LVLH frame dcm_mci2pqw = transform.dcm_eci2pqw_coe(raan, inc, arg_p) dcm_pqw2lvlh = transform.dcm_pqw2lvlh(nu) dv_lvlh = dcm_pqw2lvlh.dot(dcm_mci2pqw).dot(dv_inertial) print('Delta V : {} rhat {} that {} hhat km/sec'.format(dv_lvlh[0], dv_lvlh[1], dv_lvlh[2])) mag_dv = np.linalg.norm(dv_lvlh) mag_dv_outofplane = dv_lvlh[2] mag_dv_inplane = np.linalg.norm(dv_lvlh[0:1]) print('Percentage out of plane : {} %'.format(mag_dv_outofplane / mag_dv * 100))