手机 RTK/PPK-使用屏蔽面是否很重要呢?
原文来自于cell-phone-rtk-ppk-how-important-is-a-ground-plane,作者rtklibexplorer,这里只是做翻译记录,版权归原作者。
11-17 文章没有翻译完整,第一稿
注意,博主暂时没有太懂ground-plane具体应该翻译成什么词汇,我理解的是ground plane应该是一个屏蔽遏制多路径反射信号的器件,所以在这里翻译成了屏蔽面,如果有朋友知道准确的含义或者有相关的资料还请不吝赐教。谢谢!
在我过去的文章中,我经常强调,为了减小多路径的影响以提高定位解算结果的精度,在收集观测数据时使用一个屏蔽面放在天线底下很重要。这对传统的陶瓷贴片天线来说当然正确,但在用手机收集数据时(为了减少多路径的影响)也很重要。
通常与低成本 GNSS 接收机一起使用的陶瓷贴片天线具有一些内置的防多径保护。它在垂直方向上具有最大增益的方向性,而且还具有圆极化特性,这是由于反射信号与直射信号的极化相反所致。在这种情况下,在天线下面增加一个屏蔽面,通过减弱低仰角信号和消除地平线以下的信号来减少多径,但这只是多径抑制的一部分。
另一方面,手机天线是全方位的,极有可能是线性极化的。因此,它对反射信号几乎没有或根本没有内置的保护。在这种情况下,对抗多路径的唯一防御是屏蔽面,因此它变得更加关键。
最近,我偶然发现了一个非常不错的手机数据集,这个数据集是由几年前我第一篇关于手机解决方案的文章中使用的数据的同一个作者在网上共享的。这张照片是用小米8手机拍摄的,包括40天的静态数据,每次观测时长在10到15分钟之间。每天都有来自三个地点的观测数据,这三个地点头顶的可视情况不同,包括: 开阔环境,部分森林遮挡,以及完全森林遮挡。这些数据之所以特别有趣,是因为在这40天中,有一半的时间采集数据时手机下方都带了一个屏蔽面,而另一半时间是在没有使用屏蔽面的情况下进行的。然后作者声明,带屏蔽面的数据算得的结果比那些从没有屏蔽面得出的结果要精确得多。不幸的是,他们的论文在没有登录服务的情况下是不可用的,但是这里有一个简短的摘要:
在这篇文章中,我将尝试使用他们的数据重复他们的分析,以确认我得到了相同的结果。他们实际上使用了 demo5 RTKLIB 的早期版本进行分析,但我将使用最新版本的代码(b34d)和更新的配置文件。在这次测试中,我只分析开阔场景下的数据,更具挑战性的数据留给另一篇文章。
数据集是非常完整的,其中包含附近基站的观测数据和广播星历数据。最后一点很重要,因为正如我之前提到的,Mi8 Galileo 的导航数据要么存在 bug,要么与 RTKLIB 不兼容。出于这个原因,我使用下载的广播星历数据而不是手机收集的星历数据来处理数据。
我从上一篇关于手机定位的文章中描述的配置文件开始进行测试,但是做了一些修改。我在这篇文章的最后添加了最终配置文件的内容。我将在下文描述我所做的改变。
First of all, this data is static, unlike the previous data, so I changed the solution mode from “kinematic” to “static”.
首先,与以前的数据不同,这些数据是静态的,因此我将解算模式从“kinematic”改为“static”。
接下来,观察用 RTKPLOT 绘制的初始解的残差,我注意到L1和L5之间伪距残差的大小有显著差异。在下图中,左边的图表示 L1残差,右边的图表示 L5残差。载波相位残差相似,但 l5的伪距残差要小得多。这其实并不意外,因为新版L5信号比之前的信号结构更好,功率更高。详细情况在这篇文章中进行了说明。
Solution residuals for L1(left) and L5(right) observations L1(左)和 L5(右)观测值解算结果残差图
为了利用这种差异,我调整了 L1(stats-eratio1)的伪距/载波相位(code/carrier phase)残差ratio值,从300调整到1500,并将L5的错误率(stats-eratio5)设00。这使得在卡尔曼滤波器中,L5伪距观测值的权重比 L1观测更大。在 RTKPOST,这个参数是在“选项Options ”菜单的“统计Statistics ”选项卡中设置的。注意,在 b34d 代码之前,L5错误率(error ratio)参数是存在的,但是不能通过 RTKPOST 的 GUI 界面进行配置,但是现在已经修复了。
接下来,根据下面绘制的观测值的信噪比图,我选择将最小信噪比阈值从34dbHz 降低到24dbHz。这是一个有点随意的设置,可能并不是最佳的,但是对于这个数据集来说,将它保持在34dbHz 会舍弃掉太多可用的卫星。它也可以分别调整 l1和 L5的信噪比阈值,但我没有选择这样做。有趣的是,尽管在之前我们提到L5的信号功率增强了,但是L5的观测信噪比并没有高于 L1。这可能是由于天线性能有限吧。
观测值信噪比,L1(左)和 L5(右)
最后,我将解算结果的类型(RTKPOST 选项菜单中的 Filter 模式)从“ Combined”更改为“ Combined-no phase reset”。这是 demo5代码中一个相对较新的选项。官方的2.4.3代码总是重置前向和后向解之间的相位偏差估计,这是一个更常规的方法。在早期版本的 demo5代码中,如果模糊度的固定方法设置为fix-and-hold来重置相位估计,但没有重置它们。重置它们的原因是为了确保前向和后向解的独立性,但对于较短的数据集,使用收敛后的解作为后向解的起点是有利的。因为在这个实验中,测量时间相当短(10-15分钟) ,所以我选择不重置偏差值。
下一步是对所有40天的数据进行解算。如果要处理的对象是单个数据集并且解算参数设置不同,显然RTKPOST是个不错的选择。但是如果要同时快速处理多个不同的解算数据集时,显然,这时候使用 RTKPOST的命令行版本的RNX2RTKP更容易对这些数据集进行批量处理。我使用一个简单的 python 脚本在多个并发线程中运行 RNX2RTKP (RTKPOST 的 CLI 版本) 来加快解算进程,因为一个 RTKLIB 应用实例只能处理一份数据。我将在下一篇文章中更详细地讨论这个脚本。
然后我用 python 来绘制解算误差,总共40个点,其中有20个点为使用了屏蔽面的结果,另外20个没有。用真值减去每个点对应的解算结果即为误差。
空旷环境下的静态 PPK 解,有与没有使用屏蔽面
请注意,这里的参考真值点是由测量型接收机生成的一个点,它只是手机天线点的一个近似值,因为我们并不知道这个天线在手机的哪个位置。而且手机天线的物理中心参考点和它的相位中心也有偏差线。这里没有对它们进行改正。
正如预期的那样,带屏蔽面的结果比不带屏蔽面的解更加精确。事实上,使用屏蔽面的的20个结果中,19个解的结果相距不到几厘米。而在没有使用屏蔽面的20次测量中,只有7次符合同样的标准。总的来说,我认为这些数据为使用屏蔽面供了一个非常有说服力的论据。我知道在手机的应用中并不总是可以做到这一点,但是至少理解这个选择的意义是很重要的。
研究结果也足以表明,尽管手机的天线性能较差,但至少在开阔环境下,手机正成为一种可行的实用测量方法。同样值得注意的是,虽然没有使用屏蔽面的情况下误差要大得多,但即使是这些解的误差也一直远小于于1米。
重要的是要记住,这些数据都是在开阔环境下获得的,不应该期望在更具挑战性的条件下也能获得如此好的结果。事实是,低成本的接收机(如果)配有高质量的天线也能提供更加健壮和可靠的解决方案。
这个数据集中还有很多数据,我在这篇文章并中处理它们,希望在以后能够进一步了解处理他们。
用于这个实验的配置文件:
\# 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)
原文链接:cell-phone-rtk-ppk-how-important-is-a-ground-plane