def test_accel_z_bias_converges(z_bias):
    """Make sure the accelerometer bias in z-direction is estimated correctly
    """
    ekf = ecl_EKF.Ekf()

    time_usec = 1000
    dt_usec = ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000

    # Run for a while
    n_samples = 10000

    # Prepare data collection for plotting
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        plot_data = namedtuple('PlotData', ['time', 'accel_bias', 'altitude'])
        plot_data.time = np.array(
            [i * dt_usec * 1e-6 for i in range(n_samples)])
        plot_data.accel_bias = np.zeros(n_samples)
        plot_data.altitude = np.zeros(n_samples)

    # Simulation
    for i in range(n_samples):
        update_sensors(ekf,
                       time_usec,
                       dt_usec,
                       accel=float_array([0.0, 0.0, -ecl_EKF.one_g + z_bias]))
        ekf.update()
        time_usec += dt_usec

        if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
            plot_data.altitude[i] = ekf.get_position()[2]
            plot_data.accel_bias[i] = ekf.get_accel_bias()[2]

    # Plot if necessary
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        from plot_utils import figure
        with figure(params={'z_bias': z_bias},
                    subplots=(2, 1)) as (_, (ax1, ax2)):
            ax1.plot(plot_data.time,
                     plot_data.altitude,
                     label='Altitude Estimate')
            ax1.legend(loc='best')
            ax1.set_ylabel('Altitude $[m]$')
            ax2.plot(plot_data.time,
                     plot_data.accel_bias,
                     label='Accel Z Bias Estimate')
            ax2.axhline(z_bias, color='k', label='Accel Bias Value')
            ax2.legend(loc='best')
            ax2.set_ylabel('Bias $[m / s^2]$')
            ax2.set_xlabel('Time $[s]$')

    # Check assumptions
    converged_pos = ekf.get_position()
    converged_vel = ekf.get_velocity()
    converged_accel_bias = ekf.get_accel_bias()
    for i in range(3):
        assert converged_pos[i] == pytest.approx(0.0, abs=1e-2)
        assert converged_vel[i] == pytest.approx(0.0, abs=1e-2)
    for i in range(2):
        assert converged_accel_bias[i] == pytest.approx(0.0, abs=1e-3)
    assert converged_accel_bias[2] == pytest.approx(z_bias, abs=1e-2)
def test_converges_to_zero():
    """Make sure the EKF with zero inputs converges to / stays at zero
    """
    ekf = ecl.Ekf()

    time_usec = 1000
    dt_usec = 5000

    # Provide a few samples
    for _ in range(10000):
        update_sensors(ekf, time_usec, dt_usec)
        ekf.update()
        time_usec += dt_usec

    converged_pos = ekf.get_position()
    converged_vel = ekf.get_velocity()
    converged_accel_bias = ekf.get_accel_bias()
    converged_gyro_bias = ekf.get_gyro_bias()
    for i in range(3):
        assert converged_pos[i] == pytest.approx(0.0, abs=1e-6)
        assert converged_vel[i] == pytest.approx(0.0, abs=1e-6)
        assert converged_accel_bias[i] == pytest.approx(0.0, abs=1e-5)
        assert converged_gyro_bias[i] == pytest.approx(0.0, abs=1e-5)
Exemple #3
0
def test_converges_to_zero():
    """Make sure the EKF with zero inputs converges to / stays at zero
    """
    ekf = ecl_EKF.Ekf()

    time_usec = 1000
    dt_usec = 5000

    # Provide a few samples
    for _ in range(10000):
        update_sensors(ekf, time_usec, dt_usec)
        ekf.update()
        time_usec += dt_usec

    converged_pos = ekf.get_position()
    converged_vel = ekf.get_velocity()
    converged_accel_bias = ekf.get_accel_bias()
    converged_gyro_bias = ekf.get_gyro_bias()
    for i in range(3):
        assert converged_pos[i] == pytest.approx(0.0, abs=1e-6)
        assert converged_vel[i] == pytest.approx(0.0, abs=1e-6)
        assert converged_accel_bias[i] == pytest.approx(0.0, abs=1e-5)
        assert converged_gyro_bias[i] == pytest.approx(0.0, abs=1e-5)
def test_converges_to_baro_altitude(altitude):
    """Make sure that the ekf converges to (arbitrary) baro altitudes

    Increase the altitude with a bang-bang acceleration profile to target
    altitude, then wait there for a while and make sure it converges
    """
    # Due to hypothesis not interacting with pytest, cannot use fixture here
    ekf, time_usec = initialized_ekf()

    dt_usec = ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000

    # No samples, half are used for ramping up / down to the altitude
    n_samples = 200

    # Compute smooth acceleration profile
    rampup_accel = altitude / (((n_samples // 2 // 2) * (dt_usec / 1e6))**2)

    # Prepare data collection for plotting
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        plot_data = namedtuple('PlotData',
                               ['time', 'baro', 'altitude', 'accel_z_bias'])
        plot_data.time = np.array(
            [i * dt_usec * 1e-6 for i in range(n_samples)])
        plot_data.baro = np.zeros(n_samples)
        plot_data.accel_z_bias = np.zeros(n_samples)
        plot_data.altitude = np.zeros(n_samples)

    # Simulate
    current_state = namedtuple('State', ['alt', 'vel'])
    current_state.alt = 0.0
    current_state.vel = 0.0
    for i in range(n_samples // 2):
        update_sensors(
            ekf,
            time_usec,
            dt_usec,
            accel=float_array([
                0, 0, -ecl_EKF.one_g -
                rampup_accel if i < n_samples // 4 else -ecl_EKF.one_g +
                rampup_accel
            ]),
            baro_data=current_state.alt)
        ekf.update()

        if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
            plot_data.baro[i] = current_state.alt
            plot_data.altitude[i] = -ekf.get_position()[2]
            plot_data.accel_z_bias[i] = ekf.get_accel_bias()[2]

        # Euler step
        current_state.vel += (dt_usec / 1e6) * (
            rampup_accel if i < n_samples // 4 else -rampup_accel)
        current_state.alt += current_state.vel * dt_usec / 1e6
        time_usec += dt_usec

    # Stay at altitude
    for i in range(n_samples // 2):
        update_sensors(ekf, time_usec, dt_usec, baro_data=altitude)
        ekf.update()
        time_usec += dt_usec

        if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
            plot_data.baro[n_samples // 2 + i] = altitude
            plot_data.altitude[n_samples // 2 + i] = -ekf.get_position()[2]
            plot_data.accel_z_bias[n_samples // 2 +
                                   i] = ekf.get_accel_bias()[2]

    # Plot if necessary
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        from plot_utils import figure
        with figure(params={'altitude': altitude},
                    subplots=(2, 1)) as (_, (ax1, ax2)):
            ax1.plot(plot_data.time,
                     plot_data.altitude,
                     label='Altitude Estimate')
            ax1.plot(plot_data.time, plot_data.altitude, label='Baro Input')
            ax1.legend(loc='best')
            ax1.set_ylabel('Altitude $[m]$')
            ax2.plot(plot_data.time,
                     plot_data.accel_z_bias,
                     label='Accel Z Bias Estimate')
            ax2.legend(loc='best')
            ax2.set_ylabel('Bias $[m / s^2]$')
            ax2.set_xlabel('Time $[s]$')
    # plt.plot(np.array(baro_vs_pos))
    # plt.show()
    # print(ekf.get_accel_bias())

    converged_pos = ekf.get_position()
    converged_vel = ekf.get_velocity()
    assert converged_pos[0] == pytest.approx(0.0, abs=1e-6)
    assert converged_pos[1] == pytest.approx(0.0, abs=1e-6)
    # Check for 10cm level accuracy
    assert converged_pos[2] == pytest.approx(-altitude, abs=1e-1)
    assert converged_vel[0] == pytest.approx(0.0, abs=1e-3)
    assert converged_vel[1] == pytest.approx(0.0, abs=1e-3)
    assert converged_vel[2] == pytest.approx(0.0, abs=1e-1)
Exemple #5
0
def test_accel_z_bias_converges(z_bias):
    """Make sure the accelerometer bias in z-direction is estimated correctly
    """
    ekf = ecl_EKF.Ekf()

    time_usec = 1000
    dt_usec = ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000

    # Run for a while
    n_samples = 10000

    # Prepare data collection for plotting
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        plot_data = namedtuple('PlotData', ['time', 'accel_bias', 'altitude'])
        plot_data.time = np.array([i * dt_usec * 1e-6
                                   for i in range(n_samples)])
        plot_data.accel_bias = np.zeros(n_samples)
        plot_data.altitude = np.zeros(n_samples)

    # Simulation
    for i in range(n_samples):
        update_sensors(ekf,
                       time_usec,
                       dt_usec,
                       accel=float_array([0.0,
                                          0.0,
                                          -ecl_EKF.one_g + z_bias]))
        ekf.update()
        time_usec += dt_usec

        if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
            plot_data.altitude[i] = ekf.get_position()[2]
            plot_data.accel_bias[i] = ekf.get_accel_bias()[2]

    # Plot if necessary
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        from plot_utils import figure
        with figure(params={'z_bias': z_bias},
                    subplots=(2, 1)) as (_, (ax1, ax2)):
            ax1.plot(plot_data.time,
                     plot_data.altitude,
                     label='Altitude Estimate')
            ax1.legend(loc='best')
            ax1.set_ylabel('Altitude $[m]$')
            ax2.plot(plot_data.time,
                     plot_data.accel_bias,
                     label='Accel Z Bias Estimate')
            ax2.axhline(z_bias, color='k', label='Accel Bias Value')
            ax2.legend(loc='best')
            ax2.set_ylabel('Bias $[m / s^2]$')
            ax2.set_xlabel('Time $[s]$')

    # Check assumptions
    converged_pos = ekf.get_position()
    converged_vel = ekf.get_velocity()
    converged_accel_bias = ekf.get_accel_bias()
    for i in range(3):
        assert converged_pos[i] == pytest.approx(0.0, abs=1e-2)
        assert converged_vel[i] == pytest.approx(0.0, abs=1e-2)
    for i in range(2):
        assert converged_accel_bias[i] == pytest.approx(0.0, abs=1e-3)
    assert converged_accel_bias[2] == pytest.approx(z_bias, abs=1e-2)
Exemple #6
0
def test_converges_to_baro_altitude(altitude):
    """Make sure that the ekf converges to (arbitrary) baro altitudes

    Increase the altitude with a bang-bang acceleration profile to target
    altitude, then wait there for a while and make sure it converges
    """
    # Due to hypothesis not interacting with pytest, cannot use fixture here
    ekf, time_usec = initialized_ekf()

    dt_usec = ecl_EKF.Ekf.FILTER_UPDATE_PERIOD_MS * 1000

    # No samples, half are used for ramping up / down to the altitude
    n_samples = 200

    # Compute smooth acceleration profile
    rampup_accel = altitude / (((n_samples // 2 // 2) * (dt_usec / 1e6))**2)

    # Prepare data collection for plotting
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        plot_data = namedtuple('PlotData', ['time',
                                            'baro',
                                            'altitude',
                                            'accel_z_bias'])
        plot_data.time = np.array([i * dt_usec * 1e-6
                                   for i in range(n_samples)])
        plot_data.baro = np.zeros(n_samples)
        plot_data.accel_z_bias = np.zeros(n_samples)
        plot_data.altitude = np.zeros(n_samples)

    # Simulate
    current_state = namedtuple('State', ['alt', 'vel'])
    current_state.alt = 0.0
    current_state.vel = 0.0
    for i in range(n_samples // 2):
        update_sensors(ekf,
                       time_usec,
                       dt_usec,
                       accel=float_array([0,
                                          0,
                                          -ecl_EKF.one_g - rampup_accel
                                          if i < n_samples // 4
                                          else -ecl_EKF.one_g + rampup_accel]),
                       baro_data=current_state.alt)
        ekf.update()

        if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
            plot_data.baro[i] = current_state.alt
            plot_data.altitude[i] = -ekf.get_position()[2]
            plot_data.accel_z_bias[i] = ekf.get_accel_bias()[2]

        # Euler step
        current_state.vel += (dt_usec / 1e6) * (rampup_accel
                                                if i < n_samples // 4
                                                else -rampup_accel)
        current_state.alt += current_state.vel * dt_usec / 1e6
        time_usec += dt_usec

    # Stay at altitude
    for i in range(n_samples // 2):
        update_sensors(ekf, time_usec, dt_usec, baro_data=altitude)
        ekf.update()
        time_usec += dt_usec

        if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
            plot_data.baro[n_samples // 2 + i] = altitude
            plot_data.altitude[n_samples // 2 + i] = -ekf.get_position()[2]
            plot_data.accel_z_bias[
                n_samples // 2 + i] = ekf.get_accel_bias()[2]

    # Plot if necessary
    if pytest.ENABLE_PLOTTING:  # pylint: disable=no-member
        from plot_utils import figure
        with figure(params={'altitude': altitude},
                    subplots=(2, 1)) as (_, (ax1, ax2)):
            ax1.plot(plot_data.time,
                     plot_data.altitude,
                     label='Altitude Estimate')
            ax1.plot(plot_data.time,
                     plot_data.altitude,
                     label='Baro Input')
            ax1.legend(loc='best')
            ax1.set_ylabel('Altitude $[m]$')
            ax2.plot(plot_data.time,
                     plot_data.accel_z_bias,
                     label='Accel Z Bias Estimate')
            ax2.legend(loc='best')
            ax2.set_ylabel('Bias $[m / s^2]$')
            ax2.set_xlabel('Time $[s]$')
    # plt.plot(np.array(baro_vs_pos))
    # plt.show()
    # print(ekf.get_accel_bias())

    converged_pos = ekf.get_position()
    converged_vel = ekf.get_velocity()
    assert converged_pos[0] == pytest.approx(0.0, abs=1e-6)
    assert converged_pos[1] == pytest.approx(0.0, abs=1e-6)
    # Check for 10cm level accuracy
    assert converged_pos[2] == pytest.approx(-altitude, abs=1e-1)
    assert converged_vel[0] == pytest.approx(0.0, abs=1e-3)
    assert converged_vel[1] == pytest.approx(0.0, abs=1e-3)
    assert converged_vel[2] == pytest.approx(0.0, abs=1e-1)