本科生学习GNSS算法 中级教程(四)- rtklib多系统多频单点定位算法 - rtklib日志解析以及算法调试

初步介绍

本节将初步介绍如何使用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和自动驾驶

猜你喜欢

转载自blog.csdn.net/dong20081991/article/details/126754625