Skip to content

Commit ad7e6d0

Browse files
committed
DOC: Add comprehensive documentation for acceleration-based parachute triggers
- Created docs/user/parachute_triggers.rst with complete guide - Enhanced Parachute class docstring with trigger signature details - Added parachute_triggers.rst to docs/user/index.rst Documentation covers: - Built-in triggers (burnout, apogee_acc, freefall, liftoff) - Custom trigger examples (3, 4, and 5-parameter signatures) - IMU noise simulation - Performance considerations - Best practices and complete dual-deploy example
1 parent a7f5c3a commit ad7e6d0

3 files changed

Lines changed: 367 additions & 22 deletions

File tree

docs/user/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ RocketPy's User Guide
2424
:caption: Special Case Simulations
2525

2626
Compare Flights Class<compare_flights.rst>
27+
Parachute Triggers (Acceleration-Based) <parachute_triggers.rst>
2728
Deployable Payload <deployable.rst>
2829
Air Brakes Example <airbrakes.rst>
2930
../notebooks/sensors.ipynb

docs/user/parachute_triggers.rst

Lines changed: 329 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,329 @@
1+
Acceleration-Based Parachute Triggers
2+
======================================
3+
4+
RocketPy supports advanced parachute deployment logic using acceleration data
5+
from simulated IMU (Inertial Measurement Unit) sensors. This enables realistic
6+
avionics algorithms that mimic real-world flight computers.
7+
8+
Overview
9+
--------
10+
11+
Traditional parachute triggers rely on altitude and velocity. Acceleration-based
12+
triggers provide additional capabilities:
13+
14+
- **Motor burnout detection**: Detect thrust termination via sudden deceleration
15+
- **Apogee detection**: Use acceleration and velocity together for precise apogee
16+
- **Freefall detection**: Identify ballistic coasting phases
17+
- **Liftoff detection**: Confirm motor ignition via high acceleration
18+
19+
These triggers can optionally include sensor noise to simulate realistic IMU
20+
behavior, making simulations more representative of actual flight conditions.
21+
22+
Built-in Triggers
23+
-----------------
24+
25+
RocketPy provides four built-in acceleration-based triggers:
26+
27+
Motor Burnout Detection
28+
~~~~~~~~~~~~~~~~~~~~~~~~
29+
30+
Detects when the motor stops producing thrust by monitoring sudden drops in
31+
acceleration magnitude.
32+
33+
.. code-block:: python
34+
35+
from rocketpy import Parachute
36+
37+
drogue = Parachute(
38+
name="Drogue",
39+
cd_s=1.0,
40+
trigger="burnout", # Built-in trigger
41+
sampling_rate=100,
42+
lag=1.5
43+
)
44+
45+
**Detection criteria:**
46+
- Vertical acceleration < -8.0 m/s² (end of thrust phase), OR
47+
- Total acceleration magnitude < 2.0 m/s² (coasting detected)
48+
- Rocket must be above 5m altitude and ascending (prevents false triggers at launch)
49+
50+
Apogee Detection
51+
~~~~~~~~~~~~~~~~
52+
53+
Detects apogee using both near-zero vertical velocity and negative vertical
54+
acceleration.
55+
56+
.. code-block:: python
57+
58+
main = Parachute(
59+
name="Main",
60+
cd_s=10.0,
61+
trigger="apogee_acc", # Acceleration-based apogee
62+
sampling_rate=100,
63+
lag=0.5
64+
)
65+
66+
**Detection criteria:**
67+
- Absolute vertical velocity < 1.0 m/s
68+
- Vertical acceleration < -0.1 m/s² (downward)
69+
70+
Freefall Detection
71+
~~~~~~~~~~~~~~~~~~
72+
73+
Detects free-fall by monitoring very low total acceleration (near gravitational
74+
acceleration only).
75+
76+
.. code-block:: python
77+
78+
drogue = Parachute(
79+
name="Drogue",
80+
cd_s=1.0,
81+
trigger="freefall",
82+
sampling_rate=100,
83+
lag=1.0
84+
)
85+
86+
**Detection criteria:**
87+
- Total acceleration magnitude < 11.5 m/s²
88+
- Rocket descending (vz < -0.2 m/s)
89+
- Altitude > 5m (prevents ground-level false triggers)
90+
91+
Liftoff Detection
92+
~~~~~~~~~~~~~~~~~
93+
94+
Detects motor ignition via high total acceleration.
95+
96+
.. code-block:: python
97+
98+
test_parachute = Parachute(
99+
name="Test",
100+
cd_s=0.5,
101+
trigger="liftoff",
102+
sampling_rate=100,
103+
lag=0.0
104+
)
105+
106+
**Detection criteria:**
107+
- Total acceleration magnitude > 15.0 m/s²
108+
109+
Custom Triggers
110+
---------------
111+
112+
You can create custom triggers that use acceleration data:
113+
114+
.. code-block:: python
115+
116+
def custom_trigger(pressure, height, state_vector, u_dot):
117+
"""
118+
Custom trigger using acceleration data.
119+
120+
Parameters
121+
----------
122+
pressure : float
123+
Atmospheric pressure in Pa (with optional noise)
124+
height : float
125+
Height above ground level in meters (with optional noise)
126+
state_vector : array
127+
[x, y, z, vx, vy, vz, e0, e1, e2, e3, wx, wy, wz]
128+
u_dot : array
129+
Derivative: [vx, vy, vz, ax, ay, az, e0_dot, ...]
130+
Accelerations are at indices [3:6]
131+
132+
Returns
133+
-------
134+
bool
135+
True to trigger parachute deployment
136+
"""
137+
# Extract acceleration components (m/s²)
138+
ax = u_dot[3]
139+
ay = u_dot[4]
140+
az = u_dot[5]
141+
142+
# Calculate total acceleration magnitude
143+
total_acc = (ax**2 + ay**2 + az**2)**0.5
144+
145+
# Custom logic: deploy if total acceleration < 5 m/s² while descending
146+
vz = state_vector[5]
147+
return total_acc < 5.0 and vz < -10.0
148+
149+
# Use custom trigger
150+
parachute = Parachute(
151+
name="Custom",
152+
cd_s=2.0,
153+
trigger=custom_trigger,
154+
sampling_rate=100,
155+
lag=1.0
156+
)
157+
158+
Sensor and Acceleration Triggers
159+
---------------------------------
160+
161+
Triggers can also accept sensor data alongside acceleration:
162+
163+
.. code-block:: python
164+
165+
def advanced_trigger(pressure, height, state_vector, sensors, u_dot):
166+
"""
167+
Advanced trigger using both sensors and acceleration.
168+
169+
Parameters
170+
----------
171+
sensors : list
172+
List of sensor objects attached to the rocket
173+
u_dot : array
174+
State derivative including accelerations
175+
176+
Returns
177+
-------
178+
bool
179+
"""
180+
# Access sensor measurements
181+
if len(sensors) > 0:
182+
imu_reading = sensors[0].measurement
183+
184+
# Use acceleration data
185+
az = u_dot[5]
186+
187+
# Combine sensor and acceleration logic
188+
return az < -5.0 and imu_reading > threshold
189+
190+
parachute = Parachute(
191+
name="Advanced",
192+
cd_s=1.5,
193+
trigger=advanced_trigger,
194+
sampling_rate=100
195+
)
196+
197+
Adding Acceleration Noise
198+
--------------------------
199+
200+
To simulate realistic IMU behavior, you can add noise to acceleration data:
201+
202+
.. code-block:: python
203+
204+
from rocketpy import Flight
205+
206+
flight = Flight(
207+
rocket=my_rocket,
208+
environment=env,
209+
rail_length=5.2,
210+
inclination=85,
211+
heading=0,
212+
acceleration_noise_function=lambda: np.random.normal(0, 0.5, 3)
213+
)
214+
215+
The ``acceleration_noise_function`` returns a 3-element array ``[noise_x, noise_y, noise_z]``
216+
that is added to the acceleration components before passing to the trigger function.
217+
218+
**Example with time-correlated noise:**
219+
220+
.. code-block:: python
221+
222+
class NoiseGenerator:
223+
def __init__(self, stddev=0.5, correlation=0.9):
224+
self.stddev = stddev
225+
self.correlation = correlation
226+
self.last_noise = np.zeros(3)
227+
228+
def __call__(self):
229+
# Time-correlated noise (AR(1) process)
230+
white_noise = np.random.normal(0, self.stddev, 3)
231+
self.last_noise = (self.correlation * self.last_noise +
232+
np.sqrt(1 - self.correlation**2) * white_noise)
233+
return self.last_noise
234+
235+
flight = Flight(
236+
rocket=my_rocket,
237+
environment=env,
238+
rail_length=5.2,
239+
inclination=85,
240+
heading=0,
241+
acceleration_noise_function=NoiseGenerator(stddev=0.3, correlation=0.95)
242+
)
243+
244+
Performance Considerations
245+
--------------------------
246+
247+
Computing acceleration (``u_dot``) requires evaluating the equations of motion,
248+
which adds computational cost. RocketPy optimizes this by:
249+
250+
1. **Lazy evaluation**: ``u_dot`` is only computed if the trigger actually needs it
251+
2. **Metadata detection**: The wrapper inspects trigger signatures to determine requirements
252+
3. **Caching**: Derivative evaluations are reused when possible
253+
254+
**Trigger signature detection:**
255+
256+
- 3 parameters ``(p, h, y)``: Legacy trigger, no ``u_dot`` computed
257+
- 4 parameters with ``u_dot``: Only acceleration computed
258+
- 4 parameters with ``sensors``: Only sensors passed
259+
- 5 parameters: Both sensors and acceleration provided
260+
261+
Best Practices
262+
--------------
263+
264+
1. **Choose appropriate sampling rates**: 50-200 Hz is typical for flight computers
265+
2. **Add realistic noise**: Real IMUs have noise; simulate it for validation
266+
3. **Test edge cases**: Verify triggers work at low altitudes, high speeds, etc.
267+
4. **Use built-in triggers**: They handle edge cases (NaN, Inf) automatically
268+
5. **Document custom triggers**: Include detection criteria in docstrings
269+
270+
Example: Complete Dual-Deploy System
271+
-------------------------------------
272+
273+
.. code-block:: python
274+
275+
from rocketpy import Rocket, Parachute, Flight, Environment
276+
import numpy as np
277+
278+
# Environment and rocket setup
279+
env = Environment(latitude=32.99, longitude=-106.97, elevation=1400)
280+
env.set_atmospheric_model(type="standard_atmosphere")
281+
282+
my_rocket = Rocket(...) # Define your rocket
283+
284+
# Drogue parachute: Deploy at motor burnout
285+
drogue = Parachute(
286+
name="Drogue",
287+
cd_s=1.0,
288+
trigger="burnout",
289+
sampling_rate=100,
290+
lag=1.5,
291+
noise=(0, 8.3, 0.5) # Pressure sensor noise
292+
)
293+
my_rocket.add_parachute(drogue)
294+
295+
# Main parachute: Deploy at 800m using custom trigger
296+
def main_deploy_trigger(pressure, height, state_vector, u_dot):
297+
"""Deploy main at 800m while descending with positive vertical acceleration."""
298+
vz = state_vector[5]
299+
az = u_dot[5]
300+
return height < 800 and vz < -5 and az > -15
301+
302+
main = Parachute(
303+
name="Main",
304+
cd_s=10.0,
305+
trigger=main_deploy_trigger,
306+
sampling_rate=100,
307+
lag=0.5,
308+
noise=(0, 8.3, 0.5)
309+
)
310+
my_rocket.add_parachute(main)
311+
312+
# Flight with IMU noise simulation
313+
flight = Flight(
314+
rocket=my_rocket,
315+
environment=env,
316+
rail_length=5.2,
317+
inclination=85,
318+
heading=0,
319+
acceleration_noise_function=lambda: np.random.normal(0, 0.3, 3)
320+
)
321+
322+
flight.all_info()
323+
324+
See Also
325+
--------
326+
327+
- :doc:`Parachute Class Reference </reference/rocket/parachute>`
328+
- :doc:`Flight Simulation </user/flight>`
329+
- :doc:`Sensors and Controllers </user/sensors>`

0 commit comments

Comments
 (0)