一阶互补滤波,二阶互补滤波,卡尔曼滤波

本文介绍了用于姿态估计的一阶和二阶互补滤波方法,以及详细的卡尔曼滤波实现。通过对加速度计和陀螺仪数据进行融合,提高角度测量精度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一阶互补

// a=tau / (tau + loop time)
// newAngle = angle measured with atan2 using the accelerometer
//加速度传感器输出值
// newRate = angle measured using the gyro
// looptime = loop time in millis()
 
float tau=0.075;
float a=0.0;
float Complementary(float newAngle, float newRate,int looptime) 
{
float dtC = float(looptime)/1000.0;
a=tau/(tau+dtC);
//以下代码更改成白色,下载后恢复成其他颜色即可看到
x_angleC= a* (x_angleC + newRate * dtC) + (1-a) * (newAngle);
return x_angleC;

}

 

二阶互补

// newAngle = angle measured with atan2 using the accelerometer
// newRate = angle measured using the gyro
// looptime = loop time in millis()
float Complementary2(float newAngle, float newRate,int looptime) 
{
float k=10;
float dtc2=float(looptime)/1000.0;
//以下代码更改成白色,下载后恢复成其他颜色即可看到
x1 = (newAngle -   x_angle2C)*k*k;
y1 = dtc2*x1 + y1;
z1= y1 + (newAngle -   x_angle2C)*2*k + newRate;
x_angle2C = dtc2*z1 + x_angle2C;
return x_angle2C;

} Here too we just have to setthe k and magically we get the angle.

卡尔曼滤波

// KasBot V1 - Kalman filter module
 
float Q_angle  =  0.01; //0.001
float Q_gyro   =  0.0003;  //0.003
float R_angle  =  0.01;  //0.03
 
float x_bias = 0;
float P_00 = 0, P_01 = 0, P_10 = 0, P_11 = 0;
float  y, S;
float K_0, K_1;
 
// newAngle = angle measured with atan2 using the accelerometer
// newRate = angle measured using the gyro
// looptime = loop time in millis()
 
float kalmanCalculate(float newAngle, float newRate,int looptime)
{
float dt = float(looptime)/1000;
x_angle += dt * (newRate - x_bias);
//以下代码更改成白色,下载后恢复成其他颜色即可看到
P_00 +=  - dt * (P_10 + P_01) + Q_angle * dt;
P_01 +=  - dt * P_11;
P_10 +=  - dt * P_11;
P_11 +=  + Q_gyro * dt;
 
y = newAngle - x_angle;
S = P_00 + R_angle;
K_0 = P_00 / S;
K_1 = P_10 / S;
 
x_angle +=  K_0 * y;
x_bias  +=  K_1 * y;
P_00 -= K_0 * P_00;
P_01 -= K_0 * P_01;
P_10 -= K_1 * P_00;
P_11 -= K_1 * P_01;
 
return x_angle;

} To get the answer, you have toset 3 parameters: Q_angle, R_angle,R_gyro.

 

 

详细卡尔曼滤波

/* -*- indent-tabs-mode:T;c-basic-offset:8; tab-width:8; -*- vi: set ts=8:

 *$Id: tilt.c,v 1.1 2003/07/09 18:23:29 john Exp $

 *

 * 1dimensional tilt sensor using a dual axis accelerometer

 *and single axis angular rate gyro.  Thetwo sensors are fused

 *via a two state Kalman filter, with one state being the angle

 *and the other state being the gyro bias.

 *

 *Gyro bias is automatically tracked by the filter.  This seems

 *like magic.

 *

 *Please note that there are lots of comments in the functions and

 * inblocks before the functions.  Kalmanfiltering is an already complex

 *subject, made even more so by extensive hand optimizations to the C code

 *that implements the filter.  I've triedto make an effort of explaining

 *the optimizations, but feel free to send mail to the mailing list,

 *autopilot-devel@lists.sf.net, with questions about this code.

 *

 *

 *(c) 2003 Trammell Hudson <hudson@rotomotion.com>

 *

 *************

 *

 *  Thisfile is part of the autopilot onboard code package.

 * 

 * Autopilot is free software; you can redistribute it and/or modify

 *  itunder the terms of the GNU General Public License as published by

 *  theFree Software Foundation; either version 2 of the License, or

 *  (atyour option) any later version.

 * 

 * Autopilot is distributed in the hope that it will be useful,

 *  butWITHOUT ANY WARRANTY; without even the implied warranty of

 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

 *  GNUGeneral Public License for more details.

 * 

 *  Youshould have received a copy of the GNU General Public License

 *  alongwith Autopilot; if not, write to the Free Software

 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA

 *

 */

#include <math.h>

 

 

/*

 *Our update rate.  This is how often ourstate is updated with

 *gyro rate measurements.  For now, we doit every time an

 * 8bit counter running at CLK/1024 expires. You will have to

 *change this value if you update at a different rate.

 */

static const float     dt    = ( 1024.0 * 256.0 )/ 8000000.0;

 

 

/*

 *Our covariance matrix.  This is updatedat every time step to

 *determine how well the sensors are tracking the actual state.

 */

static float             P[2][2] = {

       {1, 0 },

       {0, 1 },

};

 

 

/*

 *Our two states, the angle and the gyro bias. As a byproduct of computing

 *the angle, we also have an unbiased angular rate available.   These are

 *read-only to the user of the module.

 */

float               angle;

float               q_bias;

float               rate;

 

 

/*

 * Rrepresents the measurement covariance noise. In this case,

 * itis a 1x1 matrix that says that we expect 0.3 rad jitter

 *from the accelerometer.

 */

static const float     R_angle   = 0.3;

 

 

/*

 * Qis a 2x2 matrix that represents the process covariance noise.

 * Inthis case, it indicates how much we trust the acceleromter

 *relative to the gyros.

 */

static const float     Q_angle  = 0.001;

static const float     Q_gyro   = 0.003;

 

 

/*

 *state_update is called every dt with a biased gyro measurement

 * bythe user of the module.  It updates thecurrent angle and

 *rate estimate.

 *

 *The pitch gyro measurement should be scaled into real units, but

 *does not need any bias removal.  Thefilter will track the bias.

 *

 *Our state vector is:

 *

 *    X = [ angle, gyro_bias ]

 *

 * Itruns the state estimation forward via the state functions:

 *

 *    Xdot = [ angle_dot, gyro_bias_dot ]

 *

 *    angle_dot       =gyro - gyro_bias

 *    gyro_bias_dot = 0

 *

 *And updates the covariance matrix via the function:

 *

 *    Pdot = A*P + P*A' + Q

 *

 * Ais the Jacobian of Xdot with respect to the states:

 *

 *    A = [ d(angle_dot)/d(angle)     d(angle_dot)/d(gyro_bias) ]

 *        [d(gyro_bias_dot)/d(angle) d(gyro_bias_dot)/d(gyro_bias) ]

 *

 *      = [0 -1 ]

 *        [0  0 ]

 *

 *Due to the small CPU available on the microcontroller, we've

 *hand optimized the C code to only compute the terms that are

 *explicitly non-zero, as well as expanded out the matrix math

 * tobe done in as few steps as possible. This does make it harder

 * toread, debug and extend, but also allows us to do this with

 *very little CPU time.

 */

void

state_update(   const float             q_m /* Pitch gyro measurement */)

{

       /*Unbias our gyro */

       constfloat             q = q_m - q_bias;

 

       /*

        * Compute the derivative of the covariancematrix

        *

        *    Pdot= A*P + P*A' + Q

        *

        * We've hand computed the expansion of A = [ 0-1, 0 0 ] multiplied

        * by P and P multiplied by A' = [ 0 0, -1, 0].  This is then added

        * to the diagonal elements of Q, which areQ_angle and Q_gyro.

        */

       constfloat             Pdot[2 * 2] = {

              Q_angle- P[0][1] - P[1][0],  /* 0,0 */

                      - P[1][1],              /* 0,1 */

                      -P[1][1],              /* 1,0 */

              Q_gyro                        /* 1,1 */

       };

 

       /*Store our unbias gyro estimate */

       rate= q;

 

       /*

        * Update our angle estimate

        * angle += angle_dot * dt

        *      += (gyro - gyro_bias) * dt

        *      += q * dt

        */

       angle+= q * dt;

 

       /*Update the covariance matrix */

       P[0][0]+= Pdot[0] * dt;

       P[0][1]+= Pdot[1] * dt;

       P[1][0]+= Pdot[2] * dt;

       P[1][1]+= Pdot[3] * dt;

}

 

 

/*

 *kalman_update is called by a user of the module when a new

 *accelerometer measurement is available. ax_m and az_m do not

 *need to be scaled into actual units, but must be zeroed and have

 *the same scale.

 *

 *This does not need to be called every time step, but can be if

 *the accelerometer data are available at the same rate as the

 *rate gyro measurement.

 *

 *For a two-axis accelerometer mounted perpendicular to the rotation

 *axis, we can compute the angle for the full 360 degree rotation

 *with no linearization errors by using the arctangent of the two

 *readings.

 *

 * Ascommented in state_update, the math here is simplified to

 *make it possible to execute on a small microcontroller with no

 *floating point unit.  It will be hard toread the actual code and

 *see what is happening, which is why there is this extensive

 *comment block.

 *

 *The C matrix is a 1x2 (measurements x states) matrix that

 * isthe Jacobian matrix of the measurement value with respect

 * tothe states.  In this case, C is:

 *

 *    C = [ d(angle_m)/d(angle)  d(angle_m)/d(gyro_bias) ]

 *      = [1 0 ]

 *

 *because the angle measurement directly corresponds to the angle

 *estimate and the angle measurement has no relation to the gyro

 *bias.

 */

void

kalman_update(

       constfloat             ax_m,     /* X acceleration */

       constfloat             az_m       /* Z acceleration */

)

{

       /*Compute our measured angle and the error in our estimate */

//以下代码更改成白色,下载后恢复成其他颜色即可看到

       constfloat             angle_m = atan2( -az_m,ax_m );

       constfloat             angle_err = angle_m -angle;

 

       /*

        * C_0 shows how the state measurement directlyrelates to

        * the state estimate.

       *

        * The C_1 shows that the state measurement doesnot relate

        * to the gyro bias estimate.  We don't actually use this, so

        * we comment it out.

        */

       constfloat             C_0 = 1;

       /*const float          C_1 = 0; */

 

       /*

        * PCt<2,1> = P<2,2> *C'<2,1>, which we use twice.  Thismakes

        * it worthwhile to precompute and store thetwo values.

        * Note that C[0,1] = C_1 is zero, so we do notcompute that

        * term.

        */

       constfloat             PCt_0 = C_0 * P[0][0];/* + C_1 * P[0][1] = 0 */

       constfloat             PCt_1 = C_0 * P[1][0];/* + C_1 * P[1][1] = 0 */

             

       /*

        * Compute the error estimate.  From the Kalman filter paper:

        *

        *    E =C P C' + R

        *

        * Dimensionally,

        *

        *    E<1,1>= C<1,2> P<2,2> C'<2,1> + R<1,1>

        *

        * Again, note that C_1 is zero, so we do notcompute the term.

        */

       constfloat             E =

              R_angle

              +C_0 * PCt_0

       /*    + C_1 * PCt_1 = 0 */

       ;

 

       /*

        * Compute the Kalman filter gains.  From the Kalman paper:

        *

        *    K =P C' inv(E)

        *

        * Dimensionally:

        *

        *    K<2,1>= P<2,2> C'<2,1> inv(E)<1,1>

        *

        * Luckilly, E is <1,1>, so the inverseof E is just 1/E.

        */

       constfloat             K_0 = PCt_0 / E;

       constfloat             K_1 = PCt_1 / E;

             

       /*

        * Update covariance matrix.  Again, from the Kalman filter paper:

        *

        *    P =P - K C P

        *

        * Dimensionally:

        *

        *    P<2,2>-= K<2,1> C<1,2> P<2,2>

        *

        * We first compute t<1,2> = C P.  Note that:

        *

        *    t[0,0]= C[0,0] * P[0,0] + C[0,1] * P[1,0]

        *

        * But, since C_1 is zero, we have:

        *

        *    t[0,0]= C[0,0] * P[0,0] = PCt[0,0]

        *

        * This saves us a floating point multiply.

        */

       constfloat             t_0 = PCt_0; /* C_0 *P[0][0] + C_1 * P[1][0] */

       constfloat             t_1 = C_0 * P[0][1]; /*+ C_1 * P[1][1]  = 0 */

 

       P[0][0]-= K_0 * t_0;

       P[0][1]-= K_0 * t_1;

       P[1][0]-= K_1 * t_0;

       P[1][1]-= K_1 * t_1;

      

       /*

        * Update our state estimate.  Again, from the Kalman paper:

        *

        *    X +=K * err

        *

        * And, dimensionally,

        *

        *    X<2>= X<2> + K<2,1> * err<1,1>

        *

        * err is a measurement of the difference inthe measured state

        * and the estimate state.  In our case, it is just the difference

        * between the two accelerometer measured angleand our estimated

        * angle.

        */

       angle       += K_0 * angle_err;

       q_bias     += K_1 * angle_err;

}

 

### 卡尔曼滤波互补滤波融合算法的仿真方法及代码实现 卡尔曼滤波互补滤波都是常用的传感器数据处理技术,分别适用于不同场景下的状态估计。为了充分利用两者的优点,可以通过某种方式将两者结合起来形成种混合滤波策略。以下是基于 MATLAB 的具体实现方案: #### 1. 算法概述 卡尔曼滤波能够有效减少高斯白噪声的影响,但在某些情况下可能对非线性系统表现不佳;而互补滤波则简单高效,在低频信号中表现出色[^1]。因此,可以设计种机制来动态权衡这两种滤波器的结果。 #### 2. MATLAB 实现代码 ```matlab % 参数初始化 clc; clear; fs = 50; % 采样频率 (Hz) T = 1/fs; % 采样周期 (秒) N = 200; % 数据样本数量 time = T*(0:N-1); % 时间向量 % 模拟真实角度随时间变化的情况 true_angle = sin(time / 2); % 添加随机噪声到陀螺仪和加速度计测量值中 gyro_noise = randn(size(true_angle)) * 0.01; % 给陀螺仪数据增加噪声 acc_noise = randn(size(true_angle)) * 0.1; % 给加速度计数据增加噪声 % 计算陀螺仪角速率和加速度计测得的角度 angle_gyro = diff([0, true_angle]) ./ T + gyro_noise; % 根据真实角度计算陀螺仪输出 angle_acc = true_angle + acc_noise; % 加速度计输出等于带噪的真实角度 % === 卡尔曼滤波部分 === Q = 1e-5; % 过程噪声协方差矩阵 R = 0.1; % 测量噪声协方差矩阵 P = zeros(1, N); % 初始化误差协方差矩阵 K = zeros(1, N); % 初始化卡尔曼增益数组 kalman_angle = zeros(1, N); % 存储卡尔曼滤波后的角度估计值 state_estimate = angle_acc(1); % 初始状态估计设为第个加速度计测量值 for i = 2:N % 预测段 state_predict = state_estimate + angle_gyro(i) * T; % 使用陀螺仪更新预测状态 % 更新误差协方差矩阵 P(i) = P(i-1) + Q; % 计算卡尔曼增益 K(i) = P(i) / (P(i) + R); % 更新段 state_estimate = state_predict + K(i) * (angle_acc(i) - state_predict); % 保存当前时刻的状态估计作为卡尔曼滤波结果 kalman_angle(i) = state_estimate; end % === 互补滤波部分 === alpha = 0.98; % 设置滤波增益参数 complementary_angle = zeros(1, N); % 存储互补滤波后的角度估计值 for i = 2:N % 应用互补滤波公式 complementary_angle(i) = ... alpha * (complementary_angle(i-1) + angle_gyro(i)*T) + ... (1-alpha) * angle_acc(i); end % === 融合部分 === fusion_weight_kalman = 0.7; % 权重因子(可根据实际情况调整) fusion_weight_complementary = 0.3; % 权重因子 fusion_angle = fusion_weight_kalman * kalman_angle + ... fusion_weight_complementary * complementary_angle; % === 结果可视化 === figure; plot(time, true_angle, 'k', 'LineWidth', 2); hold on; plot(time, kalman_angle, 'b--'); plot(time, complementary_angle, 'r-.'); plot(time, fusion_angle, 'm:', 'LineWidth', 2); plot(time, angle_acc, 'g:'); legend('真实角度', '卡尔曼滤波结果', '互补滤波结果', '融合结果', '加速度计测量值'); xlabel('时间 (s)'); ylabel('角度 (弧度)'); title('卡尔曼滤波互补滤波及其融合性能对比'); grid on; ``` --- #### 3. Python 实现代码 如果希望在 Python 中完成类似的仿真,可参考如下代码片段: ```python import numpy as np import matplotlib.pyplot as plt # 参数初始化 fs = 50 # 采样频率 (Hz) T = 1 / fs # 采样周期 (秒) N = 200 # 数据样本数量 time = np.arange(N) * T # 时间向量 # 模拟真实角度随时间变化的情况 true_angle = np.sin(time / 2) # 添加随机噪声到陀螺仪和加速度计测量值中 np.random.seed(42) gyro_noise = np.random.randn(len(true_angle)) * 0.01 # 给陀螺仪数据增加噪声 acc_noise = np.random.randn(len(true_angle)) * 0.1 # 给加速度计数据增加噪声 # 计算陀螺仪角速率和加速度计测得的角度 angle_gyro = np.diff(np.insert(true_angle, 0, 0)) / T + gyro_noise[:-1] angle_acc = true_angle + acc_noise # === 卡尔曼滤波部分 === Q = 1e-5 # 过程噪声协方差矩阵 R = 0.1 # 测量噪声协方差矩阵 P = np.zeros_like(angle_acc) # 初始化误差协方差矩阵 K = np.zeros_like(angle_acc) # 初始化卡尔曼增益数组 kalman_angle = np.zeros_like(angle_acc) # 存储卡尔曼滤波后的角度估计值 state_estimate = angle_acc[0] for i in range(1, len(angle_acc)): # 预测段 state_predict = state_estimate + angle_gyro[i-1] * T # 使用陀螺仪更新预测状态 # 更新误差协方差矩阵 P[i] = P[i-1] + Q # 计算卡尔曼增益 K[i] = P[i] / (P[i] + R) # 更新段 state_estimate = state_predict + K[i] * (angle_acc[i] - state_predict) # 保存当前时刻的状态估计作为卡尔曼滤波结果 kalman_angle[i] = state_estimate # === 互补滤波部分 === alpha = 0.98 # 设置滤波增益参数 complementary_angle = np.zeros_like(angle_acc) # 存储互补滤波后的角度估计值 for i in range(1, len(angle_acc)): # 应用互补滤波公式 complementary_angle[i] = \ alpha * (complementary_angle[i-1] + angle_gyro[i-1]*T) + \ (1-alpha) * angle_acc[i] # === 融合部分 === fusion_weight_kalman = 0.7 # 权重因子(可根据实际情况调整) fusion_weight_complementary = 0.3 # 权重因子 fusion_angle = fusion_weight_kalman * kalman_angle + \ fusion_weight_complementary * complementary_angle # === 结果可视化 === plt.figure(figsize=(10, 6)) plt.plot(time, true_angle, 'k-', linewidth=2, label='真实角度') plt.plot(time[:len(kalman_angle)], kalman_angle, 'b--', label='卡尔曼滤波结果') plt.plot(time[:len(complementary_angle)], complementary_angle, 'r-.', label='互补滤波结果') plt.plot(time[:len(fusion_angle)], fusion_angle, 'm:', linewidth=2, label='融合结果') plt.plot(time, angle_acc, 'g:', label='加速度计测量值') plt.legend() plt.xlabel('时间 (s)') plt.ylabel('角度 (弧度)') plt.title('卡尔曼滤波互补滤波及其融合性能对比') plt.grid(True) plt.show() ``` --- ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值