运动模型非线性扩展卡尔曼跟踪融合滤波算法(Matlab仿真)

news/2024/7/24 2:29:03 标签: 算法, 人工智能, 自动驾驶, 目标检测, matlab

        卡尔曼滤波的原理和理论在CSDN已有很多文章,这里不再赘述,仅分享个人的理解和Matlab仿真代码。

1 单目标跟踪

        匀速转弯(CTRV)运动模型下,摄像头输出目标状态camera_state = [x, y, theta, v],雷达输出目标状态radar_state = [x, y, theta, v]。如果状态为[x, y, vx, vy],也可以转成[x, y, theta, v]。其中theta=atan(vy/vx),v=sqrt(vx*vx + vy*vy),测量噪声设置要相应改变。

        目标运动状态可以表示为:

        由于存在非线性,可以用一阶泰勒展开的雅可比矩阵做线性化,考虑到w的除0情况,区分w=0或w≠0的结果。

        w≠0时,

        w=0时,

        估计值和测量值为线性关系,状态观测矩阵可以用下面的矩阵表示。

        

        和线性卡尔曼滤波的对比如下:

        这里由于测量和估计是线性关系,因此后验估计和卡尔曼滤波一样,直接用H矩阵。将上述公式用matlab编程即可得到滤波结果。

% 匀速转弯运动模型的扩展卡尔曼滤波算法仿真
% 目标的测量值为x,y,theta,v
clc;clear;close all;

% 匀速转弯运动的初始值
x0 = 0;                                     % 目标的初始横向位置
y0 = 0;                                     % 目标的初始纵向位置
theta = 0;                                  % 目标的偏航角(目标在当前坐标系下和x轴的夹角)
v = 3;                                      % 目标的速度
omga = 0.1;                                 % 目标的偏航角速度
N = 150;                                    % 数据量
dt = 0.2;                                   % 单帧时间
t = dt*(1:1:N);                             % 时间轴

% 更新超参数
sigma_q_x = 0.2;
sigma_q_y = 0.2;
sigma_q_theta = 0.01;
sigma_q_v = 0.1;
sigma_q_omga = 0.01;
Q_mat_ctrv = diag([sigma_q_x^2, sigma_q_y^2, sigma_q_theta^2, sigma_q_v^2, sigma_q_omga^2]);
sigma_R_ctrv = 0.4;
R_ctrv = diag([sigma_R_ctrv^2, sigma_R_ctrv^2, sigma_R_ctrv^2, sigma_R_ctrv^2]);

% 初始化参数
Xest_ekf = zeros(5, N);
P_ekf = zeros(5, 5, N);
P_ekf(:,:,1) = eye(5);
Z_ctrv = zeros(4, N);                               % 4维测量向量
H_ctrv = [1 0 0 0 0;
          0 1 0 0 0;
          0 0 1 0 0;
          0 0 0 1 0];
X_ctrv = zeros(5, N);
X_ctrv(:,1) = [1; 1; 0; 1; 0.1];                    % 初始状态,包括位置、偏航角、速度和偏航角速度
V_ctrv = mvnrnd(zeros(1,4), R_ctrv)';               % 观测误差矩阵
Z_ctrv(:,1) = H_ctrv * X_ctrv(:, 1) + V_ctrv;
Xest_ekf(1:4,1) = Z_ctrv(:,1);

% 扩展卡尔曼滤波的核心算法
for i = 2:N
    % 状态更新
    X_ctrv(:,i) = ekf_predict(X_ctrv(:,i-1), dt);
    W_ctrv = mvnrnd(zeros(1,5), Q_mat_ctrv)';       % 过程噪声向量
    X_ctrv(:,i) = X_ctrv(:,i) + W_ctrv;             % 加过程噪声

    % 预测步骤
    Xest_ekf(:,i) = ekf_predict(Xest_ekf(:,i-1), dt);
    F = ekf_jacobian(Xest_ekf(:,i-1), dt);
    P_ekf(:,:,i) = F * P_ekf(:,:,i-1) * F' + Q_mat_ctrv;

    % 测量模型更新
    V_ctrv = mvnrnd(zeros(1,4), R_ctrv)';           % 观测误差矩阵
    Z_ctrv(:,i) = H_ctrv * X_ctrv(:, i) + V_ctrv;

    % 更新步骤
    H_ekf = H_ctrv;                                 % 测量模型的雅可比矩阵
    K_ekf = P_ekf(:,:,i) * H_ekf' / (H_ekf * P_ekf(:,:,i) * H_ekf' + R_ctrv);
    Xest_ekf(:,i) = Xest_ekf(:,i) + K_ekf * (Z_ctrv(:,i) - H_ekf * Xest_ekf(:,i));
    P_ekf(:,:,i) = (eye(5) - K_ekf * H_ekf) * P_ekf(:,:,i); 
end

% 绘图部分保持不变
figure;
size = 10;
width = 2;
% 位置曲线图
subplot(2,2,1);
plot(Z_ctrv(1,:),'.g','MarkerSize',size); hold on;              % 画出测量值
plot(Xest_ekf(1,:),'b','LineWidth',width);hold on;              % 画出最优估计值
plot(X_ctrv(1,:),'r','LineWidth',width);                        % 画出实际状态值
title('X位置状态曲线');
legend('位置测量值', '位置最优估计值', '实际位置');

% 位置曲线图
subplot(2,2,2);
plot(Z_ctrv(2,:),'.g','MarkerSize',size);hold on;               % 画出测量值
plot(Xest_ekf(2,:),'b','LineWidth',width);hold on;              % 画出最优估计值
plot(X_ctrv(2,:),'r','LineWidth',width);                        % 画出实际状态值
title('Y位置状态曲线');
legend('位置测量值', '位置最优估计值', '实际位置');

% 偏航角曲线图
subplot(2,2,3);
plot(Z_ctrv(3,:),'.g','MarkerSize',size); hold on;              % 画出测量值
plot(Xest_ekf(3,:),'b','LineWidth',width); hold on;             % 画出最优估计值
plot(X_ctrv(3,:),'r','LineWidth',width);                        % 画出实际状态值
title('偏航角状态曲线');
legend('偏航角测量值', '偏航角最优估计值', '实际偏航角');

% 速度曲线图
subplot(2,2,4);
plot(Z_ctrv(4,:),'.g','MarkerSize',size); hold on;              % 画出测量值
plot(Xest_ekf(4,:),'b','LineWidth',width); hold on;             % 画出最优估计值
plot(X_ctrv(4,:),'r','LineWidth',width);                        % 画出实际状态值
title('速度状态曲线');
legend('速度测量值', '速度最优估计值', '实际速度');

% 位置平面图
% figure;
% plot(Z_ctrv(1,:),Z_ctrv(2,:));hold on;          % 画出测量值
% plot(Xest_ekf(1,:),Xest_ekf(2,:));              % 画出最优估计值
% plot(X_ctrv(1,:),X_ctrv(2,:));hold on;          % 画出实际值
% title('目标运动曲线');
% legend('位置测量值', '位置最优估计值', '实际位置');

% 扩展卡尔曼滤波的预测模型
function x_pred = ekf_predict(x, dt)
    % CTRV模型的预测模型
    theta = x(3);
    v = x(4);
    omega = x(5);

    if omega == 0 % 避免除以0
        dx = v * cos(theta) * dt;
        dy = v * sin(theta) * dt;
    else
        dx = v/omega * (sin(theta + omega * dt) - sin(theta));
        dy = v/omega * (-cos(theta + omega * dt) + cos(theta));
    end

    dtheta = omega * dt;
    
    x_pred = x + [dx; dy; dtheta; 0; 0];              % 速度和转向率的变化假设为0
end

% 根据推导的公式计算状态转移雅可比矩阵
function F = ekf_jacobian(x, dt)
    theta = x(3);
    v = x(4);
    omega = x(5);

    F = eye(5);

    if omega == 0 % 避免除以0
        F(1, 3) = -v * sin(theta) * dt;
        F(1, 4) = cos(theta) * dt;
        F(2, 3) = v * cos(theta) * dt;
        F(2, 4) = sin(theta) * dt;
    else
        F(1, 3) = v/omega * (cos(theta + omega * dt) - cos(theta));
        F(1, 4) = 1/omega * (sin(theta + omega * dt) - sin(theta));
        F(1, 5) = v/omega^2 * (sin(theta) - sin(theta + omega * dt)) + v * dt * cos(theta + omega * dt)/omega;
        F(2, 3) = v/omega * (sin(theta + omega * dt) - sin(theta));
        F(2, 4) = 1/omega * (-cos(theta + omega * dt) + cos(theta));
        F(2, 5) = v/omega^2 * (-cos(theta) + cos(theta + omega * dt)) + v * dt * sin(theta + omega * dt)/omega;
    end

    F(3, 5) = dt;
end

        下图仿真运行的结果,这个文件仿真了单个匀速转弯扩展卡尔曼滤波算法结果。

2 多传感器融合定位跟踪 

        如果是两个或多个目标,类似线性卡尔曼跟踪融合滤波算法(Matlab仿真)-CSDN博客中的融合仿真算法,分别交错仿真摄像头和雷达目标,代码如下。

% 匀速转弯运动模型的扩展卡尔曼滤波算法仿真
% 摄像头和雷达的测量值为x,y,theta,v
clc;clear;close all;

% 匀速转弯运动的初始值
x0 = 0;                                     % 目标的初始横向位置
y0 = 0;                                     % 目标的初始纵向位置
theta = 0;                                  % 目标的偏航角(目标在当前坐标系下和x轴的夹角)
v = 3;                                      % 目标的速度
omga = 0.1;                                 % 目标的偏航角速度
N = 150;                                    % 数据量
dt = 0.2;                                   % 单帧时间
t = dt*(1:1:N);                             % 时间轴

% 更新超参数
sigma_q_x = 0.2;
sigma_q_y = 0.2;
sigma_q_theta = 0.01;
sigma_q_v = 0.1;
sigma_q_omga = 0.01;
Q_matrix_ctrv = diag([sigma_q_x^2, sigma_q_y^2, sigma_q_theta^2, sigma_q_v^2, sigma_q_omga^2]);
% 设置测量噪声协方差矩阵R,噪声来自测量的误差
sigma_r_x = 1.0;
sigma_r_y = 0.2; 
sigma_r_theta = 0.01; 
sigma_r_v = 0.5;
R_matrix_ctrv_camera = diag([sigma_r_x^2, sigma_r_y^2, sigma_r_theta^2, sigma_r_v^2]);
% 上面是摄像头噪声协方差矩阵,下面是雷达噪声协方差矩阵
sigma_r_x = 0.4;
sigma_r_y = 0.4; 
sigma_r_theta = 0.01; 
sigma_r_v = 0.1;
R_matrix_ctrv_radar = diag([sigma_r_x^2, sigma_r_y^2, sigma_r_theta^2, sigma_r_v^2]);

% 初始化参数
Xest_ekf = zeros(5, N);
P_ekf = zeros(5, 5, N);
P_ekf(:,:,1) = eye(5);
Z_ctrv = zeros(4, N);                               % 4维测量向量
H_ctrv = [1 0 0 0 0;
          0 1 0 0 0;
          0 0 1 0 0;
          0 0 0 1 0];
X_ctrv = zeros(5, N);
X_ctrv(:,1) = [1; 1; 0; 1; 0.1];                    % 初始状态,包括位置、偏航角、速度和偏航角速度
R_matrix_ctrv = R_matrix_ctrv_camera;               % 第1帧为摄像头
V_ctrv = mvnrnd(zeros(1,4), R_matrix_ctrv)';        % 观测误差矩阵
Z_ctrv(:,1) = H_ctrv * X_ctrv(:, 1) + V_ctrv;
Xest_ekf(1:4,1) = Z_ctrv(:,1);

% 扩展卡尔曼滤波的核心算法
for i = 2:N
    % 选择摄像头或雷达,摄像头是奇数帧,雷达是偶数帧
    if mod(i,2) == 1
        R_matrix_ctrv = R_matrix_ctrv_camera;
    else
        R_matrix_ctrv = R_matrix_ctrv_radar;
    end
    % 状态更新
    X_ctrv(:,i) = ekf_predict(X_ctrv(:,i-1), dt);
    W_ctrv = mvnrnd(zeros(1,5), Q_matrix_ctrv)';        % 过程噪声向量
    X_ctrv(:,i) = X_ctrv(:,i) + W_ctrv;                 % 加过程噪声

    % 预测步骤
    Xest_ekf(:,i) = ekf_predict(Xest_ekf(:,i-1), dt);
    F = ekf_jacobian(Xest_ekf(:,i-1), dt);
    P_ekf(:,:,i) = F * P_ekf(:,:,i-1) * F' + Q_matrix_ctrv;

    % 测量模型更新
    V_ctrv = mvnrnd(zeros(1,4), R_matrix_ctrv)';            % 观测误差矩阵
    Z_ctrv(:,i) = H_ctrv * X_ctrv(:, i) + V_ctrv;

    % 更新步骤
    H_ekf = H_ctrv;                                         % 测量模型的雅可比矩阵
    K_ekf = P_ekf(:,:,i) * H_ekf' / (H_ekf * P_ekf(:,:,i) * H_ekf' + R_matrix_ctrv);
    Xest_ekf(:,i) = Xest_ekf(:,i) + K_ekf * (Z_ctrv(:,i) - H_ekf * Xest_ekf(:,i));
    P_ekf(:,:,i) = (eye(5) - K_ekf * H_ekf) * P_ekf(:,:,i); 
end

% 绘图部分保持不变
figure;
size = 10;
width = 2;
% 位置曲线图
subplot(2,2,1);
plot(Z_ctrv(1,:),'.g','MarkerSize',size); hold on;              % 画出测量值
plot(Xest_ekf(1,:),'b','LineWidth',width);hold on;              % 画出最优估计值
plot(X_ctrv(1,:),'r','LineWidth',width);                        % 画出实际状态值
title('X位置状态曲线');
legend('位置测量值', '位置最优估计值', '实际位置');

% 位置曲线图
subplot(2,2,2);
plot(Z_ctrv(2,:),'.g','MarkerSize',size);hold on;               % 画出测量值
plot(Xest_ekf(2,:),'b','LineWidth',width);hold on;              % 画出最优估计值
plot(X_ctrv(2,:),'r','LineWidth',width);                        % 画出实际状态值
title('Y位置状态曲线');
legend('位置测量值', '位置最优估计值', '实际位置');

% 偏航角曲线图
subplot(2,2,3);
plot(Z_ctrv(3,:),'.g','MarkerSize',size); hold on;              % 画出测量值
plot(Xest_ekf(3,:),'b','LineWidth',width); hold on;             % 画出最优估计值
plot(X_ctrv(3,:),'r','LineWidth',width);                        % 画出实际状态值
title('偏航角状态曲线');
legend('偏航角测量值', '偏航角最优估计值', '实际偏航角');

% 速度曲线图
subplot(2,2,4);
plot(Z_ctrv(4,:),'.g','MarkerSize',size); hold on;              % 画出测量值
plot(Xest_ekf(4,:),'b','LineWidth',width); hold on;             % 画出最优估计值
plot(X_ctrv(4,:),'r','LineWidth',width);                        % 画出实际状态值
title('速度状态曲线');
legend('速度测量值', '速度最优估计值', '实际速度');

% 分别提取摄像头和雷达目标
% 确定摄像头和雷达帧数
if mod(N,2) == 0
    N_camera = N/2;
    N_radar = N/2;
else
    N_camera = floor(N/2) + 1;
    N_radar = floor(N/2);
end
Z_ctrv_camera = zeros(4,N_camera);
Z_ctrv_radar = zeros(4,N_radar);
camera_frame = zeros(1,N_camera);
radar_frame = zeros(1,N_radar);
camera_count = 0;
radar_count = 0;
% 提取摄像头和雷达帧的数据,摄像头在奇数帧,雷达在偶数帧
for i = 1:N
    if mod(i,2) == 1                                        
        camera_count = camera_count + 1;
        camera_frame(camera_count) = i;
        Z_ctrv_camera(:,camera_count) = Z_ctrv(:,i);            % 摄像头数据
    else
        radar_count = radar_count + 1;
        radar_frame(radar_count) = i;
        Z_ctrv_radar(:,radar_count) = Z_ctrv(:,i);              % 雷达数据
    end
end

% 绘图部分保持不变
figure;size = 10;width = 2;
% X位置曲线图
subplot(2,2,1);
plot(camera_frame,Z_ctrv_camera(1,:),'.g','MarkerSize',size); hold on;                % 画出测量值
plot(radar_frame,Z_ctrv_radar(1,:),'.k','MarkerSize',size); hold on;                  % 画出测量值
plot(Xest_ekf(1,:),'b','LineWidth',width);hold on;                                    % 画出最优估计值
plot(X_ctrv(1,:),'r','LineWidth',width);                                              % 画出实际状态值
title('X位置状态曲线');
legend('摄像头位置测量值', '雷达位置测量值','位置最优估计值', '实际位置');

% Y位置曲线图
subplot(2,2,2);
plot(camera_frame,Z_ctrv_camera(2,:),'.g','MarkerSize',size); hold on;                % 画出测量值
plot(radar_frame,Z_ctrv_radar(2,:),'.k','MarkerSize',size); hold on;                  % 画出测量值
plot(Xest_ekf(2,:),'b','LineWidth',width);hold on;                                    % 画出最优估计值
plot(X_ctrv(2,:),'r','LineWidth',width);                                              % 画出实际状态值
title('Y位置状态曲线');
legend('摄像头位置测量值', '雷达位置测量值','位置最优估计值', '实际位置');

% 偏航角曲线图
subplot(2,2,3);
plot(camera_frame,Z_ctrv_camera(3,:),'.g','MarkerSize',size); hold on;                % 画出测量值
plot(radar_frame,Z_ctrv_radar(3,:),'.k','MarkerSize',size); hold on;                  % 画出测量值
plot(Xest_ekf(3,:),'b','LineWidth',width); hold on;                                   % 画出最优估计值
plot(X_ctrv(3,:),'r','LineWidth',width);                                              % 画出实际状态值
title('偏航角状态曲线');
legend('偏航角测量值', '偏航角测量值', '偏航角最优估计值', '实际偏航角');

% 速度曲线图
subplot(2,2,4);
plot(camera_frame,Z_ctrv_camera(4,:),'.g','MarkerSize',size); hold on;                % 画出测量值
plot(radar_frame,Z_ctrv_radar(4,:),'.k','MarkerSize',size); hold on;                  % 画出测量值
plot(Xest_ekf(4,:),'b','LineWidth',width); hold on;                                   % 画出最优估计值
plot(X_ctrv(4,:),'r','LineWidth',width);                                              % 画出实际状态值
title('速度状态曲线');
legend('摄像头速度测量值', '雷达速度测量值', '速度最优估计值', '实际速度');

% 位置平面图
% figure;
% plot(Z_ctrv(1,:),Z_ctrv(2,:));hold on;          % 画出测量值
% plot(Xest_ekf(1,:),Xest_ekf(2,:));              % 画出最优估计值
% plot(X_ctrv(1,:),X_ctrv(2,:));hold on;          % 画出实际值
% title('目标运动曲线');
% legend('位置测量值', '位置最优估计值', '实际位置');

% 扩展卡尔曼滤波的预测模型
function x_pred = ekf_predict(x, dt)
    % CTRV模型的预测模型
    theta = x(3);
    v = x(4);
    omega = x(5);

    if omega == 0 % 避免除以0
        dx = v * cos(theta) * dt;
        dy = v * sin(theta) * dt;
    else
        dx = v/omega * (sin(theta + omega * dt) - sin(theta));
        dy = v/omega * (-cos(theta + omega * dt) + cos(theta));
    end

    dtheta = omega * dt;
    
    x_pred = x + [dx; dy; dtheta; 0; 0]; % 速度和转向率的变化假设为0
end

function F = ekf_jacobian(x, dt)
    theta = x(3);
    v = x(4);
    omega = x(5);

    F = eye(5);

    if omega == 0 % 避免除以0
        F(1, 3) = -v * sin(theta) * dt;
        F(1, 4) = cos(theta) * dt;
        F(2, 3) = v * cos(theta) * dt;
        F(2, 4) = sin(theta) * dt;
    else
        F(1, 3) = v/omega * (cos(theta + omega * dt) - cos(theta));
        F(1, 4) = 1/omega * (sin(theta + omega * dt) - sin(theta));
        F(1, 5) = v/omega^2 * (sin(theta) - sin(theta + omega * dt)) + v * dt * cos(theta + omega * dt)/omega;
        F(2, 3) = v/omega * (sin(theta + omega * dt) - sin(theta));
        F(2, 4) = 1/omega * (-cos(theta + omega * dt) + cos(theta));
        F(2, 5) = v/omega^2 * (-cos(theta) + cos(theta + omega * dt)) + v * dt * sin(theta + omega * dt)/omega;
    end

    F(3, 5) = dt;
end

       仿真代码给出摄像头和雷达目标定位跟踪融合的结果,第一张图的测量值没有区分摄像头和雷达,第二张图做了区分。


http://www.niftyadmin.cn/n/5319096.html

相关文章

flutter 文件下载及存储路径

flutter 文件下载及存储路径 前言一、下载进度条二、文件路径二、文件上传总结 前言 日常开发中,经常会遇到下载文件的功能,往往我们在需要保存文件的路径上去调试,比如Android中的路径,有些会报错在SD卡中,但是有些手…

移动端测试体系建设

一、测试 or 开发期间: 1、静态代码检查 1、在编译和运行代码之前,使用静态代码分析工具对代码进行分析,查找潜在问题,如:内存泄露,缓冲区溢出、未初始化的变量等低级语法错误等,常作为流水线卡点自动执行 2、Android端常见静态代码检查工具:Android Lint、FindBugs、Q…

CSS基础方法——引入方式、属性、基础选择器

CSS 主要用于设置 HTML 页面中的文本样式(字体、大小、颜色、对齐方式……)、图片样式(宽高、边框样式、边距……)以及版面的布局和外观显示样式。 1、CSS引入方式 行内样式 写在标签中,通常不使用,只做…

MySQL篇—通过Clone插件进行本地克隆数据(第二篇,总共三篇)

在上一篇文章中,我们深入探讨了Clone技术的多种用途,以及使用它所需满足的前提条件。我们也详细分析了Clone存在的限制,并深入了解了其背后的备份原理。今天,我们将继续探索MySQL Clone Plugin的强大功能,Clone其实最重…

安卓接入google的Firebase登录教程

1.https://console.firebase.google.com创建安卓项目 2.添加google登录 3.添加项目的SHA证书指纹 4. FireBase自动生成(API和服务) https://console.cloud.google.com/apis/credentials?authuser1&projectbattle-against-darkness 5.下载goog…

C++力扣题目--94,144,145二叉树递归遍历

思路 这次我们要好好谈一谈递归,为什么很多同学看递归算法都是“一看就会,一写就废”。 主要是对递归不成体系,没有方法论,每次写递归算法 ,都是靠玄学来写代码,代码能不能编过都靠运气。 本篇将介绍前后…

TCP/IP 网络模型

TCP/IP 网络通常是由上到下分成 4 层,分别是应用层,传输层,网络层和网络接口层。 应用层 应用层专注于为用户提供应用功能,比如 HTTP、FTP、Telnet、DNS、SMTP等。我们电脑或手机使用的应用软件都是在应用层实现。应用层是不用去关…

在vue项目中使用天地图,点击可打点,搜索打点组件封装

一、在index.html文件中引入天地图JavaScript API&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name&quo…