Exemple #1
0
QxN = sparse.diags([1, 1])

Qu = 0.01 * sparse.eye(1)
QDu = 0.0 * sparse.eye(1)

x0 = np.array([1, 0])

uminus1 = np.array([0.0])

Np = 1000

K = MPCController(Ad,
                  Bd,
                  Np=Np,
                  x0=x0,
                  xref=xref,
                  uminus1=uminus1,
                  Qx=Qx,
                  QxN=QxN,
                  Qu=Qu,
                  QDu=QDu,
                  xmin=xmin,
                  xmax=xmax,
                  umin=umin,
                  umax=umax,
                  Dumin=Dumin,
                  Dumax=Dumax)
K.setup()
uMPC = K.output()
# uMPC = K.output(return_u_seq=True)
print(uMPC)
Exemple #2
0
    nsim = int(len_sim / Ts)  # simulation length(timesteps)
    xsim = np.zeros((nsim, nx))
    usim = np.zeros((nsim, nu))
    tsim = np.arange(0, nsim) * Ts

    time_start = time.time()

    t_step = t0
    uMPC = uminus1
    for i in range(nsim):
        xsim[i, :] = system_dyn.y

        # MPC update and step. Could be in just one function call
        xref = r_fun(t_step)  # reference state
        K.update(system_dyn.y, uMPC, xref=xref)  # update with measurement
        uMPC = K.output()  # MPC step (u_k value)
        usim[i, :] = uMPC

        # System simulation step
        system_dyn.set_f_params(uMPC)  # set current input value
        system_dyn.integrate(t_step + Ts)

        # Update simulation time
        t_step += Ts

    time_sim = time.time() - time_start

    fig, axes = plt.subplots(3, 1, figsize=(10, 10))
    axes[0].plot(tsim, xsim[:, 0], "k", label='p')
    axes[0].plot(tsim, xref[0] * np.ones(np.shape(tsim)), "r--", label="p_ref")
    axes[0].set_title("Position (m)")
Exemple #3
0
    uMPC = uminus1
    for i in range(nsim):

        # System output

        # Save system data
        xsim[i, :] = xstep
        ystep = Cd.dot(x0)  # + noise ?
        ysim[i, :] = ystep

        # Save estimator data
        xest[i, :] = xstep_est

        # MPC update and step. Could be in just one function call
        K.update(xstep_est, uMPC)  # update with measurement
        uMPC, infoMPC = K.output(return_x_seq=True)  # MPC step (u_k value)
        usim[i, :] = uMPC
        xpred[i, :, :] = infoMPC['x_seq']  # save predictions for further use

        # System simulation step
        F = uMPC
        v = xstep[1]
        theta = xstep[2]
        omega = xstep[3]
        der = np.zeros(nx)
        der[0] = v
        der[1] = (m * l * np.sin(theta) * omega**2 - m * g * np.sin(theta) *
                  np.cos(theta) + m * ftheta * np.cos(theta) * omega + F -
                  b * v) / (M + m * (1 - np.cos(theta)**2))
        der[2] = omega
        der[3] = ((M + m) * (g * np.sin(theta) - ftheta * omega) -
def simulate_pendulum_MPC(sim_options):

    use_NN_model = get_parameter(sim_options, 'use_NN_model')

    if use_NN_model:
        Ts_fit = 10e-3  # model was fitted with this sampling time
        ss_model = CartPoleStateSpaceModel(Ts=Ts_fit)
        nn_solution = NeuralStateSpaceSimulator(ss_model, Ts=Ts_fit)
        model_name = "model_SS_1step_nonoise.pkl"
        nn_solution.ss_model.load_state_dict(
            torch.load(os.path.join("models", model_name)))
        f_ODE = nn_solution.f_ODE
    else:
        f_ODE = f_ODE_wrapped

    seed_val = get_parameter(sim_options, 'seed_val')
    if seed_val is not None:
        np.random.seed(seed_val)

    Ac = get_parameter(sim_options, 'Ac')
    Bc = get_parameter(sim_options, 'Bc')

    Cc = np.array([[1., 0., 0., 0.], [0., 0., 1., 0.]])

    Dc = np.zeros((2, 1))

    [nx, nu] = Bc.shape  # number of states and number or inputs
    ny = np.shape(Cc)[0]

    Ts_MPC = get_parameter(sim_options, 'Ts_MPC')
    ratio_Ts = int(Ts_MPC // Ts_fast)
    Ts_MPC = (
        (Ts_MPC //
         Ts_fast)) * Ts_fast  # make Ts_MPC an integer multiple of Ts_fast

    # Brutal forward euler discretization
    Ad = np.eye(nx) + Ac * Ts_MPC
    Bd = Bc * Ts_MPC
    Cd = Cc
    Dd = Dc

    # Standard deviation of the measurement noise on position and angle

    std_npos = get_parameter(sim_options, 'std_npos')
    std_nphi = get_parameter(sim_options, 'std_nphi')

    # Force disturbance
    std_dF = get_parameter(sim_options, 'std_dF')

    # disturbance power spectrum
    w_F = get_parameter(sim_options,
                        'w_F')  # bandwidth of the force disturbance
    tau_F = 1 / w_F
    Hu = control.TransferFunction([1], [1 / w_F, 1])
    Hu = Hu * Hu
    Hud = control.matlab.c2d(Hu, Ts_MPC)
    N_sim_imp = tau_F / Ts_MPC * 20
    t_imp = np.arange(N_sim_imp) * Ts_MPC
    t, y = control.impulse_response(Hud, t_imp)
    y = y[0]
    std_tmp = np.sqrt(np.sum(y**2))  # np.sqrt(trapz(y**2,t))
    Hu = Hu / (std_tmp) * std_dF

    N_skip = 1  #int(20 * tau_F // Ts_MPC) # skip initial samples to get a regime sample of d
    t_sim_d = get_parameter(sim_options, 'len_sim')  # simulation length (s)
    N_sim_d = int(t_sim_d // Ts_MPC)
    N_sim_d = N_sim_d + N_skip + 1
    e = np.random.randn(N_sim_d)
    te = np.arange(N_sim_d) * Ts_MPC
    _, d, _ = control.forced_response(Hu, te, e)
    d = d.ravel()
    p_ref = d[N_skip:]
    #td = np.arange(len(d)) * Ts_fast

    Np = get_parameter(sim_options, 'Np')
    Nc = get_parameter(sim_options, 'Nc')

    Qx = get_parameter(sim_options, 'Qx')
    QxN = get_parameter(sim_options, 'QxN')
    Qu = get_parameter(sim_options, 'Qu')
    QDu = get_parameter(sim_options, 'QDu')

    # Reference input and states
    xref_fun = get_parameter(sim_options, 'xref_fun')  # reference state
    xref_fun_v = np.vectorize(xref_fun, signature='()->(n)')

    t0 = 0
    xref_MPC = xref_fun(t0)
    uref = get_parameter(sim_options, 'uref')
    uminus1 = np.array(
        [0.0]
    )  # input at time step negative one - used to penalize the first delta u at time instant 0. Could be the same as uref.

    # Constraints
    xmin = np.array([-1000, -1000, -1000, -1000])
    xmax = np.array([1000, 1000.0, 1000, 1000])

    umin = np.array([-10])
    umax = np.array([10])

    Dumin = np.array([-100 * Ts_MPC])
    Dumax = np.array([100 * Ts_MPC])

    # Initialize simulation system
    phi0 = 0.0  #10*2*np.pi/360
    x0 = np.array([0, 0, phi0, 0])  # initial state
    #    system_dyn = ode(f_ODE_wrapped).set_integrator('vode', method='bdf') #    dopri5
    system_dyn = ode(f_ODE).set_integrator('dopri5')
    system_dyn.set_initial_value(x0, t0)
    system_dyn.set_f_params(0.0)

    QP_eps_rel = get_parameter(sim_options, 'QP_eps_rel')
    QP_eps_abs = get_parameter(sim_options, 'QP_eps_abs')

    # Emergency exit conditions

    EMERGENCY_STOP = False
    EMERGENCY_POS = 30.0
    EMERGENCY_ANGLE = 90 * DEG_TO_RAD

    K = MPCController(Ad,
                      Bd,
                      Np=Np,
                      Nc=Nc,
                      x0=x0,
                      xref=xref_MPC,
                      uminus1=uminus1,
                      Qx=Qx,
                      QxN=QxN,
                      Qu=Qu,
                      QDu=QDu,
                      xmin=xmin,
                      xmax=xmax,
                      umin=umin,
                      umax=umax,
                      Dumin=Dumin,
                      Dumax=Dumax,
                      eps_feas=1e3,
                      eps_rel=QP_eps_rel,
                      eps_abs=QP_eps_abs)

    try:
        K.setup(solve=True)  # setup initial problem and also solve it
    except:
        EMERGENCY_STOP = True

    if not EMERGENCY_STOP:
        if K.res.info.status != 'solved':
            EMERGENCY_STOP = True

    # Basic Kalman filter design
    Q_kal = get_parameter(sim_options, 'Q_kal')
    R_kal = get_parameter(sim_options, 'R_kal')
    L, P, W = kalman_design_simple(Ad,
                                   Bd,
                                   Cd,
                                   Dd,
                                   Q_kal,
                                   R_kal,
                                   type='predictor')
    x0_est = x0
    KF = LinearStateEstimator(x0_est, Ad, Bd, Cd, Dd, L)

    # Simulate in closed loop
    len_sim = get_parameter(sim_options, 'len_sim')  # simulation length (s)
    nsim = int(
        np.ceil(len_sim / Ts_MPC)
    )  # simulation length(timesteps) # watch out! +1 added, is it correct?
    t_vec = np.zeros((nsim, 1))
    t_calc_vec = np.zeros(
        (nsim, 1))  # computational time to get MPC solution (+ estimator)
    status_vec = np.zeros((nsim, 1))
    x_vec = np.zeros((nsim, nx))
    x_ref_vec = np.zeros((nsim, nx))
    y_vec = np.zeros((nsim, ny))
    y_meas_vec = np.zeros((nsim, ny))
    y_est_vec = np.zeros((nsim, ny))
    x_est_vec = np.zeros((nsim, nx))
    u_vec = np.zeros((nsim, nu))
    x_MPC_pred = np.zeros(
        (nsim, Np + 1, nx))  # on-line predictions from the Kalman Filter

    nsim_fast = int(len_sim // Ts_fast)
    t_vec_fast = np.zeros((nsim_fast, 1))
    x_vec_fast = np.zeros(
        (nsim_fast, nx))  # finer integration grid for performance evaluation
    x_ref_vec_fast = np.zeros(
        (nsim_fast, nx))  # finer integration grid for performance evaluatio
    u_vec_fast = np.zeros(
        (nsim_fast, nu))  # finer integration grid for performance evaluatio
    Fd_vec_fast = np.zeros((nsim_fast, nu))  #
    t_int_vec_fast = np.zeros((nsim_fast, 1))
    emergency_vec_fast = np.zeros((nsim_fast, 1))  #

    t_pred_all = t0 + np.arange(nsim + Np + 1) * Ts_MPC
    Xref_MPC_all = xref_fun_v(t_pred_all)

    t_step = t0
    x_step = x0
    u_MPC = None
    for idx_fast in range(nsim_fast):

        ## Determine step type: fast simulation only or MPC step
        idx_MPC = idx_fast // ratio_Ts
        run_MPC = (idx_fast % ratio_Ts) == 0

        # Output for step i
        # Ts_MPC outputs
        if run_MPC:  # it is also a step of the simulation at rate Ts_MPC
            t_vec[idx_MPC, :] = t_step
            x_vec[idx_MPC, :] = x_step  #system_dyn.y
            xref_MPC = np.array([p_ref[idx_MPC], 0.0, 0.0, 0.0])
            #xref_MPC = xref_fun(t_step)  # reference state
            t_pred = t_step + np.arange(Np + 1) * Ts_MPC
            x_ref_vec[idx_MPC, :] = xref_MPC

            if not EMERGENCY_STOP:
                #                u_MPC, info_MPC = K.output(return_x_seq=True, return_status=True)  # u[i] = k(\hat x[i]) possibly computed at time instant -1
                u_MPC, info_MPC = K.output(
                    return_status=True, return_x_seq=True
                )  # u[i] = k(\hat x[i]) possibly computed at time instant -1
            else:
                u_MPC = np.zeros(nu)

            if not EMERGENCY_STOP:
                if info_MPC['status'] != 'solved':
                    EMERGENCY_STOP = True

            if not EMERGENCY_STOP:
                #pass
                x_MPC_pred[idx_MPC, :, :] = info_MPC[
                    'x_seq']  # x_MPC_pred[i,i+1,...| possibly computed at time instant -1]
            u_vec[idx_MPC, :] = u_MPC

            y_step = Cd.dot(x_step)  # y[i] from the system
            ymeas_step = np.copy(y_step)
            ymeas_step[0] += std_npos * np.random.randn()
            ymeas_step[1] += std_nphi * np.random.randn()
            y_vec[idx_MPC, :] = y_step
            y_meas_vec[idx_MPC, :] = ymeas_step
            if not EMERGENCY_STOP:
                status_vec[idx_MPC, :] = (info_MPC['status'] != 'solved')

            if np.abs(ymeas_step[0]) > EMERGENCY_POS or np.abs(
                    ymeas_step[1]) > EMERGENCY_ANGLE:
                EMERGENCY_STOP = True

        # Ts_fast outputs
        t_vec_fast[idx_fast, :] = t_step
        x_vec_fast[idx_fast, :] = x_step  #system_dyn.y
        x_ref_vec_fast[idx_fast, :] = xref_MPC
        u_fast = u_MPC
        u_vec_fast[idx_fast, :] = u_fast
        Fd_vec_fast[idx_fast, :] = 0.0
        emergency_vec_fast[idx_fast, :] = EMERGENCY_STOP

        ## Update to step i+1

        # Controller simulation step at rate Ts_MPC
        if run_MPC:
            time_calc_start = time.perf_counter()
            # Kalman filter: update and predict
            #KF.update(ymeas_step) # \hat x[i|i]
            #KF.predict(u_MPC)    # \hat x[i+1|i]
            KF.predict_update(u_MPC, ymeas_step)
            # MPC update
            if not EMERGENCY_STOP:
                #Xref_MPC = Xref_MPC_all[idx_MPC:idx_MPC + Np + 1]
                K.update(
                    KF.x, u_MPC,
                    xref=xref_MPC)  # update with measurement and reference
                #K.update(KF.x, u_MPC, xref=xref_MPC)  # update with measurement and reference
            t_calc_vec[idx_MPC, :] = time.perf_counter() - time_calc_start
            if t_calc_vec[idx_MPC, :] > 2 * Ts_MPC:
                EMERGENCY_STOP = True

        # System simulation step at rate Ts_fast
        time_integrate_start = time.perf_counter()
        system_dyn.set_f_params(u_fast)
        system_dyn.integrate(t_step + Ts_fast)
        x_step = system_dyn.y
        #x_step = x_step + f_ODE(t_step, x_step, u_fast)*Ts_fast
        t_int_vec_fast[
            idx_fast, :] = time.perf_counter() - time_integrate_start

        # Time update
        t_step += Ts_fast

    simout = {
        't': t_vec,
        'x': x_vec,
        'u': u_vec,
        'y': y_vec,
        'y_meas': y_meas_vec,
        'x_ref': x_ref_vec,
        'x_MPC_pred': x_MPC_pred,
        'status': status_vec,
        'Fd_fast': Fd_vec_fast,
        't_fast': t_vec_fast,
        'x_fast': x_vec_fast,
        'x_ref_fast': x_ref_vec_fast,
        'u_fast': u_vec_fast,
        'emergency_fast': emergency_vec_fast,
        'KF': KF,
        'K': K,
        'nsim': nsim,
        'Ts_MPC': Ts_MPC,
        't_calc': t_calc_vec,
        't_int_fast': t_int_vec_fast,
        'use_NN_model': use_NN_model
    }

    return simout
Exemple #5
0
    uMPC = uminus1
    y_step = None
    ymeas_step = None
    #x_step = x0
    for i in range(nsim):
        # Output for step i
        # System
        y_step = Cd.dot(system_dyn.y)  # y[i] from the system
        ymeas_step = y_step
        ymeas_step[0] += std_npos * np.random.randn()
        ymeas_step[1] += std_nphi * np.random.randn()
        # Estimator

        #        time_MPC_start = time.time()
        uMPC, infoMPC = K.output(
            return_x_seq=True
        )  # u[i] = k(\hat x[i]) possibly computed at time instant -1
        #        t_MPC_CPU[i] = time.time() - time_MPC_start

        x_MPC_pred[i, :, :] = infoMPC[
            'x_seq']  # x_MPC_pred[i,i+1,...| possibly computed at time instant -1]

        # Save output for step i
        y_vec[i, :] = y_step  # y[i]
        y_meas_vec[i, :] = ymeas_step  # y_meas[i]
        x_vec[i, :] = system_dyn.y  # x[i]
        y_est_vec[i, :] = KF.y  # \hat y[i|i-1]
        x_est_vec[i, :] = KF.x  # \hat x[i|i-1]
        u_vec[i, :] = uMPC  # u[i]
        #        x_vec_EA[i,:] = x_step
Exemple #6
0
    # Simulate in closed loop
    [nx, nu] = Bd.shape  # number of states and number or inputs
    len_sim = 30  # simulation length (s)
    nsim = int(len_sim / Ts)  # simulation length(timesteps)
    xsim = np.zeros((nsim, nx))
    usim = np.zeros((nsim, nu))
    tsim = np.arange(0, nsim) * Ts
    J_opt = np.zeros((nsim, 1))

    time_start = time.time()
    xstep = x0
    for i in range(nsim):
        uMPC, info = K.output(return_u_seq=True,
                              return_x_seq=True,
                              return_eps_seq=True,
                              return_status=True,
                              return_obj_val=True)
        xstep = Ad.dot(xstep) + Bd.dot(uMPC)  # system step
        J_opt[i, :] = info['obj_val']
        K.update(xstep)  # update with measurement
        K.solve()
        xsim[i, :] = xstep
        usim[i, :] = uMPC

    time_sim = time.time() - time_start

    #K.__controller_function__(np.array([0,0]), np.array([0]))

    fig, axes = plt.subplots(4, 1, figsize=(10, 10))
    axes[0].plot(tsim, xsim[:, 0], "k", label='p')
def simulate_pendulum_MPC(sim_options):

    seed_val = get_parameter(sim_options,'seed_val')
    if seed_val is not None:
        np.random.seed(seed_val)

    # In[Sample times]
    Ts_MPC = get_parameter(sim_options, 'Ts_MPC')
    ratio_Ts = int(Ts_MPC // Ts_PID)

    # In[Real System]
    Cc = np.array([[1., 0., 0., 0.],
                   [0., 0., 1., 0.]])

    Cd = np.copy(Cc)
    nx, nu = 4,1
    ny = 2

    # In[initialize simulation system]
    t0 = 0
    phi0 = -0.0 * 2 * np.pi / 360 # initial angle
    x0 = np.array([0, 0, phi0, 0])  # initial state
    #system_dyn = ode(f_ODE_wrapped).set_integrator('vode', method='bdf')  # dopri5
    system_dyn = ode(f_ODE_wrapped).set_integrator('dopri5')  # dopri5

    #    system_dyn = ode(f_ODE_wrapped).set_integrator('dopri5')
    system_dyn.set_initial_value(x0, t0)
    system_dyn.set_f_params(0.0)

    #In[MPC params --model]
    Acl_c = get_parameter(sim_options, 'Acl_c')
    Bcl_c = get_parameter(sim_options, 'Bcl_c')
    Ccl_c = np.array([[1., 0., 0],
                      [0., 0., 1]])
    Dcl_c = np.zeros((2, 1))
    ncl_x, ncl_u = Bcl_c.shape  # number of states and number or inputs
    #ncl_y = np.shape(Ccl_c)[0]

    #In[MPC matrices discretization]

    Acl_d = np.eye(ncl_x) + Acl_c*Ts_MPC
    Bcl_d = Bcl_c*Ts_MPC
    Ccl_d = Ccl_c
    Dcl_d = Dcl_c

    x0_cl = np.array([0,0,phi0])
    M_cl = LinearStateSpaceSystem(A=Acl_d, B=Bcl_d, C=Ccl_d, D=Dcl_d, x0=x0_cl)

    # MPC parameters
    Np = get_parameter(sim_options, 'Np')
    Nc = get_parameter(sim_options, 'Nc')

    Qx = get_parameter(sim_options, 'Qx')
    QxN = get_parameter(sim_options, 'QxN')
    Qr = get_parameter(sim_options, 'Qr')
    QDr = get_parameter(sim_options, 'QDr')

    # Constraints
    #xmin = np.array([-1.5, -100,    -100])
    #xmax = np.array([1.5,   100.0,   100])

    #umin = np.array([-10])
    #umax = np.array([10])

    #Dumin = np.array([-100 * Ts_MPC_def])
    #Dumax = np.array([100 * Ts_MPC_def])

    QP_eps_rel = get_parameter(sim_options, 'QP_eps_rel')
    QP_eps_abs = get_parameter(sim_options, 'QP_eps_abs')

    # Emergency exit conditions
    EMERGENCY_STOP = False
    EMERGENCY_POS = 2.0
    EMERGENCY_ANGLE = 30 * DEG_TO_RAD

    # Reference input and states
    xref_cl_fun = get_parameter(sim_options, 'xref_cl_fun') # reference state
    xref_cl_fun_v = np.vectorize(xref_cl_fun, signature='()->(n)')

    t0 = 0
    xref_MPC = xref_cl_fun(t0)
    uref = get_parameter(sim_options, 'uref')
    uminus1 = np.array([0.0])     # input at time step negative one - used to penalize the first delta u at time instant 0. Could be the same as uref.

    kMPC = MPCController(Acl_d, Bcl_d, Np=Np, Nc=Nc, x0=x0_cl, xref=xref_MPC, uminus1=uminus1,
                      Qx=Qx, QxN=QxN, Qu=Qr, QDu=QDr,
                      eps_feas=1e3, eps_rel=QP_eps_rel, eps_abs=QP_eps_abs)

    try:
        kMPC.setup(solve=True)  # setup initial problem and also solve it
    except:
        EMERGENCY_STOP = True

    if not EMERGENCY_STOP:
        if kMPC.res.info.status != 'solved':
            EMERGENCY_STOP = True

    # In[initialize PID]

    # Default controller parameters -
    P = -100.0
    I = -1
    D = -20
    N = 100.0

    kP = control.tf(P,1, Ts_PID)
    kI = I*Ts_PID*control.tf([0, 1], [1,-1], Ts_PID)
    kD = D*control.tf([N, -N], [1.0, Ts_PID*N - 1], Ts_PID)
    PID_tf = kP + kD + kI
    PID_ss = control.ss(PID_tf)
    k_PID = LinearStateSpaceSystem(A=PID_ss.A, B=PID_ss.B, C=PID_ss.C, D=PID_ss.D)

    # In[initialize noise]

    # Standard deviation of the measurement noise on position and angle
    std_npos = get_parameter(sim_options, 'std_npos')
    std_nphi = get_parameter(sim_options, 'std_nphi')

    # Force disturbance
    std_dF = get_parameter(sim_options, 'std_dF')

    # Disturbance power spectrum
    w_F = get_parameter(sim_options, 'w_F') # bandwidth of the force disturbance
    tau_F = 1 / w_F
    Hu = control.TransferFunction([1], [1 / w_F, 1])
    Hu = Hu * Hu
    Hud = control.matlab.c2d(Hu, Ts_PID)
    N_sim_imp = tau_F / Ts_PID * 20
    t_imp = np.arange(N_sim_imp) * Ts_PID
    t, y = control.impulse_response(Hud, t_imp)
    y = y[0]
    std_tmp = np.sqrt(np.sum(y ** 2))  # np.sqrt(trapz(y**2,t))
    Hu = Hu / (std_tmp) * std_dF


    N_skip = int(20 * tau_F // Ts_PID) # skip initial samples to get a regime sample of d
    t_sim_d = get_parameter(sim_options, 'len_sim')  # simulation length (s)
    N_sim_d = int(t_sim_d // Ts_PID)
    N_sim_d = N_sim_d + N_skip + 1
    e = np.random.randn(N_sim_d)
    te = np.arange(N_sim_d) * Ts_PID
    _, d, _ = control.forced_response(Hu, te, e)
    d = d.ravel()

    # Simulate in closed loop
    len_sim = get_parameter(sim_options, 'len_sim')  # simulation length (s)
    nsim = int(len_sim // Ts_MPC) #int(np.ceil(len_sim / Ts_MPC))  # simulation length(timesteps) # watch out! +1 added, is it correct?
    t_vec = np.zeros((nsim, 1))
    status_vec = np.zeros((nsim,1))
    x_vec = np.zeros((nsim, nx))
    x_ref_vec = np.zeros((nsim, ncl_x))
    y_vec = np.zeros((nsim, ny))
    y_meas_vec = np.zeros((nsim, ny))
    u_vec = np.zeros((nsim, nu))
    x_model_vec = np.zeros((nsim,3))

    nsim_fast = int(len_sim // Ts_PID)
    t_vec_fast = np.zeros((nsim_fast, 1))
    x_vec_fast = np.zeros((nsim_fast, nx)) # finer integration grid for performance evaluation
    ref_phi_vec_fast = np.zeros((nsim_fast, 1))
    y_meas_vec_fast = np.zeros((nsim_fast, ny))
    x_ref_vec_fast = np.zeros((nsim_fast, nx)) # finer integration grid for performance evaluatio
    u_vec_fast = np.zeros((nsim_fast, nu)) # finer integration grid for performance evaluatio
    Fd_vec_fast = np.zeros((nsim_fast, nu))  #
    t_int_vec_fast = np.zeros((nsim_fast, 1))
    emergency_vec_fast = np.zeros((nsim_fast, 1))  #

    t_step = t0
    x_step = x0
    u_PID = None
    t_pred_all = t0 + np.arange(nsim + Np + 1) * Ts_MPC
    Xref_MPC_all = xref_cl_fun_v(t_pred_all)

    for idx_fast in range(nsim_fast):

        ## Determine step type: fast simulation only or MPC step
        idx_MPC = idx_fast // ratio_Ts
        run_MPC_controller = (idx_fast % ratio_Ts) == 0

        y_step = Cd.dot(x_step)  # y[i] from the system
        ymeas_step = np.copy(y_step)
        ymeas_step[0] += std_npos * np.random.randn()
        ymeas_step[1] += std_nphi * np.random.randn()
        y_meas_vec_fast[idx_fast,:] = ymeas_step
        # Output for step i
        # Ts_MPC outputs

        if run_MPC_controller: # it is also a step of the simulation at rate Ts_MPC
            if idx_MPC < nsim:
                t_vec[idx_MPC, :] = t_step
                y_vec[idx_MPC,:] = y_step
                y_meas_vec[idx_MPC,:] = ymeas_step
                u_vec[idx_MPC, :] = u_PID
                x_model_vec[idx_MPC, :] = M_cl.x.ravel()
                xref_MPC = xref_cl_fun(t_step)
                x_ref_vec[idx_MPC,:] = xref_MPC.ravel()

            if not EMERGENCY_STOP:
                phi_ref_MPC, info_MPC = kMPC.output(return_status=True)  # u[i] = k(\hat x[i]) possibly computed at time instant -1
            else:
                phi_ref_MPC = np.zeros(nu)

        # PID angle CONTROLLER
        ref_phi = phi_ref_MPC.ravel()
        error_phi = ref_phi - ymeas_step[1]
        u_PID = k_PID.output(error_phi)
        u_PID[u_PID > 10.0] = 10.0
        u_PID[u_PID < -10.0] = -10.0
        u_TOT = u_PID

        # Ts_fast outputs
        t_vec_fast[idx_fast,:] = t_step
        x_vec_fast[idx_fast, :] = x_step #system_dyn.y
        u_vec_fast[idx_fast,:] = u_TOT
        Fd_vec_fast[idx_fast,:] = 0.0
        ref_phi_vec_fast[idx_fast,:] = ref_phi

        ## Update to step i+1
        k_PID.update(error_phi)

        # Controller simulation step at rate Ts_MPC
        if run_MPC_controller:
            M_cl.update(ref_phi)
            if not EMERGENCY_STOP:
                x_cl = np.array([x_step[0], x_step[1], x_step[2]])
                Xref_MPC = Xref_MPC_all[idx_MPC:idx_MPC + Np + 1]
                xref_MPC = Xref_MPC_all[idx_MPC]
                kMPC.update(x_cl, phi_ref_MPC, xref=xref_MPC) # update with measurement and reference

        # System simulation step at rate Ts_fast
        time_integrate_start = time.perf_counter()
        system_dyn.set_f_params(u_TOT)
        system_dyn.integrate(t_step + Ts_PID)
        x_step = system_dyn.y
        t_int_vec_fast[idx_fast,:] = time.perf_counter() - time_integrate_start

        # Time update
        t_step += Ts_PID

    simout = {'t': t_vec, 'x': x_vec, 'u': u_vec, 'y': y_vec, 'y_meas': y_meas_vec, 'x_ref': x_ref_vec,  'status': status_vec, 'Fd_fast': Fd_vec_fast,
              't_fast': t_vec_fast, 'x_fast': x_vec_fast, 'x_ref_fast': x_ref_vec_fast, 'u_fast': u_vec_fast, 'y_meas_fast': y_meas_vec_fast, 'emergency_fast': emergency_vec_fast,
              'PID_tf': PID_tf, 'Ts_MPC': Ts_MPC,  'ref_phi_fast': ref_phi_vec_fast, 'x_model': x_model_vec,
              't_int_fast': t_int_vec_fast
              }

    return simout