资讯

GPS says ~5m accuracy but the fixes agree to 9 cm. Anyone else seen this?

ROS Discourse·2026/9/2 18:29:57🔗 原文

📌 概要

一位机器人开发者发现u-blox接收器标称约5米水平定位精度,但连续定位解之间的实际差值中位数仅约0.1米,最差也只有1米,与白噪声假设下的预期相差达160倍。作者推测接收器内部做了平滑处理,5米指的是含多路径效应的绝对误差,并希望社区验证这一解读。

⚡ 关键要点

  • u-blox接收器标称5米精度,但相邻定位解差异中位数仅约0.1米,相差约160倍
  • 若噪声为5米白噪声,秒差中位数理论上应约14米,实测远低于此
  • 作者推测接收器内部平滑,5米为含多路径的绝对误差而非相对误差

So I’ve been chasing something for a couple of days and I figured I’d just post it, partly in case it helps someone and partly because I’m not totally sure I’m reading it right.

I’ve got a u-blox on a small rover doing 1 Hz fixes. The receiver puts ~5m horizontal 1-sigma in position_covariance, which honestly seemed believable for where I was driving. But then I looked at how much the fixes actually move relative to each other, and the median second difference is around ~0.1 m. The worst one in the whole run was about 1 m. If the noise were really white at ~5m I’d have expected that number to be somewhere around 14 m.

So there’s roughly a factor of 160 between what it says and how it behaves.

My guess, and this is the bit I’d like a sanity check on, is that the receiver smooths internally. So the 5m is the absolute error, mostly multipath, and it’s an honest number. But the fix-to-fix noise is centimetres because consecutive fixes are now heavily correlated. Which would mean the covariance is true, it’s just not the thing a Kalman filter is asking for, since the filter assumes the noise is white and independent.

Anyway, if that’s right then it explains my gate. My NIS sits around 0.03 where it should be near 3, so the chi-squared threshold ends up miles above anything that ever actually happens and nothing can trip it.

Two things I genuinely don’t know:

  1. Is this a u-blox thing specifically, or do other receivers do the same? I’ve only got the one so I can’t really tell.
  2. And what do people actually do about it in practice? Shrinking R feels wrong to me, because then you’d just track the multipath bias and confidently report centimetre accuracy while sitting metres off. I’ve seen a slowly varying GPS bias state mentioned as the proper fix but I haven’t tried it yet.

Here’s the script I used if anyone wants to check theirs. Works on any bag with a NavSatFix, nothing else needed:

#!/usr/bin/env python3
"""python3 gps_cov_check.py """
import sys, math, statistics, rosbag2_py
from rclpy.serialization import deserialize_message
from rosidl_runtime_py.utilities import get_message

bag = sys.argv[1]
r = rosbag2_py.SequentialReader()
r.open(rosbag2_py.StorageOptions(uri=bag, storage_id=""), rosbag2_py.ConverterOptions("", ""))
topic = next(t.name for t in r.get_all_topics_and_types()
if t.type == "sensor_msgs/msg/NavSatFix")
r.set_filter(rosbag2_py.StorageFilter(topics=[topic]))
M = get_message("sensor_msgs/msg/NavSatFix")

lat, lon, sig = [], [], []
while r.has_next():
_, data, _ = r.read_next()
m = deserialize_message(data, M)
if m.position_covariance_type == 0:
continue
lat.append(m.latitude); lon.append(m.longitude)
sig.append(math.sqrt(max(m.position_covariance[0], 0.0)))

R = 6371000.0
xs = [math.radians(v - lon[0]) * R * math.cos(math.radians(lat[0])) for v in lon]
ys = [math.radians(v - lat[0]) * R for v in lat]
d2 = sorted(math.hypot(xs[i+1] - 2*xs[i] + xs[i-1], ys[i+1] - 2*ys[i] + ys[i-1])
for i in range(1, len(xs) - 1))
declared = statistics.median(sig)
observed = d2[len(d2) // 2]
expected = math.sqrt(6.0) * 1.1774 * declared

print("declared 1-sigma %.2f m" % declared)
print("median |2nd difference| %.3f m" % observed)
print(" if that were white %.1f m" % expected)
print("ratio %.0fx smoother" % (expected / max(observed, 1e-9)))

Would be curious what ratio other people get and which receiver you’re on, especially if anyone’s running RTK fixed or something that doesn’t smooth its output. Thanks

1 post - 1 participant

Read full topic