eaglelandsonce commited on
Commit
5dce9ae
·
verified ·
1 Parent(s): 2d72d2f

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +148 -0
app.py ADDED
@@ -0,0 +1,148 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import numpy as np
3
+ import matplotlib.pyplot as plt
4
+
5
+ # ===============================
6
+ # Streamlit Interface Setup
7
+ # ===============================
8
+ st.title("Spin Launch & Orbital Attachment Simulation")
9
+
10
+ st.markdown(
11
+ """
12
+ This simulation demonstrates a two‑phase launch:
13
+
14
+ 1. **Spin‑Launch Phase:** A payload is accelerated from an elevated platform.
15
+ 2. **Orbital Phase:** At a chosen altitude, the payload “docks” with a human‑rated upper stage by
16
+ instantly setting its velocity to that of a circular orbit.
17
+
18
+ Adjust the parameters in the sidebar and click "Run Simulation" to see the result.
19
+ """
20
+ )
21
+
22
+ # Sidebar parameters for simulation
23
+ st.sidebar.header("Simulation Parameters")
24
+
25
+ # Time and integration parameters:
26
+ dt = st.sidebar.number_input("Time Step (s)", min_value=0.01, max_value=1.0, value=0.1, step=0.01)
27
+ t_max = st.sidebar.number_input("Total Simulation Time (s)", min_value=100, max_value=5000, value=1000, step=100)
28
+
29
+ # Launch conditions:
30
+ initial_altitude_km = st.sidebar.number_input("Initial Altitude (km)", min_value=1, max_value=100, value=50, step=1)
31
+ initial_velocity = st.sidebar.number_input("Initial Velocity (m/s)", min_value=100, max_value=5000, value=1200, step=100)
32
+
33
+ # Docking/Orbital attachment altitude:
34
+ docking_altitude_km = st.sidebar.number_input("Docking Altitude (km)", min_value=1, max_value=500, value=100, step=1)
35
+
36
+ # Button to run simulation
37
+ run_sim = st.sidebar.button("Run Simulation")
38
+
39
+ if run_sim:
40
+ # ===============================
41
+ # Physical Constants and Conversions
42
+ # ===============================
43
+ mu = 3.986e14 # Earth's gravitational parameter, m^3/s^2
44
+ R_E = 6.371e6 # Earth's radius, m
45
+
46
+ # Convert altitude values from km to m:
47
+ initial_altitude = initial_altitude_km * 1000.0 # initial altitude above Earth's surface (m)
48
+ docking_altitude = docking_altitude_km * 1000.0 # docking altitude above Earth's surface (m)
49
+ r_dock = R_E + docking_altitude # docking radius from Earth's center (m)
50
+
51
+ # ===============================
52
+ # Initial Conditions for the Simulation
53
+ # ===============================
54
+ # Starting at a point along the x-axis at a radial distance (Earth's radius + initial altitude)
55
+ initial_position = np.array([R_E + initial_altitude, 0.0])
56
+ # Initial velocity is chosen to be radial (pointing outward) at the chosen speed.
57
+ initial_velocity_vec = np.array([initial_velocity, 0.0])
58
+
59
+ # ===============================
60
+ # Define the Acceleration Function
61
+ # ===============================
62
+ def acceleration(pos):
63
+ """
64
+ Compute acceleration due to Earth's gravity at position pos (in m).
65
+ """
66
+ r = np.linalg.norm(pos)
67
+ return -mu * pos / r**3
68
+
69
+ # ===============================
70
+ # Run the Simulation Loop
71
+ # ===============================
72
+ states = [] # Will store tuples of (time, x, y, phase)
73
+ phase = 1 # Phase 1: spin-launch, Phase 2: orbital phase after docking
74
+ t = 0.0
75
+ pos = initial_position.copy()
76
+ vel = initial_velocity_vec.copy()
77
+ docking_done = False
78
+ docking_event_time = None
79
+ docking_event_coords = None
80
+
81
+ while t < t_max:
82
+ # --- Check for the Docking Event ---
83
+ # When the payload's distance from Earth's center exceeds the docking radius
84
+ # and it is still moving outward (positive radial velocity), we trigger the docking.
85
+ if phase == 1 and not docking_done and np.linalg.norm(pos) >= r_dock and vel.dot(pos) > 0:
86
+ docking_done = True
87
+ phase = 2 # Switch to orbital phase
88
+ r_current = np.linalg.norm(pos)
89
+ # Compute the circular orbital speed at the current radius:
90
+ v_circ = np.sqrt(mu / r_current)
91
+ # For a prograde orbit, choose a tangential direction (perpendicular to the radial vector):
92
+ tangential_dir = np.array([-pos[1], pos[0]]) / r_current
93
+ vel = v_circ * tangential_dir # Instantaneously change velocity for orbital insertion
94
+ docking_event_time = t
95
+ docking_event_coords = pos.copy()
96
+ st.write(f"**Docking Event:** t = {t:.1f} s, Altitude = {(r_current - R_E)/1000:.1f} km, Circular Speed = {v_circ:.1f} m/s")
97
+
98
+ # Record current state: (time, x, y, phase)
99
+ states.append((t, pos[0], pos[1], phase))
100
+
101
+ # --- Propagate the state using simple Euler integration ---
102
+ a = acceleration(pos)
103
+ pos = pos + vel * dt
104
+ vel = vel + a * dt
105
+ t += dt
106
+
107
+ # Convert states to a NumPy array for easier slicing:
108
+ states = np.array(states) # columns: time, x, y, phase
109
+
110
+ # ===============================
111
+ # Create the Trajectory Plot with Matplotlib
112
+ # ===============================
113
+ fig, ax = plt.subplots(figsize=(8, 8))
114
+ ax.set_aspect('equal')
115
+ ax.set_xlabel("x (km)")
116
+ ax.set_ylabel("y (km)")
117
+ ax.set_title("Trajectory: Spin Launch and Orbital Attachment")
118
+
119
+ # Draw Earth as a blue circle (Earth's radius in km)
120
+ earth = plt.Circle((0, 0), R_E / 1000, color='blue', alpha=0.3, label="Earth")
121
+ ax.add_artist(earth)
122
+
123
+ # Define plot limits (extend to show orbit, e.g., Earth's radius plus 300 km):
124
+ max_extent = (R_E + 300e3) / 1000 # in km
125
+ ax.set_xlim(-max_extent, max_extent)
126
+ ax.set_ylim(-max_extent, max_extent)
127
+
128
+ # Separate the recorded states into spin-launch and orbital phases:
129
+ spin_phase = states[states[:, 3] == 1]
130
+ orbital_phase = states[states[:, 3] == 2]
131
+
132
+ # Plot the spin-launch phase in red:
133
+ if spin_phase.size > 0:
134
+ ax.plot(spin_phase[:, 1] / 1000, spin_phase[:, 2] / 1000, 'r-', label="Spin‑Launch Phase")
135
+ # Plot the orbital phase in green:
136
+ if orbital_phase.size > 0:
137
+ ax.plot(orbital_phase[:, 1] / 1000, orbital_phase[:, 2] / 1000, 'g-', label="Orbital Phase")
138
+
139
+ # Mark the launch start:
140
+ ax.plot(initial_position[0] / 1000, initial_position[1] / 1000, 'ko', label="Launch Start")
141
+ # Mark the docking event, if it occurred:
142
+ if docking_done and docking_event_coords is not None:
143
+ ax.plot(docking_event_coords[0] / 1000, docking_event_coords[1] / 1000, 'bo', markersize=8, label="Docking Event")
144
+
145
+ ax.legend()
146
+ st.pyplot(fig)
147
+
148
+ st.markdown("**Note:** This is a simplified simulation. In a realistic system, the spin‑launch phase, docking maneuver, and orbital insertion would be modeled with far more complexity (including aerodynamic forces, gradual burns, and detailed guidance dynamics).")