初步介绍
本节将初步介绍如何使用rtklib自带的日志系统来进行问题分析和定位,希望好好阅读,好好利用rtklib的日志系统,快速的定位算法问题。
代码问题
上节提到,截至到以下commit,定位结果是有问题的
a5af554bebc4061872a850c4dc58f453a55725fa
下图就展示了有问题的定位结果。我们可以发现定位是不完整的,也就是一些历元没有定位结果;同时从卫星数目的序列中,也可以看到,GPS+BDS+GAL的卫星数目不应该这么少,所以卫星数目应该也存在问题。
总结以上,总共有两个问题:定位结果丢失以及卫星数不正常。
问题排查方法
一般我们排查问题或者程序debug
如果在vs上,我们可以使用单步调试,来一步一步的查看每一步是否运行正常;或者如果可以确认是在哪一行代码出现问题,直接在这附近增加断点,运行到此行代码,可以查看或者监测想要了解的变量。
如果在linux平台上,或者不使用带有丰富UI的vs工具,依然可以使用gdb进行单步调试。具体的gdb的调试方法或者vs的调试经验,可以csdn或者bilibili自行学习。
单步调试的前提是你大概知道问题出在哪一处代码逻辑,在没有任何输入时,我们无法下手。所以就需要通过日志打印的方式,来确认问题到底出在哪一块代码。
rtklib日志介绍
rtklib中的日志主要分为5个等级,分别为1-5。5则代表打印所有日志。来看一下estpos函数中的第一条日志
trace(3,"estpos : n=%d\n",n);
这其实一条指示数据处理流程的日志,也就是说看到这条日志,我们就知道程序运行到了这个函数,后续的如果有日志打印,可以指示是在该函数中进行的输出。rtklib中指示是哪一个函数的日志,都在3这个层级。
我们来看一下这个trace函数,第一个参数就是日志的级别,第二个和后续的参数,其实和printf函数是一样的。
extern void trace(int level, const char *format, ...)
{
va_list ap;
/* print error message to stderr */
if (level<=1) {
va_start(ap,format); vfprintf(stderr,format,ap); va_end(ap);
}
if (!fp_trace||level>level_trace) return;
traceswap();
fprintf(fp_trace,"%d ",level);
va_start(ap,format); vfprintf(fp_trace,format,ap); va_end(ap);
fflush(fp_trace);
}
其实现在有一些的日志系统,不会打印函数名来指示日志打印在哪个逻辑中,因为每一条语句都会指示出是在哪一行哪一列触发的打印。感兴趣可以自行学习。
具体问题分析
接下来我们来使用rtklib的trace日志,来分析一下上面提到的问题。
首先,我们来看一下rtkpos这个函数入口处打印的输入的观测值。打印观测值的代码如下
extern void traceobs(int level, const obsd_t *obs, int n)
{
char str[64],id[16];
int i;
if (!fp_trace||level>level_trace) return;
for (i=0;i<n;i++) {
time2str(obs[i].time,str,3);
satno2id(obs[i].sat,id);
fprintf(fp_trace," (%2d) %s %-3s rcv%d %13.3f %13.3f %13.3f %13.3f %d %d %d %d %3.1f %3.1f\n",
i+1,str,id,obs[i].rcv,obs[i].L[0],obs[i].L[1],obs[i].P[0],
obs[i].P[1],obs[i].LLI[0],obs[i].LLI[1],obs[i].code[0],
obs[i].code[1],obs[i].SNR[0]*SNR_UNIT,obs[i].SNR[1]*SNR_UNIT);
}
fflush(fp_trace);
}
调用函数在rtkpos.c的1766行,代码如下
trace(3,"rtkpos : time=%s n=%d\n",time_str(obs[0].time,3),n);
trace(4,"obs=\n"); traceobs(4,obs,n);
打印的日志如下图所示,一目了然,我们可以发现只有GPS的观测值。所以这就是问题所在。问题就变为为何其他系统数据未正常读取进内存。
接着往下看日志,发现在decode_obsdata中有较多的报错,显示为
unsupported sat sat=xxx
我个人以前没有遇到过该错误,也不知道具体代码在哪,所以我们将报错的字段在vscode中搜索,找到问题代码段。搜索“unsupported sat sat=”,因为明显sat=后面的为可变字段。
同时查找报错的上一个标识日志level为3的日志,来确认是哪个函数。
经定位,发现是rinex.c的762行报错。报错的代码段如下:
if (!obs->sat)
{
trace(4,"decode_obsdata: unsupported sat sat=%s\n",satid);
stat=0;
}
后续我们就可以使用vs实时在该代码打断点,在此逻辑上下进行debug调试,查看变量内存等手段来确认问题所在。
此次问题最后定位为satid2no未将BDS和GAL系统进行卫星id转换,具体原因是我们未开启GAL系统和BDS系统,在项目属性-> C/C++ -> 预处理器中增加宏后
ENACMP
ENAGAL
ENAQZS
各系统使用就表现正常了。
定位结果缺失问题排查
关于第一个问题,就是个别时间定位结果缺失的现象。
同样可以找到下图中的问题报错,发现是“point pos error ( gdop error nv=47 gdop=0.0)”即gdop计算错误。问题定位到pntpos.c->660行,发现是valsol计算dop有问题,具体原因是我们使用了多频数据,对后续的一些gdop计算没有进行兼容,导致报错,然后定位结果丢失。
先禁用相关逻辑后,定位结果恢复正常,设置好基准坐标后,多频的单点定位结果如下图所示。具体为何高程精度出现定位偏差,具体原因还待探究。
同时增加了如下文件 /curtin_data/CU-GNSS-receivers-setup.pdf,该pdf是cuntin大学GNSS数据基准站的坐标和分布图。
本次修改提交在以下commit
1ba7cdd50da1149ed1998de3268394976e9061aa
下节会针对多频单点引发的后续逻辑问题进行修复。
公众号
有时会将代码 或者资源放在个人公众号上,有问题,在公众号后台回复,也回答的比较快一些,欢迎关注 GNSS和自动驾驶