Usually there are two specs related to the covariance matrix in a Kalman filter. Let's only take gyro for example because accel is similar. The two specs are ARW and Bias Instability. ARW reperesents the noise level of the gyro output: ARW = std*sqrt(dt), where std is the standard deviation of gyro noise and dt is the sampling interval. Depending on your system equation in the EKF, you might also need to estimate the gyro bias in real time, and then you need bias instability to model the varying gyro bias. Bias instability is hard to model and is a much difficult topic. Generally we can model it as a random walk or a first-order Gauss-Markov process. We provide an online document for your reference: https://openimu.readthedocs.io/en/latest/algorithms.html
If you want to esimate gyro bias by averaging its output, you need to put it static for some time. Static time can be determined by running an Allan Variance analysis on its output. Or you can just use 100sec.
Posts made by Dong xiaoguang
That depends on the dynamic profile and measurement range of your application. However, 0.1deg is a pretty high accuracy. If you further consider the temperatur range, it is quite chanllenging. In our spec, the static angle accuracy of the full temperature range (-40C to 85C) is 0.15deg.
Generally, this is difficult. However, you can use a first-order approximation.
euler_angles = f(quaternion) ≈ f(quaternion_0) + (df/dquaternion)*(delta_quaterninon) H = df/dquaternion = [droll/dq0 droll/dq1 droll/dq2 droll/dq2 dpitch/dq0 dpitch/dq1 dpitch/dq2 dpitch/dq3 dyaw/dq0 dyaw/dq1 dyaw/dq2 dyaw/dq3] cov(euler_angles) = H*cov(quaternion)*H'
The choice of the function f depends on the rotation sequence of Euler angles you want. We use ZYX in our code.
In my test, I adds ublox nav_pvt support. Since it is open-source, it is very easy to add support of GPS receivers.
To set the heading from GNSS always valid, you need set a variable in UpdateFunctions.c called "useMagHeading" FALSE.
Indeed, you need to a bit more to make this work reliably. For single antenna GNSS receiver, heading is derived from velocity, and heading accuracy is determined by velocity. We estimate heading variance used in the Kalman fitler according to GNSS velocity.
But since you decide to use a dual-antenan GNSS receiver, the heading accuracy is decided by the separation between the antenna and the positioning engine (RTK, PPP).
Yes, you can. But you need to modify some of the source code:
- You need prepare GPS receiver driver to handle the UBLOX messages. Nav-pvt is supported now.
- Currently, we use ground speed to determine if the heading from GNSS is valid. You need to change the code to set the heading from GNSS always valid.
There are a few things to notice.
- The algorithm output rate is 25Hz, which is defined in ekfSim_ins.cfg, The max rate can be 100Hz because this algorithm indeed run in an embeded system and there is only limited computational resources. If you want to manually compare the algo output with reference, reference need be downsampled to match the algo output. In the simulation, to deal with cases like this, interp is performaed to align the two sets of data. Please refer to the source code for details.
- Algo output is in the form of Lat/Lon/Alt. If you want to convert it to [m, m, m], there are two routines in the simulation. But you need to do this manually. The first is to use lla2ecef_batch or lla2ecef in geoparams.py to convert LLA to ECEF positions. However, we usually want position error in NED frame instead of the ECEF frame. So, the second is to further convert the above ECEF position to NED position. You can refer to function array_error in ins_data_manager.py for details.
def array_error(self, x, r, angle=False, lla=0): ''' Calculate the error of an array w.r.t its reference. Args: x: input data, numpy array. r: reference data, same size as x. angle: True if x contains angles, False if not. pos: 0 if x is not in LLA form; 1 if x is in LLA form, and NED error is required; >=2 if x is in LLA form, and ECEF error is required. Returns: err: error ''' if lla == 0: err = x - r if angle: for j in range(len(err.flat)): err.flat[j] = attitude.angle_range_pi(err.flat[j]) else: # convert x and r to ECEF first x_ecef = geoparams.lla2ecef_batch(x) r_ecef = geoparams.lla2ecef_batch(r) err = x_ecef - r_ecef # convert ecef err to NED err if lla == 1: n = err.shape for i in range(0, n): c_ne = attitude.ecef_to_ned(r[i, 0], r[i, 1]) err[i, :] = c_ne.dot(err[i, :]) return err