Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7b34022
ENH: addition of bella lui based 3 dof and 6 dof comparison notebook
aZira371 Nov 27, 2025
3e4423f
ENH: addition of weathercocking model to flight.py
aZira371 Nov 27, 2025
ef1d003
ENH: added tests for weathercocking to test_flight_3dof.py
aZira371 Nov 27, 2025
194943a
DOC: updating 3 dof documentation and corresponding index.rst
aZira371 Nov 27, 2025
7cd0050
MNT: corrections to test_flight_3dof.py
aZira371 Nov 27, 2025
5ff03cd
MNT: docstring corrections to flight.py around new weathercocking imp…
aZira371 Nov 27, 2025
14d199d
BUG: correction of singularity bug during align on vectors in weather…
aZira371 Nov 27, 2025
fc4228c
MNT: updating location of 3 dof doc in users index.rst
aZira371 Nov 27, 2025
a564397
DOC: three_dof_simulation.rst update to add explanation of weather co…
aZira371 Nov 30, 2025
174efa9
MNT: changed default value of weather_coeff in flight.py and added fi…
aZira371 Nov 30, 2025
c6b8efe
MNT: shifting test_flight_dof.py to integration tests.
aZira371 Nov 30, 2025
9afa353
MNT: docsrting update in test_flight_3dof.py
aZira371 Dec 1, 2025
a179962
MNT: Update of docstring in test_flight_3dof.py
aZira371 Dec 1, 2025
dc18ed8
DOC: Update of three_dof_simulation.rst
aZira371 Dec 1, 2025
d5b9f37
Update tests/integration/simulation/test_flight_3dof.py
aZira371 Dec 1, 2025
3d1a6ed
Docstring Update tests/integration/simulation/test_flight_3dof.py
aZira371 Dec 3, 2025
b1e6212
docstring Update tests/integration/simulation/test_flight_3dof.py
aZira371 Dec 3, 2025
8b35366
docstring Update docs/user/three_dof_simulation.rst
aZira371 Dec 3, 2025
f3f3b0a
Docstring Update rocketpy/simulation/flight.py
aZira371 Dec 3, 2025
90acba7
MNT: Docstring updates to various files related to 3 dof
aZira371 Dec 3, 2025
b309d5e
MNT: unit vector edge case check in flight.py
aZira371 Dec 3, 2025
b1eb6cb
DOC: Add note about motor file paths in 3-DOF comparison section (#902)
Copilot Dec 3, 2025
70c6b5f
MNT: eliminate quaternion derivative code duplication in u_dot_genera…
Copilot Dec 3, 2025
0e104ff
Merge branch 'develop' into enh/3-dof-lateral-motion-improvement
aZira371 Dec 3, 2025
3693e5e
DOC: CHANGELOG.md update to reflect implementation of 3 dof lateral m…
aZira371 Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/user/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ RocketPy's User Guide

Installation and Requirements <installation.rst>
First Simulation <first_simulation.rst>
3-DOF Simulations <three_dof_simulation.rst>
3 DOF Simulations and comparison <three_dof_simulation.rst>
Comment thread
aZira371 marked this conversation as resolved.
Outdated

.. toctree::
:maxdepth: 1
Expand Down
325 changes: 317 additions & 8 deletions docs/user/three_dof_simulation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,316 @@ Here's a complete 3-DOF simulation from start to finish:

flight.plots.trajectory_3d()

Weathercocking Model
--------------------

RocketPy's 3-DOF simulation mode includes a weathercocking model that allows
the rocket's attitude to evolve during flight. This feature simulates how a
statically stable rocket naturally aligns with the relative wind direction.

Understanding Weathercocking
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Weathercocking is the tendency of a rocket to align its body axis with the
direction of the relative wind. In reality, this occurs due to aerodynamic
restoring moments from fins and other stabilizing surfaces. The 3-DOF
weathercocking model provides a simplified representation of this behavior
without requiring full 6-DOF rotational dynamics.

The ``weathercock_coeff`` Parameter
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The weathercocking behavior is controlled by the ``weathercock_coeff`` parameter
in the :class:`rocketpy.Flight` class:

.. jupyter-execute::

from rocketpy import Environment, PointMassMotor, PointMassRocket, Flight

env = Environment(
latitude=32.990254,
longitude=-106.974998,
elevation=1400
)
env.set_atmospheric_model(type="StandardAtmosphere")

motor = PointMassMotor(
thrust_source=1500,
dry_mass=1.5,
propellant_initial_mass=2.5,
burn_time=3.5,
)

rocket = PointMassRocket(
radius=0.078,
mass=15.0,
center_of_mass_without_motor=0.0,
power_off_drag=0.43,
power_on_drag=0.43,
)
rocket.add_motor(motor, position=0)

# Flight with weathercocking enabled
flight = Flight(
rocket=rocket,
environment=env,
rail_length=4.2,
inclination=85,
heading=45,
simulation_mode="3 DOF",
weathercock_coeff=1.0, # Default value
Comment thread
aZira371 marked this conversation as resolved.
Outdated
)

print(f"Apogee: {flight.apogee - env.elevation:.2f} m")

The ``weathercock_coeff`` parameter controls the rate at which the rocket
aligns with the relative wind:

- ``weathercock_coeff=0``: No weathercocking (original fixed-attitude behavior)
- ``weathercock_coeff=1.0``: Default moderate alignment rate
Comment thread
aZira371 marked this conversation as resolved.
Outdated
- ``weathercock_coeff>1.0``: Faster alignment (more stable rocket)

Effect of Weathercocking Coefficient
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Higher values of ``weathercock_coeff`` result in faster alignment with the
relative wind. This affects the lateral motion and impact point:

.. list-table:: Weathercocking Coefficient Effects
Comment thread
aZira371 marked this conversation as resolved.
:header-rows: 1
:widths: 25 25 50

* - Coefficient
- Alignment Speed
- Typical Use Case
* - 0
- None (fixed attitude)
- Original 3-DOF behavior
* - 1.0
- Moderate
- Default, general purpose
Comment thread
aZira371 marked this conversation as resolved.
Outdated
* - 2.0-5.0
- Fast
- Highly stable rockets
* - >5.0
- Very fast
- Rockets with large fins

3-DOF vs 6-DOF Comparison Results
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The following example compares a 6-DOF simulation using the full Bella Lui rocket
with 3-DOF simulations using ``PointMassRocket`` and different weathercocking
coefficients. This demonstrates the trade-off between computational speed and
accuracy.

**Setup the simulations:**

.. jupyter-execute::

import numpy as np
import time
from rocketpy import Environment, Flight, Rocket, SolidMotor
from rocketpy.rocket.point_mass_rocket import PointMassRocket
from rocketpy.motors.point_mass_motor import PointMassMotor

# Environment
env = Environment(
gravity=9.81,
latitude=47.213476,
longitude=9.003336,
elevation=407,
)
env.set_atmospheric_model(type="StandardAtmosphere")
env.max_expected_height = 2000

# Full 6-DOF Motor
motor_6dof = SolidMotor(
thrust_source="../data/motors/aerotech/AeroTech_K828FJ.eng",
Comment thread
aZira371 marked this conversation as resolved.
burn_time=2.43,
dry_mass=1,
dry_inertia=(0, 0, 0),
center_of_dry_mass_position=0,
grains_center_of_mass_position=-1,
grain_number=3,
grain_separation=0.003,
grain_density=782.4,
grain_outer_radius=0.042799,
grain_initial_inner_radius=0.033147,
grain_initial_height=0.1524,
nozzle_radius=0.04445,
throat_radius=0.0214376,
nozzle_position=-1.1356,
)

# Full 6-DOF Rocket
rocket_6dof = Rocket(
radius=0.078,
mass=17.227,
inertia=(0.78267, 0.78267, 0.064244),
power_off_drag=0.43,
power_on_drag=0.43,
center_of_mass_without_motor=0,
)
rocket_6dof.set_rail_buttons(0.1, -0.5)
rocket_6dof.add_motor(motor_6dof, -1.1356)
rocket_6dof.add_nose(length=0.242, kind="tangent", position=1.542)
rocket_6dof.add_trapezoidal_fins(3, span=0.200, root_chord=0.280, tip_chord=0.125, position=-0.75)

# Point Mass Motor for 3-DOF
motor_3dof = PointMassMotor(
thrust_source="../data/motors/aerotech/AeroTech_K828FJ.eng",
dry_mass=1.0,
propellant_initial_mass=1.373,
)

# Point Mass Rocket for 3-DOF
rocket_3dof = PointMassRocket(
radius=0.078,
mass=17.227,
center_of_mass_without_motor=0,
power_off_drag=0.43,
power_on_drag=0.43,
)
rocket_3dof.add_motor(motor_3dof, -1.1356)

**Run simulations and compare results:**

.. jupyter-execute::

# 6-DOF Flight
start = time.time()
flight_6dof = Flight(
rocket=rocket_6dof,
environment=env,
rail_length=4.2,
inclination=89,
heading=45,
terminate_on_apogee=True,
)
time_6dof = time.time() - start

# 3-DOF with no weathercocking
start = time.time()
flight_3dof_0 = Flight(
rocket=rocket_3dof,
environment=env,
rail_length=4.2,
inclination=89,
heading=45,
terminate_on_apogee=True,
simulation_mode="3 DOF",
weathercock_coeff=0.0,
)
time_3dof_0 = time.time() - start

# 3-DOF with default weathercocking
start = time.time()
flight_3dof_1 = Flight(
rocket=rocket_3dof,
environment=env,
rail_length=4.2,
inclination=89,
heading=45,
terminate_on_apogee=True,
simulation_mode="3 DOF",
weathercock_coeff=1.0,
)
time_3dof_1 = time.time() - start

# 3-DOF with high weathercocking
start = time.time()
flight_3dof_5 = Flight(
rocket=rocket_3dof,
environment=env,
rail_length=4.2,
inclination=89,
heading=45,
terminate_on_apogee=True,
simulation_mode="3 DOF",
weathercock_coeff=5.0,
)
time_3dof_5 = time.time() - start

# Print comparison table
print("=" * 80)
print("SIMULATION RESULTS COMPARISON")
print("=" * 80)
print("\n{:<30} {:>12} {:>12} {:>12} {:>12}".format(
"Parameter", "6-DOF", "3DOF(wc=0)", "3DOF(wc=1)", "3DOF(wc=5)"
))
print("-" * 80)
print("{:<30} {:>12.2f} {:>12.2f} {:>12.2f} {:>12.2f}".format(
"Apogee (m AGL)",
flight_6dof.apogee - env.elevation,
flight_3dof_0.apogee - env.elevation,
flight_3dof_1.apogee - env.elevation,
flight_3dof_5.apogee - env.elevation,
))
print("{:<30} {:>12.2f} {:>12.2f} {:>12.2f} {:>12.2f}".format(
"Apogee Time (s)",
flight_6dof.apogee_time,
flight_3dof_0.apogee_time,
flight_3dof_1.apogee_time,
flight_3dof_5.apogee_time,
))
print("{:<30} {:>12.2f} {:>12.2f} {:>12.2f} {:>12.2f}".format(
"Max Speed (m/s)",
flight_6dof.max_speed,
flight_3dof_0.max_speed,
flight_3dof_1.max_speed,
flight_3dof_5.max_speed,
))
print("{:<30} {:>12.3f} {:>12.3f} {:>12.3f} {:>12.3f}".format(
"Runtime (s)",
time_6dof,
time_3dof_0,
time_3dof_1,
time_3dof_5,
))
print("-" * 80)
print("Speedup vs 6-DOF: {:>12} {:>12.1f}x {:>12.1f}x {:>12.1f}x".format(
"-",
time_6dof / time_3dof_0 if time_3dof_0 > 0 else 0,
time_6dof / time_3dof_1 if time_3dof_1 > 0 else 0,
time_6dof / time_3dof_5 if time_3dof_5 > 0 else 0,
))

**3D Trajectory Comparison:**

.. jupyter-execute::

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D

fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection="3d")

# Plot all trajectories
ax.plot(flight_6dof.x[:, 1], flight_6dof.y[:, 1], flight_6dof.z[:, 1] - env.elevation,
"b-", linewidth=2, label="6-DOF")
ax.plot(flight_3dof_0.x[:, 1], flight_3dof_0.y[:, 1], flight_3dof_0.z[:, 1] - env.elevation,
"r--", linewidth=2, label="3-DOF (wc=0)")
ax.plot(flight_3dof_1.x[:, 1], flight_3dof_1.y[:, 1], flight_3dof_1.z[:, 1] - env.elevation,
"g--", linewidth=2, label="3-DOF (wc=1)")
ax.plot(flight_3dof_5.x[:, 1], flight_3dof_5.y[:, 1], flight_3dof_5.z[:, 1] - env.elevation,
"m--", linewidth=2, label="3-DOF (wc=5)")

ax.set_xlabel("X (m)")
ax.set_ylabel("Y (m)")
ax.set_zlabel("Altitude AGL (m)")
ax.set_title("3-DOF vs 6-DOF Trajectory Comparison with Weathercocking")
ax.legend()
plt.tight_layout()
plt.show()

The results show that:

- **3-DOF is 5-7x faster** than 6-DOF simulations
- **Apogee prediction** is within 1-3% of 6-DOF
- **Weathercocking** improves trajectory accuracy by aligning the rocket with relative wind
- **Higher weathercock_coeff** values result in trajectories closer to 6-DOF

Comparison: 3-DOF vs 6-DOF
---------------------------

Expand All @@ -353,10 +663,10 @@ Understanding the differences between simulation modes:
- 3-DOF
- 6-DOF
* - Computational Speed
- Fast
- Slower
- 5-7x faster
- Slower (more accurate)
* - Rocket Orientation
- Fixed (no rotation)
- Weathercocking model
- Full attitude dynamics
* - Stability Analysis
- ❌ Not available
Expand All @@ -371,10 +681,10 @@ Understanding the differences between simulation modes:
- ❌ Not needed
- ✅ Required
* - Use Cases
- Quick estimates, education
- Quick estimates, Monte Carlo
- Detailed design, stability
* - Trajectory Accuracy
- Good for stable rockets
- Good (~1.5% error)
- Highly accurate

Best Practices
Expand All @@ -401,8 +711,7 @@ Limitations and Warnings

- **No stability checking** - The simulation cannot detect unstable rockets
- **No attitude control** - Air brakes and thrust vectoring are not supported
- **Assumes perfect alignment** - Rocket always points along velocity vector
- **No wind weathercocking** - Wind effects on orientation are ignored
- **Simplified weathercocking** - Uses proportional alignment model, not full dynamics

.. warning::

Expand All @@ -428,4 +737,4 @@ For more information about point mass trajectory simulations:

- `Trajectory Optimization <https://en.wikipedia.org/wiki/Trajectory_optimization>`_
- `Equations of Motion <https://en.wikipedia.org/wiki/Equations_of_motion>`_
- `Point Mass Model <https://www.grc.nasa.gov/www/k-12/airplane/flteqs.html>`_
- `Point Mass Model <https://www.grc.nasa.gov/www/k-12/airplane/flteqs.html>`_
Loading