diff --git a/rocketpy/rocket/aero_surface.py b/rocketpy/rocket/aero_surface.py index d41240ac9..9649d1bf0 100644 --- a/rocketpy/rocket/aero_surface.py +++ b/rocketpy/rocket/aero_surface.py @@ -1977,8 +1977,9 @@ def __init__( brakes drag coefficient will be used for the entire rocket instead. Default is False. deployment_level : float, optional - Current deployment level, ranging from 0 to 1. Deployment level is the - fraction of the total airbrake area that is Deployment. Default is 0. + Initial deployment level, ranging from 0 to 1. Deployment level is + the fraction of the total airbrake area that is Deployment. Default + is 0. name : str, optional Name of the air brakes. Default is "AirBrakes". @@ -1996,6 +1997,7 @@ def __init__( self.reference_area = reference_area self.clamp = clamp self.override_rocket_drag = override_rocket_drag + self.initial_deployment_level = deployment_level self.deployment_level = deployment_level self.prints = _AirBrakesPrints(self) self.plots = _AirBrakesPlots(self) @@ -2022,6 +2024,12 @@ def deployment_level(self, value): ) self._deployment_level = value + def _reset(self): + """Resets the air brakes to their initial state. This is ran at the + beginning of each simulation to ensure the air brakes are in the correct + state.""" + self.deployment_level = self.initial_deployment_level + def evaluate_center_of_pressure(self): """Evaluates the center of pressure of the aerodynamic surface in local coordinates. diff --git a/rocketpy/simulation/flight.py b/rocketpy/simulation/flight.py index b4bc1a3be..58e63f60c 100644 --- a/rocketpy/simulation/flight.py +++ b/rocketpy/simulation/flight.py @@ -590,7 +590,6 @@ def __init__( if self.rail_length <= 0: raise ValueError("Rail length must be a positive value.") self.parachutes = self.rocket.parachutes[:] - self._controllers = self.rocket._controllers[:] self.inclination = inclination self.heading = heading self.max_time = max_time @@ -604,6 +603,9 @@ def __init__( self.name = name self.equations_of_motion = equations_of_motion + # Controller initialization + self.__init_controllers() + # Flight initialization self.__init_solution_monitors() self.__init_equations_of_motion() @@ -996,8 +998,15 @@ def __simulate(self, verbose): [self.t, parachute] ) + # If controlled flight, post process must be done on sim time + if self._controllers: + phase.derivative(self.t, self.y_sol, post_processing=True) + self.t_final = self.t self.__transform_pressure_signals_lists_to_functions() + if self._controllers: + # cache post process variables + self.__evaluate_post_process = np.array(self.__post_processed_variables) if verbose: print(f"\n>>> Simulation Completed at Time: {self.t:3.4f} s") @@ -1049,6 +1058,7 @@ def __init_solution_monitors(self): self.impact_state = np.array([0]) self.parachute_events = [] self.post_processed = False + self.__post_processed_variables = [] def __init_flight_state(self): """Initialize flight state variables.""" @@ -1101,6 +1111,11 @@ def __init_flight_state(self): self.out_of_rail_time = self.initial_solution[0] self.out_of_rail_time_index = 0 self.initial_derivative = self.u_dot_generalized + if self._controllers: + # Handle post process during simulation, get initial accel/forces + self.initial_derivative( + self.t_initial, self.initial_solution[1:], post_processing=True + ) def __init_solver_monitors(self): # Initialize solver monitors @@ -1120,6 +1135,19 @@ def __init_equations_of_motion(self): # NOTE: The u_dot is faster, but only works for solid propulsion self.u_dot_generalized = self.u_dot + def __init_controllers(self): + """Initialize controllers""" + self._controllers = self.rocket._controllers[:] + if self._controllers: + if self.time_overshoot: + self.time_overshoot = False + warnings.warn( + "time_overshoot has been set to False due to the presence of controllers. " + ) + # reset controllable object to initial state (only airbrakes for now) + for air_brakes in self.rocket.air_brakes: + air_brakes._reset() + @cached_property def effective_1rl(self): """Original rail length minus the distance measured from nozzle exit @@ -1237,13 +1265,10 @@ def udot_rail1(self, t, u, post_processing=False): ax, ay, az = 0, 0, 0 if post_processing: + # Use u_dot post processing code for forces, moments and env data self.u_dot_generalized(t, u, post_processing=True) - self.__post_processed_variables[-1][1] = ax - self.__post_processed_variables[-1][2] = ay - self.__post_processed_variables[-1][3] = az - self.__post_processed_variables[-1][4] = 0 - self.__post_processed_variables[-1][5] = 0 - self.__post_processed_variables[-1][6] = 0 + # Save feasible accelerations + self.__post_processed_variables[-1][1:7] = [ax, ay, az, 0, 0, 0] return [vx, vy, vz, ax, ay, az, 0, 0, 0, 0, 0, 0, 0]