脚部ZUPT算法计算航向的MATLAB实现

零速更新(Zero Velocity Update, ZUPT)算法是惯性导航系统中用于修正漂移误差的重要技术,特别适用于脚部安装的惯性测量单元(IMU)。

ZUPT算法的核心思想是:当检测到脚部处于静止状态时(如站立或脚部着地阶段),速度理论上应为零。利用这一时刻的观测来修正惯性导航系统的累积误差。

航向计算通常结合:

  1. 陀螺仪积分得到初始航向
  2. 加速度计和磁力计数据辅助修正
  3. ZUPT期间进行误差估计和补偿

代码

function [heading, position] = foot_zupt_heading_calculation(acc, gyro, mag, fs)
% FOOT_ZUPT_HEADING_CALCULATION 基于ZUPT的脚部IMU航向计算
%
% 输入:
%   acc - N×3加速度计数据 [m/s^2]
%   gyro - N×3陀螺仪数据 [rad/s]
%   mag - N×3磁力计数据 [μT]
%   fs - 采样频率 [Hz]
%
% 输出:
%   heading - 航向角序列 [度]
%   position - 位置估计序列 [m]

    % 参数设置
    dt = 1/fs;              % 采样时间间隔
    N = size(acc, 1);       % 数据点数
    
    % 初始化变量
    quaternion = zeros(N, 4);
    velocity = zeros(N, 3);
    position = zeros(N, 3);
    heading = zeros(N, 1);
    
    % 初始方向估计(使用加速度计和磁力计)
    quaternion(1, :) = initial_orientation(acc(1, :), mag(1, :));
    
    % ZUPT检测参数
    zupt_threshold = 0.5;   % 静止检测阈值 [m/s^2]
    window_size = 5;        % 滑动窗口大小
    
    % 卡尔曼滤波器参数(简化的误差状态卡尔曼滤波器)
    Q = diag([0.01, 0.01, 0.01, 0.01, 0.01, 0.01]); % 过程噪声
    R = diag([0.1, 0.1, 0.1]); % 观测噪声
    P = eye(6);             % 误差协方差矩阵
    
    % 主循环
    for k = 2:N
        % 1. 姿态更新 - 使用陀螺仪数据进行四元数积分
        quaternion(k, :) = update_quaternion(quaternion(k-1, :), gyro(k, :), dt);
        
        % 2. 速度更新 - 在导航坐标系中积分加速度
        C_bn = quat2dcm(quaternion(k, :)); % 机体到导航坐标系的旋转矩阵
        acc_nav = C_bn * acc(k, :)';       % 将加速度转换到导航坐标系
        acc_nav(3) = acc_nav(3) - 9.81;    % 去除重力影响(假设z轴向上)
        
        velocity(k, :) = velocity(k-1, :) + acc_nav' * dt;
        
        % 3. 位置更新
        position(k, :) = position(k-1, :) + velocity(k, :) * dt;
        
        % 4. ZUPT检测与处理
        is_zupt = detect_zupt(acc(k-window_size+1:k, :), zupt_threshold);
        
        if is_zupt
            % 当检测到静止时,应用ZUPT修正
            [velocity(k, :), P] = zupt_correction(velocity(k, :), P, Q, R);
            
            % 使用加速度计和磁力计重新估计姿态(减少航向漂移)
            if k > window_size
                quaternion(k, :) = reestimate_orientation(...
                    mean(acc(k-window_size+1:k, :)), ...
                    mean(mag(k-window_size+1:k, :)), ...
                    quaternion(k, :));
            end
        end
        
        % 5. 计算航向角
        [yaw, ~, ~] = quat2angle(quaternion(k, :));
        heading(k) = rad2deg(yaw);
    end
end

function zupt = detect_zupt(acc_window, threshold)
% DETECT_ZUPT 检测零速区间
% 基于加速度变化的方差检测静止状态
    acc_norm = vecnorm(acc_window, 2, 2);
    acc_var = var(acc_norm);
    zupt = acc_var < threshold;
end

function q = initial_orientation(acc, mag)
% INITIAL_ORIENTATION 初始方向估计
% 使用加速度计和磁力计计算初始四元数
    % 归一化加速度计读数(作为重力方向)
    g = acc / norm(acc);
    
    % 计算初始俯仰和横滚
    pitch = asin(-g(1));
    roll = atan2(g(2), g(3));
    
    % 基于磁力计计算偏航
    mag_n = mag / norm(mag);
    mx = mag_n(1) * cos(pitch) + mag_n(2) * sin(roll) * sin(pitch) + mag_n(3) * cos(roll) * sin(pitch);
    my = mag_n(2) * cos(roll) - mag_n(3) * sin(roll);
    yaw = atan2(-my, mx);
    
    % 转换为四元数
    q = angle2quat(yaw, pitch, roll);
end

function q_new = update_quaternion(q_old, gyro, dt)
% UPDATE_QUATERNION 使用陀螺仪数据更新四元数
    % 四元数导数
    omega = [0, gyro];
    q_dot = 0.5 * quatmultiply(q_old, omega);
    
    % 前向积分
    q_new = q_old + q_dot * dt;
    q_new = q_new / norm(q_new); % 归一化
end

function q_corrected = reestimate_orientation(acc_mean, mag_mean, q_current)
% REESTIMATE_ORIENTATION 重新估计方向
% 在ZUPT期间使用加速度计和磁力计数据修正方向
    % 计算基于加速度计的重力方向
    g_measured = acc_mean / norm(acc_mean);
    g_expected = [0, 0, 1]; % 在导航坐标系中重力向下
    
    % 计算使测量重力与期望重力对齐的旋转
    v = cross(g_measured, g_expected);
    s = norm(v);
    c = dot(g_measured, g_expected);
    
    if s < 1e-6
        % 向量几乎平行,不需要旋转
        R_acc = eye(3);
    else
        vx = [0, -v(3), v(2); v(3), 0, -v(1); -v(2), v(1), 0];
        R_acc = eye(3) + vx + vx^2 * (1-c)/s^2;
    end
    
    % 应用基于加速度计的修正
    C_bn = quat2dcm(q_current);
    C_bn_corrected = R_acc * C_bn;
    q_corrected = dcm2quat(C_bn_corrected);
    
    % 可选: 使用磁力计进一步修正偏航
    if nargin >= 3 && ~isempty(mag_mean)
        % 实现磁力计修正逻辑
        % ...
    end
end

function [v_corrected, P_corrected] = zupt_correction(v, P, Q, R)
% ZUPT_CORRECTION ZUPT误差修正
% 简化的卡尔曼滤波修正
    % 预测步骤
    F = eye(6); % 简单的位置-速度模型
    P_pred = F * P * F' + Q;
    
    % 观测模型: 我们观测到速度应为零
    H = [zeros(3), eye(3)]; % 只观测速度
    
    % 卡尔曼增益
    K = P_pred * H' / (H * P_pred * H' + R);
    
    % 更新状态(速度误差)
    dz = -v'; % 观测残差(观测到速度为零)
    dx = K * dz;
    
    % 修正速度
    v_corrected = v + dx(4:6)';
    
    % 更新协方差
    P_corrected = (eye(6) - K * H) * P_pred;
end

% 辅助函数: 四元数转换为旋转矩阵
function R = quat2dcm(q)
    q0 = q(1); q1 = q(2); q2 = q(3); q3 = q(4);
    R = [1-2*(q2^2+q3^2),   2*(q1*q2-q0*q3),   2*(q1*q3+q0*q2);
         2*(q1*q2+q0*q3),   1-2*(q1^2+q3^2),   2*(q2*q3-q0*q1);
         2*(q1*q3-q0*q2),   2*(q2*q3+q0*q1),   1-2*(q1^2+q2^2)];
end

% 辅助函数: 旋转矩阵转换为四元数
function q = dcm2quat(R)
    q0 = 0.5 * sqrt(1 + R(1,1) + R(2,2) + R(3,3));
    q1 = (R(3,2) - R(2,3)) / (4 * q0);
    q2 = (R(1,3) - R(3,1)) / (4 * q0);
    q3 = (R(2,1) - R(1,2)) / (4 * q0);
    q = [q0, q1, q2, q3];
    q = q / norm(q);
end

说明

主函数 foot_zupt_heading_calculation

这是主要的ZUPT航向计算函数,它处理以下步骤:

  1. 初始化变量和参数
  2. 使用加速度计和磁力计计算初始方向
  3. 循环处理每个时间步的数据:
    • 使用陀螺仪积分更新姿态
    • 在导航坐标系中积分加速度得到速度和位置
    • 检测零速区间(ZUPT)
    • 应用ZUPT修正
    • 计算航向角

辅助函数

  1. detect_zupt: 通过计算加速度范数的方差来检测静止状态
  2. initial_orientation: 使用加速度计和磁力计计算初始四元数方向
  3. update_quaternion: 使用陀螺仪数据通过四元数积分更新方向
  4. reestimate_orientation: 在ZUPT期间使用加速度计和磁力计重新估计方向
  5. zupt_correction: 应用卡尔曼滤波修正速度和误差协方差

参考代码 脚部zupt算法计算航向代码 www.youwenfan.com/contentcng/52434.html

使用

% 加载或生成IMU数据
% [acc, gyro, mag] = load_imu_data('data_file.csv');

% 设置采样频率
fs = 100; % Hz

% 计算航向
[heading, position] = foot_zupt_heading_calculation(acc, gyro, mag, fs);

% 可视化结果
figure;
subplot(2,1,1);
plot(heading);
title('航向角');
xlabel('样本数');
ylabel('角度 (度)');
grid on;

subplot(2,1,2);
plot3(position(:,1), position(:,2), position(:,3));
title('估计轨迹');
xlabel('X (m)');
ylabel('Y (m)');
zlabel('Z (m)');
grid on;
axis equal;
posted @ 2025-09-12 11:35  吴逸杨  阅读(84)  评论(0)    收藏  举报