卫星信号模拟器(五):怎么证明你造的信号是对的——四道关卡
系列第五篇(终)。前面四篇把信号从场景一路造到了 DAC,这一篇回答最后一个问题:你怎么知道造出来的东西是对的? 不是"看起来像"就完了,而要像查案一样,一道关卡一道关卡地验。
1. 四道关卡,各验一层
| 关卡 | 验什么 | 判据 | 能定位到哪一层的问题 |
|---|---|---|---|
| 频谱 | 载波频率、调制体制 | 中心频率对、BOC 双峰、载波被抑制 | 载波 DDS、副载波、功率配比 |
| 捕获 | 码相位、多普勒 | 捕获峰明显、多普勒/码相位误差小 | 测距码、多普勒计算 |
| 跟踪 | 环锁定、无偏置 | PLL/DLL 鉴相器收敛到 0 | 相位连续性、符号、正交关系 |
| 电文+定位 | 编解码、几何一致性 | BCH/CRC 通过、ENU 误差 cm~dm | 电文编码、伪距、星历 |
原则:按顺序验,一道不过别进下一道。 每一关的问题都会以"症状"形式在上一关冒头,越早发现越省事。
2. 关卡一:频谱双峰
BOC 调制最鲜明的特征是频谱上主瓣被劈成两个、载波处塌陷。以 B1C 为例,中频 3.996 MHz:
- BOC(1,1) 的两个主瓣骑在中频两侧:
3.996 ± 1.023MHz → 2.973 / 5.019 MHz - BOC(6,1) 的主瓣更靠外:
3.996 ± 6.138MHz → 2.142 / 10.134 MHz - 中频 3.996 MHz 处应该是"凹陷"(BOC 没有载波分量)
验证不需要全频段 FFT,算几个频点的能量就够了(Goertzel 单频检测,几十行):
// 对中频采样 buf[N],在频点 f 上做单频能量检测
double goertzel(const int8_t *buf, int N, double fs, double f)
{
double w = 2 * PI * f / fs, c = 2 * cos(w);
double q0 = 0, q1 = 0, q2 = 0;
for (int n = 0; n < N; n++) {
q0 = c * q1 - q2 + buf[n];
q2 = q1; q1 = q0;
}
double re = q1 - q2 * cos(w), im = q2 * sin(w);
return sqrt(re*re + im*im) / N;
}
实测一个正确的 B1C 信号,比值大致是:2.973/5.019 MHz(BOC11 主瓣)最强,2.142/10.134 MHz(BOC61)次之(因为只占 1/11 功率),3.996 MHz(载波)和噪声底相当。如果载波处出现一个高峰,说明副载波没加上;如果双峰位置不对,说明副载波频率错。
3. 关卡二:捕获
把信号丢进软件接收机跑一次捕获。看两样东西:
| Channel | PRN | Frequency | Doppler | Code Offset | Status |
| 1 | 23 | 3.99900e+06 | 3000 | 304733 | T |
| 2 | 6 | 3.99420e+06 | -1800 | 127845 | T |
- Doppler 要和你的理论值对得上(我们软件复现时,5 颗星的实测多普勒与计算值误差 ≤ 8 Hz);
- Code Offset 要落在合理范围(一个码周期内),且捕获峰明显、旁瓣低。
判据:多普勒误差 ≤ 25 Hz、码相位误差 ≤ 2 个采样点。Doppler 对不上 → 多普勒符号或频率控制字算错;捕获不到 → 测距码错或 PRN 对不上。
4. 关卡三:跟踪
跟踪是"长期一致性"的照妖镜。看三张图:
| 图 | 健康的样子 | 有问题的样子 |
|---|---|---|
| PLL 鉴相器(raw/filtered) | 快速收敛到 0,之后平贴 0 | 有常数偏置、或慢慢漂走 |
| DLL 鉴相器 | 同上 | 同上 |
| 相关值 I²+Q² | 稳定平台 | 周期性塌陷(失锁) |
常数偏置是最有诊断价值的信号:
- PLL 有偏置 → 载波频率/相位关系错(比如 I/Q 符号搞反);
- DLL 有偏置 → 码相位或群延迟错;
remCodePhase线性漂移 → 码频率控制字有小误差。
(附带一个常见困惑:无噪声信号 C/N0 会飙到 80~90 dB-Hz,比真实信号高一倍——这是没加噪声导致的,不是 bug。要测灵敏度就加 AWGN。)
5. 关卡四:电文 + 定位
前两关过了,才轮到这关——因为它依赖的东西最多。
电文:BCH 校验通过、CRC-24Q 通过、解出来的星历字段与编码输入逐字段一致。这里推荐做一个"往返自检":把发送端编码的星历存一份,接收端解出来的比一份,任何比例因子、位宽、交织顺序的错误都会在这里现形。
定位:让接收机解算,看 ENU 误差:
预设坐标:(40°N, 116°E, 50 m)
解算结果:东向/北向/天向误差收敛到 cm~dm 级
定位是终极一致性检查——它同时依赖伪距、多普勒、电文、码、载波五样东西全部自洽。哪怕前面每一关都"看着对",只要伪距里有一个几米的系统性误差(比如漏了相对论改正、电离层符号反了、发射时刻没迭代),定位误差就会把它放大出来。
6. 一条心法:让"验证"也形成证据链
真正可靠的验证不是"跑一遍接收机能定位",而是多个独立来源互相印证。我们复现 B1C 时用了三件事交叉锁定测距码:
- 自己写的生成器 ↔ FPGA 的 Legendre ROM 逐位比对;
- 生成结果 ↔ ICD 表格的八进制码头锚点;
- 发送端编码 ↔ 接收端解交织的逆置换关系。
三条路都指向同一个结果,才敢说"码是对的"。单点验证只能证明"没崩",多点交叉才能证明"对"。
7. 小结(也是全系列的收尾)
把五篇串起来,就是一条完整的认知链:
场景 → 选星 → 伪距/多普勒 → 频率控制字 → 码/载波/副载波 → 调制合路 → DAC
↓
定位误差 cm~dm ← 四道关卡交叉验证 ← 频谱/捕获/跟踪/电文
卫星信号模拟器的难点,从来不在某一环有多高深,而在几百个参数要在码相位和载波相位的每一个 LSB 上都自洽。验证的意义,就是逼着你把这个"自洽"一层层钉死。