示例#1
0
def state2ap( state, mu = pd.earth[ 'mu' ] ):
	h       = nt.norm( np.cross( state[ :3 ], state[ 3: ] ) )
	epsilon = nt.norm( state[ 3: ] ) ** 2 / 2.0 - mu / nt.norm( state[ :3 ] )
	e       = math.sqrt( 2 * epsilon * h ** 2 / mu ** 2 + 1 )
	a       = h ** 2 / mu / ( 1 - e ** 2 )
	ra      = a * ( 1 + e )
	rp      = a * ( 1 - e )
	return  ra, rp
示例#2
0
def state2period( state, mu = pd.earth['mu'] ):

	# specific mechanical energy
	epsilon = nt.norm( state[ 3:6 ] ) ** 2 / 2.0 - mu / nt.norm( state[ :3 ] )

	# semi major axis
	a = -mu / ( 2.0 * epsilon )

	# period
	return 2 * math.pi * math.sqrt( a ** 3 / mu )
示例#3
0
    def diffy_q(self, et, state):
        rx, ry, rz, vx, vy, vz = state

        r13_vec = [rx + self.mu, ry, rz]
        r23_vec = [rx - 1 + self.mu, ry, rz]
        r13_3 = nt.norm(r13_vec)**3
        r23_3 = nt.norm(r23_vec)**3
        omega_x = rx - self.one_mu * ( rx + self.mu ) / r13_3 -\
            self.mu * ( rx - 1 + self.mu ) / r23_3
        omega_y = ry - self.one_mu * ry / r13_3 - self.mu * ry / r23_3
        omega_z = -self.one_mu * rz / r13_3 - self.mu * rz / r23_3

        state_dot = np.zeros(6)
        state_dot[:3] = [vx, vy, vz]
        state_dot[3] = 2 * vy + omega_x
        state_dot[4] = -2 * vx + omega_y
        state_dot[5] = omega_z
        return state_dot
示例#4
0
 def calc_J2(self, et, state):
     z2 = state[2]**2
     norm_r = nt.norm(state[:3])
     r2 = norm_r**2
     tx = state[0] / norm_r * (5 * z2 / r2 - 1)
     ty = state[1] / norm_r * (5 * z2 / r2 - 1)
     tz = state[2] / norm_r * (5 * z2 / r2 - 3)
     return 1.5 * self.cb[ 'J2' ] * self.cb[ 'mu' ] *\
         self.cb[ 'radius' ] ** 2 \
       / r2 ** 2 * np.array( [ tx, ty, tz ] )
示例#5
0
def check_eclipse( et, r, body, frame = 'J2000', r_body = 0 ):
	r_sun2body  = spice.spkpos(
		str( body[ 'SPICE_ID' ] ), et, frame, 'LT', 'SUN' )[ 0 ]
	delta_ps    = nt.norm( r_sun2body )
	s_hat       = r_sun2body / delta_ps
	proj_scalar = np.dot( r, s_hat )

	if proj_scalar <= 0.0:
		return -1

	proj     = proj_scalar * s_hat
	rej_norm = nt.norm( r - proj )

	if r_body == 0:
		if check_umbra( delta_ps, body[ 'diameter' ], proj_scalar, rej_norm, r_body ):
			return 2
		elif check_penumbra( delta_ps, body[ 'diameter' ], proj_scalar, rej_norm, r_body ):
			return 1
		else:
			return -1
示例#6
0
def calc_vinfinity( tof, args ):

	r1_planet1 = spice.spkgps( args[ 'planet1_ID' ],
		args[ 'et0' ] + tof, args[ 'frame' ], args[ 'center_ID' ] )[ 0 ]

	v0_sc_depart, v1_sc_arrive = lt.lamberts_universal_variables(
		args[ 'state0_planet0' ][ :3 ], r1_planet1, tof,
		{ 'mu': args[ 'mu' ], 'tm': args[ 'tm' ] } )

	vinf = nt.norm( v0_sc_depart - args[ 'state0_planet0' ][ 3: ] )
	return args[ 'vinf' ] - vinf
示例#7
0
def check_solar_eclipse_latlons( et, body0, body1, frame = 'J2000' ):
	r_sun2body = spice.spkpos(
		str( body0[ 'SPICE_ID' ] ), et, frame, 'LT', 'SUN' )[ 0 ]
	r = spice.spkpos(
		str( body1[ 'SPICE_ID' ] ), et, frame, 'LT',
		str( body0[ 'SPICE_ID' ] ) )[ 0 ]

	delta_ps    = nt.norm( r_sun2body )
	s_hat       = r_sun2body / delta_ps
	proj_scalar = np.dot( r, s_hat )

	if proj_scalar <= 0.0:
		return -1, None

	proj     = proj_scalar * s_hat
	rej_norm = nt.norm( r - proj )
	umbra    = check_umbra( delta_ps, body0[ 'diameter' ],
		proj_scalar, rej_norm, body1[ 'radius' ] )

	if umbra:
		args = { 'r': r, 's_hat': s_hat, 'radius': body1[ 'radius' ] }
		try:
			sigma = nt.newton_root_single_fd( eclipse_root_func,
				proj_scalar - body1[ 'radius' ], args )[ 0 ]
		except RuntimeError:
			return -1, None

		r_eclipse = sigma * s_hat - r
		r_bf      = np.dot(
			spice.pxform( frame, body1[ 'body_fixed_frame' ], et ),
			r_eclipse )
		latlon        = np.array( spice.reclat( r_bf ) )
		latlon[ 1: ] *= nt.r2d

		return 2, latlon
	else:
		return -1, None
示例#8
0
    def propagate_orbit(self):
        print('Propagating orbit..')

        while self.solver.successful() and self.step < self.steps:
            self.solver.integrate(self.solver.t + self.config['dt'])
            self.states[self.step] = self.solver.y
            self.alts  [ self.step ] = nt.norm( self.solver.y[ :3 ] ) -\
                   self.cb[ 'radius' ]
            if self.check_stop_conditions():
                self.step += 1
            else:
                break

        self.ets = self.ets[:self.step]
        self.states = self.states[:self.step]
        self.alts = self.alts[:self.step]
示例#9
0
    def diffy_q(self, et, state):
        rx, ry, rz, vx, vy, vz, mass = state
        r = np.array([rx, ry, rz])
        v = np.array([vx, vy, vz])
        norm_r = nt.norm(r)
        mass_dot = 0.0
        state_dot = np.zeros(7)
        et += self.et0

        a = -r * self.cb['mu'] / norm_r**3

        for pert in self.orbit_perts_funcs:
            a += pert(et, state)

        state_dot[:3] = v
        state_dot[3:6] = a
        state_dot[6] = mass_dot
        return state_dot
示例#10
0
    def __init__(self, config):
        self.config = null_config()
        for key in config.keys():
            self.config[key] = config[key]

        self.orbit_perts = self.config['orbit_perts']
        self.cb = self.config['cb']

        if self.config['coes']:
            self.config['orbit_state'] = oc.coes2state(
                self.config['coes'], mu=self.config['cb']['mu'])

        if type(self.config['tspan']) == str:
            self.config[ 'tspan' ] = float( self.config[ 'tspan'] ) *\
             oc.state2period( self.config[ 'orbit_state' ], self.cb[ 'mu' ] )

        self.steps = int(np.ceil(self.config['tspan'] / self.config['dt']) + 1)
        self.step = 1

        self.ets = np.zeros((self.steps, 1))
        self.states = np.zeros((self.steps, 7))
        self.alts = np.zeros((self.steps, 1))

        self.states[0, :6] = self.config['orbit_state']
        self.states[0, 6] = self.config['mass0']
        self.alts  [ 0 ]     = nt.norm( self.states[ 0, :3 ] ) -\
               self.cb[ 'radius' ]

        self.assign_stop_condition_functions()
        self.assign_orbit_perturbations_functions()
        self.load_spice_kernels()

        if not os.path.exists(self.config['output_dir']):
            os.mkdir(self.config['output_dir'])

        self.solver = ode(self.diffy_q)
        self.solver.set_integrator(self.config['propagator'])
        self.solver.set_initial_value(self.states[0, :], 0)

        self.coes_calculated = False
        self.latlons_calculated = False

        if self.config['propagate']:
            self.propagate_orbit()
def test_penumbra_edge_cases():
	spice.furnsh( sd.leapseconds_kernel )
	spice.furnsh( sd.de432 )

	Dp       = 2 * 6378.0
	alt      = 600.0
	proj_mag = 6378.0 + alt
	et       = spice.str2et( '2021-11-16' )
	r_earth  = spice.spkpos( '399', et, 'J2000', 'LT', 'SUN' )[ 0 ]
	s_hat    = nt.normed( r_earth )
	v_perp   = nt.normed( np.cross( s_hat, [ 1, 0, 0 ] ) )
	Xp       = ( Dp * nt.norm( r_earth ) ) / ( pd.sun[ 'diameter' ] + Dp )
	alphap   = np.arcsin( Dp / ( 2 * Xp ) )
	kappa    = ( Xp + proj_mag ) * np.tan( alphap )

	r_sc0 = proj_mag * s_hat + v_perp * kappa * 1.01
	r_sc1 = proj_mag * s_hat + v_perp * kappa * 0.99

	assert oc.check_eclipse( et, r_sc0, pd.earth ) == -1
	assert oc.check_eclipse( et, r_sc1, pd.earth ) ==  1
示例#12
0
def vinfinity_match( planet0, planet1, v0_sc, et0, tof0, args = {} ):
	'''
	Given an incoming v-infinity vector to planet0, calculate the
	outgoing v-infinity vector that will arrive at planet1 after
	time of flight (tof) where the incoming and outgoing v-infinity
	vectors at planet0 have equal magnitude
	'''
	_args = {
		'et0'       : et0,
		'planet1_ID': planet1,
		'frame'     : 'ECLIPJ2000',
		'center_ID' : 0,
		'mu'        : pd.sun[ 'mu' ],
		'tm'        : 1,
		'diff_step' : 1e-3,
		'tol'       : 1e-4
	}
	for key in args.keys():
		_args[ key ] = args[ key ]

	_args[ 'state0_planet0' ] = spice.spkgeo( planet0, et0,
		_args[ 'frame' ], _args[ 'center_ID' ] )[ 0 ]

	_args[ 'vinf' ] = nt.norm( v0_sc - _args[ 'state0_planet0' ][ 3: ] )

	tof, steps = nt.newton_root_single_fd(
		calc_vinfinity, tof0, _args )

	r1_planet1 = spice.spkgps( planet1, et0 + tof,
		_args[ 'frame' ], _args[ 'center_ID' ] )[ 0 ]

	v0_sc_depart, v1_sc_arrive = lt.lamberts_universal_variables(
		_args[ 'state0_planet0' ][ :3 ], r1_planet1, tof,
		{ 'mu': _args[ 'mu' ], 'tm': _args[ 'tm' ] } )

	return tof, v0_sc_depart, v1_sc_arrive
from numerical_tools import norm

if __name__ == '__main__':
    spice.furnsh(sd.leapseconds_kernel)
    spice.furnsh('voyager2_jupiter_flyby.bsp')

    et = spice.str2et('1979-07-09 TDB')
    dt = 20 * 24 * 3600.0
    ets = np.arange(et - dt, et + dt, 5000.0)
    states = st.calc_ephemeris(-32, ets, 'ECLIPJ2000', 5)

    pt.plot_orbits(
        [states[:, :3]], {
            'labels': ['Voyager 2'],
            'colors': ['m'],
            'cb_radius': pd.jupiter['radius'],
            'cb_cmap': 'Oranges',
            'dist_unit': 'JR',
            'azimuth': -57,
            'elevation': 15,
            'axes_mag': 0.5,
            'show': True
        })

    hline = {'val': norm(states[0, 3:]), 'color': 'm'}
    pt.plot_velocities(ets, states[:, 3:], {
        'time_unit': 'hours',
        'hlines': [hline],
        'show': True
    })
示例#14
0
def test_norm_basic_usage():
	assert nt.norm( [ 1.0, 0, 0 ] ) == 1.0
示例#15
0
def test_norm_pythagorean():
	assert nt.norm( [ 3.0, 4.0 ] ) == 5.0
示例#16
0
import matplotlib.pyplot as plt
plt.style.use('dark_background')
plt.rcParams.update({'font.size': 13})

# AWP library
import orbit_calculations as oc
import numerical_tools as nt
import planetary_data as pd
from EVME_1963 import calc_EVME_1963

if __name__ == '__main__':
    itvim = calc_EVME_1963()
    seq1 = itvim.seq[1]
    v_arrive = seq1['state_sc_arrive'][3:]
    state_venus = spice.spkgeo(2, seq1['et'], 'ECLIPJ2000', 0)[0]
    vinf = nt.norm(v_arrive - state_venus[3:])
    span = 60 * 24 * 3600.0
    dt = 1 * 24 * 3600.0
    tofs = np.arange(seq1['tof'] - span, seq1['tof'] + span, dt)
    n_tofs = len(tofs)
    vinfs = np.zeros(n_tofs)
    args = {
        'planet1_ID': 4,
        'center_ID': 0,
        'et0': seq1['et'],
        'frame': 'ECLIPJ2000',
        'state0_planet0': state_venus,
        'mu': pd.sun['mu'],
        'tm': 1,
        'vinf': vinf
    }
示例#17
0
def eclipse_root_func( sigma, args ):
	return nt.norm( sigma * args[ 's_hat' ] - args[ 'r' ] ) - args[ 'radius' ]
示例#18
0
def lamberts_universal_variables(r0, r1, deltat, args):
    '''
	Solve Lambert's problem using universal variable method
	'''
    _args = {
        'tm': 1,
        'mu': pd.sun['mu'],
        'tol': 1e-6,
        'max_steps': 200,
        'psi': 0.0,
        'psi_u': 4.0 * math.pi**2,
        'psi_l': -4.0 * math.pi**2,
    }
    for key in args.keys():
        _args[key] = args[key]
    psi = _args['psi']
    psi_l = _args['psi_l']
    psi_u = _args['psi_u']

    sqrt_mu = math.sqrt(_args['mu'])
    r0_norm = nt.norm(r0)
    r1_norm = nt.norm(r1)
    gamma = np.dot(r0, r1) / r0_norm / r1_norm
    c2 = 0.5
    c3 = 1 / 6.0
    solved = False
    A = _args['tm'] * math.sqrt(r0_norm * r1_norm * (1 + gamma))

    if A == 0.0:
        raise RuntimeWarning(
            'Universal variables solution was passed in Hohmann transfer')
        return np.array([0, 0, 0]), np.array([0, 0, 0])

    for n in range(_args['max_steps']):
        B = r0_norm + r1_norm + A * (psi * c3 - 1) / math.sqrt(c2)

        if A > 0.0 and B < 0.0:
            psi_l += math.pi
            B *= -1.0

        chi3 = math.sqrt(B / c2)**3
        deltat_ = (chi3 * c3 + A * math.sqrt(B)) / sqrt_mu

        if abs(deltat - deltat_) < _args['tol']:
            solved = True
            break

        if deltat_ <= deltat:
            psi_l = psi

        else:
            psi_u = psi

        psi = (psi_u + psi_l) / 2.0
        c2 = C2(psi)
        c3 = C3(psi)

    if not solved:
        raise RuntimeWarning('Universal variables solver did not converge.')
        return np.array([0, 0, 0]), np.array([0, 0, 0])

    f = 1 - B / r0_norm
    g = A * math.sqrt(B / _args['mu'])
    gdot = 1 - B / r1_norm
    v0 = (r1 - f * r0) / g
    v1 = (gdot * r1 - r0) / g

    return v0, v1
Voyager 2 SPICE kernel is correct. Or you can change the path
to fit your needs
'''

# 3rd party libraries
import spiceypy as spice
import numpy as np

# AWP library
import spice_tools as st
import plotting_tools as pt
import spice_data as sd
from numerical_tools import norm

if __name__ == '__main__':
    spice.furnsh(sd.leapseconds_kernel)
    spice.furnsh('voyager2_jupiter_flyby.bsp')

    et = spice.str2et('1979-07-09 TDB')
    dt = 20 * 24 * 3600.0
    ets = np.arange(et - dt, et + dt, 5000.0)
    states = st.calc_ephemeris(-32, ets, 'ECLIPJ2000', 10)
    state_jup = spice.spkgeo(5, et, 'ECLIPJ2000', 10)[0]
    hline = {'val': norm(state_jup[3:]), 'color': 'C3'}

    pt.plot_velocities(ets, states[:, 3:], {
        'time_unit': 'days',
        'hlines': [hline],
        'show': True,
    })
示例#20
0
import spice_data as sd

import numpy as np
import spiceypy as spice
import matplotlib.pyplot as plt
plt.style.use('dark_background')

if __name__ == '__main__':
    spice.furnsh(sd.leapseconds_kernel)
    spice.furnsh(sd.de432)
    spice.furnsh(sd.pck00010)

    et = spice.str2et('2017-08-21 18:30')
    r_sun2moon = spice.spkpos('301', et, 'J2000', 'LT', 'SUN')[0]
    r_moon2earth = spice.spkpos('399', et, 'J2000', 'LT', '301')[0]
    delta_ps = nt.norm(r_sun2moon)
    s_hat = r_sun2moon / delta_ps
    proj_scalar = np.dot(r_moon2earth, s_hat)
    proj = proj_scalar * s_hat
    rej_norm = nt.norm(r_moon2earth - proj)
    args = {'r': r_moon2earth, 's_hat': s_hat, 'radius': 6378.0}
    sigma = nt.newton_root_single_fd(oc.eclipse_root_func, proj_scalar / 2.0,
                                     args)[0]
    sigmas = np.arange(sigma - 10000, sigma + 15000, 10)
    n_sigmas = len(sigmas)
    vals = np.zeros(n_sigmas)

    for n in range(n_sigmas):
        vals[n] = oc.eclipse_root_func(sigmas[n], args)

    plt.figure(figsize=(16, 8))
示例#21
0
def test_norm_zero_vector():
	assert nt.norm( [ 0, 0, 0 ] ) == 0.0