310 lines
11 KiB
C
310 lines
11 KiB
C
|
/******************** (C) COPYRIGHT 2020 VIVO************************************
|
|||
|
* File Name : simulator_location_pdr.c
|
|||
|
* Department : Sensor Algorithm Team
|
|||
|
* Current Version : V1.2
|
|||
|
* Author : ZhangJingrui@vivo.com
|
|||
|
* Date of Issued : 2020.7.4
|
|||
|
* Comments : PDR 输出轨迹平滑的功能函数
|
|||
|
********************************************************************************/
|
|||
|
/* Header File Including -----------------------------------------------------*/
|
|||
|
#include <stdlib.h>
|
|||
|
#include <math.h>
|
|||
|
#include <float.h>
|
|||
|
#include <stddef.h>
|
|||
|
#include <string.h>
|
|||
|
#include "pdr_trackSmooth.h"
|
|||
|
#include "pdr_linearFit.h"
|
|||
|
#include "pdr_util.h"
|
|||
|
|
|||
|
/* Global Variable Definition ------------------------------------------------*/
|
|||
|
|
|||
|
/* 轨迹平滑历史输入点存储缓冲区 */
|
|||
|
static LatLng *SmoothBuffer = NULL; //最新的点在[0]索引处
|
|||
|
static size_t SmoothBufferSize = 0;
|
|||
|
static size_t elemTrail = 0;
|
|||
|
/* 输出点缓存 */
|
|||
|
// #define OUTPUT_BUFFER_SIZE 5
|
|||
|
static LatLng *OutputBuffer = NULL;
|
|||
|
static size_t outputTrail = 0;
|
|||
|
static size_t outputBufferSize = 0;
|
|||
|
|
|||
|
/* 拐点存储 */
|
|||
|
static LatLng InflectionPoint = {0,0};
|
|||
|
/* 直线拟合缓存区 */
|
|||
|
|
|||
|
static LatLng fittingDock[FITTING_DOCK_SIZE] = {{0,0}};
|
|||
|
static size_t dockTrail = 0;
|
|||
|
/* 条件阈值 */
|
|||
|
const double thresholdDis = 5; // 拐点判断阈值
|
|||
|
const double thresholdFittingDockSparsity = 1; // 直线拟合样本输入点间的稀疏度(即间隙)
|
|||
|
const double thresholdFittingDis = 1; // 拟合直线更新阈值
|
|||
|
const double half = 0.5;
|
|||
|
|
|||
|
/* Function Declaration ------------------------------------------------------*/
|
|||
|
/**----------------------------------------------------------------------
|
|||
|
* Function : pushBuffer
|
|||
|
* Description : 将输入的位置坐标推入缓存buffer
|
|||
|
* Date : 2020/7/4 yuanlin_rjyb@vivo.com
|
|||
|
*---------------------------------------------------------------------**/
|
|||
|
static void pushBuffer(LatLng inLoc){
|
|||
|
size_t i;
|
|||
|
for (i = outputBufferSize - 1; i > 0; --i){
|
|||
|
OutputBuffer[i] = OutputBuffer[i-1];
|
|||
|
}
|
|||
|
OutputBuffer[0] = inLoc;
|
|||
|
if(outputTrail < outputBufferSize)
|
|||
|
++outputTrail;
|
|||
|
}
|
|||
|
|
|||
|
/**----------------------------------------------------------------------
|
|||
|
* Function : trackSmoothingSlideWindowSet
|
|||
|
* Description : 使用平滑模块时首先调用的函数,设定轨迹平滑窗口大小。也可以通过此函
|
|||
|
* 数重新设定滑动窗口大小。
|
|||
|
* Input : slideWindowSize: 滑动窗口的大小
|
|||
|
* Output : size : 当前滑动窗口的大小,一般大于0,当返回大小为0时说明设置滑动
|
|||
|
* 窗口为0或是内存申请失败。
|
|||
|
* Date : 2020/7/4 yuanlin_rjyb@vivo.com
|
|||
|
*---------------------------------------------------------------------**/
|
|||
|
int setTrackSmoothWindow(size_t slideWindowSize)
|
|||
|
{
|
|||
|
LatLng *ptr = NULL;
|
|||
|
size_t smoothBufferMallocRes = 0;
|
|||
|
size_t OutputBufferMallocRes = 0;
|
|||
|
|
|||
|
ptr = (LatLng *)malloc( sizeof(LatLng) * slideWindowSize);
|
|||
|
if (ptr != NULL)
|
|||
|
{
|
|||
|
smoothBufferMallocRes = slideWindowSize;
|
|||
|
if (SmoothBuffer != NULL)
|
|||
|
{
|
|||
|
free(SmoothBuffer);
|
|||
|
SmoothBuffer = NULL;
|
|||
|
SmoothBufferSize = 0;
|
|||
|
}
|
|||
|
SmoothBuffer = ptr;
|
|||
|
SmoothBufferSize = slideWindowSize;
|
|||
|
memset(SmoothBuffer, 0, sizeof(LatLng)*SmoothBufferSize);
|
|||
|
elemTrail = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
smoothBufferMallocRes = 0;
|
|||
|
}
|
|||
|
ptr = NULL;
|
|||
|
ptr = (LatLng *)malloc( sizeof(LatLng) * slideWindowSize);
|
|||
|
if( ptr != NULL)
|
|||
|
{
|
|||
|
OutputBufferMallocRes = slideWindowSize;
|
|||
|
if(OutputBuffer != NULL)
|
|||
|
{
|
|||
|
free(OutputBuffer);
|
|||
|
OutputBuffer = NULL;
|
|||
|
outputBufferSize = 0;
|
|||
|
}
|
|||
|
OutputBuffer = ptr;
|
|||
|
outputBufferSize = slideWindowSize;
|
|||
|
memset(OutputBuffer, 0, sizeof(LatLng)*outputBufferSize);
|
|||
|
outputTrail = 0;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
OutputBufferMallocRes = 0;
|
|||
|
}
|
|||
|
/* 不论是否重新调整SmoothBuffer和SmoothBufferSize,都会重置fittingDock和dockTrail*/
|
|||
|
memset(fittingDock, 0, sizeof(LatLng)*FITTING_DOCK_SIZE);
|
|||
|
dockTrail = 0;
|
|||
|
|
|||
|
return (int)((smoothBufferMallocRes && OutputBufferMallocRes)? slideWindowSize: 0);
|
|||
|
}
|
|||
|
/**----------------------------------------------------------------------
|
|||
|
* Function : trackSmoothing
|
|||
|
* Description : 轨迹平滑模块关闭后需要使用此函数释放资源
|
|||
|
* Input : lat: 输入纬度
|
|||
|
* lon: 输入经度
|
|||
|
* Output : outLat: 输出纬度存储变量指针
|
|||
|
* outLon: 输出经度存储变量指针
|
|||
|
* return: 返回处理状态
|
|||
|
* Date : 2020/7/4 yuanlin_rjyb@vivo.com
|
|||
|
*---------------------------------------------------------------------**/
|
|||
|
int pdr_trackSmooth(double lat, double lon, double *outLat, double *outLon)
|
|||
|
{
|
|||
|
size_t i;
|
|||
|
double distance;
|
|||
|
LatLng outLatLng;
|
|||
|
LatLng projPointLatLng;
|
|||
|
double fittingDockLat[FITTING_DOCK_SIZE] = { 0 };
|
|||
|
double fittingDockLon[FITTING_DOCK_SIZE] = { 0 };
|
|||
|
LatLng tmp_lla = { 0 };
|
|||
|
double a = 0; double b = 0; /* y = a*x + b */
|
|||
|
// double sumLat = 0; double sumLon = 0;
|
|||
|
int ret;
|
|||
|
LatLng fittingProjPoint;
|
|||
|
double distanceFitting;
|
|||
|
if( SmoothBuffer == NULL || SmoothBufferSize <= 1)
|
|||
|
{
|
|||
|
*outLat = lat;
|
|||
|
*outLon = lon;
|
|||
|
return 1;
|
|||
|
}
|
|||
|
/* 配置各个缓冲区、列表的相应内容和参数*/
|
|||
|
/* 将SmoothBuffer右移以插入新数据 */
|
|||
|
for (i = SmoothBufferSize -1 ; i > 0 ; --i){
|
|||
|
SmoothBuffer[i] = SmoothBuffer[i-1];
|
|||
|
}
|
|||
|
SmoothBuffer[0].lat = lat;
|
|||
|
SmoothBuffer[0].lon = lon;
|
|||
|
if (elemTrail == 0) { /* 当第一个点输入时,将其设置为第一个拐点 */
|
|||
|
InflectionPoint.lat = lat;
|
|||
|
InflectionPoint.lon = lon;
|
|||
|
}
|
|||
|
/* 及时更新elemTrail */
|
|||
|
if (elemTrail < SmoothBufferSize ) {
|
|||
|
++elemTrail;
|
|||
|
}
|
|||
|
/* 初始化用于集合的存储点数组fittingDock[FITTING_DOCK_SIZE]*/
|
|||
|
if (dockTrail < FITTING_DOCK_SIZE) {
|
|||
|
if (dockTrail > 0)
|
|||
|
{ /*当不是fittingDock的首个元素时,要注意fittingDock输入样本的稀疏度*/
|
|||
|
tmp_lla.lat = lat;
|
|||
|
tmp_lla.lon = lon;
|
|||
|
distance = calDistance(tmp_lla, fittingDock[dockTrail - 1]);
|
|||
|
if (distance >= thresholdFittingDockSparsity) {
|
|||
|
fittingDock[dockTrail].lat = lat;
|
|||
|
fittingDock[dockTrail].lon = lon;
|
|||
|
if (dockTrail < outputBufferSize)
|
|||
|
++dockTrail;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{ /*当本次输入的坐标点是fittingDock的首个元素,直接将此坐标点作为拟合直线的起点*/
|
|||
|
fittingDock[dockTrail].lat = lat;
|
|||
|
fittingDock[dockTrail].lon = lon;
|
|||
|
if (dockTrail < outputBufferSize)
|
|||
|
++dockTrail;
|
|||
|
}
|
|||
|
}
|
|||
|
/* 平滑处理逻辑开始 */
|
|||
|
if(elemTrail < 3 ) //计算拐点的前提是输入点至少有3个
|
|||
|
{
|
|||
|
*outLat = lat;
|
|||
|
*outLon = lon;
|
|||
|
outLatLng.lat = lat;
|
|||
|
outLatLng.lon = lon;
|
|||
|
pushBuffer(outLatLng);
|
|||
|
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
projPointLatLng = ProjPointOfLatLng(SmoothBuffer[1], InflectionPoint, SmoothBuffer[0]);
|
|||
|
distance = calDistance(SmoothBuffer[1], projPointLatLng);
|
|||
|
/*判断SmoothBuffer[1]到预测直线的距离distance,根据距离的大小执行不同的逻辑*/
|
|||
|
if( distance > thresholdDis)
|
|||
|
{
|
|||
|
/*输入坐标点被判断为拐点后,要更新拐点,清空拟合点集fittingDock*/
|
|||
|
/* 输出点(lat, lon) */
|
|||
|
outLatLng.lat = SmoothBuffer[1].lat;
|
|||
|
outLatLng.lon = SmoothBuffer[1].lon;
|
|||
|
pushBuffer(outLatLng);
|
|||
|
/* 将(lat, lon)作为新的拐点更新 InflectionPoint */
|
|||
|
InflectionPoint.lat = lat;
|
|||
|
InflectionPoint.lon = lon;
|
|||
|
/* 拐点更新后,重新设置fittingDock中的数值内容 */
|
|||
|
memset(fittingDock, 0, sizeof(LatLng) * FITTING_DOCK_SIZE);
|
|||
|
fittingDock[0].lat = lat;
|
|||
|
fittingDock[0].lon = lon;
|
|||
|
dockTrail = 1;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
/*当输入点被判断为非拐点后,根据拟合点集fittingDock的大小执行不同的逻辑*/
|
|||
|
if( dockTrail >= FITTING_DOCK_SIZE)
|
|||
|
{
|
|||
|
|
|||
|
for ( i = 0 ; i < FITTING_DOCK_SIZE ; ++i)
|
|||
|
{
|
|||
|
fittingDockLat[i] = fittingDock[i].lat;
|
|||
|
fittingDockLon[i] = fittingDock[i].lon;
|
|||
|
}
|
|||
|
ret = linearLeastSquaresFit(fittingDockLat, fittingDockLon, FITTING_DOCK_SIZE, &a, &b);
|
|||
|
fittingProjPoint = SmoothBuffer[1];
|
|||
|
if (ret == 0) /* ret==0表示直线拟合成功 */
|
|||
|
{
|
|||
|
fittingProjPoint.lat = (a*(SmoothBuffer[1].lon - b) + SmoothBuffer[1].lat) / (vivopow(a, 2) + 1);
|
|||
|
fittingProjPoint.lon = a*fittingProjPoint.lat + b;
|
|||
|
}
|
|||
|
distanceFitting = calDistance(SmoothBuffer[1], fittingProjPoint);
|
|||
|
if( distanceFitting > thresholdFittingDis)
|
|||
|
{
|
|||
|
// //FIXME: 射线拟合可能有逻辑漏洞,修复。
|
|||
|
// dockTrail = 2;
|
|||
|
// fittingDock[1] = fittingProjPoint;
|
|||
|
// //fittingDock[1] = SmoothBuffer[1]; //TEST
|
|||
|
// LatLng outLatLng = {lat, lon}; //有问题,漏更一个点
|
|||
|
// pushBuffer(outLatLng);
|
|||
|
//TODO: 测试新的添点策略
|
|||
|
dockTrail = 2; /* remove the elements whose the index >= 3 */
|
|||
|
fittingDock[1] = SmoothBuffer[1];
|
|||
|
outLatLng.lat = SmoothBuffer[1].lat;
|
|||
|
outLatLng.lon = SmoothBuffer[1].lon;
|
|||
|
pushBuffer(outLatLng);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
outLatLng.lat = fittingProjPoint.lat;
|
|||
|
outLatLng.lon = fittingProjPoint.lon;
|
|||
|
pushBuffer(outLatLng);
|
|||
|
}
|
|||
|
}else{
|
|||
|
/*当fittingDock未被装满,则说明当前输入点不符合fittingDock的输入条件,直接将其输入以保证实时性*/
|
|||
|
outLatLng.lat = lat;
|
|||
|
outLatLng.lon = lon;
|
|||
|
pushBuffer(outLatLng);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/* 2019-05-22 平滑改动:由均值滤波变成加权求和*/
|
|||
|
double factor = 0;
|
|||
|
if (outputTrail > 1)
|
|||
|
{
|
|||
|
factor = half / (outputTrail - 1);
|
|||
|
}
|
|||
|
double sumLat = 0; double sumLon = 0;
|
|||
|
for (i = 0; i < outputTrail; ++i)
|
|||
|
{
|
|||
|
sumLat += OutputBuffer[i].lat * factor;
|
|||
|
sumLon += OutputBuffer[i].lon * factor;
|
|||
|
}
|
|||
|
*outLat = sumLat + OutputBuffer[0].lat * (half - factor);
|
|||
|
*outLon = sumLon + OutputBuffer[0].lon * (half - factor);
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
/**----------------------------------------------------------------------
|
|||
|
* Function : trackSmoothSlideWindowFree
|
|||
|
* Description : 轨迹平滑模块关闭后需要使用此函数释放资源
|
|||
|
* Date : 2020/7/4 yuanlin_rjyb@vivo.com
|
|||
|
*---------------------------------------------------------------------**/
|
|||
|
int freeTrackSmooth(void)
|
|||
|
{
|
|||
|
if ( SmoothBuffer != NULL)
|
|||
|
{
|
|||
|
free(SmoothBuffer);
|
|||
|
SmoothBuffer = NULL;
|
|||
|
SmoothBufferSize = 0;
|
|||
|
elemTrail = 0;
|
|||
|
}
|
|||
|
if ( OutputBuffer != NULL)
|
|||
|
{
|
|||
|
free(OutputBuffer);
|
|||
|
OutputBuffer = NULL;
|
|||
|
outputBufferSize = 0;
|
|||
|
outputTrail = 0;
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|