手机 RTK/PPK-地面平面有多重要

手机 RTK/PPK-地面平面有多重要?

原文来自于cell-phone-rtk-ppk-how-important-is-a-ground-plane,作者rtklibexplorer,这里只是做翻译记录,版权归原作者。

11-17 文章没有翻译完整,第一稿
I often stress in my posts the importance of using a ground plane under the antenna when collecting observations for precision GNSS solutions to reduce the effect of multipath. This is true for traditional ceramic patch antennas but is even more important when collecting data with a cell phone.

在我过去的文章中,我经常强调,为了减小多路径的影响以提高定位解算结果的精度,在收集观测数据时使用一个屏蔽面放在天线底下很重要。这对传统的陶瓷贴片天线来说当然正确,但在用手机收集数据时(为了减少多路径的影响)也很重要。

A ceramic patch antenna typically used with a low cost GNSS receiver has some built in protection against multipath. It is directional with maximum gain in the vertical direction and is also circularly polarized which helps because the reflected signals have the opposite polarization of the direct signals. In this case, adding a ground plane under the antenna reduces multipath by attenuating signals from low elevation angles and eliminating signals from below the horizon, but it is only part of the multipath mitigation.

通常与低成本 GNSS 接收机一起使用的陶瓷贴片天线具有一些内置的防多径保护。它在垂直方向上具有最大增益的方向性,而且还具有圆极化特性,这是由于反射信号与直射信号的极化相反所致。在这种情况下,在天线下面增加一个屏蔽面,通过减弱低仰角信号和消除地平线以下的信号来减少多径,但这只是多径抑制的一部分。

A cell phone antenna on the other hand is omni-directional and most likely linearly polarized. Hence it has little or no built-in protection against the reflected signals. The only defense in this case against multipath is a ground plane, and so it becomes that much more critical.

另一方面,手机天线是全方位的,极有可能是线性极化的。因此,它对反射信号几乎没有或根本没有内置的保护。在这种情况下,对抗多路径的唯一防御是屏蔽面,因此它变得更加关键。

I recently stumbled across a very nice cell phone data set shared online by the same authors of the data I used in my very first post on cell phone solutions from a couple years ago. It is taken with an Xiaomi Mi8 phone and includes 40 days of static measurements, each measurement between 10 and 15 minutes long. There are measurements each day from three locations with varying sky visibility; open sky, partially forested, and forested. What makes this data particularly interesting is that for half of the 40 days, the measurements were taken with a ground plane underneath the phone and the other half were taken without a ground plane. The authors then went on to show that the solutions derived from the ground plane data were significantly more accurate than those derived from the data without ground planes. Unfortunately their paper is not available without logging into a service, but a short summary is available here.

最近,我偶然发现了一个非常不错的手机数据集,这个数据集是由几年前我第一篇关于手机解决方案的文章中使用的数据的同一个作者在网上共享的。这张照片是用小米8手机拍摄的,包括40天的静态数据,每次观测时长在10到15分钟之间。每天都有来自三个地点的观测数据,这三个地点头顶的可视情况不同,包括: 开阔环境,部分森林遮挡,以及完全森林遮挡。这些数据之所以特别有趣,是因为在这40天中,有一半的时间采集数据时手机下方都带了一个屏蔽面,而另一半时间是在没有使用屏蔽面的情况下进行的。然后作者声明,带屏蔽面的数据算得的结果比那些从没有屏蔽面得出的结果要精确得多。不幸的是,他们的论文在没有登录服务的情况下是不可用的,但是这里有一个简短的摘要。

In this post I will try to repeat their analysis using their data to confirm I get the same result. They actually used an earlier version of the demo5 RTKLIB for their analysis but I will use the latest version of the code (b34d) and a more recent configuration file. For this exercise I will analyze only the open sky measurements and will leave the more challenging measurements for another post.

在这篇文章中,我将尝试使用他们的数据重复他们的分析,以确认我得到了相同的结果。他们实际上使用了 demo5 RTKLIB 的早期版本进行分析,但我将使用最新版本的代码(b34d)和更新的配置文件。在这次测试中,我只分析开阔场景下的数据,更具挑战性的数据留给另一篇文章。

The data set is very complete and includes observations from a nearby base station as well as downloaded broadcast navigation data. This last item is important, because as I’ve noted before, the Mi8 Galileo navigation data either has a bug in it or is just incompatible with RTKLIB. For this reason, I ran all solutions with the downloaded broadcast navigation data rather than the navigation data collected by the phone.

数据集是非常完整的,其中包含附近基站的观测数据和广播星历数据。最后一点很重要,因为正如我之前提到的,Mi8 Galileo 的导航数据要么存在 bug,要么与 RTKLIB 不兼容。出于这个原因,我使用下载的广播星历数据而不是手机收集的星历数据来处理数据。

I started with the config file I described in my last cell phone post but made a few changes. I have appended the contents of the final config file I ended up with to the end of this post. I’ll describe the changes I made below.

我从上一篇文章中描述的配置文件开始进行测试,但是做了一些修改。我在这篇文章的最后添加了最终配置文件的内容。我将在下文描述我所做的改变。

First of all, this data is static, unlike the previous data, so I changed the solution mode from “kinematic” to “static”.

首先,与以前的数据不同,这些数据是静态的,因此我将解算模式从“kinematic”改为“static”。

Next, looking at the residuals from an initial solution plotted with RTKPLOT, I noticed a significant difference in the magnitude of the pseudorange residuals between L1 and L5. In the plots below, the left plot shows the L1 residuals and the right plot shows the L5 residuals. The carrier phase residuals are similar but the pseudorange residuals are much smaller for L5. This is not unexpected because the newer L5 signal has improved structure and higher power. The details are explained in this article.

接下来,观察用 RTKPLOT 绘制的初始解的残差,我注意到L1和L5之间伪距残差的大小有显著差异。在下图中,左边的图表示 L1残差,右边的图表示 L5残差。载波相位残差相似,但 l5的伪距残差要小得多。这其实并不意外,因为新版L5信号比之前的信号结构更好,功率更高。详细情况在这篇文章中进行了说明。

Solution residuals for L1(left) and L5(right) observations L1(左)和 L5(右)观测值解算结果残差图

To take advantage of this difference, I adjusted the code/carrier phase error ratio for L1 (stats-eratio1) from 300 to 1500 and left the L5 error ratio (stats-eratio5) at 300. This will cause the kalman filter to weight the L5 pseudorange observations more heavily than the L1 observations. In RTKPOST, this parameter is set in the Statistics tab of the Options menu. Note that prior to the b34d code, the L5 error ratio parameter existed but was not configurable through the GUI interface in RTKPOST, but that is fixed now.

为了利用这种差异,我调整了 L1(stats-eratio1)的伪距/载波相位(code/carrier phase)残差ratio值,从300调整到1500,并将L5的错误率(stats-eratio5)设00。这使得在卡尔曼滤波器中,L5伪距观测值的权重比 L1观测更大。在 RTKPOST,这个参数是在“选项Options ”菜单的“统计Statistics ”选项卡中设置的。注意,在 b34d 代码之前,L5错误率(error ratio)参数是存在的,但是不能通过 RTKPOST 的 GUI 界面进行配置,但是现在已经修复了。

Next, based on the SNR of the observations, plotted below, I chose to reduce the minimum SNR threshold from 34 dbHz to 24 dbHz. This is a somewhat arbitrary setting and may not be optimal, but leaving it at 34 dbHz for this data set would have thrown out too many usable satellites. It could also have been adjusted separately for L1 and L5 but I did not choose to do this. It is interesting that the L5 observations do not appear to have higher SNR than L1 despite the increased signal power mentioned above. This may be due to limitations of the antenna.

接下来,根据下面绘制的观测值的信噪比图,我选择将最小信噪比阈值从34dbHz 降低到24dbHz。这是一个有点随意的设置,可能并不是最佳的,但是对于这个数据集来说,将它保持在34dbHz 会舍弃掉太多可用的卫星。它也可以分别调整 l1和 L5的信噪比阈值,但我没有选择这样做。有趣的是,尽管在之前我们提到L5的信号功率增强了,但是L5的观测信噪比并没有高于 L1。这可能是由于天线性能有限吧。

SNR of observations, L1 (left) and L5(right) 观测值信噪比,L1(左)和 L5(右)

The last change I chose to make was to change the solution type (Filter mode in the RTKPOST options menu) from “Combined to “Combined-no phase reset”. This is a relatively new option in the demo5 code. The official 2.4.3 code always resets the phase bias estimates between the forward and backward solutions and this is a more conventional approach. Earlier versions of the demo5 code reset the phase estimates if ambiguity resolution was set to fix-and-hold but did not reset them otherwise. The reason to reset them is to insure the forward and backward solutions independent, but especially for shorter data sets, it can be advantageous to use the converged estimates as a starting point for the backwards solution. Since, in this experiment, the measurements are fairly short (10-15 minutes), I chose to not reset the biases.

最后,我将解算结果的类型(RTKPOST 选项菜单中的 Filter 模式)从“ Combined”更改为“ Combined-no phase reset”。这是 demo5代码中一个相对较新的选项。官方的2.4.3代码总是重置前向和后向解之间的相位偏差估计,这是一个更常规的方法。在早期版本的 demo5代码中,如果模糊度的固定方法设置为fix-and-hold来重置相位估计,但没有重置它们。重置它们的原因是为了确保前向和后向解的独立性,但对于较短的数据集,使用收敛后的解作为后向解的起点是有利的。因为在这个实验中,测量时间相当短(10-15分钟) ,所以我选择不重置偏差值。

The next step was to run the solution on all 40 days of data. RTKPOST is nice for working with a single data set and experimenting with different parameter settings, but to run many solutions quickly, it is easier to batch process them with the RNX2RTKP command line version of RTKPOST. I used a simple python script to run RNX2RTKP ( the CLI version of RTKPOST) in multiple simultaneous threads to make this process faster since a single instance of an RTKLIB app will only use a single processor . I’ll discuss this script in more detail in my next post.

下一步是对所有40天的数据进行解算。如果要处理的对象是单个数据集并且解算参数设置不同,显然RTKPOST是个不错的选择。但是如果要同时快速处理多个不同的解算数据集时,显然,这时候使用 RTKPOST的命令行版本的RNX2RTKP更容易对这些数据集进行批量处理。我使用一个简单的 python 脚本在多个并发线程中运行 RNX2RTKP (RTKPOST 的 CLI 版本) 来加快解算进程,因为一个 RTKLIB 应用实例只能处理一份数据。我将在下一篇文章中更详细地讨论这个脚本。

I then used python to plot the error in the solutions, 40 points in all, 2o with ground planes, 20 without. To calculate the errors, I subtracted the ground truth included with the data set from each solution position.

然后我用 python 来绘制解算误差,总共40个点,其中有20个点为使用了屏蔽面的结果,另外20个没有。用真值减去每个点对应的解算结果即为误差。

Static PPK solutions for open sky data, with and without ground plane 空旷环境下的静态 PPK 解,有与没有使用屏蔽面

Note that the ground truth was generated from a survey grade receiver but is only approximate because the exact location of the antenna within the phone was unknown. Cell phone antennas can also have large offsets between the mechanical center of the antenna (ARP) and the electrical center of the antenna (APC). No attempt was made to compensate for these.

请注意,这里的参考真值点是由测量型接收机生成的一个点,它只是手机天线点的一个近似值,因为我们并不知道这个天线在手机的哪个位置。而且手机天线的物理中心参考点和它的相位中心也有偏差线。这里没有对它们进行改正。

As expected, the ground plane solutions were significantly more accurate than the no-ground plane solutions. In fact, 19 out of the 20 measurements solutions for data using a ground plane were within a few centimeters of each other. Only 7 of the 20 measurements without ground planes met the same criteria. Overall, I would say this data makes quite a compelling argument for using a ground plane. I understand it’s not always possible in a cell phone application to do this, but it’s important to at least understand the significance of this choice.

正如预期的那样,带屏蔽面的结果比不带屏蔽面的解更加精确。事实上,使用屏蔽面的的20个结果中,19个解的结果相距不到几厘米。而在没有使用屏蔽面的20次测量中,只有7次符合同样的标准。总的来说,我认为这些数据为使用屏蔽面供了一个非常有说服力的论据。我知道在手机的应用中并不总是可以做到这一点,但是至少理解这个选择的意义是很重要的。

The results were also consistent enough to suggest that cell phones, despite their low performance antennas, are becoming a viable option for practical measurements, at least in open sky environments. It’s worth noting as well, that, although the errors were much larger without the ground plane, even the errors in these measurements were consistently well below a meter.

研究结果也足以表明,尽管手机的天线性能较差,但至少在开阔环境下,手机正成为一种可行的实用测量方法。同样值得注意的是,虽然没有使用屏蔽面的情况下误差要大得多,但即使是这些解的误差也一直远小于于1米。

It is important to remember that this data was all taken with an open sky view and that you should not expect such good results in more challenging conditions. It’s also still true that low cost receivers with higher quality antennas will still give much more robust and reliable solutions.

重要的是要记住,这些数据都是在开阔环境下获得的,不应该期望在更具挑战性的条件下也能获得如此好的结果。事实是,低成本的接收机(如果)配有高质量的天线也能提供更加健壮和可靠的解决方案。

There’s plenty more data in this data set that I didn’t look at in this post but hope to take a closer look at in the future.

这个数据集中还有很多数据,我在这篇文章并中处理它们,希望在以后能够进一步了解处理他们。

Config file used for this experiment:

用于这个实验的配置文件:

\# rtkpost options for b34d code, static Mi8 cell phone
pos1-posmode       =static     # (0:single,1:dgps,2:kinematic,3:static,4:static-start,5:movingbase,6:fixed,7:ppp-kine,8:ppp-static,9:ppp-fixed)
pos1-frequency     =l1+l2+l5   # (1:l1,2:l1+l2,3:l1+l2+l5,4:l1+l2+l5+l6)
pos1-soltype       =combined-nophasereset # (0:forward,1:backward,2:combined,3:combined-nophasereset)
pos1-elmask        =15         # (deg)
pos1-snrmask\_r     =on         # (0:off,1:on)
pos1-snrmask\_b     =on         # (0:off,1:on)
pos1-snrmask\_L1    =24,24,24,24,24,24,24,24,24
pos1-snrmask\_L2    =34,34,34,34,34,34,34,34,34
pos1-snrmask\_L5    =24,24,24,24,24,24,24,24,24
pos1-dynamics      =on         # (0:off,1:on)
pos1-tidecorr      =off        # (0:off,1:on,2:otl)
pos1-ionoopt       =brdc       # (0:off,1:brdc,2:sbas,3:dual-freq,4:est-stec,5:ionex-tec,6:qzs-brdc)
pos1-tropopt       =saas       # (0:off,1:saas,2:sbas,3:est-ztd,4:est-ztdgrad)
pos1-sateph        =brdc       # (0:brdc,1:precise,2:brdc+sbas,3:brdc+ssrapc,4:brdc+ssrcom)
pos1-posopt1       =off        # (0:off,1:on)
pos1-posopt2       =off        # (0:off,1:on)
pos1-posopt3       =off        # (0:off,1:on,2:precise)
pos1-posopt4       =off        # (0:off,1:on)
pos1-posopt5       =off        # (0:off,1:on)
pos1-posopt6       =off        # (0:off,1:on)
pos1-exclsats      =           # (prn ...)
pos1-navsys        =45         # (1:gps+2:sbas+4:glo+8:gal+16:qzs+32:bds+64:navic)
pos2-armode        =fix-and-hold # (0:off,1:continuous,2:instantaneous,3:fix-and-hold)
pos2-gloarmode     =fix-and-hold # (0:off,1:on,2:autocal,3:fix-and-hold)
pos2-bdsarmode     =on         # (0:off,1:on)
pos2-arfilter      =on         # (0:off,1:on)
pos2-arthres       =3
pos2-arthresmin    =3
pos2-arthresmax    =3
pos2-arthres1      =0.1
pos2-arthres2      =0
pos2-arthres3      =1e-09
pos2-arthres4      =1e-05
pos2-varholdamb    =0.1        # (cyc^2)
pos2-gainholdamb   =0.01
pos2-arlockcnt     =5
pos2-minfixsats    =4
pos2-minholdsats   =5
pos2-mindropsats   =10
pos2-rcvstds       =off        # (0:off,1:on)
pos2-arelmask      =15         # (deg)
pos2-arminfix      =10
pos2-armaxiter     =1
pos2-elmaskhold    =15         # (deg)
pos2-aroutcnt      =20
pos2-maxage        =30         # (s)
pos2-syncsol       =off        # (0:off,1:on)
pos2-slipthres     =0.05       # (m)
pos2-rejionno      =1          # (m)
pos2-rejgdop       =30
pos2-niter         =1
pos2-baselen       =0          # (m)
pos2-basesig       =0          # (m)
out-solformat      =llh        # (0:llh,1:xyz,2:enu,3:nmea)
out-outhead        =on         # (0:off,1:on)
out-outopt         =on         # (0:off,1:on)
out-outvel         =off        # (0:off,1:on)
out-timesys        =gpst       # (0:gpst,1:utc,2:jst)
out-timeform       =hms        # (0:tow,1:hms)
out-timendec       =3
out-degform        =deg        # (0:deg,1:dms)
out-fieldsep       =
out-outsingle      =off        # (0:off,1:on)
out-maxsolstd      =0          # (m)
out-height         =ellipsoidal # (0:ellipsoidal,1:geodetic)
out-geoid          =internal   # (0:internal,1:egm96,2:egm08\_2.5,3:egm08\_1,4:gsi2000)
out-solstatic      =all        # (0:all,1:single)
out-nmeaintv1      =0          # (s)
out-nmeaintv2      =0          # (s)
out-outstat        =residual   # (0:off,1:state,2:residual)
stats-weightmode   =elevation  # (0:elevation,1:snr)
stats-eratio1      =1500
stats-eratio2      =300
stats-eratio5      =300
stats-errphase     =0.006      # (m)
stats-errphaseel   =0.006      # (m)
stats-errphasebl   =0          # (m/10km)
stats-errdoppler   =1          # (Hz)
stats-snrmax       =52         # (dB.Hz)
stats-stdbias      =30         # (m)
stats-stdiono      =0.03       # (m)
stats-stdtrop      =0.3        # (m)
stats-prnaccelh    =3          # (m/s^2)
stats-prnaccelv    =1          # (m/s^2)
stats-prnbias      =0.001      # (m)
stats-prniono      =0.001      # (m)
stats-prntrop      =0.0001     # (m)
stats-prnpos       =0          # (m)
stats-clkstab      =5e-12      # (s/s)
ant1-postype       =llh        # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
ant1-pos1          =0          # (deg|m)
ant1-pos2          =0          # (deg|m)
ant1-pos3          =0          # (m|m)
ant1-anttype       =
ant1-antdele       =0          # (m)
ant1-antdeln       =0          # (m)
ant1-antdelu       =0          # (m)
ant2-postype       =rinexhead  # (0:llh,1:xyz,2:single,3:posfile,4:rinexhead,5:rtcm,6:raw)
ant2-pos1          =0          # (deg|m)
ant2-pos2          =0          # (deg|m)
ant2-pos3          =0          # (m|m)
ant2-anttype       =
ant2-antdele       =0          # (m)
ant2-antdeln       =0          # (m)
ant2-antdelu       =0          # (m)
ant2-maxaveep      =1
ant2-initrst       =on         # (0:off,1:on)
misc-timeinterp    =on         # (0:off,1:on)
misc-sbasatsel     =0          # (0:all)

posted on 2021-11-17 10:15  tonysss  阅读(403)  评论(0编辑  收藏  举报

导航