def METHOD_NAME(
    controller: Optional[AcadosOcpSolver],
    plant: AcadosSimSolver,
    x0: np.ndarray,
    Nsim: int,
    X_ref: np.ndarray,
    U_ref: np.ndarray,
):
    nx = X_ref.shape[1]
    nu = U_ref.shape[1]
    X = np.ndarray((Nsim + 1, nx))
    U = np.ndarray((Nsim, nu))
    timings_solver = np.zeros((Nsim))
    timings_integrator = np.zeros((Nsim))
    # closed loop
    xcurrent = x0
    X[0, :] = xcurrent
    for i in range(Nsim):
        if controller is None:
            U[i, :] = U_ref[i, :]
        else:
            # set initial state
            controller.set(0, "lbx", xcurrent)
            controller.set(0, "ubx", xcurrent)
            yref = np.concatenate((X_ref[i, :], U_ref[i, :]))
            for stage in range(controller.acados_ocp.dims.N):
                controller.set(stage, "yref", yref)
            controller.set(controller.acados_ocp.dims.N, "yref", X_ref[i, :])
            # solve ocp
            status = controller.solve()
            if status != 0:
                controller.print_statistics()
                raise Exception(
                    f"acados controller returned status {status} in simulation step {i}. Exiting."
                )
            U[i, :] = controller.get(0, "u")
            timings_solver[i] = controller.get_stats("time_tot")
        # simulate system
        plant.set("x", xcurrent)
        plant.set("u", U[i, :])
        if plant.acados_sim.solver_options.integrator_type == "IRK":
            plant.set("xdot", np.zeros((nx,)))
        status = plant.solve()
        if status != 0:
            raise Exception(
                f"acados integrator returned status {status} in simulation step {i}. Exiting."
            )
        timings_integrator[i] = plant.get("time_tot")
        # update state
        xcurrent = plant.get("x")
        X[i + 1, :] = xcurrent
    return X, U, timings_solver, timings_integrator