In [1]:
import plotly.express as px
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
Mission Milestones¶
This is the 4th notebook in the series. Earlier parts:
- ./010-video-export.html - for exporting still frames and timecodes for the videos
- ./020-video-analysis.html - for analyzing the video frames to match mission time with key events
- ./030-flight-data.html - for analyzing the flight data
Here we will compare the flight data with the mission timeline
In [2]:
df = pd.read_csv("mission-timeline.csv")
df
Out[2]:
| Unnamed: 0 | Frame | Time (s) | Description | ∆T (s) | |
|---|---|---|---|---|---|
| 0 | 0 | 25 | 18.145000 | First frame showing rocket plume | 0.000000 |
| 1 | 1 | 31 | 18.245000 | Rocket has cleared the viewport | 0.100000 |
| 2 | 2 | 91 | 19.245000 | Bottle re-acquired | 1.100000 |
| 3 | 3 | 176 | 20.663333 | Rocket at apogee, starting to descend | 2.518333 |
| 4 | 4 | 208 | 21.196667 | Rocket clearly descending and leaning right | 3.051667 |
| 5 | 5 | 245 | 21.813333 | Rocket starts executing flip to nose down | 3.668333 |
| 6 | 6 | 265 | 22.146667 | Rocket pointing downwards, precessing around z... | 4.001667 |
| 7 | 7 | 388 | 24.198333 | Possible rocket crash into building | 6.053333 |
We also found that the launch moment according to the onboard clock was 442461 ms.
In [3]:
LAUNCH_TIME = 442461
Let's look how the video compares with the data¶
We can load in the sensor data and plot the key events from the video
In [4]:
baro = pd.read_csv('data/BarometerData-20250405-162645.csv')
baro = baro.iloc[11:]
baro = baro[baro['timestamp'] > 440000]
baro['mission_time'] = (baro.timestamp - LAUNCH_TIME) / 1000
baro = baro.set_index('mission_time')
baro.head()
Out[4]:
| time | timestamp | pressure | altitude | average_altitude | temperature | |
|---|---|---|---|---|---|---|
| mission_time | ||||||
| -2.428 | 16:20:54.830000 | 440033 | 102139.593750 | 0.210183 | 0.046781 | 28.620001 |
| -2.175 | 16:20:55.083000 | 440286 | 102143.968750 | -0.150846 | 0.055706 | 28.629999 |
| -1.923 | 16:20:55.335000 | 440538 | 102141.726562 | 0.034192 | 0.055847 | 28.650000 |
| -1.669 | 16:20:55.589000 | 440792 | 102138.843750 | 0.272032 | 0.047770 | 28.629999 |
| -1.419 | 16:20:55.839000 | 441042 | 102140.531250 | 0.132747 | 0.044345 | 28.639999 |
In [5]:
imu = pd.read_csv('data/AccelData-20250405-162645.csv')
imu = imu.iloc[1000:]
imu = imu[imu['timestamp'] > 440000]
imu['mission_time'] = (imu.timestamp - LAUNCH_TIME) / 1000
imu = imu.set_index('mission_time')
imu['total_accel'] = np.sqrt(imu['accelX']**2 + imu['accelY']**2 + imu['accelZ']**2)
imu.head()
Out[5]:
| time | timestamp | accelX | accelY | accelZ | gyroX | gyroY | gyroZ | temperature | total_accel | |
|---|---|---|---|---|---|---|---|---|---|---|
| mission_time | ||||||||||
| -2.459 | 16:20:54.799000 | 440002 | -0.081984 | -0.155672 | -1.013576 | -1.40 | -2.24 | 2.24 | 42.7500 | 1.028733 |
| -2.451 | 16:20:54.807000 | 440010 | -0.083448 | -0.093208 | -0.195688 | -1.19 | -2.59 | 1.82 | 42.7500 | 0.232261 |
| -2.443 | 16:20:54.815000 | 440018 | -0.122976 | -0.087352 | -1.002840 | -1.82 | -2.73 | -8.12 | 42.6875 | 1.014121 |
| -2.435 | 16:20:54.823000 | 440026 | -0.131272 | -0.179584 | -0.770064 | -2.80 | -0.91 | -4.20 | 42.6875 | 0.801549 |
| -2.420 | 16:20:54.838000 | 440041 | 0.058072 | -0.064904 | -1.726544 | 0.49 | -1.96 | 12.88 | 42.6875 | 1.728739 |
Let's create a function to annotate the plot with the mission milestones
In [6]:
def annotate_plot(fig, y):
for _, row in df.iterrows():
fig.add_vline(
x=row['∆T (s)'],
line_dash="dash",
line_color="red",
)
fig.add_annotation(
x=row['∆T (s)'],
y=y,
text=row['Description'],
showarrow=False,
textangle=-90,
font=dict(color="grey", size=10),
xanchor="left",
yanchor="top"
)
Flight profile¶
Let's first examine how our "video" milestones compare to the real flight data
In [7]:
filtered_data = baro['altitude']
fig = px.scatter(x=filtered_data.index, y=filtered_data.values,
title="Rocket Altitude Measurements",
labels={"x": "Time (s)", "y": "Altitude (m)"})
fig.update_traces(mode='lines+markers')
fig.update_layout(height=1000)
fig.update_xaxes(range=[-0.2, 7])
fig.update_yaxes(range=[-1, 100])
annotate_plot(fig, 90)
fig.show()