def fun():
    isDone = True
    init_state = numpy.array([0.55, 450])  # initial state

    # Setup Switching Particle Filter
    A = numpy.array([[0.999, 0.001], [0.001, 0.999]])

    def fun1(x, u, w):
        return params.cstr_model.run_reactor(x, u, params.h) + w

    def fun2(x, u, w):
        return params.cstr_model_broken.run_reactor(x, u, params.h) + w

    def gs(x):
        return params.C2 @ x

    F = [fun1, fun2]
    G = [gs, gs]
    numSwitches = 2

    ydists = numpy.array([
        scipy.stats.multivariate_normal(cov=params.R2),
        scipy.stats.multivariate_normal(cov=params.R2)
    ])
    xdists = numpy.array([
        scipy.stats.multivariate_normal(cov=params.Q),
        scipy.stats.multivariate_normal(cov=params.Q)
    ])
    cstr_filter = SPF.Model(F, G, A, xdists, ydists)

    nP = 500  # number of particles
    xdist = scipy.stats.multivariate_normal(mean=init_state,
                                            cov=params.init_state_covar)
    sdist = [0.9, 0.1]
    particles = SPF.init_spf(xdist, sdist, nP, 2)

    switchtrack = numpy.zeros([2, params.N])
    maxtrack = numpy.zeros([numSwitches, params.N])
    smoothedtrack = numpy.zeros([numSwitches, params.N])

    state_noise_dist = scipy.stats.multivariate_normal(cov=params.Q)
    meas_noise_dist = scipy.stats.multivariate_normal(cov=params.R2)

    # Setup control (use linear control)
    linsystems = params.cstr_model.get_nominal_linear_systems(params.h)
    linsystems_broken = params.cstr_model_broken.get_nominal_linear_systems(
        params.h)
    opoint = 1  # the specific linear model we will use

    lin_models = [None] * 2  # type: typing.List[RBPF.Model]
    lin_models[0] = RBPF.Model(linsystems[opoint].A, linsystems[opoint].B,
                               linsystems[opoint].b, params.C2, params.Q,
                               params.R2)
    lin_models[1] = RBPF.Model(linsystems_broken[opoint].A,
                               linsystems_broken[opoint].B,
                               linsystems_broken[opoint].b, params.C2,
                               params.Q, params.R2)

    H = numpy.matrix([1, 0])  # only attempt to control the concentration
    setpoint = 0.49
    controllers = [None] * 2  # type: typing.List[LQR.Controller]
    for k in range(2):
        ysp = setpoint - lin_models[k].b[0]  # set point is set here
        x_off, u_off = LQR.offset(lin_models[k].A,
                                  numpy.matrix(lin_models[k].B), params.C2, H,
                                  numpy.matrix([ysp]))
        K = LQR.lqr(lin_models[k].A, numpy.matrix(lin_models[k].B), params.QQ,
                    params.RR)
        controllers[k] = LQR.Controller(K, x_off, u_off)

    # Setup simulation
    params.xs[:, 0] = init_state
    params.ys2[:, 0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs(
    )  # measured from actual plant

    SPF.init_filter(particles, params.ys2[:, 0], cstr_filter)

    for k in range(numSwitches):
        switchtrack[k, 0] = numpy.sum(
            particles.w[numpy.where(particles.s == k)[0]])

    maxtrack[:, 0] = SPF.get_max_track(particles, numSwitches)
    smoothedtrack[:, 0] = RBPF.smoothed_track(numSwitches, switchtrack, 1, 10)

    params.spfmeans[:, 0], params.spfcovars[:, :, 0] = SPF.get_stats(particles)

    # Controller Input
    ind = numpy.argmax(maxtrack[:, 0])  # use this model and controller
    horizon = 150
    params.us[0] = MPC.mpc_lqr(params.spfmeans[:, 0] - lin_models[ind].b,
                               horizon, lin_models[ind].A,
                               numpy.matrix(lin_models[ind].B), params.QQ,
                               params.RR, controllers[ind].x_off,
                               controllers[ind].u_off)

    # Loop through the rest of time
    for t in range(1, params.N):
        random_element = state_noise_dist.rvs()
        if params.ts[t] < 100:  # break here
            params.xs[:, t] = params.cstr_model.run_reactor(
                params.xs[:, t - 1], params.us[t - 1],
                params.h) + random_element
        else:
            params.xs[:, t] = params.cstr_model_broken.run_reactor(
                params.xs[:, t - 1], params.us[t - 1], params.h)
            params.xs[:, t] += random_element

        params.ys2[:, t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
        )  # measured from actual plant

        SPF.spf_filter(particles, params.us[t - 1], params.ys2[:, t],
                       cstr_filter)
        params.spfmeans[:, t], params.spfcovars[:, :,
                                                t] = SPF.get_stats(particles)

        for k in range(numSwitches):
            switchtrack[k, 0] = numpy.sum(
                particles.w[numpy.where(particles.s == k)[0]])

        maxtrack[:, t] = SPF.get_max_track(particles, numSwitches)
        smoothedtrack[:, t] = RBPF.smoothed_track(numSwitches, switchtrack, t,
                                                  40)

        # Controller Input
        if t % 1 == 0:
            ind = numpy.argmax(maxtrack[:, t])  # use this model and controller
            params.us[t] = MPC.mpc_lqr(
                params.spfmeans[:, t] - lin_models[ind].b, horizon,
                lin_models[ind].A, numpy.matrix(lin_models[ind].B), params.QQ,
                params.RR, controllers[ind].x_off, controllers[ind].u_off)
        else:
            params.us[t] = params.us[t - 1]
            if params.us[t] is None or numpy.isnan(params.us[t]):
                isDone = False
                break
    return isDone, setpoint
    loc = numpy.where(particles.ss == k)[0]
    s = 0
    for l in loc:
        s += particles.ws[l]

    switchtrack[k, 0] = s

maxtrack[:, 0] = RBPF.get_max_track(particles, numModels)

# Controller Input
ind = numpy.argmax(maxtrack[:, 0])  # use this model and controller
horizon = 150

params.us[0] = MPC.mpc_lqr(params.rbpfmeans[:, 0] - models[ind].b, horizon,
                           models[ind].A, numpy.matrix(models[ind].B),
                           numpy.matrix(params.QQ), numpy.matrix(params.RR),
                           controllers[ind].x_off,
                           numpy.array([controllers[ind].u_off[0]]))
# Loop through the rest of time

for t in range(1, params.N):
    params.xs[:, t] = params.cstr_model.run_reactor(params.xs[:, t - 1],
                                                    params.us[t - 1], params.h)
    params.xs[:, t] += state_noise_dist.rvs()  # actual plant
    params.ys2[:, t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
    )  # measured from actual plant
    RBPF.rbpf_filter(particles, params.us[t - 1], params.ys2[:, t], models, A)
    params.rbpfmeans[:,
                     t], params.rbpfcovars[:, :,
                                           t] = RBPF.get_ave_stats(particles)
Exemple #3
0
meas_noise_dist = scipy.stats.multivariate_normal(cov=params.R2)  # measurement distribution

# First time step of the simulation
params.xs[:, 0] = init_state  # set simulation starting point to the random initial state
params.ys2[:, 0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs()  # measure from actual plant
PF.init_filter(particles, params.ys2[:, 0], meas_noise_dist, cstr_pf)
params.pfmeans[:, 0], params.pfcovars[:, :, 0] = PF.get_stats(particles)

# Setup MPC
horizon = 150
# add state constraints
aline = 10.  # slope of constraint line ax + by + c = 0
cline = -420.0  # negative of the y axis intercept
bline = 1.0

params.us[0] = MPC.mpc_mean(params.pfmeans[:, 0]-b, horizon, A, numpy.matrix(B), b, aline, bline, cline,
                            params.QQ, params.RR, ysp, usp[0], 15000.0, 1000.0)  # get the controller input
for t in range(1, params.N):
    d = numpy.zeros(2)
    if params.ts[t] < 100:
        params.xs[:, t] = params.cstr_model.run_reactor(params.xs[:, t-1], params.us[t-1], params.h)
        params.xs[:, t] += state_noise_dist.rvs()  # actual plant
        xtemp = params.xs[:, t-1] - b
        d = params.cstr_model.run_reactor(params.xs[:, t-1], params.us[t-1], params.h)
        d -= (A @ xtemp + B * params.us[t-1] + b)
    else:
        params.xs[:, t] = params.cstr_model_broken.run_reactor(params.xs[:, t-1], params.us[t-1], params.h)
        params.xs[:, t] += state_noise_dist.rvs()  # actual plant
        xtemp = params.xs[:, t-1] - b
        d = params.cstr_model_broken.run_reactor(params.xs[:, t-1], params.us[t-1], params.h)
        d -= (A @ xtemp + B * params.us[t-1] + b)
for k in range(numSwitches):
    switchtrack[k,
                0] = numpy.sum(particles.w[numpy.where(particles.s == k)[0]])

maxtrack[:, 0] = SPF.get_max_track(particles, numSwitches)
smoothedtrack[:, 0] = RBPF.smoothed_track(numSwitches, switchtrack, 1, 10)

params.spfmeans[:, 0], params.spfcovars[:, :, 0] = SPF.get_stats(particles)

# Controller Input
# ind = indmax(smoothedtrack[:, 1]) # use this model and controller
ind = numpy.argmax(maxtrack[:, 0])  # use this model and controller
yspfix = setpoint - lin_models[ind].b
params.us[0] = MPC.mpc_mean(params.spfmeans[:, 0] - lin_models[ind].b,
                            horizon, lin_models[ind].A,
                            numpy.matrix(lin_models[ind].B), lin_models[ind].b,
                            aline, bline, cline, params.QQ, params.RR, yspfix,
                            usps[ind], 15000.0,
                            1000.0)  # get the controller input

# Loop through the rest of time
for t in range(1, params.N):
    random_element = state_noise_dist.rvs()
    if params.ts[t] < 100:  # break here
        params.xs[:, t] = params.cstr_model.run_reactor(
            params.xs[:, t - 1], params.us[t - 1], params.h) + random_element
    else:
        params.xs[:, t] = params.cstr_model_broken.run_reactor(
            params.xs[:, t - 1], params.us[t - 1], params.h)
        params.xs[:, t] += random_element

    params.ys2[:, t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
Exemple #5
0
                    params.R2)  # set up the KF object (measuring both states)
state_noise_dist = scipy.stats.multivariate_normal(cov=params.Q)
meas_noise_dist = scipy.stats.multivariate_normal(cov=params.R2)

# First time step of the simulation
params.xs[:,
          0] = init_state - b  # set simulation starting point to the random initial state
params.ys2[:, 0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs(
)  # measure from actual plant
temp = kf_cstr.init_filter(init_state - b, params.init_state_covar,
                           params.ys2[:, 0])  # filter
params.kfmeans[:, 0], params.kfcovars[:, :, 0] = temp

horizon = 150
params.us[0] = MPC.mpc_lqr(params.kfmeans[:, 0], horizon, A, numpy.matrix(B),
                           params.QQ, params.RR, numpy.array([0, 0]),
                           numpy.array([0.0]))  # get the controller input

for t in range(1, params.N):
    params.xs[:, t] = A @ (params.xs[:, t - 1] - b) + B * params.us[
        t - 1] + b + state_noise_dist.rvs()  # actual plant

    params.ys2[:, t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
    )  # measure from actual plant
    temp = kf_cstr.step_filter(params.kfmeans[:, t - 1],
                               params.kfcovars[:, :, t - 1], params.us[t - 1],
                               params.ys2[:, t] - b)
    params.kfmeans[:, t], params.kfcovars[:, :, t] = temp

    # Compute controller action
    if t % 10 == 0:
def main(mcN=1, linear=True, pf=False):
    tend = 80
    params = closedloop_scenarios_single.closedloop_params.Params(
        tend)  # end time of simulation

    # Get the linear model
    linsystems = params.cstr_model.get_nominal_linear_systems(
        params.h)  # cstr_model comes from params.jl
    opoint = 1  # the specific operating point we are going to use for control

    init_state = numpy.array([0.55, 450
                              ])  # random initial point near operating point

    # Set the state space model
    A = linsystems[opoint].A
    B = linsystems[opoint].B
    b = linsystems[opoint].b  # offset from the origin

    # Set point
    ysp = linsystems[opoint].op[0] - b[0]  # Medium concentration
    H = numpy.matrix([1, 0])  # only attempt to control the concentration
    x_off, usp = LQR.offset(A, numpy.matrix(B), params.C2, H,
                            numpy.matrix([ysp]))  # control offset
    ysp = x_off
    usp = numpy.array([usp])

    # Noise distributions
    state_noise_dist = scipy.stats.multivariate_normal(cov=params.Q)
    meas_noise_dist = scipy.stats.multivariate_normal(cov=params.R2)

    # PF functions
    def f(x, u, w):
        return params.cstr_model.run_reactor(x, u, params.h) + w

    def g(x):
        return params.C2 @ x  # state observation

    cstr_pf = PF.Model(f, g)

    # Set up the KF
    kf_cstr = LLDS.LLDS(
        A, B, params.C2, params.Q,
        params.R2)  # set up the KF object (measuring both states)

    # Setup MPC
    horizon = 150

    # add state constraints
    aline = 10  # slope of constraint line ax + by + c = 0
    if linear:
        cline = -411  # negative of the y axis intercept
    else:
        cline = -404  # negative of the y axis intercept
    bline = 1

    if linear:
        lim_u = 10000
    else:
        lim_u = 20000

    mcdists = numpy.zeros([2, mcN])
    xconcen = numpy.zeros([params.N, mcN])
    mcerrs = numpy.zeros(mcN)
    particles = None

    for mciter in range(mcN):
        # First time step of the simulation
        if linear:
            params.xs[:,
                      0] = init_state - b  # set simulation starting point to the random initial state
            params.ys2[:,
                       0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs(
                       )  # measure from actual plant
            temp = kf_cstr.init_filter(init_state - b, params.init_state_covar,
                                       params.ys2[:, 0])  # filter
            params.kfmeans[:, 0], params.kfcovars[:, :, 0] = temp
        else:
            params.xs[:,
                      0] = init_state  # set simulation starting point to the random initial state
            params.ys2[:,
                       0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs(
                       )  # measure from actual plant
            temp = kf_cstr.init_filter(init_state - b, params.init_state_covar,
                                       params.ys2[:, 0] - b)  # filter
            params.kfmeans[:, 0], params.kfcovars[:, :, 0] = temp

        if pf:
            nP = 200
            prior_dist = scipy.stats.multivariate_normal(
                mean=init_state,
                cov=params.init_state_covar)  # prior distribution

            particles = PF.init_pf(prior_dist, nP,
                                   2)  # initialise the particles

            particles = PF.init_filter(particles, params.ys2[:, 0],
                                       meas_noise_dist, cstr_pf)
            params.pfmeans[:, 0], params.pfcovars[:, :,
                                                  0] = PF.get_stats(particles)

            params.us[0] = MPC.mpc_mean(params.pfmeans[:, 0] - b, horizon, A,
                                        numpy.matrix(B), b, aline, bline,
                                        cline, params.QQ, params.RR, ysp,
                                        usp[0], lim_u,
                                        1000.0)  # get the controller input
        else:
            params.us[0] = MPC.mpc_mean(params.kfmeans[:, 0], horizon, A,
                                        numpy.matrix(B), b, aline, bline,
                                        cline, params.QQ, params.RR, ysp,
                                        usp[0], lim_u,
                                        1000.0)  # get the controller input
        for t in range(1, params.N):
            if linear:
                params.xs[:, t] = A @ params.xs[:, t - 1] + B * params.us[
                    t - 1] + state_noise_dist.rvs()
                params.ys2[:,
                           t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
                           )  # measure from actual plant
                params.kfmeans[:,
                               t], params.kfcovars[:, :,
                                                   t] = kf_cstr.step_filter(
                                                       params.kfmeans[:,
                                                                      t - 1],
                                                       params.kfcovars[:, :,
                                                                       t - 1],
                                                       params.us[t - 1],
                                                       params.ys2[:, t])
            else:
                params.xs[:, t] = params.cstr_model.run_reactor(
                    params.xs[:, t - 1], params.us[t - 1], params.h)
                params.xs[:, t] += state_noise_dist.rvs()  # actual plant
                params.ys2[:,
                           t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
                           )  # measure from actual plant
                params.kfmeans[:,
                               t], params.kfcovars[:, :,
                                                   t] = kf_cstr.step_filter(
                                                       params.kfmeans[:,
                                                                      t - 1],
                                                       params.kfcovars[:, :,
                                                                       t - 1],
                                                       params.us[t - 1],
                                                       params.ys2[:, t] - b)
            if pf:
                PF.pf_filter(particles, params.us[t - 1], params.ys2[:, t],
                             state_noise_dist, meas_noise_dist, cstr_pf)
                params.pfmeans[:,
                               t], params.pfcovars[:, :,
                                                   t] = PF.get_stats(particles)

            if t % 10 == 0:
                if pf:
                    params.us[t] = MPC.mpc_mean(params.pfmeans[:, t] - b,
                                                horizon, A, numpy.matrix(B), b,
                                                aline, bline, cline, params.QQ,
                                                params.RR, ysp, usp[0], lim_u,
                                                1000.0)
                else:
                    params.us[t] = MPC.mpc_mean(params.kfmeans[:,
                                                               t], horizon, A,
                                                numpy.matrix(B), b, aline,
                                                bline, cline, params.QQ,
                                                params.RR, ysp, usp[0], lim_u,
                                                1000.0)
                if params.us[t] is None or numpy.isnan(params.us[t]):
                    break
            else:
                params.us[t] = params.us[t - 1]

        for i in range(len(params.kfmeans[0])):
            params.kfmeans[:, i] += b
            if linear:
                params.xs[:, i] += b
                params.ys2[:, i] += b

        if mcN > 1:
            xconcen[:, mciter] = params.xs[0, :]
            mcerrs[mciter] = Results.calc_error1(params.xs, ysp[0] + b[0])
            Results.get_mc_res(params.xs, params.kfcovars, [aline, cline],
                               mcdists, mciter, params.h)
        if mcN == 1:
            # Plot the results
            if pf:
                Results.plot_tracking1(params.ts, params.xs, params.ys2,
                                       params.pfmeans, params.us, 2,
                                       ysp[0] + b[0])
                Results.plot_ellipses2(params.ts, params.xs, params.pfmeans,
                                       params.pfcovars, [aline, cline],
                                       linsystems[1].op, True,
                                       -2.0 * numpy.log(1 - 0.9), 1, "best")
            else:
                Results.plot_tracking1(params.ts, params.xs, params.ys2,
                                       params.kfmeans, params.us, 2,
                                       ysp[0] + b[0])
                Results.plot_ellipses2(params.ts, params.xs, params.kfmeans,
                                       params.kfcovars, [aline, cline],
                                       linsystems[1].op, True,
                                       -2.0 * numpy.log(1 - 0.9), 1, "best")
            Results.check_constraint(params.ts, params.xs, [aline, cline])
            Results.calc_error1(params.xs, ysp[0] + b[0])
            Results.calc_energy(params.us, 0.0)
            plt.show()

    if mcN != 1:
        print("The absolute MC average error is: ", sum(abs(mcerrs)) / mcN)
        if linear:
            if pf:
                numpy.savetxt("linmod_pf_mean_mc2.csv", xconcen, delimiter=",")
            else:
                numpy.savetxt("linmod_kf_mean_mc2.csv", xconcen, delimiter=",")
        else:
            if pf:
                numpy.savetxt("nonlinmod_pf_mean_mc2.csv",
                              xconcen,
                              delimiter=",")
            else:
                numpy.savetxt("nonlinmod_kf_mean_mc2.csv",
                              xconcen,
                              delimiter=",")

    nocount = len(mcdists[0]) - numpy.count_nonzero(mcdists[0])
    filteredResults = numpy.zeros([2, mcN - nocount])
    counter = 0
    for k in range(mcN):
        if mcdists[0, k] != 0.0:
            filteredResults[:, counter] = mcdists[:, k]
            counter += 1

    if linear:
        if pf:
            numpy.savetxt("linmod_pf_mean_mc.csv",
                          filteredResults,
                          delimiter=",",
                          fmt="%f")
        else:
            numpy.savetxt("linmod_kf_mean_mc.csv",
                          filteredResults,
                          delimiter=",",
                          fmt="%f")
    else:
        if pf:
            numpy.savetxt("nonlinmod_pf_mean_mc.csv",
                          filteredResults,
                          delimiter=",",
                          fmt="%f")
        else:
            numpy.savetxt("nonlinmod_kf_mean_mc.csv",
                          filteredResults,
                          delimiter=",",
                          fmt="%f")
SPF.init_filter(particles, params.ys2[:, 0], cstr_filter)

for k in range(numSwitches):
    switchtrack[k, 0] = numpy.sum(particles.w[numpy.where(particles.s == k)[0]])

maxtrack[:, 0] = SPF.get_max_track(particles, numSwitches)
smoothedtrack[:, 0] = RBPF.smoothed_track(numSwitches, switchtrack, 1, 10)

params.spfmeans[:, 0], params.spfcovars[:, :, 0] = SPF.get_stats(particles)

# Controller Input
ind = numpy.argmax(maxtrack[:, 0])  # use this model and controller
horizon = 150
params.us[0] = MPC.mpc_lqr(params.spfmeans[:, 0] - lin_models[ind].b, horizon, lin_models[ind].A,
                           numpy.matrix(lin_models[ind].B), params.QQ, params.RR,
                           controllers[ind].x_off, controllers[ind].u_off)

# Loop through the rest of time
for t in range(1, params.N):
    random_element = state_noise_dist.rvs()
    if params.ts[t] < 100:  # break here
        params.xs[:, t] = params.cstr_model.run_reactor(params.xs[:, t-1], params.us[t-1], params.h) + random_element
    else:
        params.xs[:, t] = params.cstr_model_broken.run_reactor(params.xs[:, t-1], params.us[t-1], params.h)
        params.xs[:, t] += random_element

    params.ys2[:, t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs()  # measured from actual plant

    SPF.spf_filter(particles, params.us[t-1], params.ys2[:, t], cstr_filter)
    params.spfmeans[:, t], params.spfcovars[:, :, t] = SPF.get_stats(particles)
for k in range(numSwitches):
    switchtrack[k,
                0] = numpy.sum(particles.w[numpy.where(particles.s == k)[0]])

maxtrack[:, 0] = SPF.get_max_track(particles, numSwitches)
smoothedtrack[:, 0] = RBPF.smoothed_track(numSwitches, switchtrack, 1, 10)

params.spfmeans[:, 0], params.spfcovars[:, :, 0] = SPF.get_stats(particles)

# Controller Input
# ind = indmax(smoothedtrack[:, 1]) # use this model and controller
ind = numpy.argmax(maxtrack[:, 0])  # use this model and controller
yspfix = setpoint - lin_models[ind].b
params.us[0] = MPC.mpc_var(params.spfmeans[:, 0] - lin_models[ind].b,
                           params.spfcovars[:, :,
                                            0], horizon, lin_models[ind].A,
                           numpy.matrix(lin_models[ind].B), lin_models[ind].b,
                           aline, bline, cline, params.QQ, params.RR, yspfix,
                           usps[ind], 15000.0, 1000.0, params.Q, 4.6052, True)

# Loop through the rest of time
for t in range(1, params.N):
    random_element = state_noise_dist.rvs()
    if params.ts[t] < 100:  # break here
        params.xs[:, t] = params.cstr_model.run_reactor(
            params.xs[:, t - 1], params.us[t - 1], params.h) + random_element
    else:
        params.xs[:, t] = params.cstr_model_broken.run_reactor(
            params.xs[:, t - 1], params.us[t - 1], params.h)
        params.xs[:, t] += random_element

    params.ys2[:, t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
def main(nine, mcN=1, linear=True, pf=False, numerical=False):
    if nine == 90:
        k_squared = 4.6052
        plot_setting = 0
    elif nine == 99:
        k_squared = 9.21
        plot_setting = 1
    elif nine == 999:
        k_squared = 13.8155
        plot_setting = 2
    else:
        return None

    tend = 80
    params = closedloop_scenarios_single.closedloop_params.Params(
        tend)  # end time of simulation

    # Get the linear model
    linsystems = params.cstr_model.get_nominal_linear_systems(
        params.h)  # cstr_model comes from params.jl
    opoint = 1  # the specific operating point we are going to use for control

    init_state = numpy.array([0.55, 450
                              ])  # random initial point near operating point

    # Set the state space model
    A = linsystems[opoint].A
    B = linsystems[opoint].B
    b = linsystems[opoint].b  # offset from the origin

    # Set point
    ysp = linsystems[opoint].op[0] - b[0]  # Medium concentration
    H = numpy.matrix([1, 0])  # only attempt to control the concentration
    x_off, usp = LQR.offset(A, numpy.matrix(B), params.C2, H,
                            numpy.matrix([ysp]))  # control offset
    ysp = x_off
    usp = numpy.array([usp])

    # PF functions
    def f(x, u, w):
        return params.cstr_model.run_reactor(x, u, params.h) + w

    def g(x):
        return params.C2 @ x  # state observation

    cstr_pf = PF.Model(f, g)

    nP = 200
    if numerical:
        nP = 500

    # Set up for numerical
    Ndiv = len(range(0, tend, 3))
    kldiv = numpy.zeros(
        Ndiv)  # Kullback-Leibler Divergence as a function of time
    basediv = numpy.zeros(Ndiv)  # Baseline
    unidiv = numpy.zeros(Ndiv)  # Uniform comparison
    klts = numpy.zeros(Ndiv)
    ndivcounter = 0
    temp_states = numpy.zeros([2, nP])

    # Set up the KF
    kf_cstr = LLDS.LLDS(
        A, B, params.C2, params.Q,
        params.R2)  # set up the KF object (measuring both states)
    state_noise_dist = scipy.stats.multivariate_normal(cov=params.Q)
    meas_noise_dist = scipy.stats.multivariate_normal(cov=params.R2)

    # Setup MPC
    horizon = 150
    # add state constraints
    aline = 10  # slope of constraint line ax + by + c = 0
    cline = -411  # negative of the y axis intercept
    bline = 1
    e = cline

    growvar = True
    if linear:
        limu = 10000
    else:
        limu = 20000

    mcdists = numpy.zeros([2, mcN])
    xconcen = numpy.zeros([params.N, mcN])
    mcerrs = numpy.zeros(mcN)

    mciter = -1

    particles = None
    while mciter < mcN - 1:
        # First time step of the simulation
        if linear:
            params.xs[:,
                      0] = init_state - b  # set simulation starting point to the random initial state
            params.ys2[:,
                       0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs(
                       )  # measure from actual plant
            temp = kf_cstr.init_filter(init_state - b, params.init_state_covar,
                                       params.ys2[:, 0])  # filter
            params.kfmeans[:, 0], params.kfcovars[:, :, 0] = temp
        else:
            params.xs[:,
                      0] = init_state  # set simulation starting point to the random initial state
            params.ys2[:,
                       0] = params.C2 @ params.xs[:, 0] + meas_noise_dist.rvs(
                       )  # measure from actual plant
            temp = kf_cstr.init_filter(init_state - b, params.init_state_covar,
                                       params.ys2[:, 0] - b)  # filter
            params.kfmeans[:, 0], params.kfcovars[:, :, 0] = temp

        if pf:
            if linear:
                prior_dist = scipy.stats.multivariate_normal(
                    mean=init_state - b,
                    cov=params.init_state_covar)  # prior distribution
            else:
                prior_dist = scipy.stats.multivariate_normal(
                    mean=init_state,
                    cov=params.init_state_covar)  # prior distribution
            particles = PF.init_pf(prior_dist, nP,
                                   2)  # initialise the particles

            particles = PF.init_filter(particles, params.ys2[:, 0],
                                       meas_noise_dist, cstr_pf)
            params.pfmeans[:, 0], params.pfcovars[:, :,
                                                  0] = PF.get_stats(particles)

            if linear:
                params.us[0] = MPC.mpc_var(params.pfmeans[:, 0],
                                           params.kfcovars[:, :,
                                                           0], horizon, A,
                                           numpy.matrix(B), b, aline, bline, e,
                                           params.QQ, params.RR, ysp, usp[0],
                                           limu, 1000.0, params.Q, k_squared,
                                           growvar)  # get controller input
            else:
                params.us[0] = MPC.mpc_var(params.pfmeans[:, 0] - b,
                                           params.kfcovars[:, :,
                                                           0], horizon, A,
                                           numpy.matrix(B), b, aline, bline, e,
                                           params.QQ, params.RR, ysp, usp[0],
                                           limu, 1000.0, params.Q, k_squared,
                                           growvar)  # get controller input
        else:
            params.us[0] = MPC.mpc_var(params.kfmeans[:, 0],
                                       params.kfcovars[:, :, 0], horizon, A,
                                       numpy.matrix(B), b, aline, bline, e,
                                       params.QQ, params.RR, ysp, usp[0], limu,
                                       1000.0, params.Q, k_squared,
                                       growvar)  # get the controller input

        if numerical:
            kldiv[ndivcounter] = Auxiliary.kl(particles.x, particles.w,
                                              params.pfmeans[:, 0],
                                              params.pfcovars[:, :,
                                                              0], temp_states)
            basediv[ndivcounter] = Auxiliary.klbase(params.pfmeans[:, 0],
                                                    params.pfcovars[:, :, 0],
                                                    temp_states, nP)
            unidiv[ndivcounter] = Auxiliary.kluniform(params.pfmeans[:, 0],
                                                      params.pfcovars[:, :, 0],
                                                      temp_states, nP)
            klts[ndivcounter] = 0.0
            ndivcounter += 1
        status = True
        for t in range(1, params.N):
            if linear:
                params.xs[:, t] = A @ params.xs[:, t - 1] + B * params.us[
                    t - 1] + state_noise_dist.rvs()  # actual plant
                params.ys2[:,
                           t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
                           )  # measure from actual plant
                params.kfmeans[:,
                               t], params.kfcovars[:, :,
                                                   t] = kf_cstr.step_filter(
                                                       params.kfmeans[:,
                                                                      t - 1],
                                                       params.kfcovars[:, :,
                                                                       t - 1],
                                                       params.us[t - 1],
                                                       params.ys2[:, t])
            else:
                params.xs[:, t] = params.cstr_model.run_reactor(
                    params.xs[:, t - 1],
                    params.us[t - 1],
                    params.h,
                )
                params.xs[:, t] += state_noise_dist.rvs()  # actual plant
                params.ys2[:,
                           t] = params.C2 @ params.xs[:, t] + meas_noise_dist.rvs(
                           )  # measure from actual plant
                params.kfmeans[:,
                               t], params.kfcovars[:, :,
                                                   t] = kf_cstr.step_filter(
                                                       params.kfmeans[:,
                                                                      t - 1],
                                                       params.kfcovars[:, :,
                                                                       t - 1],
                                                       params.us[t - 1],
                                                       params.ys2[:, t] - b)
            if pf:
                PF.pf_filter(particles, params.us[t - 1], params.ys2[:, t],
                             state_noise_dist, meas_noise_dist, cstr_pf)
                params.pfmeans[:,
                               t], params.pfcovars[:, :,
                                                   t] = PF.get_stats(particles)

            if t % 10 == 0:
                if pf:
                    if linear:
                        params.us[t] = MPC.mpc_var(
                            params.pfmeans[:,
                                           t], params.pfcovars[:, :,
                                                               t], horizon, A,
                            numpy.matrix(B), b, aline, bline, e, params.QQ,
                            params.RR, ysp, usp[0], limu, 1000, params.Q,
                            k_squared, growvar)  # controller input
                    else:
                        params.us[t] = MPC.mpc_var(
                            params.pfmeans[:, t] - b,
                            params.pfcovars[:, :, t], horizon, A,
                            numpy.matrix(B), b, aline, bline, e, params.QQ,
                            params.RR, ysp, usp[0], limu, 1000, params.Q,
                            k_squared, growvar)  # controller input
                else:
                    params.us[t] = MPC.mpc_var(params.kfmeans[:, t],
                                               params.kfcovars[:, :,
                                                               t], horizon, A,
                                               numpy.matrix(B), b, aline,
                                               bline, e, params.QQ, params.RR,
                                               ysp, usp[0], limu, 1000,
                                               params.Q, k_squared,
                                               growvar)  # get controller input

                if params.us[t] is None or numpy.isnan(params.us[t]):
                    status = False
                    break
            else:
                params.us[t] = params.us[t - 1]

            if numerical and params.ts[t] in range(0, tend, 3):
                kldiv[ndivcounter] = Auxiliary.kl(particles.x, particles.w,
                                                  params.pfmeans[:, t],
                                                  params.pfcovars[:, :, t],
                                                  temp_states)
                basediv[ndivcounter] = Auxiliary.klbase(
                    params.pfmeans[:, t], params.pfcovars[:, :, t],
                    temp_states, nP)
                unidiv[ndivcounter] = Auxiliary.kluniform(
                    params.pfmeans[:, t], params.pfcovars[:, :, t],
                    temp_states, nP)
                klts[ndivcounter] = params.ts[t]
                ndivcounter += 1

        if not status:
            continue
        else:
            mciter += 1
        for i in range(len(params.kfmeans[0])):
            params.kfmeans[:, i] += b
            if linear:
                params.xs[:, i] += b
                params.ys2[:, i] += b

        if mcN > 1:
            xconcen[:, mciter] = params.xs[0, :]
            mcerrs[mciter] = Results.calc_error1(params.xs, ysp[0] + b[0])
            mcdists = Results.get_mc_res(params.xs, params.kfcovars,
                                         [aline, cline], mcdists, mciter,
                                         params.h)

        if mcN == 1:
            # Plot the results
            if numerical:
                Results.plot_kl_div(klts, kldiv, basediv, unidiv, False)
                Results.plot_kl_div(klts, kldiv, basediv, unidiv, True)
                print("The average divergence for the baseline is: ",
                      1.0 / len(klts) * sum(basediv))
                print("The average divergence for the approximation is: ",
                      1.0 / len(klts) * sum(kldiv))
                print("The average divergence for the uniform is: ",
                      1.0 / len(klts) * sum(unidiv))
            elif pf:
                Results.plot_tracking1(params.ts, params.xs, params.ys2,
                                       params.pfmeans, params.us, 2,
                                       ysp[0] + b[0])
                plt.savefig(
                    "/home/ex/Documents/CSC/report/results/Figure_8-25_python.pdf",
                    bbox_inches="tight")
                Results.plot_ellipses2(params.ts, params.xs, params.pfmeans,
                                       params.pfcovars, [aline, cline],
                                       linsystems[1].op, True,
                                       -2.0 * numpy.log(1 - 0.9), plot_setting,
                                       "best")
                plt.savefig(
                    "/home/ex/Documents/CSC/report/results/Figure_8-26_python.pdf",
                    bbox_inches="tight")
                Results.check_constraint(params.ts, params.xs, [aline, cline])
                Results.calc_error1(params.xs, ysp[0] + b[0])
                Results.calc_energy(params.us, 0.0)
            else:
                Results.plot_tracking1(params.ts, params.xs, params.ys2,
                                       params.kfmeans, params.us, 2,
                                       ysp[0] + b[0])
                plt.savefig(
                    "/home/ex/Documents/CSC/report/results/Figure_8-19_python.pdf",
                    bbox_inches="tight")
                Results.plot_ellipses2(params.ts, params.xs, params.kfmeans,
                                       params.kfcovars, [aline, cline],
                                       linsystems[opoint].op, True, k_squared,
                                       plot_setting, "best")
                plt.savefig(
                    "/home/ex/Documents/CSC/report/results/Figure_8-20_python.pdf",
                    bbox_inches="tight")
                Results.check_constraint(params.ts, params.xs, [aline, cline])
                Results.calc_error1(params.xs, ysp[0] + b[0])
                Results.calc_energy(params.us, 0.0)

            plt.show()

    if mcN != 1:
        print("The absolute MC average error is: ", sum(abs(mcerrs)) / mcN)
        if linear:
            if pf:
                numpy.savetxt("linmod_pf_var{}_mc2.csv".format(nine),
                              xconcen,
                              delimiter=",",
                              fmt="%f")
            else:
                numpy.savetxt("linmod_kf_var{}_mc2.csv".format(nine),
                              xconcen,
                              delimiter=",",
                              fmt="%f")
        else:
            if pf:
                numpy.savetxt("nonlinmod_pf_var{}_mc2.csv".format(nine),
                              xconcen,
                              delimiter=",",
                              fmt="%f")
            else:
                numpy.savetxt("nonlinmod_kf_var{}_mc2.csv".format(nine),
                              xconcen,
                              delimiter=",",
                              fmt="%f")

        nocount = len(mcdists[0]) - numpy.count_nonzero(mcdists[0])
        filteredResults = numpy.zeros([2, mcN - nocount])
        counter = 0
        for k in range(mcN):
            if mcdists[0, k] != 0.0:
                filteredResults[:, counter] = mcdists[:, k]
                counter += 1

        if linear:
            if pf:
                numpy.savetxt("linmod_pf_var{}_mc.csv".format(nine),
                              filteredResults,
                              delimiter=",",
                              fmt="%f")
            else:
                numpy.savetxt("linmod_kf_var{}_mc.csv".format(nine),
                              filteredResults,
                              delimiter=",",
                              fmt="%f")
        else:
            if pf:
                numpy.savetxt("nonlinmod_pf_var{}_mc.csv".format(nine),
                              filteredResults,
                              delimiter=",",
                              fmt="%f")
            else:
                numpy.savetxt("nonlinmod_kf_var{}_mc.csv".format(nine),
                              filteredResults,
                              delimiter=",",
                              fmt="%f")