手机地图上的定位圆点跳来跳去、误差三五米,很多人已经习惯。另一类设备在相同天空下却能稳定输出厘米级坐标,差别并不是某颗定位芯片比另一颗强很多,而是解算路径完全不同:普通终端只做基于伪距的单点定位,厘米级终端会继续处理载波相位,并借助基准站差分把公共误差抵消掉。这篇文章从 GNSS 定位方程讲起,把“手机为什么是米级”“厘米级到底依赖哪些原理”“如何搭一条最小验证链路”这几个问题串起来讲清楚。
如果你是做 Android 定位、自动驾驶车载定位、测绘设备选型或物联网高精度方案的人,下面内容会帮助你建立一个可用的技术判断:厘米级定位不是单纯换天线、加账号就能实现,而是一套从原始观测量、差分改正到模糊度固定的完整处理链路。
1. 米级误差来自普通终端无法回避的伪距解算
GNSS 定位的原理并不复杂:卫星把自身位置和发射时间告诉接收机,接收机测量信号从卫星到接收机的时间,乘以光速就得到距离。问题是这个“距离”并不是真的几何距离,中间叠加了卫星钟差、接收机钟差、大气延迟、反射信号和噪声,所以叫伪距。
1.1 卫星定位的数学起点是测距方程
接收机看到至少 4 颗卫星后,可以列出类似下面的观测方程:
P_i = ρ_i + c * (dt_r - dt_s,i) + I_i + T_i + M_i + ε_i ρ_i = sqrt((x - x_s,i)^2 + (y - y_s,i)^2 + (z - z_s,i)^2)其中:
P_i是第 i 颗卫星的伪距观测值ρ_i是卫星到接收机的真实几何距离c是光速dt_r是接收机钟差dt_s,i是第 i 颗卫星的钟差I_i是电离层延迟T_i是对流层延迟M_i是多径误差ε_i是接收机噪声
接收机坐标 x、y、z 和接收机钟差dt_r是未知数,所以理论上至少 4 颗卫星才能解出 4 个未知量。实际定位会把多颗卫星的观测方程线性化,再用最小二乘或卡尔曼滤波求解。
这里容易误解的是:接收机并不直接测量光传播的绝对时间,而是测量信号从卫星发出到被接收机捕获的码相位。手机里的低成本接收机把码相位换算成伪距时,量化误差和噪声会比较明显。普通 GPS C/A 码的码片长度约 293 米,接收机通过相关器把测量精度做到码片的百分之一左右,也只是米级,这是手机单点定位误差很难降到分米级的最底层原因。
1.2 哪些误差把伪距推到了几米
伪距精度并不只取决于码片分辨率,还有很多误差会叠加进最终坐标。下面这张表列出的误差源,在开阔天空和城市环境中的表现差别非常大。
| 误差源 | 产生原因 | 单点定位中的影响 | 主要抑制方法 |
|---|---|---|---|
| 卫星轨道误差 | 广播星历轨道参数精度有限 | 米级残差 | 精密星历、差分、PPP |
| 卫星钟差 | 广播钟差改正后仍有残差 | 米级残差 | 双差、精密钟差产品 |
| 电离层延迟 | 信号穿过电离层产生折射 | 单频最大可达十几米 | 双频组合、差分 |
| 对流层延迟 | 信号穿过中性大气产生弯曲 | 天顶方向数米 | 大气模型、短基线差分 |
| 多径效应 | 信号经建筑物或地面反射后进入天线 | 0.5 米到十几米不等 | 抗多径天线、遮蔽低仰角卫星 |
| 接收机噪声 | 相关器、射频前端、量化误差 | 亚米到米级 | 高增益天线、连续观测平滑 |
| 天线相位中心偏差 | 天线外形导致相位中心不稳 | 亚米级 | 测量型天线 |
在城市里,多径是手机定位误差最直观的来源。高楼玻璃幕墙把卫星信号反射到手机天线上时,接收机可能把反射信号也当成直接信号参与解算,定位点就会突然跳出几十米。即使在空旷区域,手机单点定位通常也很难稳定进入 1 米以内,因为卫星轨道、钟差和大气误差并没有全部消除。
1.3 手机硬件让误差进一步放大
手机的问题是综合性的:
- 天线尺寸小,方向图不够稳定,对低仰角卫星和多径信号缺乏抑制能力
- 射频前端、时钟稳定度和相关器性能都偏向成本和功耗,而不是测量精度
- 为了省电,部分终端不会持续接收所有可见卫星,可能用得更少的观测参与解算
- 系统输出的经纬度往往已经混合了 Wi-Fi、基站和惯性传感器数据,不能直接当作纯 GNSS 精度
所以“手机定位好几米”不是某一个原因造成的。它是码伪距噪声、大气残差、低性能天线、多径和融合策略共同作用的结果。如果你想验证一台手机原始 GNSS 精度到底如何,不能只看地图上的蓝色圆点,而要通过系统 API 拿到伪距、载波频率、信噪比和累积载波相位等原始观测量。
2. 厘米级定位必须从伪距切换到载波相位
厘米级定位之所以能达到厘米,是因为接收机除了用码相位测距,还用载波相位测距。载波相位的波长只有十几厘米到二十几厘米,测量噪声可以做到毫米到厘米级,比码伪距精确得多。
2.1 同样一颗卫星,还存在第二把更精密的尺子
卫星信号里除了伪码,还把伪码调制在正弦载波上。解调伪码后,接收机继续跟踪载波相位,就能测出接收到的载波信号和接收机内部参考载波之间的相位差。
λ * φ = ρ + c * (dt_r - dt_s) - I_φ + T + λ * N + ε_φ其中:
φ是测量到的载波相位λ是载波波长N是整周模糊度,表示接收机开始跟踪时不知道经历了多少个完整波长I_φ是电离层相位延迟ε_φ是载波相位测量噪声
GPS L1 频率 1575.42 MHz 波长约 19.03 厘米,L5 频率 1176.45 MHz 波长约 25.48 厘米。接收机有能力把相位观测做到波长的极小一部分,所以载波相位观测值内部精度很高。代价是存在未知整数N:如果不知道信号到底差了多少个整周,相位测量就不可能直接换算成距离。
2.2 整周模糊度固定是能否到厘米的分水岭
把码伪距和载波相位放在一起看,两者像两把不同精度的尺子:
| 观测类型 | 测量精度 | 是否存在整周模糊度 | 直接定位结果 |
|---|---|---|---|
| 码伪距 | 分米到米级 | 否 | 普通米级定位 |
| 载波相位 | 毫米到厘米级 | 是 | 需要先确定整数 N |
定位算法可以先结合码伪距把坐标和N的浮点值估计出来,这叫浮点解。浮点解给出的坐标可能只有分米到米级,并不稳定。只有当N被约束成整数,并通过模糊度搜索和验证后,坐标才可能进入厘米级,这种解称为固定解。
整周模糊度固定过程中常用的算法是 LAMBDA,它会搜索一组使残差最小且符合整数约束的组合。固定后还要看接收机给出的 ratio 值或固定状态,如果 ratio 太低,说明用户把错误的整数组合也检验通过了,结果不可信。
2.3 没有载波相位,任何差分都不能达到厘米级
很多项目把 RTCM 差分数据接入接收机,就以为会自动变成厘米级。实际上差分数据只是把公共误差消掉了一部分,真正让精度升到厘米级的,是解算链路对载波相位观测量的使用。只处理伪距的差分,即使误差被压到分米级,也很难稳定到厘米级。
如果接收机不给原始载波相位观测值,或者算法内部根本没实现模糊度固定,那不管基准站离得多近、用了多少颗卫星,输出结果也不可能是厘米级。这个判断可以避免很多盲目选型:买设备时除了看“支持 RTK”,还要确认它是否输出载波相位、算法是否能输出固定解状态。
3. RTK 利用差分把公共误差抵消掉
有了载波相位和整周模糊度,还要解决一个现实问题:载波相位观测值里有大气延迟、轨道误差和钟差,单台接收机很难单独把它们消除干净。RTK 的思路是在旁边放一个已知位置的基准站,把双方都能看到的共视卫星误差通过差分抵消掉。
3.1 基准站到底在做什么
基准站放在坐标已经精确测好的位置,它本身并不参与移动端坐标的最终计算,而是持续接收卫星信号,生成原始观测值并通过数据链路发给流动站。
流动站收到基准站数据后,用两颗接收机共同观测到的同一颗卫星做单差,卫星端误差会被减去。再用不同卫星之间做双差,接收机钟差也会被消掉。短基线情况下,卫星轨道误差和大气误差在两端高度相关,双差残差很小。于是整周模糊度更容易固定,坐标就能被解算到厘米级。
这里要分清一个概念:基准站发出的是观测数据或改正数据,不是增强信号。移动端仍然依靠自身天线接收 GNSS 信号,RTK 并不会让卫星信号更强。所以“离基准站越近信号越强”的说法不成立,准确说法是“离基准站越近,两端大气误差和轨道残差相关性越高,模糊度固定越容易”。
3.2 单站 RTK、网络 RTK 和 PPP 的定位思路
实际工程里不会只有一个基准站。不同方案解决同一个问题的侧重点不一样:
| 定位方式 | 数据来源 | 收敛或初始化时间 | 典型精度 | 适用场景 |
|---|---|---|---|---|
| 单站 RTK | 附近一个基准站 | 几秒到几十秒 | 厘米级 | 20 公里以内,测绘、农业、机械控制 |
| 网络 RTK | 多个基准站组成的 CORS 网 | 几秒到几十秒 | 厘米级 | 城市和区域连续运行参考站覆盖区 |
| PPK | 流动站和基准站都记录原始数据,后处理 | 后处理时固定 | 厘米级 | 无人机、林区、信号不连续地区 |
| PPP | 精密卫星轨道和钟差产品 | 通常几分钟到几十分钟 | 分米级到厘米级后期 | 远洋、偏远地区,无基准站可用 |
| PPP-RTK | 卫星钟差、相位偏差和大气产品 | 分钟级 | 厘米级 | 大规模区域台站网 |
单站 RTK 的优点是结构简单,缺点是基线一旦拉长,两端大气误差不再高度相关。网络 RTK 通过多个基准站构建大气误差改正模型,让更大范围内都能快速固定。PPP 不依赖本地基准站,但收敛时间较长,早期阶段精度并不理想。PPP-RTK 则是把两者结合,用地面参考网提供相位偏差和大气改正,缩短收敛时间。
3.3 RTCM 和 NTRIP 的工程意义
差分数据常用 RTCM 格式封装。基准站接收机生成 RTCM 消息流,流动站接收后,从中解出基准站坐标和原始观测量。网络传输通常走 NTRIP,这是一种基于 HTTP 的协议,模拟一个持续下载的数据流。
工程中常见的做法是流动站通过 4G/5G 连接 CORS 平台,输入账号密码和挂载点,持续接收 RTCM 数据。NTRIP 需要的带宽并不高,但对网络延迟和断线恢复有要求。如果数据链路中断,流动站无法得到基准站观测值,整周模糊度需要重新初始化,这段时间内定位结果会退化成浮点解甚至单点解。
4. 搭一条能验证固定解的最小链路
很多人讨论厘米级定位时,停留在“理论可行”的层面。真正要验证一个接收机、一段环境数据或一套算法能不能到厘米级,最有效的方式是搭一条最小链路,让解算结果给出明确的固定状态和坐标残差。
4.1 最低配置清单
最低配置不一定要买昂贵设备。学习阶段可以在开阔场地使用支持 GNSS 原始观测的终端,加上一个能提供差分改正的 CORS 测试账号,用 RTKLIB 做后处理验证。生产验证阶段再换成专用接收机和测量天线。
| 环节 | 学习环境最低要求 | 生产环境建议 |
|---|---|---|
| 流动站设备 | 支持原始 GNSS 观测和双频的设备 | 支持 RTK 的接收机 + 测量型天线 |
| 基准站改正源 | 测试 CORS 账号或已有 RINEX 基准站文件 | 本地基准站或商用网络 RTK 服务 |
| 数据链路 | NTRIP 拉流到本地文件 | 4G/5G、数传电台,带断线自动恢复 |
| 解算软件 | RTKLIB、RTKNAVI、RTKPOST | 商用 RTK 引擎或自研解算程序 |
| 成果验证 | 固定解状态和坐标重复性 | 控制点对比、残差统计、完整质检记录 |
选择 Android 手机做实验时,要确认设备开放 GNSS Raw Measurements,并且系统版本和应用能读取载波相位信息。并不是所有支持 GNSS 的手机都会把累积载波相位、伪距和载波频率完整暴露出来。实验前先采集一段双频观测数据,用 RTKLIB 转换并检查是否有足够多的非零载波相位观测,否则后续固定解验证会很困难。
4.2 实时拉流和后处理两条路线
实时路线可以用 RTKLIB 自带的str2str从 NTRIP 服务器接收差分数据。下面的命令只是结构示例,实际项目要把主机、端口、挂载点、账号和密码替换成自己的配置:
# 从 CORS 接收 RTCM 数据并写入文件,用于后续检查 str2str -in "ntrip://USER_NAME:USER_PASSWORD@cors.example.com:2101/RTCM3" \ -out "file:///data/rtk/rtcm_stream.rtcm3" \ -n 1也可以写一个最简单的 Python NTRIP 客户端,理解数据流是从哪里来的:
import base64 import socket HOST = "cors.example.com" PORT = 2101 MOUNTPOINT = "RTCM3" USER = "your_account" PASSWORD = "your_password" client = socket.create_connection((HOST, PORT), timeout=10) auth = base64.b64encode(f"{USER}:{PASSWORD}".encode()).decode() request = ( f"GET /{MOUNTPOINT} HTTP/1.1\r\n" f"Host: {HOST}:{PORT}\r\n" "Ntrip-Version: Ntrip/2.0\r\n" "User-Agent: NTRIP_TEST\r\n" f"Authorization: Basic {auth}\r\n" "\r\n" ) client.sendall(request.encode()) while True: data = client.recv(65535) if not data: break # 真正的项目里,这段数据要按 RTCM 帧格式解析,再交给 RTK 引擎 process_rtcm(data)后处理路线更适合新手理解原理。把流动站接收机原始观测转成 RINEX 文件,再把基准站 RINEX 观测文件、导航文件一起交给 RTKLIB。处理后查看输出定位状态,如果某段时间状态为固定解,说明那段数据具备厘米级定位条件。后处理的优点是能反复调整参数,不需要实时链路保持稳定。
4.3 影响固定效果的参数不能只看卫星数量
RTKLIB 和商用接收机里都有不少可调参数,不少新人对这些参数理解不足,导致明明天空开阔却一直固定不了。
| 参数 | 作用 | 常见设置 | 设置后要注意的问题 |
|---|---|---|---|
| 截止仰角 | 过滤低仰角卫星 | 学习环境 10 到 15 度 | 设太高会减少可见卫星,设太低会引入多径 |
| 定位模式 | 选择单点/差分/动态/静态 | 移动载体用 kinematic,静态测量用 static | 选错模式会让固定解波动或收敛变慢 |
| 观测频率 | 使用单频还是双频 | 双频优先 | 终端不支持双频时自动降级 |
| 模糊度固定模式 | 是否开启固定解 | 开启,并观察固定状态 | 关闭后即使有 RTCM 也只有浮点解 |
| 基线长度判断 | 判断双差残差是否可信 | 20 公里以内单站 RTK 比较可靠 | 超出后需要网络 RTK |
| 最小 ratio 值 | 判断整周模糊度是否可信 | 常见 3.0 左右 | 设置过高会长时间不固定,设置过低会误固定 |
要看懂这批参数,核心思路是:参数不是为了“让定位更快”,而是为了保证整周模糊度固定结果可信。宁可多等几秒得到固定解,也不要为了追求速度快接受一个错误的固定解。
4.4 怎么判断结果真的到了厘米级
不能只看控制台输出一个经纬度。验证厘米级结果至少要看三类信息:
- 定位状态是否固定。RTKLIB 结果里 Q=1 通常表示固定解,Q=2 是浮点解,Q=5 是单点解。
- 坐标重复性是否稳定。同一位置连续解算,E/N/U 三个方向的波动是否在厘米级。
- 是否和已知控制点做过对比。即使固定解,如果基准站坐标本身错了几米,流动站绝对坐标也会跟着错。
下面是固定解常见的输出片段,具体格式会随软件版本不同变化:
# 示意:列中 Q 表示定位状态,1 为固定解 2024/12/01 00:00:00.000 31.230456789 121.473456789 28.1234 1 23 2024/12/01 00:00:01.000 31.230456790 121.473456788 28.1235 1 24这段结果的 E/N 坐标能在厘米级重复,说明整周模糊度已经固定。如果看到 Q=2 或 Q=5,那么坐标输出再接近某个经验值,也不能当成厘米级成果。
5. 常见问题与排查路径
高精度定位报错不像 Web 服务那样有清晰的 HTTP 状态码。多数情况下是“能定位但精度不对”,所以必须从状态、数据源、环境和设置顺序来排查。
5.1 固定不了、一直 Float 或回到 Single
这是最常见的问题。现象是接收机能看到很多卫星,但解算状态始终是浮点解或单点解。
排查顺序建议如下:
- 先确认流动站是否真的收到了差分改正数据。
- 检查基准站与流动站是否能看到相同的卫星。
- 查看流动站观测文件里是否有连续载波相位,是否有频繁的周跳。
- 缩小基线距离,或改用网络 RTK 改正源。
- 提高截止仰角,把城市多径信号滤掉一部分。
- 检查终端是否支持双频,如果只有单频,固定难度会明显上升。
- 等待一段时间,让滤波收敛后再看固定状态。
如果固定率一直很低,最有效的实验是把流动站搬到房顶或空旷场地,排除多径影响。多径是固定失败和环境强相关的第一因素。
| 现象 | 可能原因 | 处理方向 |
|---|---|---|
| 一直 Float | 卫星数少、基线长、多径强 | 缩短基线、过滤低仰角、换开阔场地 |
| 出现过 Fixed 又掉回 Single | 差分链路过早断开或周跳严重 | 检查 NTRIP 链接、接收机信号连续性 |
| 有 RTCM 但 Q=5 | 观测时段不匹配或数据处理模式错误 | 重新对齐时间,检查基准站 RINEX 文件 |
| 双频设备仍固定不了 | 天线安装位置遮挡严重 | 换外置天线或变更观测点 |
5.2 有差分数据但坐标还是跳
如果已经收到 RTCM 数据,状态也显示固定过,但坐标仍出现跳变,通常不是网络问题,而是观测质量问题。
重点检查这几个方向:
- 运动过程中是否出现整周模糊度重新初始化。固定解跳回浮点解后,坐标会瞬间偏离,等重新固定后跳回。
- 终端天线是否靠近金属物体或乘客身体,造成多径和方向图畸变。
- 是否把基准站和流动站的数据频率、星座类型搞混,部分接收机默认关闭北斗或 BDS-3,导致共视卫星不足。
- 基准站坐标是否来自不同坐标系或不同历元。参考框架不一致会造成固定解准确但绝对坐标偏离的问题。
这里的排查要以“观测质量日志”为准,而不是看地图是否连续。记录卫星信噪比、周跳标记、固定状态和 PDOP 值,就能量化判断坐标跳变是环境问题还是数据问题。
5.3 用手机做实验时容易忽略的问题
手机做高精度定位实验近年来很常见,但有几个隐藏问题:
- 系统可能在息屏或省电模式下停止高频 GNSS 原始观测,导致载波相位不连续。
- 许多手机只有 L1 单频载波相位输出稳定,L5 天线性能参差不齐。
- 地图 App 显示的坐标是融合结果,不是 RTK 解算结果。必须自己从原始 GNSS API 拿数据。
- Android 高精度实验类 App 可能需要位置权限和原始 GNSS 回调无法在后台稳定运行。
想在手机上验证厘米级,至少要先抓取一段连续 GNSS 原始数据,转换成 RINEX 后检查每个历元的卫星数和载波相位连续性。如果原始观测量本来就断续,算法再强也无法做到稳定固定。
5.4 排错时的“日志优先”原则
定位项目排错时最忌讳凭感觉调参数。建议在采集数据的同时记录以下字段:
时间、卫星号、星座、伪距、载波频率、载波相位、信噪比、 周跳标记、定位状态 Q、PDOP、接收机运行状态、RTCM 是否正确到达有了这份日志,你可以快速判断问题发生在射频前端、差分链路、算法参数还是环境遮挡。否则每次实验都会变成盲调,实验结论也缺少可复现性。
6. 工程化落地时要补上的技术保障
厘米级定位从实验到工程,中间还有很大的距离。学习环境里能跑通固定解,不代表生产环境能稳定输出高质量结果。
6.1 学习环境应完成的最小闭环
第一次做实验时,可以按这个顺序走:
- 找