KF和EKF的公式对比(基本没差别)

利用扩展卡尔曼滤波估计四元数。
下图是论文中的截图。可以和前面的卡尔曼滤波估计高度文章的那五个公式对应一下。

观测矩阵的确定。

static void NormalizeQuat(arm_matrix_instance_f32 *_q)
{
float norm = invSqrt(_q->pData[0] * _q->pData[0] + _q->pData[1] * _q->pData[1] + _q->pData[2]*_q->pData[2] + _q->pData[3]*_q->pData[3]);
// 归一化四元数
_q->pData[0] *= norm;
_q->pData[1] *= norm;
_q->pData[2] *= norm;
_q->pData[3] *= norm;
}
// Fast inverse square-root
// See: http://en.wikipedia.org/wiki/Fast_inverse_square_root
float invSqrt(float x) /*快速开平方求倒*/
{
float halfx = 0.5f * x;
float y = x;
long i = *(long*)&y;
i = 0x5f3759df - (i>>1);
y = *(float*)&i;
y = y * (1.5f - (halfx * y * y));
return y;
}
/*
* 卡尔曼公式1,2--计算先验的_q_(四元数)和_P_(误差协方差矩阵)
* 输入:机体角速度 w (rad/s), (3x1)
* 时间步长 dt (s)
* 上一次后验的四元数 _q (4x1)
* 上一次后验的协方差矩阵 _P (4x4):这里和加速度计有关
* 过程噪声协方差矩阵Q (4x4)
* 输出:先验状态,四元数 _q_ (4x1)
* 误差协方差矩阵的先验估计 _P_ (4x4)
*/
static void Km12(const Axis3f w, const float dt, const arm_matrix_instance_f32 _q, const arm_matrix_instance_f32 _P, const arm_matrix_instance_f32 _Q ,arm_matrix_instance_f32 _q_, arm_matrix_instance_f32 _P_)
{
float32_t A[16];
arm_matrix_instance_f32 _A;
float32_t A_T[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; // 矩阵A的转置
arm_matrix_instance_f32 _A_T;
float32_t T[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; // 临时定义中间变量
arm_matrix_instance_f32 _T;
float32_t T2[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; // 临时定义中间变量
arm_matrix_instance_f32 _T2;
float temp;
temp = dt / 2;
A[0] = 1.0f; A[1] = -w.x*temp; A[2] = -w.y*temp; A[3] = -w.z*temp;
A[4] = w.x*temp; A[5] = 1.0f; A[6] = w.z*temp; A[7] = -w.y*temp;
A[8] = w.y*temp; A[9] = -w.z*temp; A[10] = 1.0f; A[11] = w.x*temp;
A[12] = w.z*temp; A[13]= w.y*temp; A[14] = -w.x*temp; A[15] = 1.0f;
arm_mat_init_f32(&_A, 4, 4, A); // 转移矩阵A (4x4)
arm_mat_init_f32(&_A_T, 4, 4, A_T);
arm_mat_init_f32(&_T, 4, 4, T);
arm_mat_init_f32(&_T2, 4, 4, T2);
arm_mat_trans_f32(&_A, &_A_T); // A' (4x4)
arm_mat_mult_f32(&_A, &_P, &_T); // _T = _A*_P (4x4)
arm_mat_mult_f32(&_T, &_A_T, &_T2); // _T2_ = _T*_A_T (4x4)
arm_mat_add_f32(&_T2, &_Q, &_P_); // _P_ = _T2 + _Q = _A*_P*_A_T + _Q;误差协方差矩阵的先验估计公式
arm_mat_mult_f32(&_A, &_q, &_q_); // q_ = A*q (4x1) xk的先验估计,没有控制项
}
/*
* 卡尔曼公式3--计算卡尔曼增益
* 输入:上一次估计四元数 _q (4x1)
* 先验的误差协方差矩阵 _P_ (4x4)
* 测量噪声协方差矩阵 _R (3x3)
* 输出:卡尔曼增益 _K (4x3)
*/
static void Km3(const arm_matrix_instance_f32 _q, const arm_matrix_instance_f32 _P_, const arm_matrix_instance_f32 _R, arm_matrix_instance_f32 _K)
{
float32_t H[12]; // (3x4)
float32_t H_T[12]; // (4x3)
float32_t T[12]; // (3x4)
float32_t T1[9]; // (3x3)
float32_t M[9]; // (3x3)
float32_t M_[9]; // M的逆, (3x3)
arm_matrix_instance_f32 _H;
arm_matrix_instance_f32 _H_T;
arm_matrix_instance_f32 _T;
arm_matrix_instance_f32 _T1;
arm_matrix_instance_f32 _M;
arm_matrix_instance_f32 _M_;
// 用加速度计进行修正时的观测矩阵
H[0] = -2*_q.pData[2]; H[1] = 2*_q.pData[3]; H[2] = -2*_q.pData[0]; H[3] = 2*_q.pData[1];
H[4] = 2*_q.pData[1]; H[5] = 2*_q.pData[0]; H[6] = 2*_q.pData[3]; H[7] = 2*_q.pData[2];
H[8] = 2*_q.pData[0]; H[9] = -2*_q.pData[1]; H[10] = -2*_q.pData[2]; H[11] = 2*_q.pData[3];
// 矩阵初始化
arm_mat_init_f32(&_H, 3, 4, H); // 观测矩阵H (3x4)
arm_mat_init_f32(&_H_T, 4, 3, H_T);
arm_mat_init_f32(&_T, 3, 4, T); // T (3x4)
arm_mat_init_f32(&_M, 3, 3, M); // M (3x3)
arm_mat_init_f32(&_M_, 3, 3, M_); // M_(3x3)
arm_mat_init_f32(&_T1, 3, 3, T1);
// 卡尔曼增益
arm_mat_mult_f32(&_H, &_P_, &_T); // _T = _H*_P_ (3x4)
arm_mat_trans_f32(&_H, &_H_T); // _H_T (4x3)
arm_mat_mult_f32(&_T, &_H_T, &_T1); // _T1 = _H*_P_*_H_T (3x3)
arm_mat_add_f32(&_T1, &_R, &_M); // _M = _H*_P_*_H_T + _R (3x3)
arm_mat_inverse_f32(&_M, &_M_); // _M_ = inv(_H*_P_*_H_T + R) (3x3)
arm_mat_init_f32(&_T, 4, 3, T); // 将T初始化为 4x3 矩阵
arm_mat_mult_f32(&_P_, &_H_T, &_T); // _T = _P_ * _H_T (4x3)
arm_mat_mult_f32(&_T, &_M_, &_K); // _K = _P_ * _H_T * inv(_H*_P_*_H_T + R); (4x3)
}
/*
* 卡尔曼公式4,5
* 输入:观测的状态 a (加速度单位为 N/s^2) (3x1)
* 先验的四元数 _qi (4x1)
* 上一次估计的 _q
* 先验的噪声协方差矩阵 _P_
* 卡尔曼增益 _K (4x3)
* 输出:后验的四元数 _qo (4x1)
* 后验的噪声协方差矩阵 _P (4x4)
*/
static void Km45( const Axis3f a,
const arm_matrix_instance_f32 _qi,
const arm_matrix_instance_f32 _q,
const arm_matrix_instance_f32 _P_,
const arm_matrix_instance_f32 _K,
arm_matrix_instance_f32 _qo,
arm_matrix_instance_f32 _P)
{
float norm ; // 模长
float32_t z[3]; // 观测的向量
float32_t h[3]; // 地球系向量在机体系下的分量 (3x1)
float32_t v3[3]; // 临时向量 (3x1)
float32_t v4[4]; // 临时向量(4x1)
float32_t I[16]= {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; // 单位阵(4x4)
float32_t H[12];
float32_t T[16];
float32_t M[16];
arm_matrix_instance_f32 _z;
arm_matrix_instance_f32 _h;
arm_matrix_instance_f32 _v3;
arm_matrix_instance_f32 _v4;
arm_matrix_instance_f32 _I ;
arm_matrix_instance_f32 _H;
arm_matrix_instance_f32 _T;
arm_matrix_instance_f32 _M;
// 获取测量值
z[0] = a.x;
z[1] = a.y;
z[2] = a.z;
// 矩阵初始化
arm_mat_init_f32(&_z, 3, 1, z);
arm_mat_init_f32(&_h, 3, 1, h);
arm_mat_init_f32(&_v3, 3, 1, v3);
arm_mat_init_f32(&_v4, 4, 1, v4);
arm_mat_init_f32(&_I, 4, 4, I);
arm_mat_init_f32(&_H, 3, 4, H);
arm_mat_init_f32(&_T, 4, 4, T);
arm_mat_init_f32(&_M, 4, 4, M);
norm = invSqrt(a.x*a.x + a.y*a.y + a.z * a.z);
z[0] *= norm;
z[1] *= norm;
z[2] *= norm;
h[0] = 2*_q.pData[1]*_q.pData[3] - 2*_q.pData[0]*_q.pData[2];
h[1] = 2*_q.pData[0]*_q.pData[1] + 2*_q.pData[2]*_q.pData[3];
h[2] = _q.pData[0]*_q.pData[0] - _q.pData[1]*_q.pData[1] - _q.pData[2]*_q.pData[2] + _q.pData[3]*_q.pData[3];
// 观测矩阵
H[0] = -2*_q.pData[2]; H[1] = 2*_q.pData[3]; H[2] = -2*_q.pData[0]; H[3] = 2*_q.pData[1];
H[4] = 2*_q.pData[1]; H[5] = 2*_q.pData[0]; H[6] = 2*_q.pData[3]; H[7] = 2*_q.pData[2];
H[8] = 2*_q.pData[0]; H[9] = -2*_q.pData[1]; H[10] = -2*_q.pData[2]; H[11] = 2*_q.pData[3];
// 修正q
arm_mat_sub_f32(&_z, &_h, &_v3); // _v3 = _z - _h (3x1)
arm_mat_mult_f32(&_K, &_v3, &_v4); // _v4 = _K*(_z-_h) (4x1)
_v4.pData[3] = 0; // 加速度计修正,不改变 q3。
arm_mat_add_f32(&_qi, &_v4, &_qo); // _qo = _qi + _v4 (4x4)
// 修正P
arm_mat_mult_f32(&_K, &_H, &_T); // _T = _K*_H (4x4)
arm_mat_sub_f32(&_I, &_T, &_M); // _M = _I - _K*_H (4x4)
arm_mat_mult_f32(&_M, &_P_, &_P); // _P = (_I - _K*_H) * _P_
}
/*
* 卡尔曼滤波姿态估计
* 输入:六轴传感器数据 ,加速度 m/s^2, 加速度 rad/s,
* 此函数将更新全局变量 姿态四元数 quat_ 与 欧拉角 eular_
*/
void ekfdof6(Axis3f acc, Axis3f gyro, state_t *state , float dt)
{
float accBuf[3] = {0.f};
Axis3f tempacc = acc;
// 必须进行转换,否则微小的变动就会导致姿态变化很大。
gyro.x = gyro.x * DEG2RAD; /* 度转弧度 */
gyro.y = gyro.y * DEG2RAD;
gyro.z = gyro.z * DEG2RAD;
/* 卡尔曼滤波相关矩阵 */
static float32_t Q[16] = {1e-5f,0,0,0, 0,1e-5f,0,0, 0,0,1e-5f,0, 0,0,0,1e-5f}; // 过程噪声协方差矩阵 4X4
static float32_t R[9] = {1,0,0, 0,1,0, 0,0,1}; // 加速度计测量噪声协方差矩阵
static float32_t q[4] = {1, 0, 0, 0}; // 使用加速度计后验得到的协方差矩阵
static float32_t q_[4] = {1, 0, 0, 0}; // 先验的q
static float32_t P_[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; // 先验的误差协方差矩阵的值
static float32_t P1[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; // 通过加速度计后验得到的误差协方差矩阵
static float32_t K[12]; // 卡尔曼增益
/* 指向卡尔曼滤波相关矩阵的指针 */
static arm_matrix_instance_f32 _Q;
static arm_matrix_instance_f32 _R;
static arm_matrix_instance_f32 _q; // xk的后验估计
static arm_matrix_instance_f32 _q_; // xk的先验估计
static arm_matrix_instance_f32 _P_; // 误差协方差矩阵的先验估计
static arm_matrix_instance_f32 _P1;
static arm_matrix_instance_f32 _K;
static uint16_t km_atti_times = 0;
/* 初始化卡尔曼滤波相关矩阵 */
if (km_atti_times == 0)
{
arm_mat_init_f32(&_Q, 4, 4, Q);
arm_mat_init_f32(&_R, 3, 3, R);
arm_mat_init_f32(&_q, 4, 1, q);
arm_mat_init_f32(&_q_, 4, 1, q_);
arm_mat_init_f32(&_P_, 4, 4, P_);
arm_mat_init_f32(&_P1, 4, 4, P1);
arm_mat_init_f32(&_K, 4, 3, K);
km_atti_times = 1;
}
else if (km_atti_times < 1000) // 先信任加速度计,收敛快
{
Q[0] = 8e-3f;
Q[5] = 8e-3f;
Q[10] =8e-3f;
Q[15] = 8e-3f;
km_atti_times ++;
}
else // 后信任陀螺仪,准确
{
Q[0] = 1e-7f;
Q[5] = 1e-7f;
Q[10] = 1e-7f;
Q[15] = 1e-7f;
}
/* 卡尔曼滤波过程 */
Km12(gyro, dt, _q, _P1, _Q, _q_, _P_); // 卡尔曼公式1,2 根据陀螺仪预测
Km3(_q, _P_, _R, _K); // 卡尔曼公式3,计算卡尔曼增益
Km45(acc, _q_, _q, _P_, _K, _q, _P1); // 卡尔曼公式4,5 根据加速度修正
NormalizeQuat(&_q); // 四元数归一化
/* 赋值给全局变量 */
q0 = _q.pData[0];
q1 = _q.pData[1];
q2 = _q.pData[2];
q3 = _q.pData[3];
imuComputeRotationMatrix(); /*计算旋转矩阵*/
/*计算roll pitch yaw 欧拉角*/
state->attitude.pitch = -asinf(rMat[2][0]) * RAD2DEG;
state->attitude.roll = atan2f(rMat[2][1], rMat[2][2]) * RAD2DEG;
state->attitude.yaw = atan2f(rMat[1][0], rMat[0][0]) * RAD2DEG;
if (!isGravityCalibrated) /*未校准*/
{
accBuf[2] = tempacc.x* rMat[2][0] + tempacc.y * rMat[2][1] + tempacc.z * rMat[2][2];/*accz*/
calBaseAcc(accBuf); /*计算静态加速度*/
}
}
/*计算旋转矩阵*/
void imuComputeRotationMatrix(void)
{
float q1q1 = q1 * q1;
float q2q2 = q2 * q2;
float q3q3 = q3 * q3;
float q0q1 = q0 * q1;
float q0q2 = q0 * q2;
float q0q3 = q0 * q3;
float q1q2 = q1 * q2;
float q1q3 = q1 * q3;
float q2q3 = q2 * q3;
rMat[0][0] = 1.0f - 2.0f * q2q2 - 2.0f * q3q3;
rMat[0][1] = 2.0f * (q1q2 + -q0q3);
rMat[0][2] = 2.0f * (q1q3 - -q0q2);
rMat[1][0] = 2.0f * (q1q2 - -q0q3);
rMat[1][1] = 1.0f - 2.0f * q1q1 - 2.0f * q3q3;
rMat[1][2] = 2.0f * (q2q3 + -q0q1);
rMat[2][0] = 2.0f * (q1q3 + -q0q2);
rMat[2][1] = 2.0f * (q2q3 - -q0q1);
rMat[2][2] = 1.0f - 2.0f * q1q1 - 2.0f * q2q2;
}
6 , MiniFly V1.5\1,MiniFly Master\2,STM32F411\Firmware_F411 V1.4(改灯\FLIGHT\src\stabilizer.c
//四元数和欧拉角计算(250Hz)
if (RATE_DO_EXECUTE(ATTITUDE_ESTIMAT_RATE, tick))
{
// imuUpdate(sensorData.acc, sensorData.gyro, &state, ATTITUDE_ESTIMAT_DT);
ekfdof6(sensorData.acc, sensorData.gyro, &state, ATTITUDE_ESTIMAT_DT);
}
A Double-Stage Kalman Filter for Orientation Tracking With an Integrated Processor in 9-D IMU
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我想这样组织C源代码:+/||___+ext||||___+native_extension||||___+lib||||||___(Sourcefilesarekeptinhere-maycontainsub-folders)||||___native_extension.c||___native_extension.h||___extconf.rb||___+lib||||___(Rubysourcecode)||___Rakefile我无法使此设置与mkmf一起正常工作。native_extension/lib中的文件(包含在native_extension.c中)将被完全忽略。
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
我有一个要在我的Rails3项目中使用的数组扩展方法。它应该住在哪里?我有一个应用程序/类,我最初把它放在(array_extensions.rb)中,在我的config/application.rb中我加载路径:config.autoload_paths+=%W(#{Rails.root}/应用程序/类)。但是,当我转到railsconsole时,未加载扩展。是否有一个预定义的位置可以放置我的Rails3扩展方法?或者,一种预先定义的方式来添加它们?我知道Rails有自己的数组扩展方法。我应该将我的添加到active_support/core_ext/array/conversion
我想编写一个ruby脚本来递归复制目录结构,但排除某些文件类型。因此,给定以下目录结构:folder1folder2file1.txtfile2.txtfile3.csfile4.htmlfolder2folder3file4.dll我想复制这个结构,但不包含.txt和.cs文件。因此,生成的目录结构应如下所示:folder1folder2file4.htmlfolder2folder3file4.dll 最佳答案 您可以使用查找模块。这是一个代码片段:require"find"ignored_extensions=[".cs"
这个问题有两个部分。在RubyProgrammingLanguage一书中,有一个使用模块扩展字符串对象和类的示例(第8.1.1节)。第一个问题。为什么如果您使用新方法扩展类,然后创建该类的对象/实例,则无法访问该方法?irb(main):001:0>moduleGreeter;defciao;"Ciao!";end;end=>nilirb(main):002:0>String.extend(Greeter)=>Stringirb(main):003:0>String.ciao=>"Ciao!"irb(main):004:0>x="foobar"=>"foobar"irb(main):
假设我们有A、B、C类。Adefself.inherited(sub)#metaprogramminggoeshere#takeclassthathasjustinheritedclassA#andforfooclassesinjectprepare_foo()as#firstlineofmethodthenrunrestofthecodeenddefprepare_foo#=>prepare_foo()neededhere#somecodeendendBprepare_foo()neededhere#somecodeendend如您所见,我正在尝试将foo_prepare()调用注入
显然在Test::Unit中没有assert_false。您将如何通过扩展断言并添加文件config/initializers/assertions_helper.rb来添加它?这是最好的方法吗?我不想修改test/unit/assertions.rb。顺便说一句,我不认为这是多余的。我使用的是assert_equalfalse,something_to_evaluate。这种方法的问题是很容易意外使用assertfalse,something_to_evaluate。这将始终失败,不会引发错误或警告,并且会在测试中引入错误。 最佳答案
这个问题在这里已经有了答案:Unabletoinstallgem-Failedtobuildgemnativeextension-cannotloadsuchfile--mkmf(LoadError)(17个答案)关闭9年前。嘿,我正在尝试在一台新的ubuntu机器上安装rails。我安装了ruby和rvm,但出现“无法构建gemnative扩展”错误。这是什么意思?$sudogeminstallrails-v3.2.9(没有sudo表示我没有权限)然后它会输出很多“获取”命令,最终会出现这个错误:Buildingnativeextensions.Thiscouldtakeawhi
我在引擎样式插件中有一些代码,其中包含一些模型。在我的应用程序中,我想扩展其中一个模型。通过在初始值设定项中包含一个模块,我已经设法将实例和类方法添加到相关模型中。但是我似乎无法添加关联、回调等。我收到“找不到方法”错误。/libs/qwerty/core.rbmoduleQwertymoduleCoremoduleExtensionsmoduleUser#InstanceMethodsGoHere#ClassMethodsmoduleClassMethodshas_many:hits,:uniq=>true#nomethodfoundbefore_validation_on_crea