예제 #1
0
	def __init__(self, mu_planet, spacecraft, atmosphere, V0, X0, sim_time, R, 
		console_output=True, dt=0.1):
		# Pull in spacecraft and atmosphere classes for convenient variable access
		self.spacecraft = spacecraft
		self.atmosphere = atmosphere

		# Verbose solver output flag
		self.console_output = console_output

		# Miscellaneous initial conditions and constant variables
		self.mu = mu_planet
		self.InitalV = V0
		self.initalpos = X0
		self.simtime = sim_time
		self.dt = dt
		self.N = np.int(self.simtime / dt)
		self.R = R

		# Create empty arrays for storage of results from ODE solver
		self.sol = np.zeros([self.N, 6])
		self.V_xyz = np.zeros([self.N, 3])
		self.pos_xyz = np.zeros([self.N, 3])
		self.V_mag = np.zeros(self.N)
		self.pos_mag = np.zeros(self.N)
		self.theta = np.zeros(self.N)
		self.theta = np.zeros(self.N)
		self.h = np.zeros(self.N)

		# Forces in inertial frame
		self.F_x = np.zeros([self.N])
		self.F_y = np.zeros([self.N])
		self.F_z = np.zeros([self.N])
		self.F_mag = np.zeros(self.N)

		self.V_xyz[0, :] = V0
		self.pos_xyz[0, :] = X0

		# Velocity and position vector magnitudes
		self.V_mag[0] = np.linalg.norm(self.V_xyz[0, :])
		self.pos_mag[0] = np.linalg.norm(self.pos_xyz[0, :])

		# Interpolated atmospheric variables
		self.solver_rho 	= np.zeros(self.N)
		self.solver_mu 	= np.zeros(self.N)
		self.solver_a 	= np.zeros(self.N)
		self.solver_p 	= np.zeros(self.N)
		self.solver_T 	= np.zeros(self.N)
		self.solver_time 	= np.zeros(self.N)

		# Altitude above surface of planet (assumed to be perfectly spherical)
		self.h[0] = np.linalg.norm(self.pos_xyz[0, :]) - self.R

		self.lift = np.zeros(self.N)
		self.drag = np.zeros(self.N)
		self.side_force = np.zeros(self.N)
		self.forces_rotating = np.zeros([self.N, 3])
		self.forces_inertial = np.zeros([self.N, 3])
		self.alpha = np.zeros(self.N)
		self.theta = np.zeros(self.N)

		# Interpolate atmospheric variables
		self.solver_rho[0], self.solver_a[0], \
			self.solver_p[0], self.solver_T[0], \
			self.solver_mu[0] = interpolate_atmosphere(self, self.h[0])

		self.lift[0] = fcl.aero_force(self.solver_rho[0], self.V_mag[0],
			self.spacecraft.Cl, self.spacecraft.A)
		self.drag[0] = fcl.aero_force(self.solver_rho[0], self.V_mag[0],
			self.spacecraft.Cd, self.spacecraft.A)
		self.side_force[0] = fcl.aero_force(self.solver_rho[0], self.V_mag[0],
			self.spacecraft.Cs, self.spacecraft.A)
		self.forces_rotating[0, :] = np.array([self.lift[0], self.drag[0],
			self.side_force[0]])

		# Calculate Euler angles (pitch and yaw; roll is assumed to be zero)
		self.alpha[0], self.theta[0] = rotate_lib.vector_to_euler(self.pos_xyz[0, 0],
			self.pos_xyz[0, 1], self.pos_xyz[0, 2])

		# Transform aero forces from rotating to inertial frame
		self.forces_inertial[0, :] = rotate_lib.roty(self.forces_rotating[0, :],
			self.alpha[0], mode='rad')
		self.forces_inertial[0, :] = rotate_lib.rotz(self.forces_rotating[0, :],
			self.theta[0], mode='rad')

		# Split forces into components
		self.F_x[0] = self.forces_inertial[0, 0]
		self.F_y[0] = self.forces_inertial[0, 1]
		self.F_z[0] = self.forces_inertial[0, 2]
		
		# Calculate magnitude of forces
		self.F_mag[0] = np.abs(np.linalg.norm([self.F_x[0], self.F_y[0], 
			self.F_z[0]]))

		# Define list of keys for obejct dict (self.__dict__)
		# To be used by truncation, event interpolation, and variable
		# assignment functions 
		self.l = ['V_xyz', 'V_mag', 'F_mag', 'F_x', 'F_y', 'F_z', 'pos_xyz', 
			'pos_mag', 'alpha', 'theta', 'drag', 'lift', 'side_force', 
			'h', 'solver_time', 'solver_rho', 
			'solver_p', 'solver_T', 'solver_mu', 'solver_a', 
			'forces_inertial', 'forces_rotating']

		if self.console_output == True:
			print 'MODEL INITIALISED.  INITIAL STEP COUNT: %i' % self.N

		return None
예제 #2
0
	def simulate_dopri(self, rtol=1E-4, nsteps=1E8):
		# Store ODE solver variables
		#self.dt = dt
		self.rtol = rtol
		self.nsteps = nsteps		
		
		# Set up ODE solver
		self.eq = integrate.ode(orbit_xyz).set_integrator('dop853', 
			nsteps=self.nsteps, rtol=self.rtol)

		y_init = [self.InitalV[0], self.InitalV[1], self.InitalV[2],
			self.initalpos[0], self.initalpos[1],  self.initalpos[2]]
		self.y_init = y_init
		self.eq.set_initial_value(y_init, t=0)

		#set inital values
		params = [self.F_x[0], self.F_y[0], self.F_z[0],
			self.spacecraft.m, self.mu]
		self.eq.set_f_params(params)

		for i in range(1, self.N):
			# Update stored counter			
			self.i = i			
			
			# Update ODE solver params
			update_params = [self.F_x[i-1], self.F_y[i-1], self.F_z[i-1],
				self.spacecraft.m, self.mu]
			self.eq.set_f_params(update_params)

			# Solve ODE system
			self.sol[i, :] = self.eq.integrate(self.eq.t + self.dt)
			self.solver_time[i] = self.eq.t

			# Unpack ODE solver results
			self.V_xyz[i, :] = self.sol[i, 0:3]
			self.V_mag[i] = np.linalg.norm(self.V_xyz[i, :])
			self.pos_xyz[i, :] = self.sol[i, 3:6]
			self.pos_mag[i] = np.linalg.norm(self.pos_xyz[i, :])

			# Update altitude
			self.h[i] = np.linalg.norm(self.pos_xyz[i, :]) - self.R

			# Interpolate atmospheric variables
			self.solver_rho[i], self.solver_a[i], \
				self.solver_p[i], self.solver_T[i], \
				self.solver_mu[i] = interpolate_atmosphere(self, self.h[i])

			# Axial aero forces
			self.lift[i] = fcl.aero_force(self.solver_rho[i], self.V_mag[i],
				self.spacecraft.Cl, self.spacecraft.A)
			self.drag[i] = fcl.aero_force(self.solver_rho[i], self.V_mag[i],
				self.spacecraft.Cd, self.spacecraft.A)
			self.side_force[i] = fcl.aero_force(self.solver_rho[i], self.V_mag[i],
				self.spacecraft.Cs, self.spacecraft.A)
			self.forces_rotating[i, :] = np.array([self.lift[i], self.drag[i],
				self.side_force[i]])

			# Calculate Euler angles (pitch and yaw; roll is assumed to be zero)
			self.alpha[i], self.theta[i] = rotate_lib.vector_to_euler(self.sol[i, 3],
				self.sol[i, 4], self.sol[i, 5])

			# Transform aero forces from rotating to inertial frame
			self.forces_inertial[i, :] = rotate_lib.roty(self.forces_rotating[i, :],
				self.alpha[i], mode='rad')
			self.forces_inertial[i, :] = rotate_lib.rotz(self.forces_rotating[i, :],
				self.theta[i], mode='rad')

			# Split forces into components
			self.F_x[i] = -self.forces_inertial[i, 0]
			self.F_y[i] = -self.forces_inertial[i, 1]
			self.F_z[i] = -self.forces_inertial[i, 2]
			
			# Calculate magnitude of forces
			self.F_mag[i] = np.abs(np.linalg.norm([self.F_x[i], self.F_y[i], 
				self.F_z[i]]))

			# Print integration progress
			if self.console_output == True:
				if np.mod(i, self.N/100) == 0:
					print '%3.1f%%; ITERATION: %i; ALTITUDE: %f km' % \
						(100*(np.float(i)/self.N), i, self.h[i]/1000)

			# Check for ground strike
			if self.h[i] <= 0:
				print 'GROUND STRIKE EVENT (ALTITUDE = 0) DETECTED BETWEEN ' \
					'INDEXES %i AND %i' % (i-1, i)
				break
			
			# Check for atmospheric model interpolation errors
			# (OUT_OF_BOUNDS error)
			if np.isnan(self.solver_rho[i]) == True:
				print 'ERROR: ATMOSPHERIC INTERPOLATION OUT OF BOUNDS AT ' \
					'INDEX %i, TRY EXPANDING ALTITUDE RANGE' % i
				break

		self.final_step_event()

		return self.sol