Skip to content

Commit 11912f3

Browse files
committed
DOC: updating 3 dof documentation and corresponding index.rst
- DOC: added 3 dof and 6 dof comparison analysis to three_dof_simulation.rst - DOC: updated iusers/index.rst to build three_dof_simulation.rst - MNT: deleted the bella_lui_3dof_vs_6dof_comparison.ipynb as the doc now covers this section
1 parent b7eb899 commit 11912f3

3 files changed

Lines changed: 318 additions & 1198 deletions

File tree

docs/examples/bella_lui_3dof_vs_6dof_comparison.ipynb

Lines changed: 0 additions & 1188 deletions
This file was deleted.

docs/user/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ RocketPy's User Guide
2828
Air Brakes Example <airbrakes.rst>
2929
../notebooks/sensors.ipynb
3030
../matlab/matlab.rst
31-
31+
3 DOF Simulations and comparison<three_dof_simulation.rst>
3232
.. toctree::
3333
:maxdepth: 2
3434
:caption: Monte Carlo Simulations

docs/user/three_dof_simulation.rst

Lines changed: 317 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,316 @@ Here's a complete 3-DOF simulation from start to finish:
332332

333333
flight.plots.trajectory_3d()
334334

335+
Weathercocking Model
336+
--------------------
337+
338+
RocketPy's 3-DOF simulation mode includes a weathercocking model that allows
339+
the rocket's attitude to evolve during flight. This feature simulates how a
340+
statically stable rocket naturally aligns with the relative wind direction.
341+
342+
Understanding Weathercocking
343+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
344+
345+
Weathercocking is the tendency of a rocket to align its body axis with the
346+
direction of the relative wind. In reality, this occurs due to aerodynamic
347+
restoring moments from fins and other stabilizing surfaces. The 3-DOF
348+
weathercocking model provides a simplified representation of this behavior
349+
without requiring full 6-DOF rotational dynamics.
350+
351+
The ``weathercock_coeff`` Parameter
352+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
353+
354+
The weathercocking behavior is controlled by the ``weathercock_coeff`` parameter
355+
in the :class:`rocketpy.Flight` class:
356+
357+
.. jupyter-execute::
358+
359+
from rocketpy import Environment, PointMassMotor, PointMassRocket, Flight
360+
361+
env = Environment(
362+
latitude=32.990254,
363+
longitude=-106.974998,
364+
elevation=1400
365+
)
366+
env.set_atmospheric_model(type="StandardAtmosphere")
367+
368+
motor = PointMassMotor(
369+
thrust_source=1500,
370+
dry_mass=1.5,
371+
propellant_initial_mass=2.5,
372+
burn_time=3.5,
373+
)
374+
375+
rocket = PointMassRocket(
376+
radius=0.078,
377+
mass=15.0,
378+
center_of_mass_without_motor=0.0,
379+
power_off_drag=0.43,
380+
power_on_drag=0.43,
381+
)
382+
rocket.add_motor(motor, position=0)
383+
384+
# Flight with weathercocking enabled
385+
flight = Flight(
386+
rocket=rocket,
387+
environment=env,
388+
rail_length=4.2,
389+
inclination=85,
390+
heading=45,
391+
simulation_mode="3 DOF",
392+
weathercock_coeff=1.0, # Default value
393+
)
394+
395+
print(f"Apogee: {flight.apogee - env.elevation:.2f} m")
396+
397+
The ``weathercock_coeff`` parameter controls the rate at which the rocket
398+
aligns with the relative wind:
399+
400+
- ``weathercock_coeff=0``: No weathercocking (original fixed-attitude behavior)
401+
- ``weathercock_coeff=1.0``: Default moderate alignment rate
402+
- ``weathercock_coeff>1.0``: Faster alignment (more stable rocket)
403+
404+
Effect of Weathercocking Coefficient
405+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
406+
407+
Higher values of ``weathercock_coeff`` result in faster alignment with the
408+
relative wind. This affects the lateral motion and impact point:
409+
410+
.. list-table:: Weathercocking Coefficient Effects
411+
:header-rows: 1
412+
:widths: 25 25 50
413+
414+
* - Coefficient
415+
- Alignment Speed
416+
- Typical Use Case
417+
* - 0
418+
- None (fixed attitude)
419+
- Original 3-DOF behavior
420+
* - 1.0
421+
- Moderate
422+
- Default, general purpose
423+
* - 2.0-5.0
424+
- Fast
425+
- Highly stable rockets
426+
* - >5.0
427+
- Very fast
428+
- Rockets with large fins
429+
430+
3-DOF vs 6-DOF Comparison Results
431+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
432+
433+
The following example compares a 6-DOF simulation using the full Bella Lui rocket
434+
with 3-DOF simulations using ``PointMassRocket`` and different weathercocking
435+
coefficients. This demonstrates the trade-off between computational speed and
436+
accuracy.
437+
438+
**Setup the simulations:**
439+
440+
.. jupyter-execute::
441+
442+
import numpy as np
443+
import time
444+
from rocketpy import Environment, Flight, Rocket, SolidMotor
445+
from rocketpy.rocket.point_mass_rocket import PointMassRocket
446+
from rocketpy.motors.point_mass_motor import PointMassMotor
447+
448+
# Environment
449+
env = Environment(
450+
gravity=9.81,
451+
latitude=47.213476,
452+
longitude=9.003336,
453+
elevation=407,
454+
)
455+
env.set_atmospheric_model(type="StandardAtmosphere")
456+
env.max_expected_height = 2000
457+
458+
# Full 6-DOF Motor
459+
motor_6dof = SolidMotor(
460+
thrust_source="../data/motors/aerotech/AeroTech_K828FJ.eng",
461+
burn_time=2.43,
462+
dry_mass=1,
463+
dry_inertia=(0, 0, 0),
464+
center_of_dry_mass_position=0,
465+
grains_center_of_mass_position=-1,
466+
grain_number=3,
467+
grain_separation=0.003,
468+
grain_density=782.4,
469+
grain_outer_radius=0.042799,
470+
grain_initial_inner_radius=0.033147,
471+
grain_initial_height=0.1524,
472+
nozzle_radius=0.04445,
473+
throat_radius=0.0214376,
474+
nozzle_position=-1.1356,
475+
)
476+
477+
# Full 6-DOF Rocket
478+
rocket_6dof = Rocket(
479+
radius=0.078,
480+
mass=17.227,
481+
inertia=(0.78267, 0.78267, 0.064244),
482+
power_off_drag=0.43,
483+
power_on_drag=0.43,
484+
center_of_mass_without_motor=0,
485+
)
486+
rocket_6dof.set_rail_buttons(0.1, -0.5)
487+
rocket_6dof.add_motor(motor_6dof, -1.1356)
488+
rocket_6dof.add_nose(length=0.242, kind="tangent", position=1.542)
489+
rocket_6dof.add_trapezoidal_fins(3, span=0.200, root_chord=0.280, tip_chord=0.125, position=-0.75)
490+
491+
# Point Mass Motor for 3-DOF
492+
motor_3dof = PointMassMotor(
493+
thrust_source="../data/motors/aerotech/AeroTech_K828FJ.eng",
494+
dry_mass=1.0,
495+
propellant_initial_mass=1.373,
496+
)
497+
498+
# Point Mass Rocket for 3-DOF
499+
rocket_3dof = PointMassRocket(
500+
radius=0.078,
501+
mass=17.227,
502+
center_of_mass_without_motor=0,
503+
power_off_drag=0.43,
504+
power_on_drag=0.43,
505+
)
506+
rocket_3dof.add_motor(motor_3dof, -1.1356)
507+
508+
**Run simulations and compare results:**
509+
510+
.. jupyter-execute::
511+
512+
# 6-DOF Flight
513+
start = time.time()
514+
flight_6dof = Flight(
515+
rocket=rocket_6dof,
516+
environment=env,
517+
rail_length=4.2,
518+
inclination=89,
519+
heading=45,
520+
terminate_on_apogee=True,
521+
)
522+
time_6dof = time.time() - start
523+
524+
# 3-DOF with no weathercocking
525+
start = time.time()
526+
flight_3dof_0 = Flight(
527+
rocket=rocket_3dof,
528+
environment=env,
529+
rail_length=4.2,
530+
inclination=89,
531+
heading=45,
532+
terminate_on_apogee=True,
533+
simulation_mode="3 DOF",
534+
weathercock_coeff=0.0,
535+
)
536+
time_3dof_0 = time.time() - start
537+
538+
# 3-DOF with default weathercocking
539+
start = time.time()
540+
flight_3dof_1 = Flight(
541+
rocket=rocket_3dof,
542+
environment=env,
543+
rail_length=4.2,
544+
inclination=89,
545+
heading=45,
546+
terminate_on_apogee=True,
547+
simulation_mode="3 DOF",
548+
weathercock_coeff=1.0,
549+
)
550+
time_3dof_1 = time.time() - start
551+
552+
# 3-DOF with high weathercocking
553+
start = time.time()
554+
flight_3dof_5 = Flight(
555+
rocket=rocket_3dof,
556+
environment=env,
557+
rail_length=4.2,
558+
inclination=89,
559+
heading=45,
560+
terminate_on_apogee=True,
561+
simulation_mode="3 DOF",
562+
weathercock_coeff=5.0,
563+
)
564+
time_3dof_5 = time.time() - start
565+
566+
# Print comparison table
567+
print("=" * 80)
568+
print("SIMULATION RESULTS COMPARISON")
569+
print("=" * 80)
570+
print("\n{:<30} {:>12} {:>12} {:>12} {:>12}".format(
571+
"Parameter", "6-DOF", "3DOF(wc=0)", "3DOF(wc=1)", "3DOF(wc=5)"
572+
))
573+
print("-" * 80)
574+
print("{:<30} {:>12.2f} {:>12.2f} {:>12.2f} {:>12.2f}".format(
575+
"Apogee (m AGL)",
576+
flight_6dof.apogee - env.elevation,
577+
flight_3dof_0.apogee - env.elevation,
578+
flight_3dof_1.apogee - env.elevation,
579+
flight_3dof_5.apogee - env.elevation,
580+
))
581+
print("{:<30} {:>12.2f} {:>12.2f} {:>12.2f} {:>12.2f}".format(
582+
"Apogee Time (s)",
583+
flight_6dof.apogee_time,
584+
flight_3dof_0.apogee_time,
585+
flight_3dof_1.apogee_time,
586+
flight_3dof_5.apogee_time,
587+
))
588+
print("{:<30} {:>12.2f} {:>12.2f} {:>12.2f} {:>12.2f}".format(
589+
"Max Speed (m/s)",
590+
flight_6dof.max_speed,
591+
flight_3dof_0.max_speed,
592+
flight_3dof_1.max_speed,
593+
flight_3dof_5.max_speed,
594+
))
595+
print("{:<30} {:>12.3f} {:>12.3f} {:>12.3f} {:>12.3f}".format(
596+
"Runtime (s)",
597+
time_6dof,
598+
time_3dof_0,
599+
time_3dof_1,
600+
time_3dof_5,
601+
))
602+
print("-" * 80)
603+
print("Speedup vs 6-DOF: {:>12} {:>12.1f}x {:>12.1f}x {:>12.1f}x".format(
604+
"-",
605+
time_6dof / time_3dof_0 if time_3dof_0 > 0 else 0,
606+
time_6dof / time_3dof_1 if time_3dof_1 > 0 else 0,
607+
time_6dof / time_3dof_5 if time_3dof_5 > 0 else 0,
608+
))
609+
610+
**3D Trajectory Comparison:**
611+
612+
.. jupyter-execute::
613+
614+
import matplotlib.pyplot as plt
615+
from mpl_toolkits.mplot3d import Axes3D
616+
617+
fig = plt.figure(figsize=(12, 8))
618+
ax = fig.add_subplot(111, projection="3d")
619+
620+
# Plot all trajectories
621+
ax.plot(flight_6dof.x[:, 1], flight_6dof.y[:, 1], flight_6dof.z[:, 1] - env.elevation,
622+
"b-", linewidth=2, label="6-DOF")
623+
ax.plot(flight_3dof_0.x[:, 1], flight_3dof_0.y[:, 1], flight_3dof_0.z[:, 1] - env.elevation,
624+
"r--", linewidth=2, label="3-DOF (wc=0)")
625+
ax.plot(flight_3dof_1.x[:, 1], flight_3dof_1.y[:, 1], flight_3dof_1.z[:, 1] - env.elevation,
626+
"g--", linewidth=2, label="3-DOF (wc=1)")
627+
ax.plot(flight_3dof_5.x[:, 1], flight_3dof_5.y[:, 1], flight_3dof_5.z[:, 1] - env.elevation,
628+
"m--", linewidth=2, label="3-DOF (wc=5)")
629+
630+
ax.set_xlabel("X (m)")
631+
ax.set_ylabel("Y (m)")
632+
ax.set_zlabel("Altitude AGL (m)")
633+
ax.set_title("3-DOF vs 6-DOF Trajectory Comparison with Weathercocking")
634+
ax.legend()
635+
plt.tight_layout()
636+
plt.show()
637+
638+
The results show that:
639+
640+
- **3-DOF is 5-7x faster** than 6-DOF simulations
641+
- **Apogee prediction** is within 1-3% of 6-DOF
642+
- **Weathercocking** improves trajectory accuracy by aligning the rocket with relative wind
643+
- **Higher weathercock_coeff** values result in trajectories closer to 6-DOF
644+
335645
Comparison: 3-DOF vs 6-DOF
336646
---------------------------
337647

@@ -345,10 +655,10 @@ Understanding the differences between simulation modes:
345655
- 3-DOF
346656
- 6-DOF
347657
* - Computational Speed
348-
- Fast
349-
- Slower
658+
- 5-7x faster
659+
- Slower (more accurate)
350660
* - Rocket Orientation
351-
- Fixed (no rotation)
661+
- Weathercocking model
352662
- Full attitude dynamics
353663
* - Stability Analysis
354664
- ❌ Not available
@@ -363,10 +673,10 @@ Understanding the differences between simulation modes:
363673
- ❌ Not needed
364674
- ✅ Required
365675
* - Use Cases
366-
- Quick estimates, education
676+
- Quick estimates, Monte Carlo
367677
- Detailed design, stability
368678
* - Trajectory Accuracy
369-
- Good for stable rockets
679+
- Good (~1.5% error)
370680
- Highly accurate
371681

372682
Best Practices
@@ -393,8 +703,7 @@ Limitations and Warnings
393703

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

399708
.. warning::
400709

@@ -412,7 +721,6 @@ See Also
412721
- :ref:`First Simulation <firstsimulation>` - Standard 6-DOF simulation tutorial
413722
- :ref:`Rocket Class Usage <rocketusage>` - Full rocket modeling capabilities
414723
- :ref:`Flight Class Usage <flightusage>` - Complete flight simulation options
415-
- :doc:`../examples/3_dof_trial_sim` - Jupyter notebook example
416724

417725
Further Reading
418726
---------------
@@ -421,4 +729,4 @@ For more information about point mass trajectory simulations:
421729

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

0 commit comments

Comments
 (0)