首页 > 编程语言 >武汉大学卫星导航算法程序设计——解码与数据获取

武汉大学卫星导航算法程序设计——解码与数据获取

时间:2024-10-17 22:51:16浏览次数:7  
标签:武汉大学 return int 解码 pos raw 程序设计 data buff

还在为解码发愁吗?面对二进制文件还是无从下手吗?一篇文章帮你搞定。

我们从接收机获取的数据并不是rinex格式的文件,而是NovAtel数据格式的二进制文件。我们需要从文件中提取出我们需要的导航数据,也就是解码的过程。废话不多说,我们直接开始讲解。

一、Binary数据头格式

请不要使用文本文件打开二进制文件,会显示乱码。使用Binary Viewer软件可以打开二进制的文件,大概长下面这个样子。但是我们不需要读懂这个文件。

AA,44,12是三个同步符,读取到这三个同步符代表同步到了消息,就继续往下面读。

匹配同步符的函数如下:

/*匹配同步符的函数*/
static int sync_oem4(uint8_t *buff, uint8_t data)
{
	buff[0] = buff[1]; buff[1] = buff[2]; buff[2] = data;
	return buff[0] == OEM4SYNC1 && buff[1] == OEM4SYNC2 && buff[2] == OEM4SYNC3;
}

在数据头里,我们需要以下数据

第五列为每个数据所占的字节,按照字节数提取可。因为我们需要提取不同的数据,有的为整数,有的为浮点数,所以我们先定义一下提取不同类型数据的函数。代码如下:

/*解码辅助函数,用于获取不同类型的数据*/
class DataReader
{
public:
	//读取一个无符号8位整数
	static uint8_t U1(const uint8_t *p)
	{
		return *p;
	}

	// 获取一个有符号8位整数
	static int8_t I1(const uint8_t *p)
	{
		return *reinterpret_cast<const int8_t *>(p);
	}

	// 获取一个无符号16位整数 (小端)
	static uint16_t U2(const uint8_t *p)
	{
		uint16_t u;
		memcpy(&u, p, sizeof(u));//复制字节(第一个参数为目标空间的地址,第二个为赋值字节的地方,第三个参数为复制字节的大小)
		return u;
	}

	// 获取一个无符号32位整数 (小端)
	static uint32_t U4(const uint8_t *p)
	{
		uint32_t u;
		memcpy(&u, p, sizeof(u));
		return u;
	}

	// 获取一个有符号32位整数 (小端)
	static int32_t I4(const uint8_t *p)
	{
		int32_t i;
		memcpy(&i, p, sizeof(i));
		return i;
	}

	// 获取一个单精度浮点数 (小端)
	static float R4(const uint8_t *p)
	{
		float r;
		memcpy(&r, p, sizeof(r));
		return r;
	}

	// 获取一个双精度浮点数 (小端)
	static double R8(const uint8_t *p)
	{
		double r;
		memcpy(&r, p, sizeof(r));
		return r;
	}
};
DataReader DR;

然后我们就可以开始提取数据了。

/*获取当前解码的历元,判断消息的类型,转到不同的解码函数*/
/*------------------二进制数据解码函数-----------------*/
static int decode_oem4(raw_data *raw)
{
	double tow;
	int msg, stat, week;
	int	type = DR.U2(raw->buff + 4);//从第四个字节开始读取一个16位的整数,即为数据的类型编码...
	raw->type = type;

	/* crc校验码检查 */
	if (crc32(raw->buff, raw->len) != DR.U4(raw->buff + raw->len)) 
	{
		std::cout << "oem4 crc error: type=" << type << " len=" << raw->len << std::endl;
		return -1;
	}

	msg = (DR.U1(raw->buff + 6) >> 4) & 0x3; /* 消息的种类: 00=binary,01=ascii */
	stat = DR.U1(raw->buff + 13);//时间的状态
	week = DR.U2(raw->buff + 14);//参考历元的周数

	/*时间状态和周数检验,stat的值为0-23*/
	if (stat == 20 || week == 0)
	{
		cout << "oem4 time error: type=" << type << " msg=" << msg << " stat=" << stat << " week=" << week << endl;
		return 0;
	}

	//week = adjgpsweek(week);//改正周数
	tow = DR.U4(raw->buff + 16)*0.001;//GPS参考周秒(将ms单位转换成s)
	raw->time = gpst2time(week, tow);//转换为时间戳

	Commontime C;
	time2Commontime(raw->time, C);
	cout << ">" << " " << C.Year << " " << C.Month << " " << C.Day << " " << C.Hour << " " << C.Minute << " " << C.Second << endl;
	cout << type << endl;

	/*检查是否为我们关注的二进制数据*/
	if (msg != 0)
	{
		return 0;
	}
	/*判断需要解码的数据类型*/
	switch (type) 
	{
	case ID_RANGE: 
		return decode_rangeb(raw);
	case ID_GPSEPHEM: 
		return decode_gpsephem(raw);
	case ID_BDSEPHEMERIS: 
		return decode_bdsephemerisb(raw);
	}
	return 0;
}

crc32为校验码函数,用来检查数据在通信过程中是否存在错误,代码如下:

unsigned int crc32(const unsigned char *buff, int len)
{
	int i, j;
	unsigned int crc = 0;

	for (i = 0; i < len; i++)
	{
		crc ^= buff[i];
		for (j = 0; j < 8; j++) 
		{
			if (crc & 1) crc = (crc >> 1) ^ POLYCRC32;
			else crc >>= 1;
		}
	}
	return crc;
}

接下来就是解不同类型的消息文件了。我们要求是解RANGE,GPSEPHEM,BDSEPHEMERIS三种类型的文件。对应的消息编码为43,7,1696。

注意,在rtklib里面没有解GPSEPHEM的函数。

二、星历及观测值函数

range格式:

GPSEPHEM格式:

BDSEPHEMERIS格式:

大家也可以自行查阅oem4的官方文档,会有以上说明。

解观测值代码:

static int decode_rangeb(raw_data *raw)
{
	double psr, adr, dop, snr, lockt, tt;/*伪距,相位,多普勒频移,载噪比,锁定时间,时间差*/
	char *msg;
	int i,index,nobs, prn, sat, sys, code, freq, pos;
	int track, plock, clock, parity, halfc, lli, gfrq;
	int number_sys;

	unsigned char *p = raw->buff + OEM4HLEN;//开始截取数据的位置
	cout<<"decode_rangeb: len="<<raw->len<<endl;
	nobs = DR.U4(p);//截取卫星观测数量

	if (raw->len < OEM4HLEN + 4 + nobs * 44)//每个卫星的观测记录为44个字节
	{
		cout << "oem4 rangeb length error: len=" << raw->len << " nobs=" << nobs << endl;
	}//检查消息的长度是否包含观测数据


	/* p移动4个字节为第一个数据的位置,每44个字节为一个卫星的观测记录,循环读取数据*/
	for (i = 0, p += 4; i < nobs; i++, p += 44)
	{
		/* 解码卫星跟踪状态,返回值为0或1,0为第一个频点,1为第二个频点 */
		pos = decode_trackstat(DR.U4(p + 40), &sys, &code, &track, &plock, &clock,&parity, &halfc,number_sys);
		if (pos < 0)
		{
			continue;
		}
		prn = DR.U2(p);//截取卫星的PRN号
		sat = satno(sys, prn);//对PRN号进行判断
		if (sat <= 0)
		{
			continue;
		}

		gfrq = DR.U2(p + 2);
		psr = DR.R8(p + 4);//伪距
		adr = DR.R8(p + 16);//相位
		dop = DR.R4(p + 28);//多普勒观测值
		snr = DR.R4(p + 32);//观测噪声
		lockt = DR.R4(p + 36);//锁定时间
		/*-----周跳检测-----*/
		if (raw->tobs[sat - 1][pos].time != 0)
		{
			tt = timediff(raw->time, raw->tobs[sat - 1][pos]);
			lli = lockt - raw->lockt[sat - 1][pos] + 0.05 <= tt ? LLI_SLIP : 0;
		}
		else 
		{
			lli = 0;
		}
		raw->tobs[sat - 1][pos] = raw->time;
		raw->lockt[sat - 1][pos] = lockt;
		raw->halfc[sat - 1][pos] = halfc;

		if (!clock) psr = 0.0;     /* code unlock */
		if (!plock) adr = dop = 0.0; /* phase unlock */

		if (fabs(timediff(raw->obs.data[0].time, raw->time)) > 1E-9)
		{
			raw->obs.n = 0;
		}

		if ((index = obsindex(&raw->obs, raw->time, sat,number_sys)) >= 0)
		{
			raw->obs.data[index].L[pos] = -adr;
			raw->obs.data[index].P[pos] = psr;
			raw->obs.data[index].D[pos] = (float)dop;
			raw->obs.data[index].SNR[pos] =
				0.0 <= snr && snr < 255.0 ? (unsigned char)(snr*4.0 + 0.5) : 0;
			raw->obs.data[index].LLI[pos] = (unsigned char)lli;
			raw->obs.data[index].code[pos] = code;
			raw->obs.data[index].sat = sat;
			raw->obs.data[index].num_sys = number_sys;
			raw->obs.data[index].time = raw->time;
		}
	}
	save_obsfile(raw);//输出到文件
	return 1;
}

星历按照同样的方法读即可,我就不放代码了。

三、读文件和主函数

由于我们是从文本文件获取的数据,所以我们还有一个读文件的函数。

int readfile(ifstream &fp,raw_data *raw)
{
	
	if (raw->nbyte == 0) 
	{
		for (int i = 0; ; i++) 
		{
			if ((data = fp.get()) == EOF)
			{
				return -2; // 读取到文件结束符
			}
			if (sync_oem4(raw->buff, static_cast<uint8_t>(data)))
			{
				break;//匹配到同步符则退出循环
			}
			if (i >= 4096)
			{
				return 0;
			}//如果循环次数超过4096,说明同步失败
		}
	}
	// 从文件流读取数据 
	fp.read(reinterpret_cast<char *>(raw->buff + 3), 7); // 读取7字节
	raw->len = DR.U2(raw->buff + 8) + OEM4HLEN;//获取消息的长度
	/* 读取有效数据 */
	fp.read(reinterpret_cast<char *>(raw->buff + 10), raw->len - 6);//从buff的第10个字节开始,读取(消息长度-6字节)长度的数据
	raw->nbyte = 0;
	/* 解码 NovAtel OEM4 信息 */
	decode_oem4(raw);
	return 1;
}

主函数:

int main()
{
	string filename = "NovatelOEM20211114-01.log";
	ifstream fp(filename, ios::binary);//以二进制格式打开文件
	raw_data raw;
	while (true)
	{
		int result = readfile(fp, &raw); // 循环调用 readfile 函数
		if (result == -2)
		{
			std::cout << "读取到文件结束符" << std::endl;
			break; // 读取结束或失败,退出循环
		}
		else if (result == -1) 
		{
			std::cerr << "消息长度错误,跳过此消息" << std::endl;
			continue; // 如果长度错误,跳过此消息
		}
	}
	outfile.close();
	outfile_g.close();
	outfile_n.close();
	fp.close();
    std::cout << "Hello World!\n";
	return 0;
}

本次内容就分享到这里了,大家有什么疑问欢迎和我交流。

标签:武汉大学,return,int,解码,pos,raw,程序设计,data,buff
From: https://blog.csdn.net/qq_73763569/article/details/143029764

相关文章

  • 2024-2025-1 20241401 《计算机基础与程序设计》 第四周学习总结
    班级链接2024计算机基础与程序设计作业要求作业要求作业目标①门电路②组合电路,逻辑电路③冯诺依曼结构④CPU,内存,IO管理⑤嵌入式系统,并行结构⑥物理安全教材学习内容总结《计算机科学概论》第四章、第五章门:非(NOT)门、与(AND)门、或(OR)门、异或(XOR)......
  • python+flask框架的代驾小程序设计与实现实现18(开题+程序+论文) 计算机毕业设计
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容选题背景随着城市化进程的加速和交通安全意识的提升,代驾服务逐渐成为人们日常生活中不可或缺的一部分。特别是在饮酒后或长途驾驶疲劳时,代驾服务为......
  • # 学期(如2024-2025-1) 学号(如:20241402) 《计算机基础与程序设计》第4周学习总结
    学期(如2024-2025-1)学号(如:20241402)《计算机基础与程序设计》第4周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)这个作业的目标<写上......
  • 【软考】7 程序设计语言
     一、编译程序和解释程序 编译器和解释器都会3个分析处理 以下关于高级程序设计语言实现的编译和解释方式的叙述中,正确的是(A)。A编译程序不参与用户程序的运行控制,而解释程序则参与B编译程序可以用高级语言编写,而解释程序只能用汇编语言编写C编译方式处理源程序时不......
  • C程序设计:实际应用题
        分段计算水费,输入用户的月用水量x(吨),计算并输出该用户应支付的水费y(元)(结果保留2位小数)。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‭‬......
  • C程序设计:判断并利用三边计算三角形面积
    在c语言中sqrt函数用于计算输入数的平方根。输入三角形的三边的长,做一步判断:如果三边长的数值合理(即可组成三角形),则开始利用三边计算三角形的面积。若其数值不合理则(输出信息有误)。利用复合语句。我们把一个三角形的而三边长设定为a,b,c,其面积为s。使用海伦公式即可编写出:#......
  • C语言程序设计现代方法_读书笔记
    C语言程序设计现代方法第2章C语言基本概念(P10)在C语言中,函数仅仅是一系列组合在一起并且赋予了名字的语句。(P14)一旦变量被赋值,就可以用它来辅助计算其他变量的值。(P17)C语言的一个通用原则:在任何需要数值的地方,都可以使用具有相同类型的表达式。(P19)在C语言中,标识符可......
  • # 学期(如2024-2025-1) 学号(如:20241402) 《计算机基础与程序设计》第2、3周学习总结
    学期(如2024-2025-1)学号(如:20241402)《计算机基础与程序设计》第2、3周学习总结作业信息这个作业属于哪个课程<班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里<作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)这个作业的目标<写......
  • 学期2024-2025-1 学号20241424 《计算机基础与程序设计》第4周学习总结
    学期2024-2025-1学号20241424《计算机基础与程序设计》第4周学习总结作业信息|这个作业属于(2024-2025-1-计算机基础与程序设计)||-- |-- ||这个作业要求在(2024-2025-1计算机基础与程序设计第四周作业||这个作业的目标|<写上具体方面>参考上面的学习总结模板,把学习过程通过......
  • 2024-2025-1 202421310 《计算机基础与程序设计》第3周学习总结
    学期(如2024-2025-1)学号(如:20241300)《计算机基础与程序设计》第X周学习总结作业信息|这个作业属于哪个课程|https://www.cnblogs.com/rocedu/p/9577842.html|这个作业要求在哪里|https://www.cnblogs.com/rocedu/p/9577842.html#WEEK03|这个作业的目标|数字分类与计数法位......