eaglelandsonce commited on
Commit
e0317e5
·
verified ·
1 Parent(s): 9195d59

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -41
app.py CHANGED
@@ -1,25 +1,27 @@
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:
@@ -33,7 +35,7 @@ initial_velocity = st.sidebar.number_input("Initial Velocity (m/s)", min_value=1
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:
@@ -60,17 +62,18 @@ if run_sim:
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()
@@ -81,68 +84,84 @@ if run_sim:
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).")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import streamlit as st
2
  import numpy as np
3
  import matplotlib.pyplot as plt
4
+ from matplotlib.animation import FuncAnimation
5
+ import streamlit.components.v1 as components
6
 
7
  # ===============================
8
  # Streamlit Interface Setup
9
  # ===============================
10
+ st.title("Spin Launch & Orbital Attachment Simulation (Animated)")
11
 
12
  st.markdown(
13
  """
14
  This simulation demonstrates a two‑phase launch:
15
 
16
  1. **Spin‑Launch Phase:** A payload is accelerated from an elevated platform.
17
+ 2. **Orbital Phase:** At a specified altitude, the payload “docks” with a human‑rated upper stage by
18
  instantly setting its velocity to that of a circular orbit.
19
 
20
+ Adjust the parameters on the sidebar and click **Run Simulation**.
21
  """
22
  )
23
 
24
+ # Sidebar parameters for simulation:
25
  st.sidebar.header("Simulation Parameters")
26
 
27
  # Time and integration parameters:
 
35
  # Docking/Orbital attachment altitude:
36
  docking_altitude_km = st.sidebar.number_input("Docking Altitude (km)", min_value=1, max_value=500, value=100, step=1)
37
 
38
+ # Button to run simulation:
39
  run_sim = st.sidebar.button("Run Simulation")
40
 
41
  if run_sim:
 
62
  # Define the Acceleration Function
63
  # ===============================
64
  def acceleration(pos):
65
+ """Compute acceleration due to Earth's gravity at position pos (in m)."""
 
 
66
  r = np.linalg.norm(pos)
67
  return -mu * pos / r**3
68
 
69
  # ===============================
70
  # Run the Simulation Loop
71
  # ===============================
72
+ # We'll record (time, x, y, phase)
73
+ # phase = 1: spinlaunch phase
74
+ # phase = 2: orbital phase (after docking)
75
+ states = []
76
+ phase = 1
77
  t = 0.0
78
  pos = initial_position.copy()
79
  vel = initial_velocity_vec.copy()
 
84
  while t < t_max:
85
  # --- Check for the Docking Event ---
86
  # When the payload's distance from Earth's center exceeds the docking radius
87
+ # and it's still moving outward, trigger the docking event.
88
  if phase == 1 and not docking_done and np.linalg.norm(pos) >= r_dock and vel.dot(pos) > 0:
89
  docking_done = True
90
+ phase = 2 # switch to orbital phase
91
  r_current = np.linalg.norm(pos)
92
  # Compute the circular orbital speed at the current radius:
93
  v_circ = np.sqrt(mu / r_current)
94
+ # For a prograde orbit, choose a tangential (perpendicular) direction:
95
  tangential_dir = np.array([-pos[1], pos[0]]) / r_current
96
+ vel = v_circ * tangential_dir # instantaneous burn to circular orbit
97
  docking_event_time = t
98
  docking_event_coords = pos.copy()
99
  st.write(f"**Docking Event:** t = {t:.1f} s, Altitude = {(r_current - R_E)/1000:.1f} km, Circular Speed = {v_circ:.1f} m/s")
100
 
101
+ # Record the current state: (time, x, y, phase)
102
  states.append((t, pos[0], pos[1], phase))
103
 
104
+ # --- Propagate the State (Euler Integration) ---
105
  a = acceleration(pos)
106
  pos = pos + vel * dt
107
  vel = vel + a * dt
108
  t += dt
109
 
110
+ # Convert the recorded states to a NumPy array for easier slicing.
111
  states = np.array(states) # columns: time, x, y, phase
112
 
113
  # ===============================
114
+ # Create the Animation Using Matplotlib
115
  # ===============================
116
  fig, ax = plt.subplots(figsize=(8, 8))
117
  ax.set_aspect('equal')
118
  ax.set_xlabel("x (km)")
119
  ax.set_ylabel("y (km)")
120
+ ax.set_title("Trajectory: Spin Launch & Orbital Attachment")
121
 
122
  # Draw Earth as a blue circle (Earth's radius in km)
123
  earth = plt.Circle((0, 0), R_E / 1000, color='blue', alpha=0.3, label="Earth")
124
  ax.add_artist(earth)
125
 
126
+ # Set plot limits to show the trajectory (e.g., up to Earth's radius + 300 km)
127
  max_extent = (R_E + 300e3) / 1000 # in km
128
  ax.set_xlim(-max_extent, max_extent)
129
  ax.set_ylim(-max_extent, max_extent)
130
 
131
+ # Initialize the trajectory line and payload marker for animation:
132
+ trajectory_line, = ax.plot([], [], 'r-', lw=2, label="Trajectory")
133
+ payload_marker, = ax.plot([], [], 'ko', markersize=5, label="Payload")
134
+ time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes, fontsize=10)
135
+
136
+ def init():
137
+ trajectory_line.set_data([], [])
138
+ payload_marker.set_data([], [])
139
+ time_text.set_text('')
140
+ return trajectory_line, payload_marker, time_text
141
+
142
+ def update(frame):
143
+ # Update the trajectory with all positions up to the current frame.
144
+ t_val = states[frame, 0]
145
+ x_vals = states[:frame+1, 1] / 1000 # convert m to km
146
+ y_vals = states[:frame+1, 2] / 1000 # convert m to km
147
+ trajectory_line.set_data(x_vals, y_vals)
148
+ payload_marker.set_data(states[frame, 1] / 1000, states[frame, 2] / 1000)
149
+ time_text.set_text(f"Time: {t_val:.1f} s")
150
+ return trajectory_line, payload_marker, time_text
151
+
152
+ # Create the animation. The interval (in ms) can be adjusted for speed.
153
+ anim = FuncAnimation(fig, update, frames=len(states), init_func=init, interval=20, blit=True)
154
+
155
+ # Convert the animation to an HTML5 video.
156
+ video_html = anim.to_html5_video()
157
+
158
+ st.markdown("### Simulation Animation")
159
+ components.html(video_html, height=500)
160
+
161
+ st.markdown(
162
+ """
163
+ **Note:** This is a highly simplified simulation. In a real-world scenario, the spin‑launch, docking,
164
+ and orbital insertion phases would involve much more complex physics including aerodynamics, non‑instantaneous burns,
165
+ and detailed guidance and control.
166
+ """
167
+ )