def test_engines(self): """Test that engines use fuel and accelerate at the expected.""" with PhysicsEngine('tests/habitat.json') as physics_engine: # In this test case, there is a single entity that has 300 kg fuel. # heading, velocity, and position are all 0. throttle = 1 t_delta = 5 physics_engine.handle_requests([ network.Request(ident=network.Request.HAB_THROTTLE_SET, throttle_set=throttle) ], requested_t=0) initial = physics_engine.get_state(0) moved = physics_engine.get_state(t_delta) self.assertAlmostEqual(initial[0].heading, 0) self.assertAlmostEqual( moved[0].fuel, (initial[0].fuel - t_delta * throttle * common.craft_capabilities[HABITAT].fuel_cons)) self.assertTrue( moved[0].vx < (t_delta * calc.engine_acceleration(moved))) t_no_fuel = ( initial[0].fuel / (throttle * common.craft_capabilities[HABITAT].fuel_cons)) empty_fuel = physics_engine.get_state(t_no_fuel) after_empty_fuel = physics_engine.get_state(t_no_fuel + t_delta) self.assertEqual(round(empty_fuel[0].fuel), 0) self.assertEqual(round(after_empty_fuel[0].vx), round(empty_fuel[0].vx))
def test_srbs(self): """Test that SRBs move the craft, and run out of fuel.""" with PhysicsEngine('tests/habitat.json') as physics_engine: t_delta = 5 physics_engine.handle_requests( [network.Request(ident=network.Request.IGNITE_SRBS)], requested_t=0) initial = physics_engine.get_state(0) moved = physics_engine.get_state(t_delta) self.assertAlmostEqual(initial[0].heading, 0) self.assertAlmostEqual(initial[0].vx, 0) self.assertAlmostEqual(moved[0].vx, t_delta * calc.engine_acceleration(moved)) srb_empty = physics_engine.get_state(common.SRB_BURNTIME) after_srb_empty = physics_engine.get_state(common.SRB_BURNTIME + 5) self.assertAlmostEqual(srb_empty[0].vx, after_srb_empty[0].vx)
def _create_wtexts(self): vpython.canvas.get_selected().caption += "<table>\n" self._wtexts: List[TableText] = [] self._wtexts.append( TableText("Simulation time", lambda state: datetime.fromtimestamp( state.timestamp, common.TIMEZONE).strftime('%x %X'), "Current time in simulation", new_section=False)) self._wtexts.append( TableText("Orbit speed", lambda state: common.format_num( calc.orb_speed(state.craft_entity(), state.reference_entity()), " m/s"), "Speed required for circular orbit at current altitude", new_section=False)) self._wtexts.append( TableText( "Periapsis", lambda state: common.format_num(calc.periapsis( state.craft_entity(), state.reference_entity()) / 1000, " km", decimals=3), "Lowest altitude in naïve orbit around reference", new_section=False)) self._wtexts.append( TableText( "Apoapsis", lambda state: common.format_num(calc.apoapsis( state.craft_entity(), state.reference_entity()) / 1000, " km", decimals=3), "Highest altitude in naïve orbit around reference", new_section=False)) self._wtexts.append( TableText( # The H in HRT stands for Habitat, even though craft is more # general and covers Ayse, but HRT is the familiar triple name and # the Hawking III says trans rights. "HRT phase θ", lambda state: common.format_num( calc.phase_angle( state.craft_entity(), state.reference_entity(), state.target_entity()), "°") or "Same ref and targ", "Angle between Habitat, Reference, and Target", new_section=False)) self._wtexts.append( TableText( "Throttle", lambda state: "{:.1%}".format(state.craft_entity().throttle), "Percentage of habitat's maximum rated engines", new_section=True)) self._wtexts.append( TableText("Engine Acceleration", lambda state: common.format_num( calc.engine_acceleration(state), " m/s/s") + (' [SRB]' if state.srb_time > 0 else ''), "Acceleration due to craft's engine thrust", new_section=False)) self._wtexts.append( TableText("Drag", lambda state: common.format_num( calc.fastnorm(calc.drag(state)), " m/s/s"), "Atmospheric drag acting on the craft", new_section=False)) self._wtexts.append( TableText("Fuel", lambda state: common.format_num( state.craft_entity().fuel, " kg"), "Remaining fuel of craft", new_section=False)) def rotation_formatter(state: PhysicsState) -> str: deg_spin = round(np.degrees(state.craft_entity().spin), ndigits=1) if deg_spin < 0: return f"{-deg_spin} °/s cw" elif deg_spin > 0: return f"{deg_spin} °/s ccw" else: return f"{deg_spin} °/s" self._wtexts.append( TableText("Rotation", rotation_formatter, "Rotation speed of craft", new_section=False)) self._wtexts.append( TableText( "Ref altitude", lambda state: common.format_num(calc.altitude( state.craft_entity(), state.reference_entity()) / 1000, " km", decimals=3), "Altitude of habitat above reference surface", new_section=True)) self._wtexts.append( TableText("Ref speed", lambda state: common.format_num( calc.speed(state.craft_entity(), state.reference_entity()), " m/s"), "Speed of habitat above reference surface", new_section=False)) self._wtexts.append( TableText( "Vertical speed", lambda state: common.format_num( calc.v_speed(state.craft_entity(), state.reference_entity( )), " m/s "), "Vertical speed of habitat towards/away reference surface", new_section=False)) self._wtexts.append( TableText("Horizontal speed", lambda state: common.format_num( calc.h_speed(state.craft_entity(), state.reference_entity()), " m/s "), "Horizontal speed of habitat across reference surface", new_section=False)) self._wtexts.append( TableText("Pitch θ", lambda state: common.format_num( np.degrees( calc.pitch(state.craft_entity( ), state.reference_entity())) % 360, "°"), "Horizontal speed of habitat across reference surface", new_section=False)) self._wtexts.append( TableText("Targ altitude", lambda state: common.format_num(calc.altitude( state.craft_entity(), state.target_entity()) / 1000, " km", decimals=3), "Altitude of habitat above reference surface", new_section=True)) self._wtexts.append( TableText("Targ speed", lambda state: common.format_num( calc.speed(state.craft_entity(), state.target_entity( )), " m/s"), "Speed of habitat above target surface", new_section=False)) self._wtexts.append( TableText( "Landing acc", lambda state: common.format_num( calc.landing_acceleration(state.craft_entity(), state.target_entity()), " m/s/s" ) or "no vertical landing", "Constant engine acc to land during vertical descent to target", new_section=False)) vpython.canvas.get_selected().caption += "</table>"