基于C++的GPS/INS(捷联惯性导航系统)组合导航程序,包含关键算法实现:
头文件定义 (GNSS_INS.h)
#ifndef GNSS_INS_H
#define GNSS_INS_H
#include <vector>
#include <array>
#include <Eigen/Dense>
class GNSSINS {
public:
struct IMUData {
double timestamp;
Eigen::Vector3d gyro; // 角速度 (rad/s)
Eigen::Vector3d accel; // 加速度 (m/s²)
};
struct GNSSData {
double timestamp;
Eigen::Vector3d lla; // 经纬高 (rad, rad, m)
Eigen::Vector3d velocity; // NED速度 (m/s)
double pos_std; // 位置标准差
double vel_std; // 速度标准差
};
struct NavigationState {
Eigen::Vector3d position; // 位置 (LLA)
Eigen::Vector3d velocity; // 速度 (NED)
Eigen::Matrix3d attitude; // 姿态矩阵 (C_b^n)
Eigen::Vector3d bias_gyro; // 陀螺零偏
Eigen::Vector3d bias_accel;// 加速度计零偏
};
GNSSINS();
// 初始化导航系统
bool Initialize(const GNSSData& init_gnss);
// IMU数据更新
void UpdateIMU(const IMUData& imu);
// GNSS数据更新
void UpdateGNSS(const GNSSData& gnss);
// 获取当前导航状态
NavigationState GetState() const;
private:
// 状态向量: [位置(3), 速度(3), 姿态误差(3), 陀螺零偏(3), 加速度零偏(3)]
static const int STATE_DIM = 15;
using StateVector = Eigen::Matrix<double, STATE_DIM, 1>;
using StateCovariance = Eigen::Matrix<double, STATE_DIM, STATE_DIM>;
NavigationState state_;
StateVector x_;
StateCovariance P_;
IMUData last_imu_;
bool initialized_;
double last_update_time_;
// 地球参数
const double earth_a = 6378137.0; // 地球长半轴
const double earth_f = 1.0/298.257223563; // 扁率
const double earth_omega = 7.292115e-5; // 地球自转角速度
// 噪声参数
Eigen::Matrix3d Q_gyro_;
Eigen::Matrix3d Q_accel_;
Eigen::Matrix3d R_gnss_pos_;
Eigen::Matrix3d R_gnss_vel_;
// 核心算法函数
void Predict(const IMUData& imu);
void Correct(const GNSSData& gnss);
Eigen::Matrix3d SkewSymmetric(const Eigen::Vector3d& v);
void UpdateAttitude(const Eigen::Vector3d& gyro, double dt);
Eigen::Vector3d LLAToECEF(const Eigen::Vector3d& lla);
Eigen::Vector3d ECEFToLLA(const Eigen::Vector3d& ecef);
};
#endif
主要实现文件 (GNSS_INS.cpp)
#include "GNSS_INS.h"
#include <iostream>
#include <cmath>
GNSSINS::GNSSINS() : initialized_(false), last_update_time_(0.0) {
// 初始化噪声协方差
Q_gyro_ = Eigen::Matrix3d::Identity() * 1e-6;
Q_accel_ = Eigen::Matrix3d::Identity() * 1e-4;
R_gnss_pos_ = Eigen::Matrix3d::Identity() * 1.0;
R_gnss_vel_ = Eigen::Matrix3d::Identity() * 0.1;
// 初始化状态协方差
P_ = StateCovariance::Identity() * 0.1;
}
bool GNSSINS::Initialize(const GNSSData& init_gnss) {
state_.position = init_gnss.lla;
state_.velocity = init_gnss.velocity;
state_.attitude = Eigen::Matrix3d::Identity(); // 初始假设水平
state_.bias_gyro = Eigen::Vector3d::Zero();
state_.bias_accel = Eigen::Vector3d::Zero();
x_.setZero();
initialized_ = true;
last_update_time_ = init_gnss.timestamp;
std::cout << "GNSS/INS系统初始化完成" << std::endl;
return true;
}
void GNSSINS::UpdateIMU(const IMUData& imu) {
if (!initialized_) return;
if (last_update_time_ > 0) {
double dt = imu.timestamp - last_update_time_;
if (dt > 0) {
Predict(imu);
}
}
last_imu_ = imu;
last_update_time_ = imu.timestamp;
}
void GNSSINS::UpdateGNSS(const GNSSData& gnss) {
if (!initialized_) {
Initialize(gnss);
return;
}
Correct(gnss);
}
void GNSSINS::Predict(const IMUData& imu) {
double dt = imu.timestamp - last_update_time_;
// 补偿零偏后的角速度和加速度
Eigen::Vector3d gyro = imu.gyro - state_.bias_gyro;
Eigen::Vector3d accel = imu.accel - state_.bias_accel;
// 更新姿态
UpdateAttitude(gyro, dt);
// 转换加速度到导航系并去除重力
Eigen::Vector3d acc_n = state_.attitude * accel;
acc_n(2) += 9.7803267714; // 添加重力
// 更新速度
state_.velocity += acc_n * dt;
// 更新位置 (简化处理)
Eigen::Vector3d pos_lla = state_.position;
double Rn = earth_a / sqrt(1 - earth_f * (2 - earth_f) * pow(sin(pos_lla(0)), 2));
double Rm = Rn * (1 - earth_f * (2 - earth_f)) / (1 - earth_f * (2 - earth_f) * pow(sin(pos_lla(0)), 2));
state_.position(0) += state_.velocity(0) * dt / (Rm + pos_lla(2)); // 纬度
state_.position(1) += state_.velocity(1) * dt / ((Rn + pos_lla(2)) * cos(pos_lla(0))); // 经度
state_.position(2) += -state_.velocity(2) * dt; // 高度
// 预测误差协方差 (简化扩展卡尔曼滤波)
// 这里需要计算状态转移矩阵F和过程噪声矩阵Q
// 实际实现中需要完整的误差状态方程
}
void GNSSINS::Correct(const GNSSData& gnss) {
// 量测向量
Eigen::Matrix<double, 6, 1> z;
z << gnss.lla - state_.position, gnss.velocity - state_.velocity;
// 量测矩阵
Eigen::Matrix<double, 6, STATE_DIM> H;
H.setZero();
H.block<3, 3>(0, 0) = Eigen::Matrix3d::Identity(); // 位置
H.block<3, 3>(3, 3) = Eigen::Matrix3d::Identity(); // 速度
// 量测噪声协方差
Eigen::Matrix<double, 6, 6> R;
R.setZero();
R.block<3, 3>(0, 0) = R_gnss_pos_;
R.block<3, 3>(3, 3) = R_gnss_vel_;
// 卡尔曼增益
Eigen::Matrix<double, STATE_DIM, 6> K = P_ * H.transpose() *
(H * P_ * H.transpose() + R).inverse();
// 状态修正
x_ = x_ + K * (z - H * x_);
// 协方差更新
P_ = (StateCovariance::Identity() - K * H) * P_;
// 反馈到导航状态
state_.position += x_.segment<3>(0);
state_.velocity += x_.segment<3>(3);
// 姿态修正
Eigen::Vector3d phi = x_.segment<3>(6);
Eigen::Matrix3d I_phi = Eigen::Matrix3d::Identity() - SkewSymmetric(phi);
state_.attitude = state_.attitude * I_phi;
// 零偏修正
state_.bias_gyro += x_.segment<3>(9);
state_.bias_accel += x_.segment<3>(12);
// 重置误差状态
x_.setZero();
}
void GNSSINS::UpdateAttitude(const Eigen::Vector3d& gyro, double dt) {
// 使用四阶龙格库塔法更新姿态
Eigen::Vector3d omega = gyro;
// 计算姿态矩阵的导数
Eigen::Matrix3d omega_skew = SkewSymmetric(omega);
Eigen::Matrix3d dC = state_.attitude * omega_skew;
// 更新姿态矩阵
state_.attitude = state_.attitude + dC * dt;
// 正交化姿态矩阵
Eigen::JacobiSVD<Eigen::Matrix3d> svd(state_.attitude,
Eigen::ComputeFullU | Eigen::ComputeFullV);
state_.attitude = svd.matrixU() * svd.matrixV().transpose();
}
Eigen::Matrix3d GNSSINS::SkewSymmetric(const Eigen::Vector3d& v) {
Eigen::Matrix3d M;
M << 0, -v(2), v(1),
v(2), 0, -v(0),
-v(1), v(0), 0;
return M;
}
GNSSINS::NavigationState GNSSINS::GetState() const {
return state_;
}
Eigen::Vector3d GNSSINS::LLAToECEF(const Eigen::Vector3d& lla) {
double lat = lla(0), lon = lla(1), alt = lla(2);
double e2 = earth_f * (2 - earth_f);
double N = earth_a / sqrt(1 - e2 * sin(lat) * sin(lat));
Eigen::Vector3d ecef;
ecef(0) = (N + alt) * cos(lat) * cos(lon);
ecef(1) = (N + alt) * cos(lat) * sin(lon);
ecef(2) = (N * (1 - e2) + alt) * sin(lat);
return ecef;
}
Eigen::Vector3d GNSSINS::ECEFToLLA(const Eigen::Vector3d& ecef) {
// 简化实现,实际需要迭代计算
double x = ecef(0), y = ecef(1), z = ecef(2);
double p = sqrt(x*x + y*y);
double e2 = earth_f * (2 - earth_f);
double lat = atan2(z, p * (1 - e2));
double lon = atan2(y, x);
double N = earth_a / sqrt(1 - e2 * sin(lat) * sin(lat));
double alt = p / cos(lat) - N;
return Eigen::Vector3d(lat, lon, alt);
}
使用示例 (main.cpp)
#include "GNSS_INS.h"
#include <random>
#include <fstream>
int main() {
GNSSINS navigator;
// 模拟数据生成
std::default_random_engine generator;
std::normal_distribution<double> noise(0.0, 0.1);
// 初始化GNSS数据
GNSSINS::GNSSData init_gnss;
init_gnss.timestamp = 0.0;
init_gnss.lla = Eigen::Vector3d(0.7, 1.3, 100.0); // 经纬高 (rad)
init_gnss.velocity = Eigen::Vector3d(10.0, 0.0, 0.0); // NED速度
// 初始化导航系统
navigator.Initialize(init_gnss);
// 模拟数据循环
double dt = 0.01; // 100Hz IMU, 1Hz GNSS
for (double t = dt; t < 10.0; t += dt) {
// 生成IMU数据
GNSSINS::IMUData imu;
imu.timestamp = t;
imu.gyro = Eigen::Vector3d(0.01, 0.02, 0.03) +
Eigen::Vector3d(noise(generator), noise(generator), noise(generator)) * 0.001;
imu.accel = Eigen::Vector3d(0.1, 0.0, 9.8) +
Eigen::Vector3d(noise(generator), noise(generator), noise(generator)) * 0.01;
navigator.UpdateIMU(imu);
// 每秒更新一次GNSS
if (fmod(t, 1.0) < dt) {
GNSSINS::GNSSData gnss;
gnss.timestamp = t;
gnss.lla = init_gnss.lla + Eigen::Vector3d(t * 0.0001, t * 0.0002, -t * 0.1) +
Eigen::Vector3d(noise(generator), noise(generator), noise(generator)) * 0.1;
gnss.velocity = Eigen::Vector3d(10.0 + sin(t)*0.1, cos(t)*0.1, 0.0) +
Eigen::Vector3d(noise(generator), noise(generator), noise(generator)) * 0.01;
navigator.UpdateGNSS(gnss);
auto state = navigator.GetState();
std::cout << "Time: " << t
<< " Lat: " << state.position(0)
<< " Lon: " << state.position(1)
<< " Alt: " << state.position(2) << std::endl;
}
}
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(GNSS_INS)
set(CMAKE_CXX_STANDARD 14)
find_package(Eigen3 REQUIRED)
add_executable(gnss_ins
main.cpp
GNSS_INS.cpp
)
target_link_libraries(gnss_ins Eigen3::Eigen)
参考代码 C++编写的关于GPS捷联惯性组合导航的程序 www.3dddown.com/ala/69797.html
关键特性
- 松组合架构:GNSS和INS独立解算,通过卡尔曼滤波融合
- 误差状态卡尔曼滤波:使用15状态误差模型
- 实时处理:支持高频IMU和低频GNSS数据融合
- 模块化设计:易于扩展和修改
扩展建议
- 添加紧组合模式,直接处理GNSS原始观测值
- 实现更精确的地球模型和机械编排算法
- 添加自适应卡尔曼滤波
- 集成RTK-GNSS支持
- 添加传感器标定和温度补偿