Ka 阵面星历下发与执行逻辑说明

Ka 阵面星历下发与执行逻辑说明

一、系统总体架构

整个星历跟踪系统由三层组成:

上位机(PC,Python Flask Web 应用)负责轨道解算、星历点生成、NTP 时钟校正,并通过 UDP 把星历命令发给板子。

下位机(STM32,C 固件)负责接收并解析星历命令,存入点表,按 UTC 到点时刻逐点驱动两个阵面(收发各一路 SPI)的波束指向。

阵面硬件(接收阵面 + 发射阵面)接收下位机通过串口/SPI 下发的补角指令,完成物理波束偏转。

数据流方向:

轨道六根数 → 上位机解算 → UDP → 下位机解析 → 串口/SPI → 收发阵面

二、上位机侧逻辑(web_ctrl.py + orbit.py

2.1 NTP 时钟校正(必须先做)

上位机的时间源是 PC 系统时钟,而 PC 时钟与真实 UTC 之间可能有几十到上百毫秒的偏差。

校正流程:

  1. 向 NTP 服务器(默认 ntp.aliyun.com)连续发 3 次查询

  2. 取 3 次偏差的中位数,滤除网络抖动

  3. 把偏差写入全局变量 `_clock_offset_s`

  4. 之后所有用到"当前时间"的地方调用 `utc_now()`,内部自动做 `系统时钟 - 偏差 = 真实UTC`

这样星历时间戳就对齐了真实 UTC,与板子的惯导 UTC 在同一个基准上。

2.2 轨道解算

输入参数:

  • 历元 UTC(六根数对应的参考时刻)

  • 轨道六根数:半长轴 a(米)、偏心率 e、倾角 i、近地点幅角 ω、升交点赤经 Ω、平近点角 M0(度)

  • 台站经纬度、高程

  • 载频 f0(仅用于计算多普勒,不影响角度)

解算链路:

  1. 用开普勒方程(牛顿迭代)从平近点角 M 求偏近点角 E

  2. 在轨道面内算出位置和速度

  3. 通过三次旋转(Ω, ω, i)变换到 J2000 惯性坐标系

  4. 经岁差矩阵 P、章动矩阵 N 旋转到瞬时真赤道系(TOD)

  5. 绕 Z 轴旋转格林威治真恒星时角(GAST),得到 ECEF 地固坐标

  6. 与台站 ECEF 坐标做差,投影到东北天(ENU)系,得到方位角 az 和俯仰角 el

可选的光行时修正:迭代 2 次求信号传播延迟 τ,用卫星在"发射时刻"而非"观测时刻"的位置来算角度,与 STK 结果对齐。

2.3 星历滚动下发主循环(EphemSim._loop)

核心参数:

| 参数 | 含义 | 典型值 |

|------------|------------------------------|-------------|

| count | 每组点数 | 20(固件上限)|

| step_ms | 相邻两点的时间间隔 | 50 ms |

| lead_s | 提前多久下发下一组 | 1.0 秒 |

| groups | 总组数,0 = 无限 | 0 |

| mask_deg | 仰角门限,低于此不发 | 10° |

一组的时间跨度 = count × step_ms = 20 × 50ms = 1.0 秒。

主循环每一轮做的事情:

  1. 取 group_start(这一组首点应该生效的 UTC 时刻)

  2. 算 group_start 和 group_end 两端的仰角

├─ 两端都 > mask_deg → 进入下发

└─ 任一端 ≤ mask_deg → 跳过,等待卫星升起

  1. 下发:

a. 对 group_start 起的 20 个时刻(间隔 50ms)逐个调用 obs_at() 解算 az/el

b. 拼成一条命令字符串,格式为:

$cmd,set ephem;20;YYYYMMDD,hhmm,ss.sss,az.xxxx,el.xxxx;...(重复20次)...

c. 通过 UDP 发送给板子(send_quiet,日志只记摘要不刷屏)

d. 同时把全部 20 个点的详细数据写入 info 日志,供人工核对

  1. 更新 group_start = 上一组 group_start + 组时长

计算下一组的唤醒时刻 = 新 group_start - lead_s

睡眠等待到唤醒时刻,然后回到第 1 步

时序示意(lead = 1.0s,组时长 = 1.0s):

```

时间轴 ───────────────────────────────────────────►

├── 第1组生效 ──┤├── 第2组生效 ──┤

t0 t0+1s t0+2s

▲发第1组 ▲发第2组 ▲发第3组

(t0-1s) (t0) (t0+1s)

```

每一组在"生效前 1 秒"发出,板子收到后存入 pending 槽,当前组发完自动切入。

2.4 角度约定

上位机下发的是**物理观测角**(也叫天文方位角/仰角):

  • 方位角 az:北为 0°,顺时针增大,范围 0°\~360°

  • 俯仰角 el:水平为 0°,天顶为 90°,范围 0°\~90°

补角转换由下位机完成,上位机不做任何转换。

2.5 命令格式

```

$cmd,set ephem;20;20260908,0425,58.000,295.7839,10.1234;20260908,0425,58.050,295.7854,10.1456;...;

```

各字段含义:

  • `$cmd,set ephem;` 固定前缀

  • `20` 点数(1\~20)

  • 每个点用分号分隔,内部 5 个逗号分隔的字段:

  • `YYYYMMDD` 年月日

  • `hhmm` 时分

  • `ss.sss` 秒(含毫秒)

  • `az` 方位角(度)

  • `el` 俯仰角(度)

  • 末尾可选 `*hh` 校验和(星历命令默认不加)

三、下位机侧逻辑(protocol.c 固件)

3.1 命令接收与解析(ParseEphemCommand)

收到 UDP 包或串口数据后,进入 `ParseCommand` 分发,匹配到 `$cmd,set ephem;` 前缀后调用 `ParseEphemCommand`。

解析过程:

  1. 跳过前缀,用 strtol 提取点数 count(1~20)

  2. 循环 count 次,每次:

a. strtol 取 YYYYMMDD → 拆出年月日

b. strtol 取 hhmm → 拆出时分

c. strtod 取 ss.sss → 秒

d. strtod 取 az → 方位角

e. strtod 取 el → 俯仰角

f. 合法性校验:年 2000~2099、月 1~12、日 1~31、时 0~23、分 0~59、秒 0~60、

方位 0~360、俯仰 0~90

g. 调用 EphemUtcToMs 把 UTC 转成距 2000-01-01 的毫秒数

h. 检查时间戳严格递增

i. 做补角转换:

beam_el = 90° - el(俯仰补角)

beam_az = (360° - az) mod 360°(方位补角)

乘以 100 取整,存为 0.01° 单位的整数

  1. 全部解析成功后,写入 g_ephem_pending 数组,置 pending_ready = 1

  2. 回复 "$cmd,set ephem,ack\r\n"

```

3.2 双缓冲机制(active + pending)

固件用两个数组实现无缝切换:

| 数组名 | 作用 |

|-------------------|--------------------------------------------|

| g_ephem_active | 正在逐点执行的当前组 |

| g_ephem_pending | 提前收到的下一组,等当前组发完后切入 |

`ParseEphemCommand` 每次只写 pending,不会打断正在执行的 active。

切换条件(在 `Ephem_Process` 中检查):

```

if (active_index >= active_count && pending_ready) {

把 pending 复制到 active

active_index = 0

pending_ready = 0

}

```

这样保证:当前组的 20 个点全部发完之后,才切到下一组,不会丢点也不会空档。

3.3 时基建立(Ephem_NowUtcMs)

板子的 UTC 来源是惯导(GNSS/INS),通过串口定时上报。

时间插值方法:

```

当前毫秒 = 惯导最近一帧的UTC毫秒 + (HAL_GetTick() - 收到那帧时的tick)

```

`HAL_GetTick()` 是 STM32 的 SysTick 计数器(1ms 分辨率),用来补偿"惯导帧到达"和"当前检查时刻"之间的延迟。

如果惯导 UTC 还没锁定(`g_gnss_time_valid = 0`),`Ephem_NowUtcMs` 返回 0,`Ephem_Process` 直接跳过不发,避免乱指。

3.4 到点执行(Ephem_Process,主循环中调用)

这个函数在 main 的 while(1) 里被高频调用(每轮主循环都跑一次):

```

  1. now_ms = Ephem_NowUtcMs()

如果 = 0,说明时基没建立,直接返回

  1. 检查是否需要切组(见 3.2)

  2. while 循环:

只要 now_ms >= 当前点的 utc_ms,就立刻执行:

├─ 调用 XW_On_SetBeamAngles1(az, el) → 接收阵面

├─ 调用 XW_On_SetBeamAngles2(az, el) → 发射阵面

└─ active_index++,继续检查下一个点

用 while 而非 if,是为了补发:如果主循环某一轮延迟了,

导致连续多个点都已过期,用 while 可以按序全部补发,不跳点。

```

执行时序示意:

```

时间轴 ─────────────────────────────────────►

点表 P1 P2 P3 P4 ... P20

50ms 50ms 50ms 50ms 50ms

主循环 ↑检查 ↑检查 ↑检查 ↑检查

到P1 到P2 到P3 到P4

发P1 发P2 发P3 发P4

↑ 当 P20 发完后,pending → active,从下一组 P1 继续

3.5 补角与帧下发

存入点表的角度已经是补角(0.01° 单位整数):

```

beam_el_001deg = (int)((90.0 - el) × 100 + 0.5)

beam_az_001deg = (int)(((360.0 - az) % 360) × 100 + 0.5)

```

`XW_On_SetBeamAngles1/2` 把这两个整数打包成阵面控制帧,通过串口4(发射)和串口5(接收)分别下发给两个阵面。两个阵面收到的是同一组角度。

四、完整操作流程

第1步:连接

在网页上确认 IP=192.168.254.27、板子端口=5003、本机端口=6003

点"连接",左上绿灯亮

第2步:验证链路

点"天线姿态"按钮,观察日志有 rx 回包 → 双向通了

第3步:NTP 校正

在"时钟比对"区域点"对网络时间"

日志出现"已写入星历时钟校正"即可

第4步:填轨道参数

历元 UTC、六根数、台站经纬高、载频

第5步:预览确认

点"预览一组"

看俯仰角是否 > 门限(红字 = 低于门限,当前不可见)

看方位角范围是否合理

点"查下次过境"看卫星什么时候过来

第6步:开始滚动下发

确认参数后点"开始滚动下发"

如果卫星还没过境,状态栏显示"等待过境"

卫星升起后自动开始,日志里每组 20 个点逐条打印

第7步:观察

日志里看 tx 摘要和 info 逐点记录

可以开"波束统计"的自动查询,看 call 计数是否在涨

第8步:停止

卫星落下或不需要跟了,点"停止"即可

```

五、关键时序约束

| 约束 | 原因 |

|----------------------------|------------------------------------------------|

| 提前量 ≤ 组时长 | 固件只有一个 pending 槽,提前太多会覆盖还没执行完的组 |

| 点数 ≤ 20 | 固件 EPHEM_MAX_POINTS = 20,数组定长 |

| 时间戳严格递增 | 固件解析时校验,不递增直接拒绝整条命令 |

| 方位 0\~360°、俯仰 0\~90° | 固件解析范围限制,超出返回 ack error |

| 惯导 UTC 必须已锁 | 否则 Ephem_NowUtcMs 返回 0,不执行任何点 |

| NTP 必须先做 | 否则星历时间戳与板子 UTC 有几十毫秒偏差 |

六、故障排查要点

**日志里有 tx 但没有 rx 回包:** UDP 单向通了,检查板子 IP 和本机端口是否为 6003(固件校验源端口)。

**状态一直是"等待过境":** 当前仰角低于门限,看预览里的 el 值。如果历元太旧,累积误差可能导致过境时间偏差几分钟。

**板子回 ack error:** 命令格式不对,检查是否有字段超出范围(方位负数、俯仰负数、时间戳不递增等)。

**波束统计 call 不涨:** 星历点没送到阵面,可能是惯导 UTC 没锁(Ephem_NowUtcMs 返回 0)或者 pending 没切到 active。

**角度偏差大:** 检查历元是否过旧(二体模型不含 J2 摄动,5 天偏差可达 2° 升交点漂移)、NTP 校正是否做了、台站经纬度是否填对。

相关推荐
芯片人0071 小时前
武汉广昇科技的GMUX1308A模拟开关芯片成功导入中国台湾上市企业联昌电子,助力汽车电子供应链自主可控
科技·嵌入式硬件·物联网·汽车·芯片
恒锐丰科技林技术员4 小时前
EG2181D 半桥栅极驱动芯片详解:高压 MOS/IGBT 驱动实用器件
经验分享·嵌入式硬件·硬件工程
国科安芯5 小时前
面向卫星测控应答机的抗辐射MCU信号采集与定时控制研究
单片机·嵌入式硬件·mcu·架构·卫星·商业航天·抗辐射
新晨单片机设计5 小时前
S010A-基于STM32单片机水温控制系统(数码管显示)【Proteus仿真+Keil程序+原理图】
stm32·单片机·嵌入式硬件
事界见闻6 小时前
高性能电机控制MCU选型对比:精度、功耗与实时性如何兼得?
单片机·嵌入式硬件
Brilliantwxx6 小时前
【STM32】 初认识USART串口
linux·stm32·单片机·嵌入式硬件·架构
分享资料7 小时前
用小电容消除高频信号的原因
嵌入式硬件·硬件工程
沐欣工作室_lvyiyi7 小时前
基于STM32的人脸识别门禁系统的设计与实现(论文+源码)
stm32·单片机·嵌入式硬件
zcmodeltech11 小时前
智慧矿山沙盘模型多场景控制系统设计——基于STM32与Modbus RTU的智能开采、无人矿卡、数字孪生全场景联动方案
数据库·stm32·单片机·嵌入式硬件·物联网