Barometric flight path analysis¶
In this notebook, we're going to look at analysis of the barometric data. We're going to assume the measurements are accurate and calculate flight parameters based on some very simple assumptions about aerodynamic and other forces acting upon the rocket.
import plotly.express as px
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
LAUNCH_TIME = 442461
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['altitude'].plot()
<Axes: xlabel='mission_time'>
Fitting a parabolic¶
Let's ignore air-resistance for now, and just fit a pure ballistic curve to the 'airborne' part of the curve
from scipy.optimize import curve_fit
filtered_data = baro[baro.index > 0]
time = filtered_data.index.to_numpy()
altitude = filtered_data['altitude'].to_numpy()
# Define the function with no constant term
def parabola(t, a, b):
return a * t**2 + b * t
# Fit the curve
params, _ = curve_fit(parabola, time, altitude)
a, b = params
# Predict using the fitted function
time_smooth = np.linspace(time.min(), time.max(), 500)
altitude_fit = parabola(time_smooth, a, b)
# Plot
plt.figure(figsize=(8, 5))
plt.scatter(time, altitude, label='Data', color='blue')
plt.plot(time_smooth, altitude_fit, label='Constrained Parabolic Fit', color='green')
plt.xlabel('Time (s)')
plt.ylabel('Altitude (m)')
plt.title('Ballistic Path Fit (Constrained Through Launch Point)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
It's not a great fit - and we can see some clear asymetries. We now from the other calculations we have that the barometric data is possibly slightly delayed with respect to the actual flight path. For example, the peak above is around 3 seconds - but from intertial measuruments we found this to be more like 2.5 seconds.
Re-fit but ignoring t=0, alt=0 constraint¶
Let's refit, but ignore the constraint that launch happens at t=0
df = baro[baro.index > 0].copy()
# Convert index to a NumPy array for fitting
time = df.index.to_numpy()
altitude = df['altitude'].to_numpy()
# Fit a parabola (quadratic polynomial): altitude = a*t^2 + b*t + c
coeffs = np.polyfit(time, altitude, deg=2)
fit_fn = np.poly1d(coeffs)
# Generate a smooth time range for plotting
time_smooth = np.linspace(time.min(), time.max(), 500)
altitude_fit = fit_fn(time_smooth)
# Plot the original data and the fit
plt.figure(figsize=(8, 5))
plt.scatter(time, altitude, label='Data', color='blue')
plt.plot(time_smooth, altitude_fit, label='Parabolic Fit', color='red')
plt.xlabel('Time (s)')
plt.ylabel('Altitude (m)')
plt.title('Parabolic Fit to Ballistic Path')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.show()
print(f"Parabolic parameters: {coeffs}")
Parabolic parameters: [-3.91550484 26.16052127 9.55723449]
This looks better - the path is still somewhat asymetric, which isn't totally unexpected considering increased tumbling during descent phase. Unfortunately this doesn't fit our delay hypothesis, as in fact it predicts a launch time prior to what we know to be the actual time.
a, b, c = coeffs
discriminant = b**2 - 4*a*c
t1 = (-b + np.sqrt(discriminant)) / (2*a)
t2 = (-b - np.sqrt(discriminant)) / (2*a)
print(f"X-intercepts (time when altitude = 0): {t1:.2f}s and {t2:.2f}s")
X-intercepts (time when altitude = 0): -0.35s and 7.03s