噪声模型:
airsim的imu噪声模型使用了瑞士苏黎世理工学院的kalibr标定工具库中的模型:
IMU Noise Model · ethz-asl/kalibr Wiki (github.com)
角速度测量值 (单轴,即x,y,z轴中的一个) 可以使用如下公式建模:
噪声共包含两部分:
Kalibr 中包含的噪声模型共包含两种:
高斯白噪声
:
大部分的测量噪声都是服从高斯分布的,imu的噪声模型复杂一些,但高斯白噪声是其中一部分。 , 波动非常快的附加噪声项(“白噪声”);
其中表示k时刻的噪声模型,
表示方差,其中g表示gyro(陀螺仪)。
这一项随机误差的名字可能有很多,例如“高斯白噪声”、“随机行走误差(random walk)”、“Noise density”等,表达的都是这项内容。以陀螺仪为例,单位为dps/rt(Hz),或者deg/rt(h)。
陀螺仪测量的角速度,加速度计测量的加速度的噪声是高斯白噪声。因此这一项误差表示的物理意义就是单位时间内角度不确定性(标准差)、速度不确定性(标准差)的增量。
例如,如果陀螺仪的的随机行走误差是20deg/rt(h),那意味着在一个小时后,积分得到的角度的误差的标准差是20deg。
随机游走噪声:
随机游走噪声是缓慢变化的传感器偏差。
IMU的零偏属于系统误差,可以通过某些操作在事先进行标定。但IMU在使用过程中,会出现零偏慢慢变化的情况。直观上理解,零偏不稳定性误差会使陀螺仪和加速度计的零偏随时间慢慢变化,逐渐偏离开机时校准的零偏误差。
该缓慢变换可以用布朗运动建模,即随机变量的变化量(导数)服从高斯分布,也被称作维纳过程。
其表示如下,为随机游走噪声的方差,:
离散时间与连续时间:
有了以上建模,我们还要做的工作是确定模型参数。也就是要确定高斯模型的方差。
例如,是高斯白噪声,其方差表示为
。但具体该如何确定呢?
能想到是方法是让imu静止一段时间后,根据统计方法计算这两类噪声的方差。
但我们拿到的传感器数据都是采样而来的,如果采样时间较长或者不可相对不可忽略,那么就需要区别对待离散时间的数据和连续时间的数据,因为其对应的高斯分布是不同的。
对于高斯分布,其连续时间与离散时间的方差关系如下:
对于随机游走噪声,其连续时间与离散时间的方差关系如下:
注意,一个是×一个是➗
Airsim仿真方法:
airsim中的IMU噪声设置的代码在AirSim/AirLib/include/sensors/imu/文件夹下:
文件中设置了噪声参数值(参考的数据来源在源文件注释中有提到):
// A description of the parameters:
// https://github.com/ethz-asl/kalibr/wiki/IMU-Noise-Model-and-Intrinsics
struct ImuSimpleParams
{
/* ref: Parameter values are for MPU 6000 IMU from InvenSense
Design and Characterization of a Low Cost MEMS IMU Cluster for Precision Navigation
Daniel R. Greenheck, 2009, sec 2.2, pp 17
http://epublications.marquette.edu/cgi/viewcontent.cgi?article=1326&context=theses_open
Datasheet:
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Datasheet1.pdf
For Allan Variance/Deviation plots see http://www.invensense.com/wp-content/uploads/2015/02/MPU-3300-Datasheet.pdf
*/
struct Gyroscope
{
//angular random walk (ARW)
real_T arw = 0.30f / sqrt(3600.0f) * M_PIf / 180; //deg/sqrt(hour) converted to rad/sqrt(sec)
//Bias Stability (tau = 500s)
real_T tau = 500;
real_T bias_stability = 4.6f / 3600 * M_PIf / 180; //deg/hr converted to rad/sec
Vector3r turn_on_bias = Vector3r::Zero(); //assume calibration is done
} gyro;
struct Accelerometer
{
//velocity random walk (ARW)
real_T vrw = 0.24f * EarthUtils::Gravity / 1.0E3f; //mg converted to m/s^2
//Bias Stability (tau = 800s)
real_T tau = 800;
real_T bias_stability = 36.0f * 1E-6f * EarthUtils::Gravity; //ug converted to m/s^2
Vector3r turn_on_bias = Vector3r::Zero(); //assume calibration is done
} accel;
real_T min_sample_time = 1 / 1000.0f; //internal IMU frequency
void initializeFromSettings(const AirSimSettings::ImuSetting& settings)
{
const auto& json = settings.settings;
float arw = json.getFloat("AngularRandomWalk", Utils::nan<float>());
if (!std::isnan(arw)) {
gyro.arw = arw / sqrt(3600.0f) * M_PIf / 180; // //deg/sqrt(hour) converted to rad/sqrt(sec)
}
gyro.tau = json.getFloat("GyroBiasStabilityTau", gyro.tau);
float bias_stability = json.getFloat("GyroBiasStability", Utils::nan<float>());
if (!std::isnan(bias_stability)) {
gyro.bias_stability = bias_stability / 3600 * M_PIf / 180; //deg/hr converted to rad/sec
}
auto vrw = json.getFloat("VelocityRandomWalk", Utils::nan<float>());
if (!std::isnan(vrw)) {
accel.vrw = vrw * EarthUtils::Gravity / 1.0E3f; //mg converted to m/s^2
}
accel.tau = json.getFloat("AccelBiasStabilityTau", accel.tau);
bias_stability = json.getFloat("AccelBiasStability", Utils::nan<float>());
if (!std::isnan(bias_stability)) {
accel.bias_stability = bias_stability * 1E-6f * EarthUtils::Gravity; //ug converted to m/s^2
}
}
};
可以得到AirSim中连续时间的IMU随机噪声参数如下: