C语言将NMEA定位数据中的BL转换为标准BLH及XYZ

博主在前几年写的一个应用程序,用于将NMEA格式的定位数据中的LBH转换为度分秒

NMEA格式如下:
具体每个字段代表的意义可以参考:NMEA格式说明

0001:$GNGGA,055154.00,3954.7885315,N,11615.5569597,E,1,23,0.6,79.9761,M,-9.797,M,,*67
0002:$GNGGA,055155.00,3954.7885325,N,11615.5569457,E,1,23,0.6,80.1820,M,-9.797,M,,*6C
0003:$GNGGA,055156.00,3954.7885010,N,11615.5570199,E,1,23,0.6,80.2369,M,-9.797,M,,*60
0004:$GNGGA,055157.00,3954.7885304,N,11615.5569727,E,1,23,0.6,80.2149,M,-9.797,M,,*6C
0005:$GNGGA,055158.00,3954.7885056,N,11615.5570175,E,1,23,0.6,80.1064,M,-9.797,M,,*63
0006:$GNGGA,055159.00,3954.7885151,N,11615.5570588,E,1,23,0.6,79.9814,M,-9.797,M,,*63
0007:$GNGGA,055200.00,3954.7885596,N,11615.5570476,E,1,23,0.6,80.1273,M,-9.797,M,,*66
0008:$GNGGA,055201.00,3954.7885848,N,11615.5569074,E,1,23,0.6,79.9970,M,-9.797,M,,*61
0009:$GNGGA,055202.00,3954.7885776,N,11615.5569759,E,1,23,0.6,80.0179,M,-9.797,M,,*66
0010:$GNGGA,055203.00,3954.7885262,N,11615.5569545,E,1,23,0.6,80.1997,M,-9.797,M,,*61
0011:$GNGGA,055204.00,3954.7884971,N,11615.5569766,E,1,23,0.6,80.3279,M,-9.797,M,,*64
0012:$GNGGA,055205.00,3954.7885324,N,11615.5569465,E,1,23,0.6,80.2983,M,-9.797,M,,*61

转换后的格式如下:

5.865000  39.913119 116.259283	70.179100 -2167464.937004   4393389.585787   4070636.039359	23.000000 0.600000 
5.865278  39.913119 116.259282	70.385002 -2167464.988798   4393389.735866   4070636.171979	23.000000 0.600000 
5.865556  39.913119 116.259284	70.439903 -2167465.102553   4393389.727451   4070636.206401	23.000000 0.600000 
5.865833  39.913119 116.259283	70.417900 -2167465.034468   4393389.741472   4070636.193087	23.000000 0.600000 
5.866111  39.913119 116.259284	70.309402 -2167465.055153   4393389.639102   4070636.122795	23.000000 0.600000 
5.866389  39.913119 116.259284	70.184402 -2167465.065515   4393389.527080   4070636.042592	23.000000 0.600000 
5.877778  39.913119 116.259284	70.330299 -2167465.100665   4393389.634403   4070636.136330	23.000000 0.600000 
5.866944  39.913119 116.259282	70.200005 -2167464.877354   4393389.633332   4070636.052518	23.000000 0.600000 
5.867222  39.913119 116.259283	70.220901 -2167464.971909   4393389.604359   4070636.066138	23.000000 0.600000 
5.867500  39.913119 116.259283	70.402702 -2167465.006333   4393389.743064   4070636.182574	23.000000 0.600000 
5.867778  39.913119 116.259283	70.530907 -2167465.078037   4393389.817222   4070636.264960	23.000000 0.600000 
5.868056  39.913119 116.259282	70.501305 -2167465.029571   4393389.815933   4070636.245840	23.000000 0.600000 

格式说明如下:
第一列表示时间,单位是h
第二列~第四列表示大地坐标BLH,经纬度单位为,大地高为m
第五列~第七列表示空间直角坐标XYZ,单位为m
第八列表示卫星数
第九列表示水平精度因子
源码如下:

/*32个数学函数中只有abs的数据类型是:”整型“,”int“。

log10、logE中的10与E是在log的左下角位置。其余求弧度函数需要看清楚是不是指数。

排列方式如下:函数名:函数功能参数介绍,返回值,说明。函数原型。

abs: 求整型x的绝对值,返回计算结果。 int abs(int x);

acos: 计算COS-1(x)的值,返回计算结果,x应在-1到1范围内。 double acos(double x);

asin: 计算SIN-1(x)的值,返回计算结果,x应在-1到1范围内。 double asin(double x);

atan: 计算TAN-1(x)的值,返回计算结果。  double atan(double x);

atan2: 计算TAN-1/(x/y)的值,返回计算结果。 double atan2(double x,double y);

cos: 计算COS(x)的值,返回计算结果,x的单位为弧度。 double cos(double x);

cosh: 计算x的双曲余弦COSH(x)的值,返回计算结果。 double cosh(double x);

exp: 求Ex的值,返回计算结果。 double exp(double x);

fabs: 求x的绝对值,返回计算结果。 duoble fabs(fouble x);

floor: 求出不大于x的最大整数,返回该整数的双精度实数。 double floor(double x);

fmod: 求整除x/y的余数,返回该余数的双精度。 double fmod(double x,double y);

frexp: 把双精度数val分解为数字部分(尾数)x和以2为底的指数n,即val=x*2n,n存放在eptr指向的变量中。返回数字部分x0.5<=x<1。 double frexp(double x, double *eptr);

log: 求log e x,In x。返回计算结果。 double log(double x);

log10: 求log10x。返回计算结果。 double log10(double x);

modf: 把双精度数val分解为整数部分和小数部分,把整数部分存到iptr指向的单元。返回val的小数部分。 double modf(double val,double *iptr);

pow: 计算Xy的值,返回计算结果。 double pow(double x,double *iprt);

rand: 产生-90到32767间的随机整数。返回随机整数。 int rand(void);

sin: 计算SINx的值。返回计算结果。x单位为弧度。 double sin(double x);

sinh: 计算x的双曲正弦函数SINH(x)的值,返回计算结果。 double sinh(double x);

sqrt: 计算根号x。返回计算结果。x应>=0。 double sqrt(double x);

tan: 计算TAN(x)的值,返回计算结果。x单位为弧度。 double tan(double x);

tanh: 计算x的双曲正切函数tanh(x)的值。返回计算结果。 double tanh(double x);*/

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define n 1024//导入数据的最大行数
#define m 1024//输出数据的最大行数
#define a 6378137.00//WGS84长半轴  
#define e2 0.00669437999013//第一偏心率的平方
#define pi 3.1415926535898
/*大地坐标转换为ECEF公式(大地纬度⁡∅,大地经度λ)
x=(N+h)cos⁡∅cos⁡λ
y = (N + h)cos⁡∅ sin⁡λ
z = [N(1 - e ^ 2) + h]sin⁡∅
N=a/(1-e^2*sin∅^2)^1/2
*/
#pragma warning(disable:4996)
typedef struct {
	int mode, sig;
	double nsat;
	float  H, dth, dop;
	char bsig, lsig, hsig,flag;
	double B,time, L;


}line_t;//原始数据导入的变量
typedef struct {

	int mode, sig;
	double nsat;
	float  H, dth, dop;
	char bsig, lsig, hsig, flag;
	double B1,Br, time1, L1,Lr, h, min, sec,dd,mm;
	double X, Y, Z;


}out_t;//输出到结果文件的结果变量
typedef struct {

	int y;
	char b,c,d,e,f,g;

}num_t;
int main(void)
{
	
	int i = 0,num=0,num1=0;//m是输出时行数
	line_t line[n];
	num_t nmr[1024];
	out_t output[m];
	FILE* fp,*out;
	errno_t err,arr;
	char filename[50],outfile[50];
	printf("请输入原始数据文件名:\n");
	scanf_s("%s",filename, 50);
	err=fopen_s(&fp,filename , "r");
    while (!feof(fp))
	
	{
			  
		fscanf(fp,"%4d:%c%c%c%c%c%c,%lf,%lf,%c,%lf,%c,%d,%lf,%f,%f,%c,%f,%c,%s\n",&nmr[i].y, &nmr[i].b, &nmr[i].c, &nmr[i].d, &nmr[i].e, &nmr[i].f, &nmr[i].g,&line[i].time, &line[i].B, &line[i].bsig, &line[i].L, &line[i].lsig, &line[i].mode, &line[i].nsat ,&line[i].dop, &line[i].H, &line[i].hsig, &line[i].dth, &line[i].hsig, &line[i].flag);
		//printf("%s,%f,%f,%c,%f,%c,%d,%d,%f,%f,%c,%f,%c,%s\n", &line[i].sig, line[i].time, line[i].B, &line[i].bsig, line[i].L, &line[i].lsig, line[i].mode, &line[i].nsat ,line[i].dop, line[i].H, &line[i].hsig, line[i].dth, &line[i].hsig, &line[i].flag);
		i++;
	}
	/*以下为测试读取用处
	printf("i=%d\n",i);

	printf("k=%d\n", k);
	 printf("纬度为:%.7f\n", line[1].B);
	 printf("时间为:%09.2f\n", line[1].time);
	 printf("纬度方向:%c\n", line[1].bsig);
	 printf("精度为:%13.7f\n", line[1].L);
	 printf("精度方向为:%c\n", line[1].lsig);
	 printf("定位模式:%d\n", line[1].mode);
	 printf("卫星数:%f\n", line[1].nsat);
	 printf("结果为:%04d:%c%c%c%c%c%c,%09.2f,%.7f,%c,%13.7f,%c,%d,%f\n", nmr[431].y, nmr[431].b, nmr[431].c, nmr[431].d, nmr[431].e, nmr[431].f, nmr[431].g,line[431].time, line[431].B, line[431].bsig, line[431].L, line[431].lsig, line[431].mode, line[431].nsat);*/
	int k = i;
	printf("请输入输出数据文件名:\n");
	scanf_s("%s",outfile,50);
	arr = fopen_s(&out, outfile, "w");
	 for (num = 0; num <k-1; num++)
	 {

		 for ( i=num; i <k-1; i++)
		 {
			 output[num].B1 = line[i].B+2;
			 output[num].h = floor((line[i].time/10000));
			 //printf("小时数为:%f\n", output[num].h);
			 output[num].min = floor((line[i].time/10000- output[num].h)*100);
			 output[num].sec = line[i].time - output[num].h * 10000 - output[num].min * 100;
			 output[num].time1 = output[num].h + ((double)output[num].min) / 60 + (double)output[num].sec/3600;
			 output[num].B1 = floor(line[i].B / 100) + (line[i].B - (floor(line[i].B / 100) * 100)) / 60;
			 output[num].L1= floor(line[i].L / 100) + (line[i].L - (floor(line[i].L / 100) * 100)) / 60;
			 output[num].H = line[i].H + line[i].dth;
			 output[num].Br = output[num].B1 * (pi / 180);
			 output[num].Lr= output[num].L1 * (pi / 180);
			 double N =a/(sqrt(1 - e2*(pow(sin(output[num].Br),2))));
			 output[num].X = (N+ output[num].H)*cos(output[num].Br)*cos(output[num].Lr);
			 output[num].Y = (N + output[num].H) * cos(output[num].Br) * sin(output[num].Lr);
			 output[num].Z = (N*(1-e2)+ output[num].H)* sin(output[num].Br);
			 output[num].nsat = line[i].nsat;
			 output[num].dop = line[i].dop;
			 break;
		 }
	 }
	 for (num1 = 0; num1 <k-1; num1++) {
	 
		 fprintf(out, "%0.6f  %.6f %.6f	%.6f %.6f   %.6f   %.6f	%.6f %.6f \n", output[num1].time1,output[num1].B1, output[num1].L1, output[num1].H, output[num1].X, output[num1].Y, output[num1].Z, output[num1].nsat, output[num1].dop);
	 }
	 puts("\n转换成功!\n");
	
	 fclose(fp);
	 fclose(out);

	return EXIT_SUCCESS;

		
	}

也可直接使用应用程序:
NMEA转换程序

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十八与她

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值