1+ .. _flightcomparator :
2+
13Flight Comparator
24=================
35
4- This example demonstrates how to use the RocketPy ``FlightComparator `` class to
5- compare a Flight simulation against external data sources.
6+ The :class: `rocketpy.simulation.FlightComparator ` class enables users to compare
7+ a RocketPy Flight simulation against external data sources, providing error
8+ metrics and visualization tools for validation and analysis.
9+
10+ .. seealso ::
611
7- Users must explicitly create a `FlightComparator ` instance.
12+ For comparing multiple RocketPy simulations together, see the
13+ :doc: `Compare Flights </user/compare_flights >` guide.
814
15+ Overview
16+ --------
917
1018This class is designed to compare a RocketPy Flight simulation against external
1119data sources, such as:
1220
13- - Real flight data (avionics logs, altimeter CSVs)
14- - Simulations from other software (OpenRocket, RASAero)
15- - Theoretical models or manual calculations
21+ - **Real flight data ** - Avionics logs, altimeter CSVs, GPS tracking data
22+ - **Other simulators ** - OpenRocket, RASAero, or custom simulation tools
23+ - **Theoretical models ** - Analytical solutions or manual calculations
24+
25+ Unlike :class: `rocketpy.plots.compare.CompareFlights ` (which compares multiple
26+ RocketPy simulations), ``FlightComparator `` specifically handles the challenge
27+ of aligning different time steps and calculating error metrics (RMSE, MAE, etc.)
28+ between a "Reference" simulation and "External" data.
29+
30+ Key Features
31+ ------------
32+
33+ - Automatic time-step alignment between different data sources
34+ - Error metric calculations (RMSE, MAE, etc.)
35+ - Side-by-side visualization of flight variables
36+ - Support for multiple external data sources
37+ - Direct comparison with other RocketPy Flight objects
38+
1639
17- Unlike ``CompareFlights `` (which compares multiple RocketPy simulations),
18- ``FlightComparator `` specifically handles the challenge of aligning different
19- time steps and calculating error metrics (RMSE, MAE, etc.) between a
20- "Reference" simulation and "External" data.
40+ Creating a Reference Simulation
41+ --------------------------------
2142
22- Importing classes
23- -----------------
43+ First, import the necessary classes and modules:
2444
25- We will start by importing the necessary classes and modules:
45+ Importing Classes
46+ ~~~~~~~~~~~~~~~~~
2647
2748.. jupyter-execute ::
2849
2950 import numpy as np
30-
3151 from rocketpy import Environment, Rocket, SolidMotor, Flight
3252 from rocketpy.simulation import FlightComparator, FlightDataImporter
3353
34- Create Simulation (Reference)
35- -----------------------------
54+ Setting Up the Environment
55+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
3656
3757First, let's create the standard RocketPy simulation that will serve as our
38- "Ground Truth" or reference model. This follows the standard setup .
58+ reference model. This follows the same pattern as in :ref: ` firstsimulation ` .
3959
4060.. jupyter-execute ::
4161
42- # 1. Setup Environment
62+ # Create Environment (Spaceport America, NM)
4363 env = Environment(
4464 date=(2022, 10, 1, 12),
4565 latitude=32.990254,
@@ -48,7 +68,12 @@ First, let's create the standard RocketPy simulation that will serve as our
4868 )
4969 env.set_atmospheric_model(type="standard_atmosphere")
5070
51- # 2. Setup Motor
71+ Setting Up the Motor
72+ ~~~~~~~~~~~~~~~~~~~~~
73+
74+ .. jupyter-execute ::
75+
76+ # Create a Cesaroni M1670 Solid Motor
5277 Pro75M1670 = SolidMotor(
5378 thrust_source="../data/motors/cesaroni/Cesaroni_M1670.eng",
5479 burn_time=3.9,
@@ -69,54 +94,82 @@ First, let's create the standard RocketPy simulation that will serve as our
6994 nozzle_position=0,
7095 )
7196
72- # 3. Setup Rocket
97+ Setting Up the Rocket
98+ ~~~~~~~~~~~~~~~~~~~~~~
99+
100+ .. jupyter-execute ::
101+
102+ # Create Calisto rocket
73103 calisto = Rocket(
74104 radius=127 / 2000,
75105 mass=19.197 - 2.956,
76106 inertia=(6.321, 6.321, 0.034),
77- power_off_drag="../data/calisto/powerOffDragCurve.csv",
78- power_on_drag="../data/calisto/powerOnDragCurve.csv",
107+ power_off_drag="../data/rockets/ calisto/powerOffDragCurve.csv",
108+ power_on_drag="../data/rockets/ calisto/powerOnDragCurve.csv",
79109 center_of_mass_without_motor=0,
80110 coordinate_system_orientation="tail_to_nose",
81111 )
82112
113+ # Add rail buttons
83114 calisto.set_rail_buttons(0.0818, -0.618, 45)
115+
116+ # Add motor to rocket
84117 calisto.add_motor(Pro75M1670, position=-1.255)
85118
86119 # Add aerodynamic surfaces
87- nosecone = calisto.add_nose(length=0.55829, kind="vonKarman", position=0.71971)
120+ nosecone = calisto.add_nose(
121+ length=0.55829,
122+ kind="vonKarman",
123+ position=0.71971,
124+ )
125+
88126 fin_set = calisto.add_trapezoidal_fins(
89127 n=4,
90128 root_chord=0.120,
91129 tip_chord=0.040,
92130 span=0.100,
93131 position=-1.04956,
94132 cant_angle=0.5,
95- airfoil=("../data/calisto/fins /NACA0012-radians.txt", "radians"),
133+ airfoil=("../data/airfoils /NACA0012-radians.txt", "radians"),
96134 )
135+
97136 tail = calisto.add_tail(
98137 top_radius=0.0635,
99138 bottom_radius=0.0435,
100139 length=0.060,
101140 position=-1.194656,
102141 )
103142
104- # 4. Simulate
105- flight = Flight(
106- rocket=calisto,
107- environment=env,
108- rail_length=5.2,
109- inclination=85,
110- heading=0,
111- )
143+ Running the Simulation
144+ ~~~~~~~~~~~~~~~~~~~~~~~
145+
146+ .. jupyter-execute ::
147+
148+ # Create and run flight simulation
149+ flight = Flight(
150+ rocket=calisto,
151+ environment=env,
152+ rail_length=5.2,
153+ inclination=85,
154+ heading=0,
155+ )
156+
157+ Creating the FlightComparator
158+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
159+
160+ .. jupyter-execute ::
161+
162+ # Initialize FlightComparator with reference flight
163+ comparator = FlightComparator(flight)
112164
113- # 5. Create FlightComparator instance
114- comparator = FlightComparator(flight)
115165
116- Adding Another Flight Object
117- ----------------------------
166+ Adding Comparison Data
167+ ----------------------
118168
119- You can compare against another RocketPy Flight simulation directly:
169+ Comparing with Another Flight
170+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171+
172+ You can compare against another RocketPy :class: `rocketpy.Flight ` object directly:
120173
121174.. jupyter-execute ::
122175
@@ -129,55 +182,90 @@ You can compare against another RocketPy Flight simulation directly:
129182 heading=0,
130183 )
131184
132- # Add the second flight directly
185+ # Add the second flight to comparator
133186 comparator.add_data("Alternative Sim", flight2)
134187
135- print(f"Added variables from flight2: {list(comparator.data_sources['Alternative Sim'].keys())}")
136-
137- Importing External Data (dict)
138- ------------------------------
188+ Comparing with External Data
189+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
139190
140191The primary data format expected by ``FlightComparator.add_data `` is a dictionary
141- where keys are variable names (e.g. ``"z" ``, ``"vz" ``, ``"altitude" ``) and values
192+ where keys are variable names (e.g., ``"z" ``, ``"vz" ``, ``"altitude" ``) and values
142193are either:
143194
144- - A RocketPy `` Function ` ` object, or
145- - A tuple of ``(time_array, data_array) ``.
195+ - A RocketPy :class: ` rocketpy. Function ` object, or
196+ - A tuple of ``(time_array, data_array) ``
146197
147- Let's create some synthetic external data to compare against our reference
148- simulation:
198+ Let's create some synthetic external data to demonstrate the comparison process:
149199
150200.. jupyter-execute ::
151201
152202 # Generate synthetic external data with realistic noise
153203 time_external = np.linspace(0, flight.t_final, 80) # Different time steps
154- external_altitude = flight.z(time_external) + np.random.normal(0, 3, 80) # 3m noise
155- external_velocity = flight.vz(time_external) + np.random.normal(0, 0.5, 80) # 0.5 m/s noise
204+ external_altitude = flight.z(time_external) + np.random.normal(0, 3, 80) # Add 3 m noise
205+ external_velocity = flight.vz(time_external) + np.random.normal(0, 0.5, 80) # Add 0.5 m/s noise
156206
157- # Add the external data to our comparator
207+ # Add external data to comparator
158208 comparator.add_data(
159- "External Simulator",
209+ "External Simulator",
160210 {
161211 "altitude": (time_external, external_altitude),
162212 "vz": (time_external, external_velocity),
163213 }
164214 )
165215
166- Running Comparisons
167- -------------------
216+ .. tip ::
217+ External data does not need to have the same time steps as the reference
218+ simulation. The ``FlightComparator `` automatically handles interpolation
219+ and alignment for comparison.
220+
168221
169- Now we can run the various comparison methods:
222+ Analyzing Comparison Results
223+ -----------------------------
224+
225+ Summary Report
226+ ~~~~~~~~~~~~~~
227+
228+ Generate a comprehensive summary of the comparison:
170229
171230.. jupyter-execute ::
172231
173- # Generate summary with key events
232+ # Display comparison summary with key flight events
174233 comparator.summary()
175234
176- # Compare specific variable
235+ Comparing Specific Variables
236+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
237+
238+ You can compare individual flight variables:
239+
240+ .. jupyter-execute ::
241+
242+ # Compare altitude data across all sources
177243 comparator.compare("altitude")
178244
179- # Compare all available variables
245+ The comparison plot shows the reference simulation alongside all external data
246+ sources, making it easy to identify discrepancies and validate the simulation.
247+
248+ Comparing All Variables
249+ ~~~~~~~~~~~~~~~~~~~~~~~~
250+
251+ To get a complete overview, compare all available variables at once:
252+
253+ .. jupyter-execute ::
254+
255+ # Generate plots for all common variables
180256 comparator.all()
181257
182- # Plot 2D trajectory
258+ Trajectory Visualization
259+ ~~~~~~~~~~~~~~~~~~~~~~~~~
260+
261+ Visualize 2D trajectory projections for spatial comparison:
262+
263+ .. jupyter-execute ::
264+
265+ # Plot trajectory in the XZ plane (side view)
183266 comparator.trajectories_2d(plane="xz")
267+
268+ .. seealso ::
269+
270+ For detailed API documentation and additional methods, see
271+ :class: `rocketpy.simulation.FlightComparator ` in the API reference.
0 commit comments