diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef35a934..7d847d891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added +- ENH: Add new stability margin properties to Flight class [#572](https://github.com/RocketPy-Team/RocketPy/pull/572) - ENH: adds `Function.remove_outliers` method [#554](https://github.com/RocketPy-Team/RocketPy/pull/554) ### Changed diff --git a/rocketpy/prints/flight_prints.py b/rocketpy/prints/flight_prints.py index 5b1f9b914..b9be3f6ee 100644 --- a/rocketpy/prints/flight_prints.py +++ b/rocketpy/prints/flight_prints.py @@ -33,42 +33,38 @@ def initial_conditions(self): ------- None """ - print("\nInitial Conditions\n") - # Post-process results - if self.flight.post_processed is False: - self.flight.post_process() + t_init = self.flight.time[0] + + print(f"Initial time: {t_init:.3f} s") print( - "Position - x: {:.2f} m | y: {:.2f} m | z: {:.2f} m".format( - self.flight.x(0), self.flight.y(0), self.flight.z(0) - ) + f"Position - x: {self.flight.x(t_init):.2f} m | " + f"y: {self.flight.y(t_init):.2f} m | " + f"z: {self.flight.z(t_init):.2f} m" ) print( - "Velocity - Vx: {:.2f} m/s | Vy: {:.2f} m/s | Vz: {:.2f} m/s".format( - self.flight.vx(0), self.flight.vy(0), self.flight.vz(0) - ) + f"Velocity - Vx: {self.flight.vx(t_init):.2f} m/s | " + f"Vy: {self.flight.vy(t_init):.2f} m/s | " + f"Vz: {self.flight.vz(t_init):.2f} m/s" ) print( - "Attitude - e0: {:.3f} | e1: {:.3f} | e2: {:.3f} | e3: {:.3f}".format( - self.flight.e0(0), - self.flight.e1(0), - self.flight.e2(0), - self.flight.e3(0), - ) + f"Attitude (quaternions) - e0: {self.flight.e0(t_init):.3f} | " + f"e1: {self.flight.e1(t_init):.3f} | " + f"e2: {self.flight.e2(t_init):.3f} | " + f"e3: {self.flight.e3(t_init):.3f}" ) print( - "Euler Angles - Spin φ : {:.2f}° | Nutation θ: {:.2f}° | Precession ψ: {:.2f}°".format( - self.flight.phi(0), self.flight.theta(0), self.flight.psi(0) - ) + f"Euler Angles - Spin φ : {self.flight.phi(t_init):.2f}° | " + f"Nutation θ: {self.flight.theta(t_init):.2f}° | " + f"Precession ψ: {self.flight.psi(t_init):.2f}°" ) print( - "Angular Velocity - ω1: {:.2f} rad/s | ω2: {:.2f} rad/s| ω3: {:.2f} rad/s".format( - self.flight.w1(0), self.flight.w2(0), self.flight.w3(0) - ) + f"Angular Velocity - ω1: {self.flight.w1(t_init):.2f} rad/s | " + f"ω2: {self.flight.w2(t_init):.2f} rad/s | " + f"ω3: {self.flight.w3(t_init):.2f} rad/s" ) - - return None + print(f"Initial Stability Margin: {self.flight.initial_stability_margin:.3f} c") def numerical_integration_settings(self): """Prints out the Numerical Integration settings available about the @@ -150,9 +146,8 @@ def out_of_rail_conditions(self): print("\nRail Departure State\n") print("Rail Departure Time: {:.3f} s".format(self.flight.out_of_rail_time)) print( - "Rail Departure Velocity: {:.3f} m/s".format( - self.flight.out_of_rail_velocity - ) + "Rail Departure Stability Margin: " + f"{self.flight.out_of_rail_stability_margin:.3f} c" ) print( "Rail Departure Stability Margin: {:.3f} c".format( @@ -408,9 +403,13 @@ def stability_margin(self): about the flight.""" print("\nStability Margin\n") print( - "Maximum Stability Margin: {:.3f} c at {:.2f} s".format( - self.flight.max_stability_margin, self.flight.max_stability_margin_time - ) + f"Initial Stability Margin: {self.flight.initial_stability_margin:.3f} c " + f"at {self.flight.time[0]:.2f} s" + ) + print( + "Out of Rail Stability Margin: " + f"{self.flight.out_of_rail_stability_margin:.3f} c " + f"at {self.flight.out_of_rail_time:.2f} s" ) print( "Minimum Stability Margin: {:.3f} c at {:.2f} s".format( diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index 48f94d156..77632d2f2 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -426,6 +426,10 @@ class Flight: Rocket's static margin during flight in calibers. Flight.stability_margin : Function Rocket's stability margin during flight, in calibers. + Flight.initial_stability_margin : float + Rocket's initial stability margin in calibers. + Flight.out_of_rail_stability_margin : float + Rocket's stability margin in calibers when it leaves the rail. Flight.stream_velocity_x : Function Freestream velocity x (East) component, in m/s, as a function of time. Can be called or accessed as array. @@ -2426,6 +2430,26 @@ def min_stability_margin(self): """Minimum stability margin.""" return self.stability_margin(self.min_stability_margin_time) + @property + def initial_stability_margin(self): + """Stability margin at time 0. + + Returns + ------- + float + """ + return self.stability_margin(self.time[0]) + + @property + def out_of_rail_stability_margin(self): + """Stability margin at the time the rocket leaves the rail. + + Returns + ------- + float + """ + return self.stability_margin(self.out_of_rail_time) + # Reynolds Number @funcify_method("Time (s)", "Reynolds Number", "spline", "zero") def reynolds_number(self): diff --git a/tests/unit/test_flight.py b/tests/unit/test_flight.py index 87249cf44..e6ab6b8b8 100644 --- a/tests/unit/test_flight.py +++ b/tests/unit/test_flight.py @@ -258,3 +258,31 @@ def test_get_controller_observed_variables(flight_calisto_air_brakes): obs_vars = flight_calisto_air_brakes.get_controller_observed_variables() assert isinstance(obs_vars, list) assert len(obs_vars) == 0 + + +def test_initial_stability_margin(flight_calisto_custom_wind): + """Test the initial_stability_margin method of the Flight class. + + Parameters + ---------- + flight_calisto_custom_wind : rocketpy.Flight + """ + res = flight_calisto_custom_wind.initial_stability_margin + assert isinstance(res, float) + assert res == flight_calisto_custom_wind.stability_margin(0) + assert np.isclose(res, 2.05, atol=0.1) + + +def test_out_of_rail_stability_margin(flight_calisto_custom_wind): + """Test the out_of_rail_stability_margin method of the Flight class. + + Parameters + ---------- + flight_calisto_custom_wind : rocketpy.Flight + """ + res = flight_calisto_custom_wind.out_of_rail_stability_margin + assert isinstance(res, float) + assert res == flight_calisto_custom_wind.stability_margin( + flight_calisto_custom_wind.out_of_rail_time + ) + assert np.isclose(res, 2.14, atol=0.1)