适用范围:RTCM 3、RTCM SSR、IGS SSR 编解码入门
问 题:多电文标识解决什么问题?广播星历、SSR 轨道、钟差和码偏差分别按什么颗粒度封装?
1. 结论
RTCM 中的多电文标识 (Multiple Message Indicator,MMI)是电文头中的一个 1 bit 标志,用于表示:
当前电文是否还有属于同一序列的后续电文。
典型取值如下:
| MMI | 含义 |
|---|---|
1 |
当前电文不是本序列最后一条,后面还有后续电文 |
0 |
当前电文是本序列最后一条;若本序列只有一条电文,也置为 0 |
需要特别注意:
text
MMI=1 不表示"当前电文包含多颗卫星";
MMI=0 也不证明"本序列没有发生丢包"。
对于 IGS SSR,MMI 的正式定义是连接具有相同:
- IGS Message Number;
- SSR Epoch Time;
的连续电文。工程实现时还应检查 Provider ID、Solution ID、IOD SSR 和更新间隔等字段是否一致,避免错误拼接。
2. 为什么需要多电文标识
2.1 一组数据可能装不进一条 RTCM 电文
一个 SSR 历元可能包含:
- 数十颗卫星的轨道改正;
- 数十颗卫星的钟差改正;
- 每颗卫星多个信号的码偏差;
- 每颗卫星多个信号的相位偏差。
单条 RTCM 电文的有效载荷长度有限。当一组数据无法放入一条电文时,编码端需要将其拆成多条各自具有 RTCM 帧头和 CRC 的完整电文。
例如,同一历元的 GPS 轨道改正被拆为三条:
text
第1条:G01~G12,MMI=1
第2条:G13~G24,MMI=1
第3条:G25~G30,MMI=0
接收端看到:
text
MMI=1:继续缓存,后面还有同序列电文。
MMI=0:发送端声明当前序列结束。
#mermaid-svg-mY4QR9ttH8oRfHeh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-mY4QR9ttH8oRfHeh .error-icon{fill:#552222;}#mermaid-svg-mY4QR9ttH8oRfHeh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-mY4QR9ttH8oRfHeh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-mY4QR9ttH8oRfHeh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-mY4QR9ttH8oRfHeh .marker.cross{stroke:#333333;}#mermaid-svg-mY4QR9ttH8oRfHeh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-mY4QR9ttH8oRfHeh p{margin:0;}#mermaid-svg-mY4QR9ttH8oRfHeh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh .cluster-label text{fill:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh .cluster-label span{color:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh .cluster-label span p{background-color:transparent;}#mermaid-svg-mY4QR9ttH8oRfHeh .label text,#mermaid-svg-mY4QR9ttH8oRfHeh span{fill:#333;color:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh .node rect,#mermaid-svg-mY4QR9ttH8oRfHeh .node circle,#mermaid-svg-mY4QR9ttH8oRfHeh .node ellipse,#mermaid-svg-mY4QR9ttH8oRfHeh .node polygon,#mermaid-svg-mY4QR9ttH8oRfHeh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-mY4QR9ttH8oRfHeh .rough-node .label text,#mermaid-svg-mY4QR9ttH8oRfHeh .node .label text,#mermaid-svg-mY4QR9ttH8oRfHeh .image-shape .label,#mermaid-svg-mY4QR9ttH8oRfHeh .icon-shape .label{text-anchor:middle;}#mermaid-svg-mY4QR9ttH8oRfHeh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-mY4QR9ttH8oRfHeh .rough-node .label,#mermaid-svg-mY4QR9ttH8oRfHeh .node .label,#mermaid-svg-mY4QR9ttH8oRfHeh .image-shape .label,#mermaid-svg-mY4QR9ttH8oRfHeh .icon-shape .label{text-align:center;}#mermaid-svg-mY4QR9ttH8oRfHeh .node.clickable{cursor:pointer;}#mermaid-svg-mY4QR9ttH8oRfHeh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-mY4QR9ttH8oRfHeh .arrowheadPath{fill:#333333;}#mermaid-svg-mY4QR9ttH8oRfHeh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-mY4QR9ttH8oRfHeh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-mY4QR9ttH8oRfHeh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mY4QR9ttH8oRfHeh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-mY4QR9ttH8oRfHeh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mY4QR9ttH8oRfHeh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-mY4QR9ttH8oRfHeh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-mY4QR9ttH8oRfHeh .cluster text{fill:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh .cluster span{color:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-mY4QR9ttH8oRfHeh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-mY4QR9ttH8oRfHeh rect.text{fill:none;stroke-width:0;}#mermaid-svg-mY4QR9ttH8oRfHeh .icon-shape,#mermaid-svg-mY4QR9ttH8oRfHeh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-mY4QR9ttH8oRfHeh .icon-shape p,#mermaid-svg-mY4QR9ttH8oRfHeh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-mY4QR9ttH8oRfHeh .icon-shape .label rect,#mermaid-svg-mY4QR9ttH8oRfHeh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-mY4QR9ttH8oRfHeh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-mY4QR9ttH8oRfHeh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-mY4QR9ttH8oRfHeh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 同一历元的轨道改正集合
第1条 RTCM
MMI=1
第2条 RTCM
MMI=1
第3条 RTCM
MMI=0
接收端按序列缓存
识别序列结束
2.2 MMI 解决的是"序列边界(sequence boundary)"问题
MMI 主要解决:
同一逻辑数据集(轨道、钟差、码偏差)被拆成多条 RTCM 电文后,接收端如何识别"后面还有"与"本序列结束"。
它不负责判断每一条分片是否都已收到。
3. MMI 不是什么
3.1 MMI 不是电文序号
MMI 只有 1 bit,不能表示:
- 当前是第几条;
- 总共有多少条;
- 中间是否漏了一条;
- 缺失的是哪一条。
因此,下面的序列:
text
MMI=1 → MMI=1 → MMI=0
只能说明发送端声明了"未结束、未结束、结束",不能证明三条之间没有丢包。
3.2 MMI 不是可靠传输机制
MMI 不提供:
- 丢包重传;
- 分片编号;
- 乱序恢复;
- 超时管理;
- 链路质量保证。
RTCM 帧的 CRC 可以检查当前帧是否发生比特错误,但不能证明某一整帧没有丢失。
因此:
MMI=0表示发送端声明序列结束,不等于接收端已经获得完整数据集。
3.3 MMI 不等于 MSM
RTCM 中还存在多信号观测电文(MSM = Multiple Signal Message)
两者不是同一个概念:
| 名称 | 含义 |
|---|---|
| MMI | 电文头中的续传/结束标志 |
| MSM | RTCM 多系统、多卫星、多信号观测值电文格式 |
MSM 电文中也有类似的多电文标志,但其具体分组条件应按 MSM 规范解释。不能把 SSR、MSM 和其他 RTCM 电文族的 MMI 规则完全混为一谈。
4. 先区分三个层次
理解 RTCM 封装时,应区分:
text
RTCM 传输帧
↓
RTCM 电文类型
↓
电文中的卫星数据块和信号数据块
4.1 RTCM 传输帧
每条 RTCM 帧通常包含:
text
前导码 + 长度 + 电文载荷 + CRC
每条帧都可以独立完成 CRC 校验。
4.2 RTCM 电文类型
电文类型说明载荷表达什么,例如:
- 广播星历;
- SSR 轨道改正;
- SSR 钟差改正;
- SSR 码偏差;
- MSM 观测值。
4.3 卫星块和信号块
一条 SSR 电文通常可以包含多个卫星块;码偏差电文中的每个卫星块又可以包含多个信号偏差块。
因此:
text
"一条 RTCM 电文"
不等于
"一颗卫星"
是否一颗卫星一条电文,取决于具体电文类型。
5. 广播星历:通常一颗卫星一条 RTCM 电文
常见 RTCM 广播星历电文,例如 GPS 1019、GLONASS 1020、BDS 1042、QZSS 1044、Galileo 1045/1046,通常一条电文描述一颗卫星的一套导航参数。
其逻辑结构可以概括为:
text
广播星历 RTCM 电文
├── 电文类型
├── 卫星编号
├── 星历参考时刻
├── 轨道参数
├── 卫星钟参数
├── IOD或等效版本标识
├── 健康状态
└── TGD/BGD、精度指标等其他导航参数
因此,"广播星历是一颗卫星一条电文"在常见 RTCM 3 星历消息中基本成立。
但不能把广播星历理解成只有轨道参数:
一套广播星历通常同时包含轨道、卫星钟、IOD、健康状态、群延迟和精度状态等参数。
5.1 不要混淆卫星导航电文与 RTCM 星历电文
卫星在空中播发导航数据时,一套星历参数可能分布在多个:
- 子帧;
- 字;
- 页;
- 页面类型。
接收机先从卫星信号中完成解调和组帧,再得到一套可用的广播星历参数。
RTCM 星历电文传输的通常是:
text
已经解码完成的一颗卫星星历参数集
而不是把卫星原始导航页逐页原样转发。
5.2 广播星历为何不需要按整个星座组装
每颗卫星的星历可以:
- 独立更新;
- 独立失效;
- 独立进行 IOD 检查;
- 独立参与定位。
因此,常见 RTCM 广播星历电文没有必要利用 MMI 把整个星座的星历拼成一个整体序列。
6. SSR 轨道改正:一条电文可包含多颗卫星
SSR 轨道电文通常采用:
text
公共头 + N个卫星轨道块
逻辑结构如下:
text
SSR 轨道改正电文
├── 公共头
│ ├── SSR Epoch Time
│ ├── SSR Update Interval
│ ├── MMI
│ ├── IOD SSR
│ ├── Provider ID
│ ├── Solution ID
│ └── 卫星数量 N
└── N个卫星轨道块
├── 卫星编号
├── GNSS IOD
├── 径向改正
├── 沿轨改正
├── 法向改正
└── 三个方向的改正变化率
所以:
text
一条 SSR 轨道电文可以包含多颗卫星;
每颗卫星对应一个独立轨道改正块;
卫星数量较多时,可以利用 MMI 拆成多条连续电文。
6.1 轨道改正随时间传播
轨道改正向量可写为:
δO(t)=δO0+δO˙(t−t0)\delta\mathbf{O}(t) = \delta\mathbf{O}_0 + \dot{\delta\mathbf{O}}\left(t-t_0\right)δO(t)=δO0+δO˙(t−t0)
其中:
- δO(t)\delta\mathbf{O}(t)δO(t):时刻 ttt 的轨道改正向量;
- δO0\delta\mathbf{O}_0δO0:参考时刻 t0t_0t0 的轨道改正常数项;
- δO˙\dot{\delta\mathbf{O}}δO˙:轨道改正变化率;
- ttt:计算时刻;
- t0t_0t0:SSR 轨道改正参考时刻。
在径向、沿轨、法向坐标系中:
δO(t)=δOr(t)δOa(t)δOc(t)\delta\mathbf{O}(t) = \begin{bmatrix} \delta O_r(t) \\ \delta O_a(t) \\ \delta O_c(t) \end{bmatrix}δO(t)= δOr(t)δOa(t)δOc(t)
其中:
- δOr\delta O_rδOr:径向改正;
- δOa\delta O_aδOa:沿轨改正;
- δOc\delta O_cδOc:法向或横轨改正。
将其转换到 ECEF 坐标系:
δX=erδOr+eaδOa+ecδOc\delta\mathbf{X} = \mathbf{e}_r\delta O_r + \mathbf{e}_a\delta O_a + \mathbf{e}_c\delta O_cδX=erδOr+eaδOa+ecδOc
其中:
- er\mathbf{e}_rer:径向单位向量;
- ea\mathbf{e}_aea:沿轨单位向量;
- ec\mathbf{e}_cec:法向单位向量;
- δX\delta\mathbf{X}δX:ECEF 坐标系中的卫星位置改正向量。
按照 RTCM/IGS SSR 的符号约定:
Xcorr=Xbrdc−δX\mathbf{X}{\mathrm{corr}} = \mathbf{X}{\mathrm{brdc}} - \delta\mathbf{X}Xcorr=Xbrdc−δX
其中:
- Xcorr\mathbf{X}_{\mathrm{corr}}Xcorr:施加 SSR 轨道改正后的卫星位置;
- Xbrdc\mathbf{X}_{\mathrm{brdc}}Xbrdc:由匹配的广播星历计算得到的卫星位置;
- δX\delta\mathbf{X}δX:由 SSR 轨道改正转换得到的 ECEF 改正向量。
不能仅根据程序变量名猜测正负号,必须以所采用的 RTCM/SSR 规范为准。
7. SSR 钟差改正:一条电文可包含多颗卫星
SSR 钟差电文通常采用:
text
公共头 + N个卫星钟差块
每颗卫星的普通钟差改正通常包含多项式系数:
text
C0、C1、C2
钟差距离改正可写为:
δC(t)=C0+C1(t−t0)+C2(t−t0)2\delta C(t) = C_0 + C_1\left(t-t_0\right) + C_2\left(t-t_0\right)^2δC(t)=C0+C1(t−t0)+C2(t−t0)2
其中:
- δC(t)\delta C(t)δC(t):时刻 ttt 的 SSR 钟差改正,单位通常为米;
- C0C_0C0:钟差改正常数项,单位为米;
- C1C_1C1:钟差改正一次项,单位为米每秒;
- C2C_2C2:钟差改正二次项,单位为米每二次方秒;
- ttt:计算时刻;
- t0t_0t0:钟差改正参考时刻。
按照 IGS SSR 的符号约定:
tsat,corr=tsat,brdc−δC(t)ct_{\mathrm{sat,corr}} = t_{\mathrm{sat,brdc}} - \frac{\delta C(t)}{c}tsat,corr=tsat,brdc−cδC(t)
其中:
- tsat,corrt_{\mathrm{sat,corr}}tsat,corr:施加 SSR 改正后的卫星钟;
- tsat,brdct_{\mathrm{sat,brdc}}tsat,brdc:由广播星历钟参数计算得到的卫星钟;
- ccc:真空光速;
- δC(t)\delta C(t)δC(t):以距离表示的 SSR 钟差改正。
若同时提供高频钟差改正,则完整钟差距离改正为:
δCtotal(t)=C0+C1(t−t0)+C2(t−t0)2+δCHR\delta C_{\mathrm{total}}(t) = C_0 + C_1\left(t-t_0\right) + C_2\left(t-t_0\right)^2 + \delta C_{\mathrm{HR}}δCtotal(t)=C0+C1(t−t0)+C2(t−t0)2+δCHR
其中:
- δCHR\delta C_{\mathrm{HR}}δCHR:高频钟差改正;
- δCtotal\delta C_{\mathrm{total}}δCtotal:普通钟差与高频钟差合成后的总改正。
7.1 钟差和轨道必须保持一致
SSR 钟差不是脱离广播星历独立存在的绝对卫星钟产品。
在 IGS SSR 中:
- 轨道电文的每颗卫星块包含用于匹配广播星历的
GNSS IOD; - 普通钟差电文本身通常不再逐卫星重复该
GNSS IOD; - 钟差改正应与同一服务、同一
IOD SSR和相应轨道改正保持一致。
因此,解码端不能只收到钟差系数就直接使用,还应确认:
text
广播星历
+ SSR轨道
+ SSR钟差
属于一致的数据版本和服务解。
8. SSR 码偏差:多颗卫星,每颗卫星多个信号
SSR 码偏差电文通常是两层可变结构:
text
SSR 码偏差电文
├── 公共头
│ ├── SSR Epoch Time
│ ├── SSR Update Interval
│ ├── MMI
│ ├── IOD SSR
│ ├── Provider ID
│ ├── Solution ID
│ └── 卫星数量 N
└── N个卫星码偏差块
├── 卫星编号
├── 该卫星的偏差数量 Mi
└── Mi个信号偏差块
├── 信号与跟踪模式标识
└── 码偏差值
例如:
text
G01
├── C1C码偏差
├── C1W码偏差
└── C2W码偏差
G02
├── C1C码偏差
└── C2W码偏差
其封装粒度是:
text
一条电文
→ 多颗卫星
→ 每颗卫星多个信号码偏差
不同卫星支持的信号数量可能不同,因此码偏差电文长度是可变的,也更容易被拆成多条 MMI 序列。
8.1 码偏差的符号
在 IGS SSR 的符号约定下,卫星码偏差应加到对应伪距观测值上:
Pcorr=Pobs+bcodeP_{\mathrm{corr}} = P_{\mathrm{obs}} + b_{\mathrm{code}}Pcorr=Pobs+bcode
其中:
- PcorrP_{\mathrm{corr}}Pcorr:码偏差改正后的伪距;
- PobsP_{\mathrm{obs}}Pobs:原始伪距观测值;
- bcodeb_{\mathrm{code}}bcode:对应卫星、信号和跟踪模式的 SSR 码偏差。
实际软件实现时仍应以所使用产品的格式说明和符号约定为准。
8.2 SSR 码偏差不等于广播星历 TGD/BGD
广播星历中的:
- GPS TGD;
- Galileo BGD;
- BDS TGD1/TGD2;
主要描述广播钟基准与指定信号组合之间的群延迟关系。
SSR 码偏差则按具体的:
- 卫星;
- 频点;
- 信号;
- 跟踪模式;
提供更细粒度的偏差参数。
因此:
text
SSR码偏差 ≠ 广播星历TGD/BGD
两者的参考基准、参数定义和使用方式必须分别按相应规范处理。
9. 各类数据的封装粒度对比
| 数据类型 | 一条 RTCM 电文通常包含什么 | 是否可包含多颗卫星 | 是否可能使用 MMI |
|---|---|---|---|
| 广播星历 | 一颗卫星的一套轨道、钟差、IOD、健康状态等参数 | 否 | 常见星历消息不需要 |
| SSR 轨道改正 | 公共头 + 多颗卫星轨道改正块 | 是 | 是 |
| SSR 钟差改正 | 公共头 + 多颗卫星钟差多项式块 | 是 | 是 |
| SSR 高频钟差 | 公共头 + 多颗卫星高频钟差块 | 是 | 是 |
| SSR 码偏差 | 公共头 + 多颗卫星,每颗卫星多个信号偏差 | 是 | 是 |
| SSR 相位偏差 | 公共头 + 多颗卫星,每颗卫星多个信号偏差 | 是 | 是 |
| SSR 轨道钟差组合 | 公共头 + 多颗卫星轨道和钟差联合块 | 是 | 是 |
| MSM 观测值 | 某测站、某历元的多卫星多信号观测值 | 是 | 是 |
10. 轨道、钟差和码偏差的 MMI 序列彼此独立
轨道、钟差和码偏差是不同的电文类型或子类型,通常具有各自独立的 MMI 序列。
例如:
text
轨道第1条:MMI=1
轨道第2条:MMI=0
钟差第1条:MMI=0
码偏差第1条:MMI=1
码偏差第2条:MMI=1
码偏差第3条:MMI=0
不能因为轨道出现了 MMI=0,就认为:
- 钟差也已接收完成;
- 码偏差也已接收完成;
- 整个 SSR 历元的所有产品都已到齐。
更准确地说:
MMI=0只结束当前电文类型或子类型、当前 SSR 历元对应的这一条电文序列。
此外,轨道、钟差和偏差产品可能具有不同的:
- 更新周期;
- SSR 历元;
- 到达时间;
- 有效期。
MMI 不负责同步不同类型的 SSR 产品。
11. 接收端应如何组装 MMI 序列
11.1 建立序列键
对于 SSR 电文,工程上可使用以下字段构造缓存键:
text
SSR格式或版本
+ 电文类型/子类型
+ SSR Epoch Time
+ Provider ID
+ Solution ID
+ IOD SSR
其中:
- 电文类型或子类型区分轨道、钟差、码偏差等产品;
SSR Epoch Time区分不同历元;Provider ID区分服务提供者;Solution ID区分同一提供者的不同解;IOD SSR区分 SSR 生成配置或数据版本。
IGS SSR 对 MMI 的正式连接条件是相同的 IGS Message Number 和 SSR Epoch Time;其余字段适合作为工程一致性检查,不能在不一致时强行合并。
11.2 推荐接收流程
text
1. 完成RTCM帧CRC校验;
2. 解析电文头和序列标识字段;
3. 根据序列键查找或创建缓存;
4. 写入当前电文中的卫星块;
5. MMI=1:继续等待后续电文;
6. MMI=0:结束当前序列并输出已缓存数据;
7. 超时、新历元或关键字段变化:终止旧缓存并标记异常。
伪代码如下:
c
group_key = {
ssr_format_version,
message_type,
ssr_epoch,
provider_id,
solution_id,
iod_ssr
};
append_blocks(cache[group_key], current_message);
if (mmi == 0) {
finalize_sequence(cache[group_key]);
erase_cache(group_key);
}
11.3 必须设置异常处理
接收端至少应处理:
- 等待
MMI=0超时; - 新历元提前到达;
- Provider ID 或 Solution ID 突变;
- IOD SSR 突变;
- 重复卫星块;
- 同一卫星数据冲突;
- 历元倒退;
- 缓存数量过大。
由于 MMI 没有分片序号,即使最终收到了 MMI=0,也不能仅凭 MMI 判断中间是否缺失电文。
12. 代码中的 sync 通常不是时钟同步
在部分 RTCM 编解码程序中,MMI 可能被命名为:
c
sync
该变量通常表示:
text
当前历元或当前序列后面是否还有电文
它通常不表示:
- 卫星钟同步;
- 接收机钟同步;
- 比特同步;
- 载波同步;
- 网络时间同步。
阅读代码时,应根据:
- 所处电文类型;
- 比特位置;
- 标准字段定义;
- 变量参与的缓存逻辑;
判断其真实含义,不能只按变量名理解。
13. 工程上最容易混淆的边界
13.1 MMI=1 不表示当前电文包含多颗卫星
当前电文包含多少颗卫星,由电文中的"卫星数量"字段决定。
MMI 只表示当前序列是否还有后续电文。
13.2 MMI=0 不表示整个 SSR 历元全部结束
它只结束当前电文类型或子类型的序列。
轨道、钟差、码偏差、相位偏差和 URA 等应分别处理。
13.3 MMI=0 不保证没有丢包
MMI 没有分片序号,也没有总分片数。
因此,接收端不能仅凭 MMI=0 证明数据完整。
13.4 广播星历不是只有轨道
一条广播星历 RTCM 电文通常还包含:
- 卫星钟;
- IOD;
- 健康状态;
- 群延迟;
- 精度状态;
- 其他导航参数。
13.5 SSR 轨道不是一颗卫星一条电文
一条 SSR 轨道电文通常包含多颗卫星,每颗卫星对应一个轨道改正块。
13.6 不能只按历元合并
即使历元相同,也不能把不同的:
- 电文类型;
- Provider ID;
- Solution ID;
- IOD SSR;
- SSR 格式版本;
混入同一缓存。
14. 一句话总结
常见 RTCM 广播星历通常是一颗卫星一条电文;SSR 轨道、钟差和码偏差通常是一条电文携带多颗卫星。当同一电文类型、同一 SSR 历元的数据需要拆成多条电文时,MMI 用于表示"后面还有"或"本序列结束"。MMI 只标识序列边界,不提供分片编号,也不能单独证明数据没有丢失。
参考资料
-
International GNSS Service, IGS State Space Representation Format, Version 1.00 , 2020.
-
International GNSS Service, Formats and Standards --- SSR v1.0 .
-
International GNSS Service, Real-Time Service Products .
-
RTCM Special Committee 104, RTCM Standard 10403.x: Differential GNSS Services --- Version 3/4 .