about summary refs log tree commit diff
path: root/simulation.py
blob: 70ea1712190c53961c6eb13ed5dc3969c41d916b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import math
from dataclasses import dataclass

from universe import Universe
from body import Body
from rocket import Rocket

@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 = 0 #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))
                
        force_x = 0
        force_y = 0
        if fuel_used > 0:
            total_thrust = current_stage.current_thrust(self.body.g(self.universe.G, self.y), 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
        print("g: " + str(self.body.g(G=self.universe.G, height=self.y)))

        gravitational_force = self.body.g(G=self.universe.G, height=self.y) * self.rocket.total_mass()
        print("Gravity: " + str(gravitational_force))

        #Remove gravity from force
        force_y -= gravitational_force

        print("Atmosphere density: " + str(self.body.atmosphere.density_at_height(self.y, self.body.g(G=self.universe.G, height=self.y))))

        #TODO: cross sectional area and drag coef for x should b different
        drag_force_x = (1/2) * self.body.atmosphere.density_at_height(self.y, self.body.g(G=self.universe.G, height=self.y)) * (self.speed_x ** 2) * self.rocket.s_drag_coefficient() * self.rocket.s_cross_sectional_area()
        #drag goes against speed
        if force_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) * self.body.atmosphere.density_at_height(self.y, self.body.g(G=self.universe.G, height=self.y)) * (self.speed_y ** 2) * self.rocket.s_drag_coefficient() * self.rocket.s_cross_sectional_area()
        #drag goes against speed
        if force_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)

        print("Speed x: " + str(self.speed_x))
        print("Speed y: " + str(self.speed_y))

        #TODO: HEADING behaves a bit weird, just a bit and it goes forever and hard to cancel. WELL CALCULATED OR IMPLEMENTED?
        #speedx / speedy
        #1 = 45
        #-1 = -45
        #0 = 90
        self.heading = math.degrees(self.speed_x / self.speed_y) #TODO? con speed, y luego heading influences thrust (gimbal), so pass as a parameter to func
        print("Heading: " + str(self.heading))

        #update position based on velocity and delta
        self.x += self.speed_x * delta

        #in future u should be able to go negative y (y and height are different)
        self.y += self.speed_y * delta
        if self.y < 0:
            self.y = 0
            self.speed_y = 0
            
        print("X: " + str(self.x))
        print("Y: " + str(self.y))

        print("Total Simulation Time: " + str(self.time))
        print("")

        self.ticks += 1
        self.time += delta

    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)