blob: 99ac0437477b45fb182fa6ba72ebc1a1e85e259b (
plain) (
tree)
|
|
import math
from dataclasses import dataclass
from universe import Universe
from body import Body
from rocket import Rocket
#Simulates polar orbit as no body rotation assumed
@dataclass
class Simulation_Snapshot:
universe: type[Universe]
body: type[Body]
rocket: type[Rocket]
class Simulation():
def __init__(self, universe: type[Universe], body: type[Body], rocket: type[Rocket]):
self.ticks = 0
self.time = 0
self.universe = universe
self.body = body
self.rocket = rocket
self.x = 0#TODO
self.y = self.body.radius #TODO: we need to make it so there is height() to calc height based on x and y
self.speed_x = 0
self.speed_y = 0
self.acceleration_x = 0
self.acceleration_y = 0
self.heading = 0
#simulation logic
def tick(self, delta: int) -> None:
current_stage = self.rocket.current_stage()
#calculate upwards force by fuel
fuel_used = current_stage.total_fuel_used(delta)
if current_stage.fuel_mass < fuel_used:
fuel_used = current_stage.fuel_mass
current_stage.fuel_mass -= fuel_used
print("Fuel remaining: " + str(current_stage.fuel_mass))
g = self.body.g(G=self.universe.G, height=self.rocket_altitude())
print("g: " + str(g))
force_x = 0
force_y = 0
if fuel_used > 0:
total_thrust = current_stage.current_thrust(g, self.heading)
force_x = total_thrust[0]
force_y = total_thrust[1]
print("Thrust X: " + str(force_x))
print("Thrust Y: " + str(force_y))
print("BODY MASS: " + str(self.body.mass()))
print("ROCKET TOTAL MASS: " + str(self.rocket.total_mass()))
#calculate downwards force by drag and gravity
total_gravitational_force = g * self.rocket.total_mass()
print("Total Gravity: " + str(total_gravitational_force))
print("angle_of_position_with_respect_to_origin: " + str(self.angle_of_position_with_respect_to_origin()))
gravitational_force_x = math.sin(math.radians(self.angle_of_position_with_respect_to_origin())) * total_gravitational_force
gravitational_force_y = math.cos(math.radians(self.angle_of_position_with_respect_to_origin())) * total_gravitational_force
print("Gravity X: " + str(gravitational_force_x))
print("Gravity Y: " + str(gravitational_force_y))
#Remove gravity from force
force_x -= gravitational_force_x
force_y -= gravitational_force_y
curr_atmospheric_density = self.body.atmosphere.density_at_height(self.rocket_altitude(), g)
print("Atmosphere density: " + str(curr_atmospheric_density))
#TODO: cross sectional area and drag coef for x should b different
drag_force_x = (1/2) * curr_atmospheric_density * (self.speed_x ** 2) * self.rocket.rocket_x_drag_coefficient() * self.rocket.rocket_x_cross_sectional_area()
#drag goes against speed
if self.speed_x < 0:
drag_force_x *= -1
print("Drag X: " + str(drag_force_x))
#https://www.grc.nasa.gov/www/k-12/airplane/drageq.html
drag_force_y = (1/2) * curr_atmospheric_density * (self.speed_y ** 2) * self.rocket.rocket_y_drag_coefficient() * self.rocket.rocket_y_cross_sectional_area()
#drag goes against speed
if self.speed_y < 0:
drag_force_y *= -1
print("Drag Y: " + str(drag_force_y))
#remove drag
force_x -= drag_force_x
force_y -= drag_force_y
print("Total Force X: " + str(force_x))
print("Total Force Y: " + str(force_y))
self.acceleration_x = force_x / self.rocket.total_mass()
self.acceleration_y = force_y / self.rocket.total_mass()
print("Acceleration x: " + str(self.acceleration_x))
print("Acceleration y: " + str(self.acceleration_y))
self.speed_x = self.speed_x + (self.acceleration_x * delta)
self.speed_y = self.speed_y + (self.acceleration_y * delta)
#update position based on velocity and delta
self.x += self.speed_x * delta
self.y += self.speed_y * delta
if self.rocket_altitude() < 0:
#undo positional changes
self.x -= self.speed_x * delta
self.y -= self.speed_y * delta
self.speed_x = 0
self.speed_y = 0
print("Speed x: " + str(self.speed_x))
print("Speed y: " + str(self.speed_y))
print("X: " + str(self.x))
print("Y: " + str(self.y))
ref_vec = (0, 1)
acc_vec = (self.speed_x, self.speed_y)
dot = (acc_vec[0] * ref_vec[0]) + (acc_vec[1] * ref_vec[1])
det = (acc_vec[0] * ref_vec[1]) - (acc_vec[1] * ref_vec[0])
self.heading = math.degrees(math.atan2(det, dot))
print("Heading: " + str(self.heading))
print("Total Simulation Time: " + str(self.time))
print("")
self.ticks += 1
self.time += delta
def rocket_altitude(self):
#take into account body and allow for 360 height
#TODO: try and solve it using 2 sqrt instead of having such a big number in parameters which can crass with high timesx
altitude = math.sqrt(self.x**2 + self.y**2)
altitude -= self.body.radius
return altitude
def angle_of_position_with_respect_to_origin(self):
ref_vec = (0, 1)
pos_vec = (self.x, self.y)
dot = (pos_vec[0] * ref_vec[0]) + (pos_vec[1] * ref_vec[1])
det = (pos_vec[0] * ref_vec[1]) - (pos_vec[1] * ref_vec[0])
return math.degrees(math.atan2(det, dot))
def snapshot(self) -> Simulation_Snapshot:
return Simulation_Snapshot(self.universe, self.body, self.rocket)
def str_snapshot(self) -> str:
return str(self.universe) + "\n" + \
str(self.body) + "\n" + \
str(self.rocket)
|