深夜提醒

现在是深夜,建议您注意休息,不要熬夜哦~

🏮 🏮 🏮

新年快乐

祝君万事如意心想事成!

share-image
ESC

手表离线也能秒定位?从卫星导航科普到我的智能手表星历改造实录

上个月我干了件有点疯的事:把我那块运动手表的 GPS 辅助定位数据链路完整逆向了一遍,然后用公开的卫星数据自己”造”了一份同样格式的数据,搭了自己的服务器,让我自己的 App 替代官方应用给手表下发星历。

折腾了两周多,最终手表在脱离官方 App 的情况下依然秒级定位。这篇文章把整个过程讲清楚,顺带科普一下天天挂在嘴边的”卫星定位”到底是怎么回事。

先声明:本文章仅供学习交流使用,请勿用于任何商业或不当用途。文中涉及的格式分析仅为个人研究记录。

手表离线也能秒定位?从卫星导航科普到我的智能手表星历改造实录

一、天上到底有哪些卫星?

我们平常说”GPS”,其实只是一个习惯性叫法。天上不止美国人一家有卫星导航系统,目前全球共有 六大卫星导航系统(GNSS),这也是厂商宣传的”六星”:

系统 国家/地区 简称 卫星数
GPS 美国 GPS 31 颗左右
北斗 中国 BDS 30+ 颗(三号系统)
格洛纳斯 俄罗斯 GLONASS 24+ 颗
伽利略 欧盟 Galileo 28+ 颗
准天顶 日本 QZSS 5 颗(区域增强)
NavIC 印度 IRNSS 7 颗(区域)

前四个是全球系统,后两个是区域增强系统(主要覆盖亚太)。所谓”六星定位”,就是接收机能同时搜到这几个系统的卫星一起算位置——天上的”路”多了,高楼之间、树林里自然更容易定位。

我这块手表接收的就是其中五个系统(GPS、北斗、GLONASS、伽利略、QZSS),其中北斗是我日常在国内用得最多的。

二、”双频”又是什么意思?

每颗导航卫星会同时在几个不同频率上广播信号,比如 GPS 的 L1(1575.42 MHz)和 L5(1176.45 MHz)。

信号从两万公里的高空传到地面,要穿过电离层。电离层会让信号传播速度变慢、产生延迟,这个误差最大能到几十米,是定位误差的重要来源。而电离层延迟和频率有关:频率不同,延迟不同。如果接收机能同时收两个频率的信号,就能用这个差异把电离层误差直接算出来消掉,精度可以从”米级”提升到”亚米级”。

这就是”双频”的意义。手表受体积和功耗限制,多数还是单频;手机这几年高端机型基本普及了双频。

三、定位到底在算什么东西?

卫星信号里带着它自己的轨道参数和时间。接收机知道”卫星此刻在哪里”(星历)和”信号走了多久”(伪距),三颗以上卫星就可以列方程解出自己在地球上的位置——本质上是测距交会

这里有两个关键概念:

星历(Ephemeris):精确描述每颗卫星当前轨道参数的”近期档案”,有效期只有 2 小时左右。收齐一颗星的星历通常需要 30 秒(每颗卫星只有特定时刻才广播自己的数据)。

历书(Almanac):所有卫星的”粗略全家福”,精度几公里,但有效期长达数月、收齐只要 12 分钟。它的用途是辅助搜星——让接收机大概知道”朝天上看哪些方向有卫星”。

由此就有了定位界最著名的指标 TTFF(首次定位时间)

  • 冷启动:接收机什么都没有,得先收历书再收星历,可能要 1~2 分钟甚至更久。
  • 热启动:存着星历(2 小时内),几秒内就能出位置。
  • 辅助定位(A-GPS):这就是各家厂商发力的点——通过手机网络把”星历”直接下载下来推给手表,手表开机就”知道”卫星在哪,省掉空中接收的 30 秒,把冷启动压到 10 秒以内。

手表没有 SIM 卡,所以它依赖手机中继:手表通过蓝牙告诉配套 App”我要星历”,App 去云端下载、解码,再通过蓝牙分片传回手表。

四、难点不在”下载”,在”预测”

2 小时有效期的星历,服务器现抓现发就行。但真正的问题是:手表不是天天连着手机的

登山、越野跑、骑行,经常一出去就是三五天,中间手机没电、没网、或者干脆不想带。这就要求辅助数据必须能”预知未来”——在离线的几天里,卫星会走到哪、钟差会变成多少,都要提前算好打包给手表。

所以各大厂商的辅助数据都不是原始星历,而是预测轨道:拿未来若干天的预报星历,拟合成一条时间-位置曲线。我这块表的方案是把未来 3 天切成 36 个窗口(每 2 小时一个),每个窗口内用一组数学系数(我逆向出来是 ECEF 坐标三个方向的 20 阶切比雪夫多项式拟合,分辨率 1 毫米)来描述每颗卫星的轨迹。手表收到后在未来 72 小时内都能”秒定位”,这就是手表离线 3 天也能快速定位的秘密——数据是出发前就”预支”好的

五、我为什么非要自己动手

故事的起因有点哭笑不得:这块表的离线定位越来越依赖官方 App 每天同步,一旦几天没同步,定位就慢得让人崩溃(我实测冷启动最长等到 12 分钟)。

我想要的很简单:永远不依赖官方 App,手表永远有新鲜的星历

分析下来,整条链路是这样的:

  1. 手表通过蓝牙向官方 App 请求几种数据:预测星历、实时辅助数据(AGNSS)、电离层参数,每种数据有个类似 URL 的”标签”(tag);
  2. App 去云端下载一个 seed 文件(JSON,里面是每个星座的轨道数据);
  3. App 内置的一个闭源原生解码库把 seed 解码成手表认识的二进制文件;
  4. 通过蓝牙分片加密传给手表。

我决定把这条链路全部搬到自己的基础设施上:自己造 seed、自己解码、自己打包、自己的 App 应答手表。好处是还能做 A/B 对比实验(同一块表,同一天,两种数据源交替下发,客观对比 TTFF)。

六、我是怎么实现的

1. 逆向格式

先静态分析官方 App 的 Java 层,搞清楚 tag 分派和云端接口;再从手机缓存里拿到 seed 样本。最难的是 seed 里 gpsNav 那段位流:没有文档,只能对着解码库的汇编硬啃。我用”给解码库打补丁强制导出中间值”的办法,拿到了解码过程的内部数据,再拿公开广播星历 propagated 出来的轨道和这些系数做相关性分析,最终确认:那 60 个数就是每颗卫星 ECEF 三维坐标在 12 小时区间上的 20 阶切比雪夫拟合系数

验证方式也很硬核:用官方解码库分别解码”官方 App 抓的 seed”和”我自己造的 seed”,输出文件 MD5 逐字节一致,才算格式通关。

2. 数据从哪来

造数据需要两样公开资料(全部来自 IGS 国际 GNSS 服务,免费):

  • 广播星历 RINEX:全球测站实时汇总的所有卫星当前轨道参数,每天一个文件,滚动更新;
  • 超快速预报轨道 SP3:几家分析中心发布的未来 48 小时卫星精密轨道预报,5 分钟一个点,每小时出新版。

生成器的逻辑:对每个星座每颗卫星,取未来 12 小时区间内的轨道采样点(预报覆盖不到的地方退回用广播星历外推),做 20 阶切比雪夫最小二乘拟合,定点化成 seed 里的位流。采样点必须用 8 点拉格朗日插值——我一开始图省事用线性插值,拟合出来的轨道直接偏了 6 公里。

3. 全链路

公开数据(RINEX + SP3 预报轨道)
→ 我的生成器(切比雪夫拟合,造 seed)
→ 手机上的解码 harness(复用官方解码库)
→ 质量检查(覆盖当前时段?窗口数够不够?)
→ 我的服务器(打包成 zip
→ 我的 App(蓝牙应答手表,加密分片下发)
→ 手表(秒级定位)

服务器端做了双源设计:官方源(从官方 App 缓存里每天自动抓最新 seed 重打包)和我的自造源,可以一键切换,还有兜底巡检脚本——自造数据一旦覆盖不了当前时段,自动切回官方源,保证手表永不断粮。

4. 蓝牙协议

手表和应用之间走蓝牙私有协议:手表先发”我要什么数据”的协商请求,App 回配置,然后手表按文件分片拉取。这里有个大坑后面讲——手表型号对分片加密方式要求不同,我的表必须用 TLV 加密模式,明文传一律被拒,这也是我最初”进度 0%”的根因。

七、自造数据踩过的坑(精华版)

两周时间踩的坑能写满一页 A4 纸,挑几个最有代表性的:

1. JSON 必须紧凑写出。 seed 是 JSON,但解码库按字节偏移读它。Python 默认 json.dump 会带空格分隔,解码器一个字节对不上,静默产出 0 个文件,不报错。排查半天才发现是分隔符问题。

2. 时间必须单调,空段也不能偷懒。 seed 里每颗卫星分 14 个时段。我一开始只更新自己造的那几段,没造的几段留着模板里的旧时间——结果整个时间序列出现”倒退”,解码器判定数据非法,输出全部清零。连续 5 轮测试全是 0/36 个有效窗口。教训:宁可写全零段,也不能留旧时间戳

3. 跨周要回绕。 GPS 系统时间以周为单位(一周 604800 秒),时段结束时间跨周时必须取模回绕,否则一个大于 604800 的数就足以让整份数据被判废。

4. 质量检查差一点,手表就瞎 12 分钟。 我的质量门最初只检查”文件非空”,结果一次自造数据只有 1/36 个有效窗口也上线了,顶掉了手表里 3 天有效的官方数据。那天下午我在室外站了 12 分 17 秒没等到定位。后来质量门改成硬性检查”必须覆盖当前时段”。

5. “手机里有”不等于”手表手里有”。 好多次我兴冲冲测试”新数据生效没”,结果手表根本没来拉——手表按自己的节奏决定何时更新,数据没到期它看都不看。测试效率极低,也是我最终放弃频繁实测的原因之一。

6. 小样本相关性是陷阱。 分析系数含义时,我拿 24 颗卫星做回归,相关系数 0.9+,以为找到了映射关系;扩充到全部 30 颗后相关性掉到 0.49。拟合系数是压缩派生量,不能靠线性回归反推含义——最后是靠”打补丁导出中间值 + 物理验证”才确认。

7. 蓝牙链路”谁占谁应答”。 官方 App 常驻后台会抢走手表的请求。我的解法是平时禁用它,凌晨开一个 15 分钟的窗口让它”借尸还魂”刷新一次 seed,再切回来。

8. 网络环境的坑。 运营商 DNS 解析我自托管域名失败、VPN 全局代理卡住下载——最后加了 DoH 域名解析兜底和禁用代理才稳定。

八、现状与效果

折腾两周后,两条链路都跑通了:

  • 官方源链路(目前线上主用):每天凌晨自动抓最新 seed、解码、打包,手表拿到的永远是 36/36 满窗口、覆盖未来 3 天的数据。实测秒级定位
  • 自造链路:从公开数据到手表全链路打通,手表真实收到过我造的星历。与官方同窗对比,420 个时段里 401 个逐字节一致;我重新生成的时段与官方拟合差约 50 米量级——对辅助定位来说完全够用(它只是帮手表”找星”,最终定位还是靠手表自己收信号解算)。

唯一的差距是前向覆盖时长:公开预报轨道只有未来 24 小时左右,我自造的数据有效期约 21.5 小时,而官方做到了 72 小时。要做到 3 天全自造,需要自己做短弧定轨和轨道外推(我做了个原型,12 小时外推误差 2.4 公里),那是另一个量级的工程量,我暂时不打算继续了——反正双源切换 + 兜底巡检已经能保证手表永不断粮。

九、写在最后

回头复盘,这件事最有价值的部分其实不是结果,而是过程:为了造一份几百 KB 的数据,我把卫星导航、轨道力学、二进制格式逆向、BLE 协议栈全都摸了一遍。”双频””六星””A-GPS”这些天天挂在嘴边的词,拆开看每一个都值得写一篇文章——这篇就算交作业了。

手表现在还戴在我手上,每天凌晨服务器自动刷新星历。它不知道数据是谁发的,只管准时准点地,在我抬腕的那一秒,告诉我我在哪。

再次声明:本文章仅供学习交流,所有格式分析仅为个人研究记录,请勿用于商业或不当用途。

参考资料

文章作者:阿文
文章链接: https://www.awen.me/post/8f3a2c19.html
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 阿文的博客

评论

0 条评论
😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘 🛑📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭 ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️ 🈯💹❇️ ✳️🌐 💠Ⓜ️🌀 💤🏧🚾 🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️
加载中...

留言反馈

😀😃😄 😁😅😂 🤣😊😇 🙂🙃😉 😌😍🥰 😘😗😙 😚😋😛 😝😜🤪 🤨🧐🤓 😎🥸🤩 🥳😏😒 😞😔😟 😕🙁☹️ 😣😖😫 😩🥺😢 😭😤😠 😡🤬🤯 😳🥵🥶 😱😨😰 😥😓🤗 🤔🤭🤫 🤥😶😐 😑😬🙄 😯😦😧 😮😲🥱 😴🤤😪 😵🤐🥴 🤢🤮🤧 😷🤒🤕 🤑🤠😈 👿👹👺 🤡💩👻 💀☠️👽 👾🤖🎃 😺😸😹 😻😼😽 🙀😿😾 👍👎👏 🙌👐🤲 🤝🤜🤛 ✌️🤞🤟 🤘👌🤏 👈👉👆 👇☝️ 🤚🖐️🖖 👋🤙💪 🦾🖕✍️ 🙏💅🤳 💯💢💥 💫💦💨 🕳️💣💬 👁️‍🗨️🗨️🗯️ 💭💤❤️ 🧡💛💚 💙💜🖤 🤍🤎💔 ❣️💕💞 💓💗💖 💘💝💟 ☮️✝️☪️ 🕉️☸️✡️ 🔯🕎☯️ ☦️🛐 🆔⚛️🉑 ☢️☣️📴 📳🈶🈚 🈸🈺🈷️ ✴️🆚💮 🉐㊙️㊗️ 🈴🈵🈹 🈲🅰️🅱️ 🆎🆑🅾️ 🆘 🛑📛 🚫💯💢 ♨️🚷🚯 🚳🚱🔞 📵🚭 ‼️⁉️🔅 🔆〽️⚠️ 🚸🔱⚜️ 🔰♻️ 🈯💹❇️ ✳️🌐 💠Ⓜ️🌀 💤🏧🚾 🅿️🈳 🈂🛂🛃 🛄🛅🛗 🚀🛸🚁 🚉🚆🚅 ✈️🛫🛬 🛩️💺🛰️