haversine公式_计算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有问题坐标数据;
6 小结
还是要找个旮旯角用来存放不易归类的数据,我看csdn和道客巴巴就不错;
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?