def test_skywalkerX8_force_x_dir(): control_input = ControlInput() control_input.throttle = 0.0 t = 0 state = State() state.vx = 20.0 for j in range(3): state.pitch = state.pitch + 0.05 state.roll = state.roll + 0.05 state.yaw = state.yaw + 0.05 x_update = np.zeros(11) constants = SkywalkerX8Constants() for i in range(0, 11): control_input.throttle = i * 0.1 prop = IcedSkywalkerX8Properties(control_input) params = {"prop": prop, "wind": no_wind()} update = dynamics_kinetmatics_update(t, x=state.state, u=control_input.control_input, params=params) x_update[i] = update[6] S_p = constants.propeller_area C_p = constants.motor_efficiency_fact k_m = constants.motor_constant m = constants.mass K = 2 * m / (AIR_DENSITY * S_p * C_p * k_m**2) for i in range(0, 10): throttle_0 = i * 0.1 throttle_1 = (i + 1) * 0.1 assert np.allclose(K * (x_update[i + 1] - x_update[i]), throttle_1**2 - throttle_0**2)
def aircraft_property_from_dct(aircraft: dict) -> AircraftProperties: """ Return an aircraft property class initialized with the passed dictionary """ known_types = [ SKYWALKERX8, FRICTIONLESS_BALL, AIRCRAFT_NO_FORCE, SKYWALKERX8_ASYMETRIC ] aircraft_type = aircraft.get('type', "") if aircraft_type not in known_types: raise ValueError(f"Aircraft type must be one of {known_types}") if aircraft_type == SKYWALKERX8: return IcedSkywalkerX8Properties(ControlInput(), aircraft.get('icing', 0)) elif aircraft_type == SKYWALKERX8_ASYMETRIC: return AsymetricIcedSkywalkerX8Properties( ControlInput(), aircraft.get('icing_left_wing', 0), aircraft.get('icing_right_wing', 0)) elif aircraft_type == FRICTIONLESS_BALL: return FrictionlessBall(ControlInput()) elif aircraft_type == AIRCRAFT_NO_FORCE: return SimpleTestAircraftNoForces(ControlInput()) raise ValueError("Unknown aircraft type")
def test_interconnected_system(): control_input = ControlInput() control_input.throttle = 0.5 wind_model = no_wind() state = State() state.vx = 20 prop = IcedSkywalkerX8Properties(control_input) outputs = [ "x", "y", "z", "roll", "pitch", "yaw", "vx", "vy", "vz", "ang_rate_x", "ang_rate_y", "ang_rate_z" ] aircraft_model = build_nonlin_sys(prop, wind_model, outputs) initial_control_input_state = ControlInput() initial_control_input_state.throttle = 0.4 motor_time_constant = 0.001 elevon_time_constant = 0.001 actuator_model = build_flying_wing_actuator_system(elevon_time_constant, motor_time_constant) x0 = np.concatenate( (initial_control_input_state.control_input, state.state)) connected_system = add_actuator(actuator_model, aircraft_model) t = np.linspace(0.0, 0.5, 10, endpoint=True) u = np.array([ control_input.control_input, ] * len(t)).transpose() T, yout_without_actuator = input_output_response(aircraft_model, t, U=u, X0=state.state) T, yout_with_actuator = input_output_response(connected_system, t, U=u, X0=x0) assert np.allclose(yout_with_actuator[6, :], yout_without_actuator[6, :], atol=5.e-3) assert np.allclose(yout_with_actuator[7, :], yout_without_actuator[7, :], atol=5.e-3) assert np.allclose(yout_with_actuator[8, :], yout_without_actuator[8, :], atol=5.e-3) assert np.allclose(yout_with_actuator[9, :], yout_without_actuator[9, :], atol=5.e-3) assert np.allclose(yout_with_actuator[10, :], yout_without_actuator[10, :], atol=5.e-3) assert np.allclose(yout_with_actuator[11, :], yout_without_actuator[11, :], atol=5.e-3)
def main(): # Initialize gain scheduled controller # Using two simple P-controllers, see also fcat.longitudinal_controller for more complicated examples # Note that this is just an example on how to build and simulate an aircraft system # The controllers are simple not tuned to get desired reference tracking controllers = [ SaturatedStateSpaceMatricesGS( A = -1*np.eye(1), B = np.zeros((1,1)), C = np.eye(1), D = np.zeros((1,1)), upper = 1, lower = -1, switch_signal = 0.3 ), SaturatedStateSpaceMatricesGS( A = -1*np.eye(1), B = np.zeros((1,1)), C = np.eye(1), D = np.zeros((1,1)), upper = 1, lower = -1, switch_signal = 0.6 ) ] # Using similar controllers for simplicity lat_gs_controller = init_gs_controller(controllers, Direction.LATERAL, 'icing') lon_gs_controller = init_gs_controller(controllers, Direction.LONGITUDINAL, 'icing') airspeed_pi_controller = init_airspeed_controller() control_input = ControlInput() control_input.throttle = 0.5 state = State() state.vx = 20 prop = IcedSkywalkerX8Properties(control_input) aircraft_model = build_nonlin_sys(prop, no_wind(), outputs=State.names+['icing', 'airspeed']) motor_time_constant = 0.001 elevon_time_constant = 0.001 actuator_model = build_flying_wing_actuator_system(elevon_time_constant, motor_time_constant) closed_loop = build_closed_loop(actuator_model, aircraft_model, lon_gs_controller, lat_gs_controller, airspeed_pi_controller) X0 = get_init_vector(closed_loop, control_input, state) constant_input = np.array([20, 0.04, -0.00033310605950459315]) sim_time = 15 t = np.linspace(0, sim_time, sim_time*5, endpoint=True) u = np.array([constant_input, ]*(len(t))).transpose() T, yout_non_lin, _ = input_output_response( closed_loop, U=u, T=t, X0=X0, return_x=True, method='BDF')
def test_lift_coeff(state, wind, icing, control_input, expect): prop = IcedSkywalkerX8Properties(control_input, icing=icing) assert prop.lift_coeff(state, wind) == pytest.approx(expect)