PDR/1.Software/PDR 1.04/src/Kalman.c

694 lines
20 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/******************** (C) COPYRIGHT 2020 Geek************************************
* File Name : pdr_kalman.c
* Current Version : V2.0(compare QCOM SAP 5.0)
* Author : logzhan
* Date of Issued : 2020.7.3
* Comments : PDR 卡尔曼滤波器相关
********************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>
#if !defined(LOCATION_PLATFORM_QCOM_MODEM)
#include <malloc.h>
#endif
#include "pdr_base.h"
#include "Kalman.h"
#include "Location.h"
#include "Matrix.h"
#include "Utils.h"
#include "pdr_linearFit.h"
#include "CoordTrans.h"
// 扩展卡尔曼向量缓存
static double EkfVecBuf[5][N] = { {0.0} };
// 扩展卡尔曼矩阵缓存
static double EkfMatBuf[7][N][N] = { { {0.0} } };
extern double GpsPos[HIST_GPS_NUM][3];
extern int debugCount;
extern double angle_mean[3];
static int hold_type;
static double b_timestamp;
static double b_last_time;
static double attitude_yaw;
static DETECTOR_t *g_detector;
static int hold_type;
static double BUL_duration;
static double FUR_duration;
/**----------------------------------------------------------------------
* Function : KalmanFilter_Init
* Description : 初始化卡尔曼滤波器相关
* Date : 2022/09/16 logzhan
*---------------------------------------------------------------------**/
void EKF_Init(void)
{
b_timestamp = -1;
b_last_time = -1;
BUL_duration = -1;
FUR_duration = -1;
attitude_yaw = -1;
hold_type = 0;
}
/**----------------------------------------------------------------------
* Function : pdr_ekfStatePredict
* Description : pdr卡尔曼滤波器的状态预测方程
* Date : 2020/7/22 logzhan
*---------------------------------------------------------------------**/
void EKFStatePredict(EKFPara_t *kf, double stepLen, PDR_t* g_pdr, int step) {
double (*Phi)[N] = (double(*)[N])&(EkfMatBuf[0][0][0]);
double (*pvec1)[N] = (double(*)[N])&(EkfMatBuf[1][0][0]);
double (*pvec2)[N] = (double(*)[N])&(EkfMatBuf[2][0][0]);
memset(EkfMatBuf, 0, sizeof(double) * 7 * N * N);
double deltaHeading = g_pdr->heading - g_pdr->lastHeading;
double angle = g_pdr->heading;
//printf("deltaHeading = %f\n", R2D(deltaHeading));
//if (fabs(deltaHeading) < D2R(10) && g_pdr->lastHeading != 0.0f) {
// angle = deltaHeading + kf->p_xk[3];
//}else {
// angle = g_pdr->heading;
//}
if (g_pdr->motionType != PDR_MOTION_TYPE_HANDHELD) {
deltaHeading = 0;
}
angle = deltaHeading + kf->p_xk[3];
if (fabs(deltaHeading) > 5.5) {
//printf("%f %f\n", R2D(g_pdr->heading), R2D(g_pdr->lastHeading));
//printf("d heading = %f\n", R2D(deltaHeading));
if (deltaHeading < 0) {
deltaHeading = deltaHeading + D2R(360);
}else {
deltaHeading = deltaHeading - D2R(360);
}
deltaHeading = 0;
angle = deltaHeading + kf->p_xk[3];
}
if(step == 0){
kf->p_xk[3] = angle;
}
// xk+1 = xk + step * cos(angle) PDR位置更新方程
// yk+1 = yk + step * sin(angle) PDR位置更新方程
// sk+1 = sk 步长和上一次相同
// ak+1 = ak * (angle / ak) 或 ak+1 = ak
Phi[0][0] = 1; Phi[1][0] = 0; Phi[2][0] = 0; Phi[3][0] = 0;
Phi[0][1] = 0; Phi[1][1] = 1; Phi[2][1] = 0; Phi[3][1] = 0;
Phi[0][2] = cos(angle); Phi[1][2] = sin(angle); Phi[2][2] = 1; Phi[3][2] = 0;
Phi[0][3] = 0; Phi[1][3] = 0; Phi[2][3] = 0; Phi[3][3] = 1;
for (uchar i = 0; i < step; i++) {
// logzhan 21/02/06:
// phi[3][3]是为让kf的预测每次都是最新更新值, 如果phi[3][3]每次都是1可能在惯性
// 导航更新过程中偏航角的预测是固定的实时性没有那么好下面if判断可以在一定程度
// 让预测的值更新,但是效果暂时没有感觉出明显的好
if (fabs(kf->p_xk[3]) > 0.000001 &&
fabs(angle / kf->p_xk[3]) < 3)
{
Phi[3][3] = angle / kf->p_xk[3];
}
// 卡尔曼状态更新方程
// p_xk = phi * p_xk
VecMatMultiply(kf->p_xk, Phi, kf->p_xk);
// 卡尔曼更新协方差矩阵 : Pk = FPFt + Q
MatrixMultiply(Phi, kf->p_pk, pvec1); // F*P
MatrixTrans(Phi, pvec2); // Ft
MatrixMultiply(pvec1, pvec2, pvec1); // F*P*Ft
MatrixAdd(pvec1, kf->q, kf->p_pk); // F*P*Ft + Q
}
}
/**----------------------------------------------------------------------
* Function : EKFStateUpdate
* Description : 扩展卡尔曼滤波器的状态更新方程
* Date : 2020/7/22 logzhan
*---------------------------------------------------------------------**/
void EKFStateUpdate(EKFPara_t *kf, GNSS_t *pgnss, classifer *sys, PDR_t *g_pdr,
int scene_type) {
double lambda = 0;
// NxN矩阵定义
double(*H)[N] = (double(*)[N])&(EkfMatBuf[0][0][0]);
double(*I)[N] = (double(*)[N])&(EkfMatBuf[1][0][0]);
double(*pvec1)[N] = (double(*)[N])&(EkfMatBuf[2][0][0]);
double(*Ht)[N] = (double(*)[N])&(EkfMatBuf[3][0][0]);
double(*pvec3)[N] = (double(*)[N])&(EkfMatBuf[4][0][0]);
double(*pvec4)[N] = (double(*)[N])&(EkfMatBuf[5][0][0]);
double(*pv3)[N] = (double(*)[N])&(EkfMatBuf[6][0][0]);
memset(EkfMatBuf, 0, sizeof(double) * 7 * N * N);
memset(EkfVecBuf, 0, sizeof(double) * 5 * N);
// Nx1向量定义
double* z = &(EkfVecBuf[0][0]);
double(*pvec5) = &(EkfVecBuf[1][0]);
double(*pvec6) = &(EkfVecBuf[2][0]);
double(*pv1) = &(EkfVecBuf[3][0]);
double(*pv2) = &(EkfVecBuf[4][0]);
// 创建单位矩阵
for (char i = 0; i < 4; i++) {
H[i][i] = 1;
I[i][i] = 1;
}
// 获取观测向量
z[0] = pgnss->xNed; // 北向位置
z[1] = pgnss->yNed; // 东向位置
z[2] = 0.5; // 步长默认0.5
// 这个if条件实际是使用GPS的位置变化量和步数变化量估计步长, 这部分代码还没
// 调好,实际类似于步长不变
//if (pgnss->error > 0 && pgnss->error < 3.8 && pgnss->HDOP <= 0.4 &&
// g_pdr->deltaStepsPerGps != 0 && g_pdr->deltaStepsPerGps < 5) {
// // 利用GPS速度和步频估计步长
// //if (g_pdr->motionFreq > 2.5 && (sys->type == 1)) {
// //
// // //printf("z[2] = %f\n", z[2]);
// //}
// z[2] = pgnss->vel * 0.514 / (g_pdr->deltaStepsPerGps);
//}else {
// z[2] = kf->p_xk[2];
//}
z[3] = pgnss->yaw * PI / 180; // 观测的航向角为GPS的航向角
// 计算 K = K = PHt / (R + H*P*H^T)
MatrixTrans(H, Ht); // 计算Ht
MatrixMultiply(H, kf->p_pk, pvec1); // 计算HP
MatrixMultiply(pvec1, Ht, pvec3); // pvec3 = H*P*H^T
MatrixAdd(pvec3, kf->r, pvec4); // pvec4 = R + H*P*H^T
MatrixInverse(pvec4, pvec1); // 计算 1 / (R + H*P*H^T)
for (char i = 0; i < N; i++) {
for (uchar j = 0; j < N; j++) {
pv3[i][j] = pvec3[i][j];
}
}
MatrixMultiply(kf->p_pk, Ht, pvec3); // 计算PHt
MatrixMultiply(pvec3, pvec1, kf->Kk); // 计算增益K = PHt / (R + H*P*H^T)
VecMatMultiply(kf->p_xk, H, pvec5); // pvec5 = Hx'
VectorSub(z, pvec5, pvec6); // pvec6 = Z - Hx'
modAngle(&pvec6[3], -PI, PI);
for (char i = 0; i < N; i++) {
pv1[i] = pvec6[i];
}
VecMatMultiply(pvec6, kf->Kk, pvec5); // pvec5 = K*( z - Hx')
// Get the optimally updated state estimation
VectorAdd(kf->p_xk, pvec5, kf->xk);
// ---- prepare the matrix for updated estimate covariance ------
// pvec1 = K*H
MatrixMultiply(kf->Kk, H, pvec1);
// pvec2 = (I - K*H)
MatrixSub(I, pvec1, Ht);
// pvec3 = (I - K*H)*P
MatrixMultiply(Ht, kf->p_pk, pvec3);
// pvec4 = (I- K*H)^T
MatrixTrans(Ht, pvec4);
// pvec1 = (I - K*H)*P*(I- K*H)^T
MatrixMultiply(pvec3, pvec4, pvec1);
// pvec2 = K*R
MatrixMultiply(kf->Kk, kf->r, Ht);
// pvec3 = K^T
MatrixTrans(kf->Kk, pvec3);
// pvec4 = K*R*K^T
MatrixMultiply(Ht, pvec3, pvec4);
// Get the updated estimate covariance: P' = (I - K*H)*P*(I- K*H)^T + K*R*K^T
MatrixAdd(pvec1, pvec4, kf->pk);
// pv2 = (z - Hx')*( H*P*H^T )
VecMatMultiply(pv1, pv3, pv2);
// inner product the pre-fit residual and the transitioned residual: lamda = (z - Hx')*( H*P*H^T ) .* (z-Hx')
// Calculate the difference between original differenc and the transitioned,
// if the value is close to zero, it shows that there is a big gap in the
// oprimization. Thus, we believe our PDR algorithm
for (char i = 0; i < N; i++) {
lambda += pv2[i] * pv1[i];
}
kf->lambda = lambda;
kf->plat = pgnss->lat;
kf->plon = pgnss->lon;
if (lambda >= 200)return;
for (char i = 0; i < N; i++) {
kf->xk[i] = kf->p_xk[i];
for (int j = 0; j < N; j++) {
kf->pk[i][j] = kf->p_pk[i][j];
}
}
}
void calStepLastTime(StepPredict *stepPredict, double timestamp, unsigned long steps_last,
unsigned long steps)
{
float tmpTime = 0;
if (stepPredict->lastTime > 0 && stepPredict->deltaStep == 0 && (steps - steps_last) > 0)
{
tmpTime = (float)((timestamp - stepPredict->lastTime) / (steps - steps_last));
if (tmpTime > 300 && tmpTime < 800)
{
if (stepPredict->meanTime > 0){
stepPredict->meanTime = stepPredict->meanTime * 0.5f + tmpTime * 0.5f;
}else{
stepPredict->meanTime = tmpTime;
}
}
}
stepPredict->fnum = 0;
stepPredict->fsum = 0;
stepPredict->lastTime = timestamp;
stepPredict->deltaStep = 0;
}
int predictStep(StepPredict *stepPredict, double timestamp, unsigned long steps_last, float gnssVel)
{
int step = 0;
float mean_time = 400;
double dis = 0;
if (stepPredict->meanTime > 0)
mean_time = stepPredict->meanTime;
if ((steps_last > 0) && (stepPredict->fnum > 0) && (timestamp - stepPredict->lastTime > mean_time * 3) && (stepPredict->lastTime > 0))
{
stepPredict->fsum = stepPredict->fsum / stepPredict->fnum;
dis = sqrt(pow(GpsPos[HIST_GPS_NUM - 1][0]- GpsPos[HIST_GPS_NUM - 2][0], 2) + pow(GpsPos[HIST_GPS_NUM - 1][1] - GpsPos[HIST_GPS_NUM - 2][1], 2)
+ pow(GpsPos[HIST_GPS_NUM - 1][2] - GpsPos[HIST_GPS_NUM - 2][2], 2));
if (stepPredict->fsum != 0.0 && (gnssVel > 1.0 || (dis > 1.0 && dis < 3.0)))
{
step = (int)((timestamp - stepPredict->lastTime) / mean_time);
stepPredict->deltaStep += step;
}
stepPredict->lastTime = timestamp;
stepPredict->fnum = 0;
stepPredict->fsum = 0;
}
return step;
}
/**----------------------------------------------------------------------
* Function : StateRecognition
* Description : 根据加速度及判断当前状态是否平稳 1: 不平稳 0: 平稳
* Date : 2022/09/19 logzhan
*---------------------------------------------------------------------**/
void StateRecognition(float *acc, classifer *sys) {
}
double CalGnssTrackHeading(double gpsPos[][3], GNSS_t pgnss)
{
int i;
double lla[3] = { 0.0 };
double ned1[3] = { 0.0 };
double temp[2][HIST_GPS_NUM] = { { 0.0 } };
double angle[HIST_GPS_NUM - 1] = { 0.0 };
double ned2[3] = { 0.0 };
double maxn = 0;
double maxe = 0;
double minn = 0;
double mine = 0;
double meanx = 0;
double meany = 0;
float error = 0;
float sst = 0;
float r2 = 0;
double range = 0;
double yaw = 0;
double tempYaw = 0;
double diffAngle = 0;
double para[3] = { 0 };
int flg = 0;
lla[0] = pgnss.lat;
lla[1] = pgnss.lon;
for (i = 0; i < HIST_GPS_NUM - 1; i++)
{
gpsPos[i][0] = gpsPos[i + 1][0];
gpsPos[i][1] = gpsPos[i + 1][1];
gpsPos[i][2] = gpsPos[i + 1][2];
}
if ((lla[0] > 0) && (lla[1] > 0))
{
//经纬度WGS84转地心地固坐标系ECEF
WGS842ECEF(lla, gpsPos[HIST_GPS_NUM - 1]);
}
else
{
gpsPos[HIST_GPS_NUM - 1][0] = 0;
gpsPos[HIST_GPS_NUM - 1][1] = 0;
gpsPos[HIST_GPS_NUM - 1][2] = 0;
return -1;
}
if (pgnss.error > 40)
{
return -1;
}
for (i = 0; i < HIST_GPS_NUM - 1; i++)
{
if ((fabs(gpsPos[i][0]) < 1e-6) && (fabs(gpsPos[i][1]) < 1e-6) && (fabs(gpsPos[i][2]) < 1e-6))
{
return -1;
}
}
//地心地固坐标系ECEF转东北天坐标系NED
ECEF2NED(gpsPos[HIST_GPS_NUM - 1], lla, ned1);
for (i = HIST_GPS_NUM - 2; i >= 0; i--) {
ECEF2NED(gpsPos[i], lla, ned2);
temp[0][i] = ned1[0] - ned2[0];
temp[1][i] = ned1[1] - ned2[1];
meanx += temp[0][i] / HIST_GPS_NUM;
meany += temp[1][i] / HIST_GPS_NUM;
if (maxn > temp[0][i])
{
maxn = temp[0][i];
}
if (minn < temp[0][i])
{
minn = temp[0][i];
}
if (maxe > temp[1][i])
{
maxe = temp[1][i];
}
if (mine < temp[1][i])
{
mine = temp[1][i];
}
angle[i] = atan2(temp[1][i], temp[0][i]);
if (angle[i] < 0)
angle[i] += TWO_PI;
}
flg = leastDistanceLinearFit(temp[0], temp[1], HIST_GPS_NUM, para);
if (flg < 0)
return -1;
for (i = HIST_GPS_NUM - 1; i >= 0; i--) {
error += (float)(vivopow(para[0] * temp[0][i] + para[1] * temp[1][i] + para[2], 2) / (vivopow(para[0], 2) + vivopow(para[1], 2)));
sst += (float)(vivopow(meanx - temp[0][i], 2) + vivopow(meany - temp[1][i], 2));
}
if (sst > 0)
{
r2 = 1 - error / sst;
}
range = sqrt(vivopow(maxn - minn, 2) + vivopow(maxe - mine, 2));
//printf("%f,%f,%f\n", r2, error, range);
if (r2 < 0.95 || range < 1.5 || error > 3.0)
return -1;
yaw = atan(-para[0] / para[1]);
modAngle(&yaw, 0, TWO_PI);
tempYaw = meanAngle(angle, HIST_GPS_NUM - 1);
modAngle(&tempYaw, 0, TWO_PI);
diffAngle = tempYaw - yaw;
modAngle(&diffAngle, -PI, PI);
if (fabs(diffAngle) > PI / 2)
yaw += PI;
modAngle(&yaw, 0, TWO_PI);
return yaw;
}
/**----------------------------------------------------------------------
* Function : InsLocationPredict
* Description : PDR惯导位置更新,
* Date : 2020/07/08 logzhan
* 2021/02/06 logzhan : 感觉计步器输出不够平均,有时候
* 会造成PDR前后位置不够均匀
*---------------------------------------------------------------------**/
void InsLocationPredict(PDR_t *g_pdr, StepPredict *stepPredict, IMU_t *ss_data,
GNSS_t *pgnss, EKFPara_t *kf) {
int step;
long deltaStep;
double stepLength = 0.7;
stepPredict->fnum++;
stepPredict->fsum += g_pdr->motionFreq;
ulong steps = g_pdr->steps;
ulong lastSteps = g_pdr->lastSteps;
if (steps - lastSteps > 0 && g_pdr->motionFreq != 0.0) {
deltaStep = steps - lastSteps - stepPredict->deltaStep;
// 应该是防止计步器异常情况,一次计步特别多
if (deltaStep > 5)deltaStep = 5;
if (stepPredict->meanTime > 0)
{
step = (int)((ss_data->gyr.time - stepPredict->lastTime) / stepPredict->meanTime + 0.5);
if (step > deltaStep && step <= 3)deltaStep = step;
}
if (lastSteps == 0)deltaStep = 0;
if (g_pdr->heading > 0) {
EKFStatePredict(kf, stepLength, g_pdr, deltaStep);
g_pdr->fusionPdrFlg = PDR_TRUE;
}
calStepLastTime(stepPredict, ss_data->gyr.time, lastSteps, steps);
}else{
// 有时候计步器可能考虑到稳定性暂时不更新步数因此需要利用GNSS速度预测步数达到
// 惯导更新位置的目的
int preStep = predictStep(stepPredict, ss_data->gyr.time, lastSteps, pgnss->vel);
if (g_pdr->heading > 0){
EKFStatePredict(kf, stepLength, g_pdr, preStep);
if(preStep > 0)g_pdr->fusionPdrFlg = PDR_TRUE;
}
}
}
/**----------------------------------------------------------------------
* Function : ResetOutputResult
* Description : 1、初始化解算初始位置、卡尔曼滤波初始参数
* 2、GPS值赋值给result
* Date : 2022/09/19 logzhan
*---------------------------------------------------------------------**/
int ResetOutputResult(GNSS_t *pgnss, PDR_t* g_pdr, EKFPara_t *kf, lct_fs *result) {
double stepLength = 0.7;
double ned[3] = { 0 };
g_pdr->pllaInit[0] = pgnss->lat;
g_pdr->pllaInit[1] = pgnss->lon;
g_pdr->pllaInit[2] = 0;
WGS842NED(g_pdr->pllaInit, g_pdr->pllaInit, ned);
g_pdr->x0 = ned[0];
g_pdr->y0 = ned[1];
kf->p_xk[0] = ned[0];
kf->p_xk[1] = ned[1];
kf->p_xk[2] = stepLength;
// 重置输出GPS时GPS的航向角不一定准
kf->p_xk[3] = pgnss->yaw*RADIAN_PER_DEG;
for (uchar i = 0; i < N; i++) {
kf->xk[i] = kf->p_xk[i];
}
// 清除卡尔曼Q矩阵和R矩阵
for (int i = 0; i < N; i++) {
for (int l = 0; l < N; l++) {
kf->q[i][l] = 0.0;
kf->r[i][l] = 0.0;
}
}
// 输出GPS位置结果
OutputOriginGnssPos(pgnss, result);
g_pdr->NoGnssCount = 0;
return PDR_TRUE;
}
int InitProc(GNSS_t *pgnss, EKFPara_t *kf, PDR_t* g_pdr,lct_fs *result)
{
double stepLen = 0.7; // 初始运动步长为0.7m
if (pgnss->satellites_num > 4 && pgnss->HDOP < 2.0 && pgnss->vel >= 1.5 && pgnss->yaw != -1) {
// plla 类似位置坐标的原点(单位是经纬度)
g_pdr->pllaInit[0] = pgnss->lat;
g_pdr->pllaInit[1] = pgnss->lon;
g_pdr->pllaInit[2] = 0;
// plla 转 ned
double ned[3] = { 0 };
WGS842NED(g_pdr->pllaInit, g_pdr->pllaInit, ned);
// 在NED坐标系的计算, 单位是米
g_pdr->x0 = ned[0];
g_pdr->y0 = ned[1];
// 初始化卡尔曼滤波器的观测量
kf->p_xk[0] = ned[0]; // 状态量1: 北向x
kf->p_xk[1] = ned[1]; // 状态量2东向y
kf->p_xk[2] = stepLen; // 状态量3步长
kf->p_xk[3] = pgnss->yaw * RADIAN_PER_DEG; // 状态量4航向角
for (uchar i = 0; i < N; i++) {
kf->xk[i] = kf->p_xk[i];
}
kf->initHeading = kf->p_xk[3];
for (int i = 0; i < N; i++) {
for (int l = 0; l < N; l++) {
kf->q[i][l] = 0.0;
kf->r[i][l] = 0.0;
}
}
OutputOriginGnssPos(pgnss, result);
g_pdr->sysStatus = IS_NORMAL;
return PDR_TRUE;
}
if (pgnss->satellites_num > 4 && pgnss->HDOP < 2.0 && pgnss->vel > 0 && pgnss->yaw != -1) {
OutputOriginGnssPos(pgnss, result);
return PDR_TRUE;
}
return PDR_FALSE;
}
/**----------------------------------------------------------------------
* Function : EKFCalQRMatrix
* Description : 根据GPS信号特征调整卡尔曼滤波噪声矩阵q矩阵是过程噪声矩阵
* 需要跟惯导预测位置精度相关。r矩阵为GNSS观测噪声跟GPS输出的
* 信息精度有关。
* Date : 2022/09/19 logzhan
*---------------------------------------------------------------------**/
void EKFCalQRMatrix(lct_nmea *nmea, PDR_t *g_pdr, classifer *sys,
EKFPara_t *kf) {
if (g_pdr->motionType != PDR_MOTION_TYPE_HANDHELD &&
g_pdr->motionType != PDR_MOTION_TYPE_STATIC) {
kf->q[0][0] = 25; // PDR预测位置噪声
kf->q[1][1] = 25; // PDR预测位置噪声
kf->q[2][2] = 1; // PDR步长噪声
kf->q[3][3] = 100; // PDR方向噪声
kf->r[0][0] = 50; // GPS观测位置噪声
kf->r[1][1] = 50; // GPS观测位置噪声
kf->r[2][2] = 0.1; // GPS步长噪声
kf->r[3][3] = 50; // GPS方向噪声
return;
}
kf->q[0][0] = 0.1; // PDR预测位置噪声
kf->q[1][1] = 0.1; // PDR预测位置噪声
kf->q[2][2] = 1; // PDR步长噪声
kf->q[3][3] = 1; // PDR方向噪声
kf->r[0][0] = 100; // GPS预测位置噪声
kf->r[1][1] = 100; // GPS预测位置噪声
kf->r[2][2] = 0.1; // GPS步长噪声
kf->r[3][3] = 1000; // GPS方向噪声
if (nmea->accuracy.err > 0 &&
nmea->accuracy.err < 3.80 &&
nmea->gga.hdop <= 0.4)
{
kf->r[0][0] = 50; // GPS观测位置噪声
kf->r[1][1] = 50; // GPS观测位置噪声
kf->r[2][2] = 0.1; // GPS步长噪声
kf->r[3][3] = 50; // GPS方向噪声
}
if (fabs(R2D((g_pdr->gpsHeading - g_pdr->lastGpsHeading))) > 50 ||
g_pdr->gpsSpeed < 0.7 || g_pdr->gpsHeading == -1) {
kf->r[3][3] = 10000;
}
}
/**----------------------------------------------------------------------
* Function : GnssInsLocFusion
* Description : PDR的GNSS和INS融合定位
* Date : 2022/09/21 logzhan
*---------------------------------------------------------------------**/
void GnssInsLocFusion(GNSS_t *pgnss, PDR_t *g_pdr, classifer *sys, double yaw_bias,
EKFPara_t *kf, lct_fs *res) {
double plla[3] = { 0 };
double ned[3] = { 0 };
double yaw_thr = 6;
int scene_type = g_pdr->sceneType;
plla[0] = pgnss->lat;
plla[1] = pgnss->lon;
plla[2] = 0;
WGS842NED(plla, g_pdr->pllaInit, ned);
pgnss->xNed = ned[0];
pgnss->yNed = ned[1];
//调整融合策略
EKFStateUpdate(kf, pgnss, sys, g_pdr, scene_type);
for (uchar i = 0; i < N; i++) {
for (uchar l = 0; l < N; l++) {
kf->p_pk[i][l] = kf->pk[i][l];
}
kf->p_xk[i] = kf->xk[i];
}
ned[0] = kf -> p_xk[0] - g_pdr->x0;
ned[1] = kf -> p_xk[1] - g_pdr->y0;
ned[2] = 0;
NED2WGS84(g_pdr->pllaInit, ned, plla);
res->latitude = plla[0];
res->latitude_ns = pgnss->lat_ns;
res->longitudinal = plla[1];
res->longitudinal_ew = pgnss->lon_ew;
res->time = pgnss->timestamps;
g_pdr->NoGnssCount = 0;
}