def payload_parachute_dynamics(x, t, rocket): pos_ECI = x[0:3] vel_ECI = x[3:6] DCM_ECI2ECEF = coord.DCM_ECI2ECEF(t) pos_ECEF = DCM_ECI2ECEF.dot(pos_ECI) pos_LLH = pm.ecef2geodetic(pos_ECEF[0], pos_ECEF[1], pos_ECEF[2]) altitude = pos_LLH[2] DCM_ECEF2NED = coord.DCM_ECEF2NED(rocket.pos0_LLH) vel_ECEF = coord.vel_ECI2ECEF(vel_ECI, DCM_ECI2ECEF, pos_ECI) vel_NED = DCM_ECEF2NED.dot(vel_ECEF) vel_decent = vel_NED[2] g_NED = np.array([0.0, 0.0, env.gravity(altitude)]) Ta, Pa, rho, Cs = env.std_atmo(altitude) drag_NED = np.array([ 0, 0, -0.5 * rho * vel_decent * np.abs(vel_decent) * rocket.payload.CdS ]) acc_NED = drag_NED / rocket.payload.mass + g_NED acc_ECI = DCM_ECI2ECEF.transpose().dot( DCM_ECEF2NED.transpose().dot(acc_NED)) wind_NED = env.Wind_NED(rocket.wind_speed(altitude), rocket.wind_direction(altitude)) vel_NED = vel_NED + wind_NED vel_ecef = DCM_ECEF2NED.transpose().dot(vel_NED) vel_ECI = coord.vel_ECEF2ECI(vel_ecef, DCM_ECI2ECEF, pos_ECI) dx = np.zeros(6) dx[0:3] = vel_ECI dx[3:6] = acc_ECI return dx
def __make_log(self, rocket): self.pos_onlauncer_LLH_log = np.array([ pm.ned2geodetic(pos_NED[0], pos_NED[1], pos_NED[2], rocket.pos0_LLH[0], rocket.pos0_LLH[1], rocket.pos0_LLH[2]) for pos_NED in self.pos_onlauncher_NED_log ]) self.downrange_log = np.array([ pm.vincenty.vdist(rocket.pos0_LLH[0], rocket.pos0_LLH[1], pos[0], pos[1]) for pos in self.pos_LLH_log ])[:, 0] self.vel_AIR_BODYframe_abs_log = np.array( [np.linalg.norm(vel) for vel in self.vel_AIR_BODYframe_log]) DCM_NED2BODY_log = np.array( [coord.DCM_NED2BODY_quat(quat) for quat in self.quat_log]) self.attitude_log = np.array( [coord.quat2euler(DCM) for DCM in DCM_NED2BODY_log]) self.pos_NED_log = np.array([ pm.ecef2ned(pos_ECEF[0], pos_ECEF[1], pos_ECEF[2], rocket.pos0_LLH[0], rocket.pos0_LLH[1], rocket.pos0_LLH[2]) for pos_ECEF in self.pos_ECEF_log ]) self.pos_decent_ECEF_log = np.array([ coord.DCM_ECI2ECEF(t).dot(pos_ECI) for pos_ECI, t in zip( self.pos_decent_ECI_log, self.time_decent_log) ]) self.pos_decent_LLH_log = np.array([ pm.ecef2geodetic(pos[0], pos[1], pos[2]) for pos in self.pos_decent_ECEF_log ]) self.vel_decent_NED_log = np.array([ coord.DCM_ECEF2NED(rocket.pos0_LLH).dot( coord.vel_ECI2ECEF(vel_eci, coord.DCM_ECI2ECEF(t), pos_eci)) for vel_eci, t, pos_eci in zip(self.vel_decent_ECI_log, self.time_decent_log, self.pos_decent_ECI_log) ]) self.downrange_decent_log = np.array([ pm.vincenty.vdist(rocket.pos0_LLH[0], rocket.pos0_LLH[1], pos[0], pos[1]) for pos in self.pos_decent_LLH_log ])[:, 0] self.pos_hard_LLH_log = np.r_[self.pos_onlauncer_LLH_log, self.pos_LLH_log] index = np.argmax(self.time_log > self.time_decent_log[0]) self.pos_soft_LLH_log = np.r_[self.pos_onlauncer_LLH_log, self.pos_LLH_log[:index, :], self.pos_decent_LLH_log]
def parachute_dynamics(x, t, rocket): pos_ECI = x[0:3] vel_ECI = x[3:6] DCM_ECI2ECEF = coord.DCM_ECI2ECEF(t) pos_ECEF = DCM_ECI2ECEF.dot(pos_ECI) pos_LLH = pm.ecef2geodetic(pos_ECEF[0], pos_ECEF[1], pos_ECEF[2]) altitude = pos_LLH[2] DCM_ECEF2NED = coord.DCM_ECEF2NED(rocket.pos0_LLH) vel_ECEF = coord.vel_ECI2ECEF(vel_ECI, DCM_ECI2ECEF, pos_ECI) vel_NED = DCM_ECEF2NED.dot(vel_ECEF) vel_decent = vel_NED[2] g_NED = np.array([0.0, 0.0, env.gravity(altitude)]) Ta, Pa, rho, Cs = env.std_atmo(altitude) if rocket.timer_mode: if t > rocket.t_2nd_max or (altitude <= rocket.alt_sepa2 and t > rocket.t_2nd_min): CdS = rocket.CdS1 + rocket.CdS2 else: CdS = rocket.CdS1 else: CdS = rocket.CdS1 + rocket.CdS2 if altitude <= rocket.alt_sepa2 else rocket.CdS1 drag_NED = np.array( [0, 0, -0.5 * rho * vel_decent * np.abs(vel_decent) * CdS]) acc_NED = drag_NED / rocket.m_burnout + g_NED acc_ECI = DCM_ECI2ECEF.transpose().dot( DCM_ECEF2NED.transpose().dot(acc_NED)) wind_NED = env.Wind_NED(rocket.wind_speed(altitude), rocket.wind_direction(altitude)) vel_NED = vel_NED + wind_NED vel_ecef = DCM_ECEF2NED.transpose().dot(vel_NED) vel_ECI = coord.vel_ECEF2ECI(vel_ecef, DCM_ECI2ECEF, pos_ECI) dx = np.zeros(6) dx[0:3] = vel_ECI dx[3:6] = acc_ECI return dx
def _dynamics(pos_ECI, vel_ECI, omega_BODY, quat, t, rocket): date_current = rocket.launch_date + datetime.timedelta(seconds=t) # Translation coordinate DCM_NED2BODY = coord.DCM_NED2BODY_quat(quat) DCM_BODY2NED = DCM_NED2BODY.transpose() DCM_ECEF2NED = coord.DCM_ECEF2NED(rocket.pos0_LLH) DCM_NED2ECEF = DCM_ECEF2NED.transpose() DCM_ECI2ECEF = coord.DCM_ECI2ECEF(t) DCM_ECEF2ECI = DCM_ECI2ECEF.transpose() DCM_BODY2ECI = DCM_ECEF2ECI.dot(DCM_NED2ECEF.dot(DCM_BODY2NED)) pos_ECEF = DCM_ECI2ECEF.dot(pos_ECI) pos_LLH = pm.ecef2geodetic(pos_ECEF[0], pos_ECEF[1], pos_ECEF[2]) # pos_LLH = pm.eci2geodetic(pos_ECI, date_current) vel_ECEF = coord.vel_ECI2ECEF(vel_ECI, DCM_ECI2ECEF, pos_ECI) vel_NED = DCM_ECEF2NED.dot(vel_ECEF) altitude = pos_LLH[2] g0 = 9.80665 # alpha beta vel_Air wind_NED = env.Wind_NED(rocket.wind_speed(altitude), rocket.wind_direction(altitude)) vel_AIR_BODYframe = DCM_NED2BODY.dot(vel_NED - wind_NED) vel_AIR_BODYframe_abs = np.linalg.norm(vel_AIR_BODYframe) if vel_AIR_BODYframe_abs <= 0.0 or np.abs(vel_AIR_BODYframe[0]) <= 0.0: alpha = 0.0 beta = 0.0 else: alpha = np.arctan2(vel_AIR_BODYframe[2], vel_AIR_BODYframe[0]) beta = np.arcsin(-vel_AIR_BODYframe[1] / vel_AIR_BODYframe_abs) # Air Condition Ta0, Pa0, rho0, Cs0 = env.std_atmo(0.0) Ta, Pa, rho, Cs = env.std_atmo(altitude) Mach = vel_AIR_BODYframe_abs / Cs dynamic_pressure = 0.5 * rho * vel_AIR_BODYframe_abs**2 # Mass if rocket.thrust(t) <= 0.0: thrust = 0.0 Isp = 0.0 mdot_p = 0.0 mdot_f = 0.0 mdot_ox = 0.0 else: mdot_p = rocket.mdot_p(t) mdot_f = rocket.mdot_f(t) mdot_ox = rocket.mdot_ox(t) pressure_thrust = (Pa0 - Pa) * rocket.Ae thrust = rocket.thrust(t) + pressure_thrust Isp = rocket.Isp + pressure_thrust / (mdot_p * g0) mf = rocket.mf(t) mox = rocket.mox(t) mp = mf + mox m = rocket.ms + mp # Aero Force drag = dynamic_pressure * rocket.Cd(Mach) * rocket.A normal = dynamic_pressure * rocket.CNa(Mach) * rocket.A F_aero_WIND = np.array([-drag, 0, 0]) F_aero_BODY = coord.DCM_WIND2BODY(alpha, beta).dot(F_aero_WIND) + np.array( [0, normal * beta, -normal * alpha]) F_aero_WIND = coord.DCM_WIND2BODY(alpha, beta).transpose().dot(F_aero_BODY) # Newton Equation g_NED = np.array([0.0, 0.0, env.gravity(altitude)]) force_BODY = F_aero_BODY + np.array([thrust, 0, 0]) acc_BODY = force_BODY / m + DCM_NED2BODY.dot(g_NED) acc_ECI = DCM_BODY2ECI.dot(acc_BODY) # Center of Gravity Lcg_p = rocket.Lcg_p(t) Lcg = rocket.Lcg(t) Lcp = rocket.Lcp(Mach) moment_arm = np.array([Lcg - Lcp, 0, 0]) # Inertia Moment Ij_pitch = rocket.Ij_pitch(t) Ij_roll = rocket.Ij_roll(t) Ij = np.array([Ij_roll, Ij_pitch, Ij_pitch]) Ijdot_f_pitch = rocket.Ijdot_f_pitch(t) Ijdot_f_roll = rocket.Ijdot_f_roll(t) Ijdot_f = np.array([Ijdot_f_roll, Ijdot_f_pitch, Ijdot_f_pitch]) # Aero Moment moment_aero = np.cross(F_aero_BODY, moment_arm) # Aero Dumping Moment moment_aero_dumping = np.zeros(3) moment_aero_dumping[ 0] = dynamic_pressure * rocket.Clp * rocket.A * rocket.d**2 * 0.5 / vel_AIR_BODYframe_abs * omega_BODY[ 0] moment_aero_dumping[ 1] = dynamic_pressure * rocket.Cmq * rocket.A * rocket.L**2 * 0.5 / vel_AIR_BODYframe_abs * omega_BODY[ 1] moment_aero_dumping[ 2] = dynamic_pressure * rocket.Cnr * rocket.A * rocket.L**2 * 0.5 / vel_AIR_BODYframe_abs * omega_BODY[ 2] # Jet Dumping Moment moment_jet_dumping = np.zeros(3) moment_jet_dumping[0] = (-Ijdot_f[0] + mdot_p * 0.5 * (0.25 * rocket.de**2)) * omega_BODY[0] moment_jet_dumping[1] = (-Ijdot_f[1] + mdot_p * ((Lcg - Lcg_p)**2 - (rocket.L - Lcg_p)**2)) * omega_BODY[1] moment_jet_dumping[2] = (-Ijdot_f[2] + mdot_p * ((Lcg - Lcg_p)**2 - (rocket.L - Lcg_p)**2)) * omega_BODY[2] # moment_jet_dumping[0] = -(mdot_p * 0.5 * (0.25 * rocket.de ** 2)) * omega_BODY[0] # moment_jet_dumping[0] = 0.0 # moment_jet_dumping[1] = -(mdot_p * ((Lcg - Lcg_p) ** 2 - (rocket.L - Lcg_p) ** 2)) * omega_BODY[1] # moment_jet_dumping[2] = -(mdot_p * ((Lcg - Lcg_p) ** 2 - (rocket.L - Lcg_p) ** 2)) * omega_BODY[2] # Euler Equation moment = moment_aero + moment_aero_dumping + moment_jet_dumping p = omega_BODY[0] q = omega_BODY[1] r = omega_BODY[2] omegadot = np.zeros(3) omegadot[0] = ((Ij[1] - Ij[2]) * q * r + moment[0]) / Ij[0] omegadot[1] = ((Ij[2] - Ij[0]) * p * r + moment[1]) / Ij[1] omegadot[2] = ((Ij[0] - Ij[1]) * p * q + moment[2]) / Ij[2] # Kinematic Equation tersor_0 = [0.0, r, -q, p] tersor_1 = [-r, 0.0, p, q] tersor_2 = [q, -p, 0.0, r] tersor_3 = [-p, -q, -r, 0.0] tersor = np.array([tersor_0, tersor_1, tersor_2, tersor_3]) quatdot = 0.5 * tersor.dot(quat) output_data = [ date_current, pos_ECEF, pos_LLH, vel_ECEF, vel_NED, vel_AIR_BODYframe, alpha, beta, Ta, Pa, rho, Cs, Mach, dynamic_pressure, mdot_p, mdot_f, mdot_ox, thrust, Isp, mf, mox, mp, m, drag, normal, F_aero_WIND, F_aero_BODY, g_NED, force_BODY, acc_BODY, acc_ECI, Lcg_p, Lcg, Lcp, Ij, Ijdot_f, moment_aero, moment_aero_dumping, moment_jet_dumping, moment ] return vel_ECI, acc_ECI, omegadot, quatdot, output_data
def solve_trajectory(rocket): # Initial Attitude ############################# quat0 = coord.euler2quat(rocket.azimuth0, rocket.elevation0) DCM_LAUNCHER2NED = coord.DCM_NED2BODY_quat(quat0).transpose() ################################################ # Initial Position ############################# pos0_ECEF = pm.geodetic2ecef(rocket.pos0_LLH[0], rocket.pos0_LLH[1], rocket.pos0_LLH[2]) pos0_ECI = pm.ecef2eci(pos0_ECEF, rocket.launch_date) pos0_NED = DCM_LAUNCHER2NED.dot(np.array([rocket.Lcg0, 0.0, 0.0])) ################################################ # onLauncher Trajectory ################################################## # lower launch lugがランチャレール長を越した時点でランチクリア # lower lugが抜けた時点での重心各値をメインのソルバへ渡す time = np.arange( 0.0, 0.5 + np.sqrt( 2.0 * rocket.launcher_rail * rocket.m(0.0) / rocket.ref_thrust), 0.01) x0 = np.zeros(13) x0[0:3] = pos0_NED # Pos_NED x0[3:6] = np.zeros((1, 3)) # Vel_NED x0[6:9] = np.zeros((1, 3)) # omega x0[9:13] = quat0 # quat ode_log = odeint(onlauncher_dynamics, x0, time, args=(rocket, DCM_LAUNCHER2NED.transpose())) # onLauncher post ###### pos_LAUNCHER = np.array( [DCM_LAUNCHER2NED.transpose().dot(pos) for pos in ode_log[:, 0:3]]) # ランチクリアまででカット index_launch_clear = np.argmax( rocket.launcher_rail <= pos_LAUNCHER[:, 0] - rocket.lower_lug) # log rocket.result.time_onlauncher_log = time[:index_launch_clear + 1] rocket.result.pos_onlauncher_NED_log = ode_log[:index_launch_clear + 1, 0:3] rocket.result.vel_onlauncher_NED_log = ode_log[:index_launch_clear + 1, 3:6] rocket.result.omega_onlauncher_log = ode_log[:index_launch_clear + 1, 6:9] rocket.result.quat_onlauncher_log = ode_log[:index_launch_clear + 1, 9:13] pos_launch_clear_NED = rocket.result.pos_onlauncher_NED_log[-1, :] vel_launch_clear_NED = rocket.result.vel_onlauncher_NED_log[-1, :] omega_launch_clear = rocket.result.omega_onlauncher_log[-1, :] quat_launch_clear = rocket.result.quat_onlauncher_log[-1, :] time_launch_clear = rocket.result.time_onlauncher_log[-1] altitude_launch_clear = -pos_launch_clear_NED[2] DCM_NED2BODY = coord.DCM_NED2BODY_quat(quat_launch_clear) # tipoff moment if rocket.tipoff_exist: mg_tipoff_NED = np.array([ 0, 0, rocket.m(time_launch_clear) * env.gravity(altitude_launch_clear) ]) mg_tipoff_BODY = DCM_NED2BODY.dot(mg_tipoff_NED) moment_arm_tipoff = np.array( [rocket.lower_lug - rocket.Lcg(time_launch_clear), 0, 0]) moment_tipoff = np.cross(mg_tipoff_BODY, moment_arm_tipoff) Ij_pitch = rocket.Ij_pitch( time_launch_clear) + rocket.m(time_launch_clear) * np.abs( rocket.Lcg(time_launch_clear) - rocket.lower_lug)**2 Ij_roll = rocket.Ij_roll(time_launch_clear) Ij = np.array([Ij_roll, Ij_pitch, Ij_pitch]) omegadot_tipoff = moment_tipoff / Ij # 下部ラグを支点とした機体質量でのチップオフ角加速度。あとで角速度に変換する else: omegadot_tipoff = 0.0 ################################################ # Main Trajectory ################################################## def estimate_end(total_impulse): It = total_impulse tf = 2.37 * It**0.37 tf_order = len(str(int(tf))) - 1 dt = 10.0**(tf_order - 4) return 1.4 * tf, dt if rocket.auto_end: rocket.end_time, rocket.time_step = estimate_end(rocket.total_impulse) start_time = time_launch_clear # + rocket.time_step time = np.arange(start_time, rocket.end_time, rocket.time_step) pos_launch_clear_ECEF = pm.ned2ecef(pos_launch_clear_NED[0], pos_launch_clear_NED[1], pos_launch_clear_NED[2], rocket.pos0_LLH[0], rocket.pos0_LLH[1], rocket.pos0_LLH[2]) pos_launch_clear_ECI = coord.DCM_ECI2ECEF( time_launch_clear).transpose().dot(pos_launch_clear_ECEF) DCM_NED2ECEF = coord.DCM_ECEF2NED(rocket.pos0_LLH).transpose() DCM_ECI2ECEF = coord.DCM_ECI2ECEF(time_launch_clear) x0 = np.zeros(13) x0[0:3] = pos_launch_clear_ECI x0[3:6] = coord.vel_ECEF2ECI(DCM_NED2ECEF.dot(vel_launch_clear_NED), DCM_ECI2ECEF, pos_launch_clear_ECI) x0[6:9] = omega_launch_clear + omegadot_tipoff * rocket.time_step x0[9:13] = quat_launch_clear ode_log = odeint(dynamics_odeint, x0, time, args=(rocket, )) # Main post ###### date_array = rocket.launch_date + np.array( [datetime.timedelta(seconds=sec) for sec in time]) pos_ECEF = np.array([ coord.DCM_ECI2ECEF(t).dot(pos) for pos, t in zip(ode_log[:, 0:3], time) ]) pos_LLH = np.array( [pm.ecef2geodetic(pos[0], pos[1], pos[2]) for pos in pos_ECEF]) # 着地後の分をカット index_hard_landing = np.argmax(pos_LLH[:, 2] <= 0.0) # log rocket.result.time_log = time[:index_hard_landing + 1] rocket.result.pos_ECI_log = ode_log[:index_hard_landing + 1, 0:3] rocket.result.vel_ECI_log = ode_log[:index_hard_landing + 1, 3:6] rocket.result.omega_log = ode_log[:index_hard_landing + 1, 6:9] rocket.result.quat_log = ode_log[:index_hard_landing + 1, 9:13] dynamics_result(rocket) ################################################ # Decent Trajectory ################################################## if rocket.timer_mode: index_apogee = np.argmax(rocket.result.time_log > rocket.t_1st) else: index_apogee = np.argmax(pos_LLH[:, 2]) time_apogee = rocket.result.time_log[index_apogee] pos_apogee_ECI = rocket.result.pos_ECI_log[index_apogee] vel_apogee_ECI = rocket.result.vel_ECI_log[index_apogee] vel_apogee_ned = np.array([ 0, 0, coord.DCM_ECEF2NED(rocket.pos0_LLH).dot( coord.vel_ECI2ECEF(vel_apogee_ECI, coord.DCM_ECI2ECEF(time_apogee), pos_apogee_ECI))[2] ]) vel_apogee_ECI = coord.vel_ECEF2ECI( coord.DCM_ECEF2NED(rocket.pos0_LLH).transpose().dot(vel_apogee_ned), coord.DCM_ECI2ECEF(time_apogee), pos_apogee_ECI) if rocket.payload_exist: rocket.m_burnout -= rocket.payload.mass est_landing_payload = pos_LLH[index_apogee, 2] / np.sqrt( 2.0 * rocket.payload.mass * env.gravity(pos_LLH[index_apogee, 2]) / (env.get_std_density(0.0) * rocket.payload.CdS)) est_landing = pos_LLH[index_apogee, 2] / np.sqrt( 2.0 * rocket.result.m_log[index_apogee] * env.gravity(pos_LLH[index_apogee, 2]) / (env.get_std_density(0.0) * (rocket.CdS1 + rocket.CdS2))) time = np.arange(time_apogee, time_apogee + 1.2 * est_landing, 0.1) x0 = np.zeros(6) x0[0:3] = pos_apogee_ECI x0[3:6] = vel_apogee_ECI ode_log = odeint(parachute_dynamics, x0, time, args=(rocket, )) # Decent post ###### date_array = rocket.launch_date + np.array( [datetime.timedelta(seconds=sec) for sec in time]) pos_ECEF = np.array([ coord.DCM_ECI2ECEF(t).dot(pos) for pos, t in zip(ode_log[:, 0:3], time) ]) pos_LLH = np.array( [pm.ecef2geodetic(pos[0], pos[1], pos[2]) for pos in pos_ECEF]) # 着地後の分をカット index_soft_landing = np.argmax(pos_LLH[:, 2] <= 0.0) # log rocket.result.time_decent_log = time[:index_soft_landing + 1] rocket.result.pos_decent_ECI_log = ode_log[:index_soft_landing + 1, 0:3] rocket.result.vel_decent_ECI_log = ode_log[:index_soft_landing + 1, 3:6] # Payload #### if rocket.payload_exist: time = np.arange(time_apogee, time_apogee + 1.2 * est_landing_payload, 0.01) x0 = np.zeros(6) x0[0:3] = pos_apogee_ECI x0[3:6] = vel_apogee_ECI ode_log = odeint(payload_parachute_dynamics, x0, time, args=(rocket, )) date_array = rocket.launch_date + np.array( [datetime.timedelta(seconds=sec) for sec in time]) pos_ECEF = np.array([ coord.DCM_ECI2ECEF(t).dot(pos) for pos, t in zip(ode_log[:, 0:3], time) ]) pos_LLH = np.array( [pm.ecef2geodetic(pos[0], pos[1], pos[2]) for pos in pos_ECEF]) # 着地後の分をカット index_payload_landing = np.argmax(pos_LLH[:, 2] <= 0.0) # log rocket.payload.result.time_decent_log = time[:index_payload_landing + 1] rocket.payload.result.pos_decent_LLH_log = pos_LLH[: index_payload_landing + 1, :]
def __post_event(self, rocket): # Launch Clear self.time_launch_clear = self.time_onlauncher_log[-1] self.acc_gauge_launch_clear = rocket.thrust( self.time_launch_clear) / rocket.m( self.time_launch_clear) # 本来はDragとかもあるがランチクリア時点では小さいので無視 self.vel_launch_clear = coord.DCM_NED2BODY_quat( self.quat_onlauncher_log[-1, :]).dot( self.vel_onlauncher_NED_log[-1, :])[0] # Apogee index_apogee = np.argmax(self.pos_LLH_log[:, 2]) self.time_apogee = self.time_log[index_apogee] self.alt_apogee = self.pos_LLH_log[index_apogee, 2] self.downrange_apogee = self.downrange_log[index_apogee] self.vel_apogee = self.vel_AIR_BODYframe_abs_log[index_apogee] # Max Q/Drag/Vel index = np.argmax(self.dynamic_pressure_log[:index_apogee]) self.time_maxQ = self.time_log[index] self.alt_maxQ = self.pos_LLH_log[index, 2] self.maxQ = self.dynamic_pressure_log[index] index = np.argmax(self.vel_AIR_BODYframe_log[:index_apogee, 0]) self.time_vel_max = self.time_log[index] self.alt_vel_max = self.pos_LLH_log[index, 2] self.vel_max = self.vel_AIR_BODYframe_log[index, 0] index = np.argmax(self.Mach_log[:index_apogee]) self.time_Mach_max = self.time_log[index] self.alt_Mach_max = self.pos_LLH_log[index, 2] self.Mach_max = self.Mach_log[index] # Ballistic Landing self.time_hard_landing = self.time_log[-1] self.downrange_hard_landing = self.downrange_log[-1] self.vel_hard_landing = np.linalg.norm( coord.DCM_ECEF2NED(rocket.pos0_LLH).dot( coord.vel_ECI2ECEF(self.vel_ECI_log[-1, :], coord.DCM_ECI2ECEF(self.time_log[-1]), self.pos_ECI_log[-1, :]))) # Decent Landing self.time_soft_landing = self.time_decent_log[-1] self.downrange_soft_landing = self.downrange_decent_log[-1] self.vel_soft_landing = coord.DCM_ECEF2NED(rocket.pos0_LLH).dot( coord.vel_ECI2ECEF(self.vel_decent_ECI_log[-1, :], coord.DCM_ECI2ECEF(self.time_decent_log[-1]), self.pos_decent_ECI_log[-1, :]))[2] # 2nd Separation if rocket.timer_mode: index_sepa2 = np.min([ np.argmax(self.time_decent_log > rocket.t_2nd_max), np.max([ np.argmax( self.pos_decent_LLH_log[:, 2] <= rocket.alt_sepa2), np.argmax(self.time_decent_log > rocket.t_2nd_min) ]) ]) else: index_sepa2 = np.argmax( self.pos_decent_LLH_log[:, 2] <= rocket.alt_sepa2) self.time_separation_2nd = self.time_decent_log[index_sepa2] self.vel_decent_1st = coord.DCM_ECEF2NED(rocket.pos0_LLH).dot( coord.vel_ECI2ECEF( self.vel_decent_ECI_log[index_sepa2, :], coord.DCM_ECI2ECEF(self.time_decent_log[index_sepa2]), self.pos_decent_ECI_log[index_sepa2, :]))[2] # 1st Separation self.time_separation_1st = self.time_decent_log[0] self.vel_separation_1st = coord.DCM_ECEF2NED(rocket.pos0_LLH).dot( coord.vel_ECI2ECEF(self.vel_decent_ECI_log[0, :], coord.DCM_ECI2ECEF(self.time_decent_log[0]), self.pos_decent_ECI_log[0, :]))[2]