예제 #1
0
Ts_IMU = Ts_IMU[start:]

GNSSk = 0

for k in tqdm(range(N - start)):
    if timeIMU[k] >= timeGNSS[GNSSk]:
        R_GNSS = (0.5 * accuracy_GNSS[GNSSk])**2 * np.diag(
            [1, 1, 1])  # Current GNSS covariance

        (
            NIS[GNSSk],
            NIS_x[GNSSk],
            NIS_y[GNSSk],
            NIS_z[GNSSk],
            NIS_xy[GNSSk],
        ) = eskf.NIS_GNSS_position(x_pred[k], P_pred[k], z_GNSS[GNSSk], R_GNSS,
                                   lever_arm)

        x_est[k], P_est[k] = eskf.update_GNSS_position(x_pred[k], P_pred[k],
                                                       z_GNSS[GNSSk], R_GNSS,
                                                       lever_arm)
        if eskf.debug:
            assert np.all(np.isfinite(
                P_est[k])), f"Not finite P_pred at index {k}"

        GNSSk += 1
    else:
        # no updates, so estimate = prediction
        x_est[k] = x_pred[k]
        P_est[k] = P_pred[k]

    if k < N - 1:
예제 #2
0
def run_experiment(parameters):
    # read parameters
    cont_gyro_noise_std = parameters["cont_gyro_noise_std"]
    cont_acc_noise_std = parameters["cont_acc_noise_std"]
    rate_std_factor = parameters["rate_std_factor"]
    acc_std_factor = parameters["acc_std_factor"]
    rate_bias_driving_noise_std = parameters["rate_bias_driving_noise_std"]
    cont_rate_bias_factor = parameters["cont_rate_bias_factor"]
    acc_bias_driving_noise_std = parameters["acc_bias_driving_noise_std"]
    cont_acc_bias_factor = parameters["cont_acc_bias_factor"]
    p_acc = parameters["p_acc"]
    p_gyro = parameters["p_gyro"]
    p_std = parameters["p_std"]
    sigma_pos = parameters["sigma_pos"]
    sigma_vel = parameters["sigma_vel"]
    sigma_rollpitch = parameters["sigma_rollpitch"]
    sigma_yaw = parameters["sigma_yaw"]
    sigma_err_acc_bias = parameters["sigma_err_acc_bias"]
    sigma_err_gyro_bias = parameters["sigma_err_gyro_bias"]
    N = parameters["N"]
    doGNSS = parameters["doGNSS"]
    debug = parameters["debug"]
    dosavefigures = parameters["dosavefigures"]
    figdir = parameters["figdir"]
    doshowplot = parameters["doshowplot"]

    # derived parameters
    rate_std = rate_std_factor * cont_gyro_noise_std * np.sqrt(
        1 / dt)  # Hvorfor gange med en halv? (eq. 10.70)
    acc_std = acc_std_factor * cont_acc_noise_std * np.sqrt(1 / dt)
    cont_rate_bias_driving_noise_std = cont_rate_bias_factor * rate_bias_driving_noise_std / np.sqrt(
        1 / dt)
    cont_acc_bias_driving_noise_std = cont_acc_bias_factor * acc_bias_driving_noise_std / np.sqrt(
        1 / dt)
    R_GNSS = np.diag(p_std**2)

    # %% Estimator
    eskf = ESKF(
        acc_std,
        rate_std,
        cont_acc_bias_driving_noise_std,
        cont_rate_bias_driving_noise_std,
        p_acc,
        p_gyro,
        S_a=S_a,  # set the accelerometer correction matrix
        S_g=S_g,  # set the gyro correction matrix,
        debug=
        debug  # TODO: False to avoid expensive debug checks, can also be suppressed by calling 'python -O run_INS_simulated.py'
    )

    # %% Allocate
    x_est = np.zeros((steps, 16))
    P_est = np.zeros((steps, 15, 15))

    x_pred = np.zeros((steps, 16))
    P_pred = np.zeros((steps, 15, 15))

    delta_x = np.zeros((steps, 15))

    NIS = np.zeros(gnss_steps)
    NIS_x = np.zeros(gnss_steps)
    NIS_y = np.zeros(gnss_steps)
    NIS_z = np.zeros(gnss_steps)
    NIS_xy = np.zeros(gnss_steps)

    NEES_all = np.zeros(steps)
    NEES_pos = np.zeros(steps)
    NEES_vel = np.zeros(steps)
    NEES_att = np.zeros(steps)
    NEES_accbias = np.zeros(steps)
    NEES_gyrobias = np.zeros(steps)

    # %% Initialise
    x_pred[0, POS_IDX] = np.array([0, 0, -5])  # starting 5 metres above ground
    x_pred[0, VEL_IDX] = np.array([20, 0, 0])  # starting at 20 m/s due north
    x_pred[
        0,
        6] = 1  # no initial rotation: nose to North, right to East, and belly down

    # These have to be set reasonably to get good results
    P_pred[0][POS_IDX**2] = sigma_pos**2 * np.eye(3)
    P_pred[0][VEL_IDX**2] = sigma_vel**2 * np.eye(3)
    P_pred[0][ERR_ATT_IDX**2] = np.diag(
        [sigma_rollpitch, sigma_rollpitch, sigma_yaw])**2
    P_pred[0][ERR_ACC_BIAS_IDX**2] = sigma_err_acc_bias**2 * np.eye(3)
    P_pred[0][ERR_GYRO_BIAS_IDX**2] = sigma_err_gyro_bias**2 * np.eye(3)

    # %% Run estimation
    # run this file with 'python -O run_INS_simulated.py' to turn of assertions and get about 8/5 speed increase for longer runs

    GNSSk: int = 0  # keep track of current step in GNSS measurements
    for k in tqdm.trange(N):
        if doGNSS and timeIMU[k] >= timeGNSS[GNSSk]:
            (
                NIS[GNSSk],
                NIS_x[GNSSk],
                NIS_y[GNSSk],
                NIS_z[GNSSk],
                NIS_xy[GNSSk],
            ) = eskf.NIS_GNSS_position(x_pred[k], P_pred[k], z_GNSS[GNSSk],
                                       R_GNSS, lever_arm)

            x_est[k], P_est[k] = eskf.update_GNSS_position(
                x_pred[k], P_pred[k], z_GNSS[GNSSk], R_GNSS, lever_arm)
            assert np.all(np.isfinite(
                P_est[k])), f"Not finite P_pred at index {k}"

            GNSSk += 1
        else:
            # no updates, so let us take estimate = prediction
            x_est[k] = x_pred[k]
            P_est[k] = P_pred[k]

        delta_x[k] = eskf.delta_x(x_est[k], x_true[k])
        (
            NEES_all[k],
            NEES_pos[k],
            NEES_vel[k],
            NEES_att[k],
            NEES_accbias[k],
            NEES_gyrobias[k],
        ) = eskf.NEESes(x_est[k], P_est[k], x_true[k])

        if k < N - 1:
            x_pred[k + 1], P_pred[k + 1] = eskf.predict(
                x_est[k], P_est[k], z_acceleration[k + 1], z_gyroscope[k + 1],
                Ts_IMU[k + 1])

        if eskf.debug:
            assert np.all(np.isfinite(
                P_pred[k])), f"Not finite P_pred at index {k + 1}"

    # %% Consistency
    confprob = 0.95
    CI15 = np.array(scipy.stats.chi2.interval(confprob, 15)).reshape((2, 1))
    CI3 = np.array(scipy.stats.chi2.interval(confprob, 3)).reshape((2, 1))
    CI1 = np.array(scipy.stats.chi2.interval(confprob, 1)).reshape((2, 1))
    CI2 = np.array(scipy.stats.chi2.interval(confprob, 2)).reshape((2, 1))
    CI3N = np.array(scipy.stats.chi2.interval(confprob, 3 * N)) / N
    CI15N = np.array(scipy.stats.chi2.interval(confprob, 15 * N)) / N

    ANIS = NIS[:GNSSk].mean()
    ANEES = NEES_all[:N].mean()
    ANEES_pos = NEES_pos[:N].mean()
    ANEES_vel = NEES_vel[:N].mean()
    ANEES_att = NEES_att[:N].mean()
    ANEES_accbias = NEES_accbias[:N].mean()
    ANEES_gyrobias = NEES_gyrobias[:N].mean()

    print(rf'{"ANEES:":<20} {ANEES:^25} {CI15N}')
    print(rf'{"ANEESS_pos:":<20} {ANEES_pos:^25} {CI3N}')
    print(rf'{"ANEES_vel:":<20} {ANEES_vel:^25} {CI3N}')
    print(rf'{"ANEES_att:":<20} {ANEES_att:^25} {CI3N}')
    print(rf'{"ANEES_accbias:":<20} {ANEES_accbias:^25} {CI3N}')
    print(rf'{"ANEES_gyrobias:":<20} {ANEES_gyrobias:^25} {CI3N}')
    print(rf'{"ANIS:":<20} {ANIS:^25} {CI3N}')

    eul = np.apply_along_axis(quaternion_to_euler, 1, x_est[:N, ATT_IDX])
    eul_true = np.apply_along_axis(quaternion_to_euler, 1, x_true[:N, ATT_IDX])
    wrap_to_pi = lambda rads: (rads + np.pi) % (2 * np.pi) - np.pi
    eul_error = wrap_to_pi(eul[:N] - eul_true[:N]) * 180 / np.pi
    pos_err = np.linalg.norm(delta_x[:N, POS_IDX], axis=1)
    meas_err = np.linalg.norm(x_true[99:N:100, POS_IDX] - z_GNSS[:GNSSk],
                              axis=1)

    # %% plotting
    dosavefigures = True
    doplothandout = True

    t = np.linspace(0, dt * (N - 1), N)
    if doplothandout:
        # 3d position plot
        fig1, ax1 = plot.trajectoryPlot3D(x_est, x_true, z_GNSS, N, GNSSk)
        fig1.tight_layout()
        if dosavefigures: fig1.savefig(figdir + "ned.pdf")

        # state estimation plot

        fig2all, fig2pos, fig2vel, fig2ang, fig2ab, fig2gb = \
                plot.stateplot(t, x_est, eul, N, "States estimates")
        # fig2vehicle = plot.kinematicplot(t, x_est, eul, N, "Kinematic estimates")
        # fig2bias = plot.biasplot(t, x_est, eul, N, "Bias estimates")
        if dosavefigures:
            fig2all.savefig(figdir + "state_estimates.pdf")
            fig2pos.savefig(figdir + "estimate_pos.pdf")
            fig2vel.savefig(figdir + "estimate_vel.pdf")
            fig2ang.savefig(figdir + "estimate_eul.pdf")
            fig2ab.savefig(figdir + "estimate_aclbias.pdf")
            fig2gb.savefig(figdir + "estimate_gyrobias.pdf")

        # state error plots
        # fig3.tight_layout()

        fig3all, fig3pos, fig3vel, fig3ang, fig3ab, fig3gb = \
                plot.stateerrorplot(t, delta_x, eul_error, N, "State estimate errors")
        if dosavefigures:
            fig3all.savefig(figdir + "state_estimate_errors.pdf")
            fig3pos.savefig(figdir + "estimate_error_pos.pdf")
            fig3vel.savefig(figdir + "estimate_error_vel.pdf")
            fig3ang.savefig(figdir + "estimate_errors_eul.pdf")
            fig3ab.savefig(figdir + "estimate_errors_aclbias.pdf")
            fig3gb.savefig(figdir + "estimate_errors_gyrobias.pdf")

        # Error distance plot
        fig4, axs4 = plt.subplots(2, 1, num=4, clear=True, sharex=True)

        est_error = np.sqrt(np.mean(np.sum(delta_x[:N, POS_IDX]**2, axis=1)))
        meas_error = np.sqrt(
            np.mean(
                np.sum((x_true[99:N:100, POS_IDX] - z_GNSS[:GNSSk])**2,
                       axis=1)))
        axs4[0].plot(t, pos_err, label=f"Est error ({est_error:.3f})")
        axs4[0].plot(np.arange(0, N, 100) * dt,
                     meas_err,
                     label=f"GNSS error ({meas_error:.3f})")
        axs4[0].set(title=r"Position error $[m]$")
        axs4[0].legend(loc='upper right')

        vel_rmse = np.sqrt(np.mean(np.sum(delta_x[:N, VEL_IDX]**2, axis=1)))
        axs4[1].plot(t,
                     np.linalg.norm(delta_x[:N, VEL_IDX], axis=1),
                     label=f"RMSE: {vel_rmse:.3f}")
        axs4[1].set(title=r"Speed error $[m/s]$")
        axs4[1].legend(loc='upper right')
        fig4.tight_layout()

        latexutils.save_value("Estimation error", f"{est_error:.3f}",
                              "csvs/sim_est_error_pos.csv")
        latexutils.save_value("GNSS error", f"{meas_error:.3f}",
                              "csvs/sim_meas_error_pos.csv")

        #fig4.tight_layout()
        if dosavefigures:
            fig4.savefig(figdir + "estimate_vs_measurement_error.pdf")

        fig5, axs5 = plt.subplots(4, 1, num=5, clear=True, sharex=True)
        fig5.subplots_adjust(hspace=0.4)  # so ytick dont overlap
        fig5.set_size_inches((3.5, 5))

        insideCItot = np.mean(
            (CI15[0] <= NEES_all[:N]) * (NEES_all[:N] <= CI15[1]))
        plot.pretty_NEESNIS(axs5[0],
                            t,
                            NEES_all[:N],
                            "total",
                            CI15,
                            fillCI=True,
                            upperY=50)
        axs5[0].legend(loc="upper right", ncol=1)

        plot.pretty_NEESNIS(axs5[1],
                            t,
                            NEES_pos[:N],
                            "pos",
                            CI3,
                            fillCI=True,
                            upperY=20)
        plot.pretty_NEESNIS(axs5[1],
                            t,
                            NEES_vel[:N],
                            "vel",
                            CI3,
                            fillCI=False,
                            upperY=20)
        plot.pretty_NEESNIS(axs5[1],
                            t,
                            NEES_att[:N],
                            "att",
                            CI3,
                            fillCI=False,
                            upperY=20)
        #axs5[1].plot([t[0], t[~0]], (CI3 @ np.ones((1, 2))).T)
        # axs5[1].plot(t, (NEES_pos[0:N]).T, label="pos")
        # axs5[1].plot(t, (NEES_vel[0:N]).T, label="vel")
        # axs5[1].plot(t, (NEES_att[0:N]).T, label="att")
        # axs5[1].set_ylim([0, 20])
        axs5[1].legend(loc="best", ncol=3)

        #axs5[2].plot([t[0], t[~0]], (CI3 @ np.ones((1, 2))).T)
        plot.pretty_NEESNIS(axs5[2],
                            t,
                            NEES_accbias[:N],
                            "accel bias",
                            CI3,
                            fillCI=True,
                            upperY=20)
        plot.pretty_NEESNIS(axs5[2],
                            t,
                            NEES_gyrobias[:N],
                            "gyro bias",
                            CI3,
                            fillCI=False,
                            upperY=20)
        # axs5[2].plot(t, (NEES_accbias[0:N]).T,  label="accel bias")
        # axs5[2].plot(t, (NEES_gyrobias[0:N]).T, label="gyro bias")
        # axs5[2].set_ylim([0, 20])
        axs5[2].legend(loc="best", ncol=2)

        t_gnssk = np.linspace(t[0], t[~0], GNSSk)
        plot.pretty_NEESNIS(axs5[3],
                            t_gnssk,
                            NIS[:GNSSk],
                            "NIS",
                            CI3,
                            fillCI=True,
                            upperY=20)
        # axs5[3].plot([t[0], t[~0]], (CI3 @ np.ones((1, 2))).T)
        # axs5[3].plot(NIS[:GNSSk], label="NIS")
        # axs5[3].set_ylim([0, 20])
        axs5[3].legend(loc="upper right")

        for ax in axs5:
            ax.set_xlim([t[0], t[~0]])

        #fig5.tight_layout()

        insideCIpos = np.mean(
            (CI3[0] <= NEES_pos[:N]) * (NEES_pos[:N] <= CI3[1]))
        insideCIvel = np.mean(
            (CI3[0] <= NEES_vel[:N]) * (NEES_vel[:N] <= CI3[1]))
        insideCIatt = np.mean(
            (CI3[0] <= NEES_att[:N]) * (NEES_att[:N] <= CI3[1]))
        insideCIab = np.mean(
            (CI3[0] <= NEES_accbias[:N]) * (NEES_accbias[:N] <= CI3[1]))
        insideCIgb = np.mean(
            (CI3[0] <= NEES_gyrobias[:N]) * (NEES_gyrobias[:N] <= CI3[1]))
        insideCInis = np.mean(
            (CI3[0] <= NIS[:GNSSk]) * (NIS[:GNSSk] <= CI3[1]))

        print("Inside CI total", insideCItot)
        print("Inside CI pos", insideCIpos)
        print("Inside CI vel", insideCIvel)
        print("Inside CI att", insideCIatt)
        print("Inside CI ab", insideCIab)
        print("Inside CI gb", insideCIgb)
        print("Inside CI NIS", insideCInis)

        #fig5.tight_layout()
        if dosavefigures:
            fig5.savefig(figdir + "nees_nis.pdf")

        # boxplot
        fig6, axs6 = plt.subplots(1,
                                  3,
                                  gridspec_kw={"width_ratios": [1, 1, 2]})
        plot.boxplot(axs6[0], [NIS[:GNSSk]], 3, ["NIS"])
        plot.boxplot(axs6[1], [NEES_all[0:N].T], 15, ["NEES"])
        plot.boxplot(axs6[2], [
            NEES_pos[0:N].T, NEES_vel[0:N].T, NEES_att[0:N].T,
            NEES_accbias[0:N].T, NEES_gyrobias[0:N].T
        ], 3, ['pos', 'vel', 'att', 'accbias', 'gyrobias'])
        fig6.tight_layout()

        #fig6.tight_layout()
        if dosavefigures:
            fig6.savefig(figdir + "boxplot.pdf")

        plot.plot_NIS(NIS_x, CI1, "NIS_x", confprob, dt, N, GNSSk)
        plot.plot_NIS(NIS_y, CI1, "NIS_y", confprob, dt, N, GNSSk)
        plot.plot_NIS(NIS_z, CI1, "NIS_z", confprob, dt, N, GNSSk)
        plot.plot_NIS(NIS_xy, CI2, "NIS_xy", confprob, dt, N, GNSSk)

        consistencydatas = [
            dict(avg=ANEES, inside=insideCItot, text="NEES", CI=CI15N),
            dict(avg=ANEES_pos, inside=insideCIpos, text="NEES pos", CI=CI3N),
            dict(avg=ANEES_vel, inside=insideCIvel, text="NEES vel", CI=CI3N),
            dict(avg=ANEES_att, inside=insideCIatt, text="NEES att", CI=CI3N),
            dict(avg=ANEES_gyrobias,
                 inside=insideCIgb,
                 text="NEES gyro bias",
                 CI=CI3N),
            dict(avg=ANEES_accbias,
                 inside=insideCIab,
                 text="NEES acc bias",
                 CI=CI3N),
            dict(avg=ANIS, inside=insideCInis, text="NIS", CI=CI3N),
        ]

        latexutils.save_consistency_results(consistencydatas,
                                            "csvs/sim_consistency.csv")

    if doshowplot:
        plt.show()
예제 #3
0
    3)  # error rotation vector (not quat)
P_pred[0][ERR_ACC_BIAS_IDX**2] = 0.1**2 * np.eye(3)
P_pred[0][ERR_GYRO_BIAS_IDX**2] = 0.01**2 * np.eye(3)

# %% Run estimation

N = 50000
startSample = 50000
GNSSkstart = floor(startSample * gnss_steps / steps)
GNSSk = GNSSkstart

for k in tqdm(range(N)):
    if timeIMU[k] >= timeGNSS[GNSSk - GNSSkstart]:
        R_GNSS = np.diag(p_std**2 *
                         accuracy_GNSS[GNSSk])  # TODO: Current GNSS covariance
        NIS[GNSSk - GNSSkstart] = eskf.NIS_GNSS_position(
            x_pred[k], P_pred[k], z_GNSS[GNSSk], R_GNSS, lever_arm)  # TODO
        v, S = eskf.innovation_GNSS_position(x_pred[k], P_pred[k],
                                             z_GNSS[GNSSk], R_GNSS,
                                             lever_arm)  # Ugly inline
        NISplanar[GNSSk - GNSSkstart] = v[0:2] @ la.solve(S[0:2, 0:2], v[0:2])
        NISaltitude[GNSSk - GNSSkstart] = v[2]**2 / S[2, 2]

        x_est[k], P_est[k] = eskf.update_GNSS_position(x_pred[k], P_pred[k],
                                                       z_GNSS[GNSSk], R_GNSS,
                                                       lever_arm)  # TODO

        if eskf.debug:
            assert np.all(np.isfinite(
                P_est[k])), f"Not finite P_pred at index {k}"

        GNSSk += 1
예제 #4
0
P_pred[0][ERR_ACC_BIAS_IDX**2] = 0.005**2 * np.eye(3)
P_pred[0][ERR_GYRO_BIAS_IDX**2] = (1e-3)**2 * np.eye(3)

# %% Run estimation
# Position and velocity measurement


N = steps
GNSSk = 0

for k in tqdm(range(N)):
    if timeIMU[k] >= timeGNSS[GNSSk]:
        #R_GNSS = # TODO: Current GNSS covariance
        p_std = (accuracy_GNSS[GNSSk])*np.array([0.3,0.3,0.5])
        R_GNSS = 0.1*np.diag(p_std**2)
        NIS[GNSSk],NIS_planar[GNSSk],NIS_altitude[GNSSk] = eskf.NIS_GNSS_position(x_pred[k], P_pred[k], z_GNSS[GNSSk], R_GNSS, lever_arm)
        x_est[k], P_est[k] = eskf.update_GNSS_position(x_pred[k], P_pred[k], z_GNSS[GNSSk], R_GNSS, lever_arm)
        if eskf.debug:
            assert np.all(np.isfinite(P_est[k])), f"Not finite P_pred at index {k}"

        GNSSk += 1
    else:
        # no updates, so estimate = prediction
        x_est[k] = x_pred[k]# TODO
        P_est[k] = P_pred[k]# TODO

    if k < N - 1:
        x_pred[k + 1], P_pred[k + 1] = eskf.predict(x_est[k], P_est[k], z_acceleration[k+1], z_gyroscope[k+1], Ts = timeIMU[k+1]-timeIMU[k])# TODO

    if eskf.debug:
        assert np.all(np.isfinite(P_pred[k])), f"Not finite P_pred at index {k + 1}"
예제 #5
0
    3)  # TODO # error rotation vector (not quat)
P_pred[0][ERR_ACC_BIAS_IDX**2] = 0.001 * np.eye(3)  # TODO
P_pred[0][ERR_GYRO_BIAS_IDX**2] = 0.001 * np.eye(3)  # TODO

# %% Run estimation
# run this file with 'python -O run_INS_simulated.py' to turn of assertions and get about 8/5 speed increase for longer runs

N: int = steps  # TODO: choose a small value to begin with (500?), and gradually increase as you OK results
doGNSS: bool = True  # TODO: Set this to False if you want to check that the predictions make sense over reasonable time lenghts

GNSSk: int = 0  # keep track of current step in GNSS measurements
taylor_approx_degree = 2  # The order of the taylor approximation to be done in discretizing the error-state matrices

for k in tqdm(range(N)):
    if doGNSS and timeIMU[k] >= timeGNSS[GNSSk]:
        NIS[GNSSk], NIS_xy[GNSSk], NIS_z[GNSSk] = eskf.NIS_GNSS_position(
            x_pred[k], P_pred[k], z_GNSS[GNSSk], R_GNSS, lever_arm=lever_arm)

        x_est[k], P_est[k] = eskf.update_GNSS_position(x_pred[k],
                                                       P_pred[k],
                                                       z_GNSS[GNSSk],
                                                       R_GNSS,
                                                       lever_arm=lever_arm)
        assert np.all(np.isfinite(P_est[k])), f"Not finite P_pred at index {k}"

        GNSSk += 1
    else:
        # no updates, so let us take estimate = prediction
        x_est[k] = x_pred[k]
        P_est[k] = P_pred[k]

    delta_x[k] = eskf.delta_x(x_est[k], x_true[k])