PDR/3.BackUp/PDR-Origin-Version/src/pdr_trackSmooth.c

310 lines
11 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 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;
}