🛰️SkyStreak

卫星追踪器的逆运算。它不问这颗卫星在哪里,而是问我的视场里是谁——这样照片上一条来历不明的轨迹就能与星表目录进行匹配。

给它一个观测站、一个历元与时间跨度、一个指向(J2000 赤经/赤纬、方位/高度,或从轨道上观察的 LVLH 角)和一个视场。它会找出穿越该视场的每一个已编目对象,并把每条轨迹绘制在真实恒星背景的日晷投影(gnomonic)星图上,可直接与你的照片对比。

观测站本身也可以是一颗卫星(天基空间态势感知):按 NORAD 编号在已加载目录中选择任意对象,扫描就从它的传感器出发——从轨道上看,谁穿过了我的视场。

SkyStreak 由 SatIdentifier 升级而来:在“识别视场中的卫星”这一核心之上,新增条纹匹配、图像叠加配准、多站点并行扫描、观测计划、3D 轨道可视化、众包报告、CLI/API 服务等一整层能力。

screenshot.png

本地 Python 后端(星表获取、缓存、持久化——仅标准库)+ 浏览器前端(Web Worker 中的 SGP4、canvas 星图)。SatObserver-MX 的姊妹项目,共享其架构与代码风格。

模块 API 见 CONTRACT.md;构建过程与测量数据见 DEVLOG.md

核心能力

  • 逆向轨迹识别(基础)——扫描视场内的每一次穿越,逐条绘制轨迹,按来源显示 TLE 时效与星等估算方法。
  • 条纹匹配(Track Match)——照片上一条来历不明的条纹,与候选穿越按位置角、角速率、长度、时间重叠四个分量打分匹配,输出 Top-N 候选并标注 TLE 年龄与测光可信度。条纹可手动录入(RA/Dec 或方向角+长度)、在星图上直接绘制,或从图像叠加的端点拾取。
  • 图像叠加(Image Overlay)——把实拍照片(JPG/PNG 拖放,或 FITS 上传由后端纯标准库转 PNG)叠加到星图上,手动(≥2 点仿射)或自动(亮星提取 + 最小二乘)配准,透明度可调;配准状态随设置持久化。
  • 多站点并行扫描——一个观测计划同时覆盖多个地面/轨道站点,Worker 按站点独立跑完整三阶段,结果按站点分组统计。
  • 观测计划与提醒(Plan)——未来 24h/7d 的过境计划表(最大高度、方位、亮度),一键导出 ICS 日历,过境前系统通知提醒。
  • 深空星表应用内构建——Catalogue 窗口一键后台构建 V≤13 深空瓦片(--vmax 参数化、可续跑、进度轮询),完成后星图自动重探。
  • 3D 轨道可视化——Three.js 场景:地球、站点、轨道线、视场锥;与星图选择联动,双击轨道线反选对象;未安装时优雅降级。
  • 众包报告(Community Reports)——提交未知目标的观测快照(含图像),用匹配引擎回填候选识别,报告存 data/reports.json 本地共享。
  • CLI 批量扫描与 API 服务——python3 server.py --scan config.json -o out.csv 无头批量扫描;POST /api/scan 异步作业(并发上限、取消、CORS 可选),可被任意脚本驱动。
  • 引擎深度——增量扫描(参数哈希差分复用阶段缓存,结果与全量一致)、WebGPU 粗扫(WGSL 移植 SGP4,失败自动回退 CPU)、实验性大气阻力修正(F10.7 指数 + BSTAR 一阶外推,默认关闭)。
  • 体验层——中/英双语 i18n、明暗主题、键盘快捷键、TLE 拖放导入、PWA(离线静态壳 + 移动端触控适配)。

环境要求

打包应用(位于 release/)——无运行时依赖;Python 与恒星目录已内置。获取星表需要联网(缓存数据可离线使用)。完整星表可从 CelesTrak 免账号加载,或——更完整,包含分析对象与新编目对象——从免费的 space-track.org 账号获取(首次使用时保存在本地)。

  • macOSSkyStreak-macOS-arm64.zip):Apple Silicon。未签名——在其他机器上首次启动需右键 → 打开一次。用户数据位于 ~/Library/Application Support/SatIdentifier/(数据目录沿用旧名,升级不迁移数据)。
  • WindowsSkyStreak-windows-x64.zip,如有):由 CI 在 Windows runner 上构建,未在真实硬件上测试——与 SatObserver-MX 的 Windows 构建存在同样的注意事项。

从源码运行(浏览器模式):

  • Python ≥ 3.10 —— 仅标准库,无需任何包
  • 任意现代浏览器(针对 Chrome 开发;打包应用使用 WKWebView)

重建 .apppython3 -m venv .venv-build && .venv-build/bin/pip install pywebview pyinstaller (重新生成图标额外需要 pillow),然后:

sh
复制代码
.venv-build/bin/pyinstaller --noconfirm --clean --windowed \ --name "SkyStreak" --icon build_icon/SkyStreak.icns \ --add-data "app:app" --osx-bundle-identifier "local.skystreak" desktop.py

运行

macOS 应用:解压 release/SkyStreak-macOS-arm64.zip,双击 SkyStreak.app。原生窗口;关闭即退出。

开发 / 浏览器模式

sh
复制代码
python3 server.py

http://127.0.0.1:8476 启动本地服务器并打开浏览器。选项:--port N--no-browser--scan <config.json>(无头批量扫描)、--max-jobs N(并发 API 作业上限)、--api-cors(跨源 API)。或双击 SkyStreak.command。开发模式下数据位于 ./data/

CLI 批量扫描示例

sh
复制代码
python3 server.py --scan scan-config.json -o out.csv

工作流程

  1. 目录——从任一来源加载完整星表:CelesTrak(批量星表文件,无需账号;旧版 TLE 文件省略 2026-07 之后编目的对象)或 Space-Track(完整 GP;需免费账号,保存在本地;完整集合——含分析对象与 6 位编号对象)。可添加 CelesTrak 单对象查询(NORAD / COSPAR / 名称包含,无需账号——同一标签页的 Fetch SATCAT metadata 按钮下载的是驱动测光、而非轨道根数的 SATCAT 表)、McCants 保密轨道根数,或粘贴/拖放 TLE 文件——所有数据合并为一个目录,按 NORAD 去重、以最新轨道根数优先,并且按来源显示根数时效统计,因为陈旧根数是识别失败的主要原因。
  2. 站点——添加观测站并标记为活动。两种类型:地面(经度 / 纬度 / 海拔)或轨道(观测卫星,从已加载目录中按 NORAD 编号或名称选取——TLE 实时从目录解析,因此观测者永远不会相对于目标变陈旧)。勾选多个站点即可并行扫描。
  3. 指向——开始时间、时间跨度、指向、视场。
  4. 过境列表——按下 Scan(扫描),等待三阶段引擎的结果;进度条按站点并行推进。
  5. 星图——将轨迹与你的照片对比。
  6. 条纹匹配——Track Match 窗口录入或绘制照片上的条纹,得到带分数分解的候选列表,点击即定位到对应穿越。
  7. 图像叠加——Image Overlay 窗口把照片直接叠到星图上,自动或手动配准后肉眼比对。
  8. 计划与分享——Plan 窗口生成观测计划并导出 ICS;导出菜单支持 KML(Google Earth 轨道轨迹)、FITS 头(Astropy 可读)、PDF 报告;Community Reports 提交未知目标供本地社区匹配。

从轨道观测(天基空间态势感知)

激活 Orbit 站点后,同一管线为星载仪器回答"谁穿过了我的传感器视场":

  • 方位/高度变为 LVLH 角(标记为 AzL/ElL):Az 从沿轨(速度)方向指向轨道法线,El 从当地水平面指向天顶(径向向外;−90° = 天底)。Mount 跟踪模式变为 LVLH——一台固定在星体上的凝视传感器,以轨道速率漂过星空,正如静止的地面支架以恒星速率漂移。
  • 地球临边遮挡取代地平线:仅当视线穿过地球本身时目标才被剔除,进出场时间以解析视场边缘的同样方式解析目标从临边后方升起。在轨道上永远不做折射修正。
  • 观测者永远不会识别出自己,其自身的 TLE 误差会加入匹配容差——在传感器处它与目标的误差无法区分。
  • All-Sky 是地面地平线投影,在 Orbit 站点上会明确说明;星图对两种站点都适用。

健全性证明同样覆盖轨道几何:关闭几何剔除后返回的穿越集合与开启时完全一致,且每个报告位置与独立的二体重算在 ~0.01″ 内吻合(见 tools/test_scan.js 第 [o] 节)。

它计算什么

  • 穿越:进入 / 最近接近 / 离开时间、角距、赤经/赤纬(J2000)、方位/高度、距离、距离变化率、角速度与位置角、估计星等、光照/半影/本影、轨道类别、TLE 年龄、所属站点(多站点扫描)。

  • 两种角速度,因为哪一种会让你的照片产生条纹取决于你当时的跟踪方式。相对恒星d(RA,Dec)/dt)是恒星跟踪照片上的条纹——注意对地静止对象在这里并非静止,它以 ~15″/s 漂移,这正是 GEO 在跟踪图像中呈短划的原因。相对地平线d(alt,az)/dt)是静止支架所见的景象,此时 GEO 是固定点而恒星在拖尾——在 Orbit 站点上这第二种速率相对 LVLH 坐标系测量,即星体固定凝视传感器记录到的内容。星图绘制与你的跟踪模式相匹配的轨迹,包括静止支架所见到的视场旋转;跨越视场从进入到离开绘制的轨迹,正是应当拿去与照片比对的东西。

  • 条纹匹配分数:位置角、角速率、长度、时间重叠四个分量各自归一化打分,加权求和并逐项分解显示,附 TLE 年龄与测光方法标注。

  • 恒星背景(Gaia DR3):深度随视场自适应——本地分块数据库达到 V = 13,服务于小于 3° 的视野(可在应用内一键构建,或 python3 tools/make_starcat.py --deep-tiles;运行时绝不联网);更宽的视野使用内置星表(V ≤ 10.5,549 037 颗恒星),视场越大深度越浅。深度构建是可选的:开箱即用、不做深度构建时,每个视场都从内置星表绘制,上限为 V = 10.5。星点遵循 Stellarium 的渲染法则,在极限星等处平滑淡出至不可见。太阳/月亮(含月相)、星座叠层、卫星标签与卫星轨迹各有工具栏开关;All-Sky 面板使用亮星集合(V ≤ 4.6)并带有银河辉光。两种视图都没有暮光或日光着色。

    深度是磁盘容量的权衡,而非代码变更。 分块构建器是星等参数化的——同一个 --deep-tiles 构建会写入你要求的任意 --vmax,前端从文件头读取星等上限并自动适配。更深的代价是磁盘与构建时间:

    深度文件大小(约)恒星数(约)适用场景
    V ≤ 11~10 MB~1 M广域寻星;手机存储
    V ≤ 13~60 MB~6 M默认;1° 视场约显示 200 颗恒星
    V ≤ 15~320 MB~30 M窄视场成像(≤ 20′ 视场)
    V ≤ 17~1.4 GB~150 M天体测量级底片;仅限 SSD

    内置 starcat.js(V ≤ 10.5)始终加载并填充宽视野,因此深度分块只在大约 3° 以下才开始起作用——如果你从不拍摄比这更窄的视场,V ≤ 13 就是收益递减点。更深的构建耗时也按比例更长(V ≤ 15 大约需要一天左右的 VizieR TAP 拉取;V ≤ 17 需要数天),且可续跑——重跑即继续。请将分块目录排除在版本控制之外(data/deepstars/ 已在 gitignore 中);make_starcat.py --deep-tiles --vmax 15 --json-status build.json 为长时间会话报告进度。

  • 时间基准:UT1−UTC 差(DUT1)可自动从网络获取(软失败回退 0),F10.7 太阳通量指数缓存 6 小时供阻力修正使用。

精度 — 在信任一次识别之前请先阅读

坐标框架处理刻意严谨,因为本工具要把卫星位置与恒星场对比:

  • 坐标为 J2000 平春分点。SGP4 返回 TEME,而 TEME 不是 J2000——自 J2000 以来的岁差在 2026 年已达 0.36°,是典型望远镜视场的二十倍。完整的 TEME → J2000 旋转(IAU-1976 岁差、IAU-1980 章动、二分点方程)均已应用。已对照 satellite.js 自身的方位/高度路径,在覆盖 LEO/HEO/GEO 与四个站点的 1102 个样本上验证:符合度 1.4e-5 角秒
  • 折射始终施加于方位/高度(El 30° 处 1.7′,El 10° 处 5.4′),且逆运算通过迭代求解,使模式切换完全可逆。

但坐标框架并非限制性误差——轨道根数才是:

量级是否施加?
TLE 位置误差(新鲜 → 一周)~1–20 km ⇒ 在 500 km 距离上7′–2°不可消除
默认忽略 UT1−UTC≤ 0.9 s ⇒≤ 2.9′可选DUT1 设置(可自动)
折射El 30° 处 1.7′,El 10° 处 5.4′始终施加
周年光行差≤ 20.5″否——见下文
光行时 + 轨道光行差(Orbit 站点)各 ≤ ~5″否——比 TLE 误差低两个数量级
岁差 + 章动< 1″

光行差对卫星和恒星都不施加,因此星图与对象保持相互一致;只修正一侧反而会更糟。TLE 年龄逐行显示,也在卫星信息中显示,因为它才是决定一次识别是否可信的数字。

星等是估算值,且大多为先验。 方法逐行显示:

方法含义
qsmagMcCants 标准星等——真实观测值
rcs由 SATCAT 雷达散射截面假定的漫射球体
model有文献记载的星座亮度(Starlink、OneWeb)
type由 SATCAT 对象类型得出的尺寸等级(R/B ≫ PAY ≫ DEB)
default1 m 球体。属于猜测,并如此标注

两个数据事实使低层级成为必需而非可选:CelesTrak 不发布 NORAD 50000 以上的 RCS(实测:40000 以下覆盖率 41–97%,40000–49999 为 25.6%,50000 以上为 0.0%),且 mmccants.org/programs/qsmag.zip 目前返回 HTTP 404。在现代星表上,大多数对象因此落在一个先验值上,真实离散度有一个星等或更多。请勿把星等列当作测光结果。

仓库结构

text
复制代码
server.py Python 3 仅标准库后端:静态文件 + JSON API desktop.py pywebview 原生窗口外壳 SkyStreak.command 双击启动器(开发模式) app/ index.html 按固定顺序加载 CSS 与脚本;PWA 注册 css/app.css 设计系统,暗/亮主题(CSS 变量) manifest.webmanifest PWA 清单;sw.js 网络优先离线静态壳 assets/stars_deep.bin Gaia DR3 至 V=10.5,549 037 颗恒星,5.5 MB(首选) assets/stars_m9.bin Tycho-2 至 V=9.0,130 183 颗恒星,1.3 MB(回退) js/frames.js 坐标框架、岁差/章动、折射、TAN js/propagate.js SGP4 封装与地心视差解 js/scan.js worker 池、合并、预算、增量扫描调度 js/worker/scan-worker.js 三阶段扫描引擎(stage1 筛选/stage2 窗口/stage3 细化) js/worker/gpu.js WebGPU 粗扫(WGSL 移植 SGP4,自动回退 CPU) js/matching.js 条纹匹配评分引擎(PA/速率/长度/时间) js/stars.js 深空恒星目录、锥形查询 js/photometry.js 五层星等模型、地球阴影 js/chart.js 日晷投影星图(主视图),图像叠加层 js/crossings.js 过境列表(主列表),KML/FITS 头/PDF 导出 js/pointing.js 输入窗口 js/allsky.js 带视场足迹的全天背景视图 js/trackmatch.js Track Match 窗口(条纹录入/绘制/匹配) js/imgoverlay.js Image Overlay 窗口(配准/叠加) js/planner.js Plan 窗口(过境计划、ICS、提醒) js/orbit3d.js 3D Orbits 窗口(Three.js) js/reports.js Community Reports 窗口 js/i18n.js 中/英双语字典与 t() 模板 js/state.js util.js clock.js windows.js sources.js locations.js satinfo.js js/vendor/ satellite.js、starcat.js、mwdata.js、three.min.js tools/ make_starcat.py 构建恒星目录资源;--deep-tiles 将本地 V=13 分块集 构建到 data/deepstars/(已 gitignore),--vmax 参数化 scan_cli.js 无头批量扫描(复用 scan-worker 引擎) test_*.js 验证工具——见 DEVLOG test_server.py 后端 API 测试 docs/ 截图 data/ 状态、缓存、凭据、深空恒星分块(已 gitignore)

开源地址

Gitee地址:https://gitee.com/zd_g/sky-streak.git

致谢

SkyStreak 的前身 SatIdentifier——本文档描述的全部基础能力(逆问题框架、坐标框架、三阶段扫描、星等模型)均由其奠基,构建过程与测量数据见 DEVLOG.md

传播: satellite.js(SGP4/SDP4)。恒星:经 VizieR 获取的 Gaia DR3(Gaia Collaboration 2022)与 Tycho-2(Hog+ 2000),以及经由 d3-celestial 的 BSC5/HYG 亮星测光。星表数据:CelesTrak、Space-Track、Mike McCants。扫描的结构——将 SGP4 初始化移出时间循环、旋转指向而非旋转星表、用廉价标量测试为昂贵计算把关——取自 Bill Gray 的 sat_code;岁差处理遵循其 lunar/precess.cpp 中的思路。问题框架受惠于 SatSkyMap

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP