首页 > 其他分享 >haversine公式_计算gps距离接口例程

haversine公式_计算gps距离接口例程

时间:2024-02-26 22:47:07浏览次数:28  
标签:fpSrc 例程 uint8 && haversine uint32 gps

1 haversine公式

  先放着,后续补充原理;

2 接口函数目的

  前几天测试反馈了一条骑行记录的bug,实际记录和具体坐标对不上;骑行记录的数据又多,分析不直观;

  实际gps坐标数据拿出来模拟仿真没什么问题,估计采样点还是哪里有问题把,先放放;

  这几天没什么事,整了一个函数接口用来对预处理的gps数据进行解析,

  gps数据都解析完了,干脆把haversine公式的接口也整上好了,复制粘贴一下也很快;

  gps数据的私有协议如下图所示,为实际数据存储record的格式;

  orgfile.log为预处理数据,已经去掉协议头部分,剩下的全部是12字节一组的record;

  gpsPztSimulator.c作为一个单独的仿真例程,直接使用vscode+mingw就可以编译了;

3 gps记录私有协议

  将gsensor传感器采集的gps经纬度坐标通过haversine公式,计算出运动距离;

  

4 haversine使用接口

#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <stdbool.h>
#include <math.h>


#define uint8_t    unsigned char 
#define uint16_t   unsigned short
#define uint32_t   unsigned int


#define FILE_PATH_SRC  "C:/Users/WINDOWS/Desktop/orgfile.log"

//读取src文件大小
uint32_t  readFileSrcLen(FILE *fpSrc){

    uint32_t lenRet = 0;
   
    fseek(fpSrc, 0, SEEK_END); 
    lenRet = ftell(fpSrc);       
    rewind(fpSrc); 

    printf("orgfile lenRet:(d)%d  \n",lenRet);
    return lenRet;
}

//读取 文件数据 至psrcData数组
bool readFileCharDataToBuff(uint8_t *psrcData, uint32_t *plenSrcData, FILE *fpSrc,uint32_t lenFileSize ){

    uint8_t  charGet = 0;
    uint32_t charCnt = 0;   
    do{
        charGet = (uint8_t)fgetc(fpSrc);
        if( ((char)charGet>='0')&&((uint8_t)charGet <='9') ){
            psrcData[charCnt] = (uint8_t)charGet;
            charCnt++;
        }
        else if(((uint8_t)charGet>='a')&&((uint8_t)charGet <='f') ){
            psrcData[charCnt] = (uint8_t)charGet;
            charCnt++;
        }
        //printf("%c",charGet);
    
    //文件结尾标志符EOF = (int)(-1); -1怎么截都是0xff,那我直接截成char型也不是不行。。。
    }while(charGet!= 0xff);

    *plenSrcData = charCnt;

    printf("*plenSrcData:(d)%d \n",*plenSrcData);
    for(uint32_t i=0;i<charCnt;i++)    printf("%c ",psrcData[i]); printf("\n");

    return true;
}

//将 字符数组 两两组合为16进制数组
bool changeCharToHexData(uint8_t *phexData, uint32_t *phexDataCnt, uint8_t *psrcData, uint32_t srcDataLen){

    uint8_t  hbits,lbits;
    uint32_t  hexDataCnt = 0; 

    for(uint32_t i = 0;i<srcDataLen;i++){

        hbits = psrcData[i];
        if(  (hbits >= '0')&&(hbits<='9')  ){
            hbits = hbits-'0';
        }
        else if(  (hbits >= 'a')&&(hbits<='f')  ){
            hbits = (hbits - 'a')+10;
        }

        lbits = psrcData[i+1];
        if(  (lbits >= '0')&&(lbits<='9')  ){
            lbits = lbits-'0';
        }
        else if(  (lbits >= 'a')&&(lbits<='f')  ){
            lbits = (lbits - 'a')+10;
        }

        phexData[hexDataCnt] = hbits*16 + lbits;
        hexDataCnt++;  

        i++;    //i每次加2;for循环中+1,这里+1;为什么要写的这么皮,因为for循环中不能i+2;
    }

    *phexDataCnt = hexDataCnt;

    printf("*phexDataCnt(d):%d  \n",*phexDataCnt);
    for(uint32_t i=0;i<hexDataCnt;i++)  printf("%02x,",phexData[i]);  

    return true;  
}

#define DBP_EXERCISE  printf
#define GPS_PI                      3.1415926
#define EARTH_RADIUS                6378.137        //地球近似半径

//求弧度
float CalculateRadian(float d){
    return d * GPS_PI / 180.0;   //角度1˚ = π / 180
}

//Haversine算法公式
float count_gpsdistance(float old_latitude, float old_longitude, float cur_latitude, float cur_longitude){ 

    DBP_EXERCISE("gps pzt: %f  %f  %f  %f   ",old_latitude,old_longitude,cur_latitude,cur_longitude);

    if((old_latitude == 0)||(old_longitude == 0)||(cur_latitude == 0)||(cur_longitude == 0)){
        DBP_EXERCISE("\n");
         return 0 ;
    }
       
        
    float rad_cur_latitude = CalculateRadian(old_latitude);             //获取当前纬度弧度
    float rad_pro_latitude = CalculateRadian(cur_latitude);             //获取运动过程纬度弧度
    float latitude_difference = rad_cur_latitude - rad_pro_latitude;    //获取到纬度弧度差
    float longitude_difference = CalculateRadian(old_longitude) - CalculateRadian(cur_longitude);//获取到经度弧度差

    //Haversine公式:通过gps坐标计算位置距离;
    float gpsdistance = 2 * asin((sqrt(pow(sin(latitude_difference / 2), 2) + cos(rad_cur_latitude) * cos(rad_pro_latitude) * pow(sin(longitude_difference / 2), 2) )));

    gpsdistance = gpsdistance * EARTH_RADIUS;
    gpsdistance = round(gpsdistance * 10000) / 10000;

    gpsdistance = gpsdistance * 1000;  //千米换算为米
    DBP_EXERCISE("delta_gpsDistance:%0.3f \n", gpsdistance);

    return gpsdistance;
};


//调用haversine公式,通过gps坐标差值计算运动距离
void gpsDistanceSimulator(uint8_t *pDataBuf, uint32_t lenofBuff){
    //record: 4bytes_lati, 4bytes_longi,     gpsSpeed, jumpState,heartRates, reserved
    //0x23,0x10,0xe4,0x42,  0x19,0x92,0xb5,0x41,   0x00,0x00,0x64,0x00,

    float old_latitude = *(float*)(&pDataBuf[0]);
    float old_longitude= *(float*)(&pDataBuf[4]);
    DBP_EXERCISE("lat:  %f  %f  \n",old_latitude,old_longitude) ;
    float cur_latitude;
    float cur_longitude;
    float delta_distance = 0;
    float total_distance =0;
   
   uint32_t i = 0;
    do{
        cur_latitude = *(float*)(&pDataBuf[i]);
        cur_longitude = *(float*)(&pDataBuf[i+4]);
        
        //提取坐标后,将坐标数据传入Haversine算法处理
        delta_distance = count_gpsdistance(old_latitude, old_longitude, cur_latitude, cur_longitude);
        total_distance +=delta_distance;
        i += 12;
        old_latitude = cur_latitude;
        old_longitude = cur_longitude;

    }while( i<lenofBuff );

    DBP_EXERCISE("total_distance:%f  \n",total_distance);

}

//打印出记录块中的跳变点
void gpsDistanceJumpPoint(uint8_t *pDataBuf,uint32_t lenofbuff){

    DBP_EXERCISE("lenofbuff(d):%d  \n",lenofbuff);

    float cur_latitude;
    float cur_longitude;
    float delta_distance = 0.0;
    float total_distance =0.0;
   
   uint32_t i = 9;
   uint8_t state = 0;
    do{
        state = *(uint8_t *)(&pDataBuf[i]);
        if(state){
            cur_latitude = *(float*)(&pDataBuf[i-9]);
            cur_longitude = *(float*)(&pDataBuf[i-5]);

            DBP_EXERCISE("cae:%f  %f  state=%x  i=%d  record=%d  min=%d \n",cur_latitude,cur_longitude,state,i,(i/12),((i/12)/30));
        }

        i += 12;    
    }while( i<lenofbuff );
}

//Haversine公式:将gps坐标delta值 换算成运动距离的算法;
//以一组切好的30分钟骑行的gps坐标记录数据为例
//1 先把文件数据提取到数组中
//2 从数组中两两组合提取16进制数到数组中
//3 以record为单位提取gps坐标,调用Haversine算法计算距离
int main(){
    
    FILE     *fpSrc = NULL;
    long     lenFileSize = 0; 

    uint8_t  *psrcData = NULL;
    uint32_t lenSrcData = 0;  

    uint8_t *phexData = NULL; 
    uint32_t phexDataCnt = 0;   

    fpSrc = fopen(FILE_PATH_SRC, "r+");
    lenFileSize= readFileSrcLen(fpSrc);              
    
    //读取桌面源文件至psrcData数组
    psrcData = malloc(lenFileSize);
    if(psrcData==NULL){
        printf("malloc psrcData fail; \n");
        return false;
    }
    else
        memset(psrcData,0,lenFileSize);
    readFileCharDataToBuff(psrcData, &lenSrcData, fpSrc, lenFileSize );

    //将字符型数组提取为16进制数组
    phexData = malloc(lenSrcData);
    if(phexData ==NULL){
        printf("malloc phexData fail;  \n");
        return false;
    }
    else
        memset(phexData,0,lenSrcData);
    changeCharToHexData(phexData, &phexDataCnt, psrcData, lenSrcData);

    //将16进制数据按协议提取后打印出来
    gpsDistanceSimulator(phexData,phexDataCnt);
    gpsDistanceJumpPoint(phexData,phexDataCnt);

    fclose(fpSrc);
    if(psrcData){
        free(psrcData);
        psrcData = NULL;    
    }  
    if(phexData){
        free(phexData);
        phexData = NULL;
    }  
    
    return 0;
}

5 orgfile.log预处理文本数据

  将预处理文本放到桌面,运行前文代码即可进行解析;数据为不知道谁运动的一组实际骑行gps有问题坐标数据;

  一组29分钟多的实际骑行记录的gps坐标资源-CSDN文库

6 小结

  还是要找个旮旯角用来存放不易归类的数据,我看csdn和道客巴巴就不错;

标签:fpSrc,例程,uint8,&&,haversine,uint32,gps
From: https://www.cnblogs.com/caesura-k/p/18035758

相关文章

  • 关于8串口服务器例程的使用
    打开该例程之后,首先看一下该例程注释,注释中介绍:该8串口服务器例程设置串口波特率为921600,且仅可用于10M网络,例程中将ld文件中FLASH、RAM的大小配置为192,注意在下载使用时要将MCUFLASH、RAM的配置改为192+128,具体修改方法如下: 此外,由于将8个串口都用于实现8串口网络服务器通......
  • 关于DHCP例程的使用
    DHCP例程主要演示DHCP自动获取IP,并建立TCP连接进行数据回传。关于DHCP介绍:DHCP,全称DynamicHostConfigurationProtocol,即动态主机配置协议,该协议允许服务器向客户端动态分配IP地址和配置信息。通常DHCP服务器至少要向客户端提供以下信息:IP地址、子网掩码、默认网关等。因此例......
  • 关于WebServer例程的使用
    关于WebServer例程,该例程主要实现通过网页对WCHNET网络参数的配置以及用户名密码的管理,关于该例程的使用,具体如下:首先,关于HTTPS.c文件中,以下几个数组数据需要注意一下,如下图:其中:01,02,03,04,05,06表示的是单片机网络通信的MAC地址,此处建议在使用例程时将第一个字节改为02......
  • 获取手机GPS权限demo
    <!DOCTYPEhtml><htmllang="cn"><head><metacharset="UTF-8"><metahttp-equiv="X-UA-Compatible"content="IE=edge"><title>原生H5页面获取手机坐标</title>......
  • Qt实用技巧:QCustomPlot做北斗GPS显示绝对位置运动轨迹和相对位置运动轨迹图的时,使图按
    需求  使用QCustomPlot绘制多个目标的北斗运行轨迹图,包括累计绝对位置图和记录时刻的相对位置图。  当前绘制存在问题:    交付客户前,公司内部自测流程发现的问题。  实际预期效果为:   原因  QCustomPlot加入数据是按照x轴排列,也可以按照y轴排列,使用图层......
  • CH573 CH582 CH579 TMR例程
    CH573CH582CH579外设TMR例程讲解1.定时器0中断IO翻转#if1/*定时器0,设定100ms定时器进行IO口闪灯,PB15-LED*/GPIOB_SetBits(GPIO_Pin_15);GPIOB_ModeCfg(GPIO_Pin_15,GPIO_ModeOut_PP_5mA);TMR0_TimerInit(FREQ_SYS/10);//设置定时时间10......
  • Qt 解决qtcreator工程文件例程报错error: cannot initialize object parameter of typ
    qt下载好并且环境配置完成,kits和qt都已配置完成在qtcreator中,在终端手动编译qmakemake都完全没问题,但是在qtcreator中却报错。即使是新建工程例程都报错。版本qt5.6.0qtcreator4.11.0报错main.cpp:96:error:cannotinitializeobjectparameteroftype‘QWidget’wi......
  • BDS/GNSS/GPS卫星定位SOC芯片AT6558R
    产品简介AT6558R是一款高性能BDS/GNSS多模卫星导航接收机SOC单芯片,片上集成射频前端,数字基带处理器,32位的RISCCPU,电源管理功能。芯片支持多种卫星导航系统,包括中国的北斗卫星导航系统BDS,美国的GPS,俄罗斯的GLONASS,日本QZSS系统,并实现多系统联合定位。芯片应用车载......
  • 使用核模型高斯过程(KMGPs)进行数据建模
    核模型高斯过程(KMGPs)作为一种复杂的工具可以处理各种数据集的复杂性。他通过核函数来扩展高斯过程的传统概念。本文将深入探讨kmgp的理论基础、实际应用以及它们所面临的挑战。核模型高斯过程是机器学习和统计学中对传统高斯过程的一种扩展。要理解kmgp,首先掌握高斯过程的基础......
  • GPS信号的数字接收处理matlab仿真,包括频率点搜索,捕获跟踪,相关峰检测等步骤
    1.算法运行效果图预览 低信噪比下仿真结果如下:  2.算法运行软件版本matlab2022a 3.算法理论概述        GPS(全球定位系统)信号的数字接收处理是GPS接收机核心技术之一,它涉及到从接收到的卫星信号中提取导航数据和解算出位置信息的一系列处理过程。这个......