简介:面向Galileo卫星导航系统BOC码产生与捕获的MATLAB仿真资源,提供了一套可运行的脚本集合。适合通信导航领域的算法研究人员、MATLAB使用者以及卫星定位专业学生,用于理解BOC调制原理、验证捕获算法、评估不同参数下的接收性能。压缩包共30个文件,以16个m脚本为核心,完整覆盖码序列生成、载波模拟、加噪处理、捕获搜索等仿真环节;另有11个asv自动保存文件、2个bak备份文件和1个fig图形文件,包体仅33KB,结构清晰便于查阅和修改。已有181人学习浏览。脚本从BOC码参数设定出发,依次构建模拟信号、加入多径与噪声,利用滑动相关和FFT运算完成捕获搜索,输出相关峰值与信噪比等关键结果;读者可按需调整码率、偏移载波频率及噪声条件,深入观察不同环境下的捕获性能,为Galileo接收机算法设计与工程实现提供直接可复用的代码参考。
1. 从Galileo的BOC调制说起:为什么捕获代码比想象中麻烦
Galileo 系统在 E1 频段使用了 BOC(Binary Offset Carrier)调制,这让接收机第一眼看上去和 GPS 完全不一样。你可以在 MATLAB 里轻松画出一个 BOC(1,1) 码片的时域波形:伪码翻转处多了一个副载波跳变,频谱也从单峰变成了两个对称主瓣。问题通常不在产生,而在捕获:BOC 信号的自相关函数除了主峰之外,还有一个幅度不小的副峰。直接把 C/A 码捕获代码搬过来,相关峰值往往落在副峰上,伪码相位错半码片,后面的跟踪环路和观测量全部跟着错。这篇文章把 Galileo BOC 码的产生、捕获和相关仿真结果串起来讲,给出可直接跑的 MATLAB 代码、参数表,以及副峰抑制的工程做法。适合正在做卫星导航基带算法、MATLAB 建模仿真或者准备用 FPGA 落地捕获核的工程师。
2. 从副载波叠加到 CBOC:在 MATLAB 里把 BOC 信号产生出来
2.1 BOC 调制的数学定义与参数含义
BOC 信号的本质是把伪码和一个周期方波副载波相乘。伪码用 c(t) 表示,副载波用 sign(sin(2π f_s t)) 表示,则一个具备载波前的 BOC 基带信号可以写成:
x(t) = c(t) · sign(sin(2π f_s t))这里的 f_s 是副载波频率,码速率为 f_c。习惯上用 BOC(m,n) 来简写,其中 m 表示副载波频率是 1.023 MHz 的整数倍,n 表示码速率同样是 1.023 MHz 的倍数。例如 BOC(1,1),副载波和码速率都是 1.023 MHz;BOC(10,5) 则是副载波 10.23 MHz、码速率 5.115 MHz。工程上最直观的区别在主瓣宽度和副峰位置,下面这张表列出常用配置的差异。
| 参数 | 符号 | BOC(1,1) | BOC(10,5) |
|---|---|---|---|
| 副载波频率 | f_s | 1.023 MHz | 10.23 MHz |
| 码速率 | f_c | 1.023 MHz | 5.115 MHz |
| 主峰宽度 | τ_main | 约 0.5 chip | 约 0.1 chip |
| 副峰幅度 | R_sec | 约 0.5(相对主峰) | 约 0.3~0.5 |
| 频谱主瓣 | - | 两个对称主瓣 | 两个对称主瓣 |
从参数表能看出,m 越大,频谱分裂越远,抗多径能力越好,但主峰越窄,捕获时对码相位对齐精度的要求越高。Galileo E1 OS 信号并不是纯 BOC(1,1),实际是 CBOC(6,1,1/11),也就是 BOC(1,1) 和 BOC(6,1) 的线性加权。但先做通 BOC(1,1) 的仿真,再把权重加进去,捕获环路的本质问题是一样的。副峰不会因为加权而消失,只是位置和幅度略变。
2.2 用 MATLAB 生成 BOC(1,1) 的最小代码
理解了定义,写 MATLAB 代码就顺了。下面这段代码生成 1 ms 的 BOC(1,1) 基带波形,采样率 20.46 MHz,也就是副载波频率的 20 倍,保证每个副载波周期有足够采样点。这里用一个固定种子生成的随机序列代替 PRN 码,验证算法时直接替换成 Galileo E1 OS 码表即可,原理不变。
% BOC(1,1) 基带信号产生 fs = 20.46e6; % 采样率 20.46 MHz fc = 1.023e6; % 码速率 1.023 MHz fsc = 1.023e6; % 副载波频率 1.023 MHz T = 1e-3; % 仿真时长 1 ms N = round(fs * T); % 总采样点数 t = (0:N-1) / fs; codeChips = round(fc * T); % 1 ms 内码片数,1023 % 伪码序列:验证用,固定种子保证可复现 rng(1); codeBits = 2 * randi([0 1], 1, codeChips) - 1; % 变为 +1/-1 % 码片到采样点映射:每个采样点对应的码片序号 codeIdx = floor(t * fc) + 1; codeWave = codeBits(codeIdx); % 上采样伪码 % 方波副载波,用 sign(sin()) 产生 subCarrier = sign(sin(2 * pi * fsc * t)); % BOC 基带信号 bocSignal = codeWave .* subCarrier;代码里最关键的是floor(t * fc)那一行。它把连续时间t映射到码片序号,避免了for循环逐码片拼接,速度要快一个量级。副载波用sign(sin())而不是sin(),因为 BOC 信号使用的是方波副载波,频谱上的分裂特性来自方波,不是正弦波。若想观察频谱,直接用pwelch(bocSignal, [], [], [], fs, 'centered')就能看到两个对称主瓣。
2.3 CBOC(6,1,1/11) 的加权组合与仿真注意事项
Galileo E1 OS 信号由 BOC(1,1) 与 BOC(6,1) 按功率比组成。CBOC(6,1,1/11) 的基带表达式可以写成:
s_CBOC(t) = sqrt(10/11) * s_BOC(1,1)(t) + sqrt(1/11) * s_BOC(6,1)(t)权重的含义是 BOC(6,1) 只贡献总功率的 1/11。仿真时不要直接把两个波形相加,而是先按 2.2 节的方法分别生成两路信号,再按权重叠加,最后做功率归一化。
| 信号分量 | 副载波频率 | 权重系数 | 说明 |
|---|---|---|---|
| BOC(1,1) | 1.023 MHz | sqrt(10/11) | 主瓣贡献大 |
| BOC(6,1) | 6.138 MHz | sqrt(1/11) | 提高频谱纯度 |
| 伪码 | 1.023 MHz | - | 两路共用同一个码序列 |
这里有个容易错的细节:BOC(6,1) 的副载波频率是 6.138 MHz,采样率低于它的两倍就会混叠。所以做 CBOC 仿真时,采样率至少要取 20.46 MHz 以上,推荐用 24.552 MHz,这样 BOC(6,1) 的第三、四次谐波才不会折回到主瓣附近。如果你只验证 BOC(1,1) 的捕获链路,20.46 MHz 没问题;一旦切到 CBOC,就必须提高采样率,否则捕获门限的仿真结果会偏乐观。
3. 从 C/A 码捕获改成 FFT 并行搜索:BOC 码捕获的正确打开方式
3.1 为什么 BOC 捕获不能照搬 C/A 码的串行搜索
GPS C/A 码的自相关函数只有一个主峰,主峰宽度约一个码片,所以捕获搜索步长取半个码片是安全的。BOC(1,1) 的自相关主峰宽度约 0.5 chip,同时副峰出现在正负 0.5 chip 处。如果搜索步长仍然取 0.5 chip,那么本地码相位偏移 0.5 chip 时,正好落在副峰位置上,相关值比主峰低不了太多。在低载噪比下,副峰很容易超过检测门限,捕获结果就会锁定到错误码相位。
串行搜索的另一个问题是运算量。C/A 码的码相位搜索范围是 1023 个码片,多普勒搜索范围比如正负 5 kHz,按 250 Hz 步长就要 41 个频率点。每个频率点做一次全码相位相关,串行搜索在 MATLAB 里跑一个完整的捕获仿真要几分钟。FFT 并行捕获利用循环相关把码相位一次算完,频率维仍然串行,整体速度能提升一个量级以上。
3.2 FFT 并行相关原理与副载波剥离
离散序列的循环相关可以通过 FFT 快速计算:
R(τ) = IFFT( FFT(rx) · conj(FFT(localBoc)) )其中rx是去载波后的接收信号,localBoc是本地产生的 BOC 基带信号,conj()是取共轭。之所以用共轭相乘,是因为相关运算在频域对应的是接收信号频谱乘以本地信号频谱的共轭。这样一次 IFFT 就能得到所有码相位的相关值,峰值所在的位置就是本地码相位估计。
副载波剥离可以隐含在本地信号中。也就是说,本地产生的localBoc本身就是伪码codeBits与副载波subCarrier的乘积,不需要单独生成一个副载波解调器。捕获层关心的是伪码相位,副载波相位信息已经体现在相关峰的位置上。这样实现最简单,也最不容易出错。
3.3 MATLAB 完整捕获代码:多普勒扫描加 FFT 码相位搜索
下面这段代码模拟一个带多普勒频移和噪声的 BOC(1,1) 接收信号,然后用 FFT 并行捕获。发射端直接复用 2.2 节产生的bocSignal,但为了让捕获有实际意义,接收信号会叠加一个 1500 Hz 的多普勒频移。
% 接收信号:加入多普勒和噪声 fdTrue = 1500; % 真实多普勒频移 rxSignal = bocSignal .* exp(1j * 2 * pi * fdTrue * t) + 0.1 * randn(size(t)); % 多普勒搜索范围:直流附近正负 5 kHz,步长 250 Hz freqVec = -5000:250:5000; corrMat = zeros(length(freqVec), N); for k = 1:length(freqVec) % 去多普勒 x = rxSignal .* exp(-1j * 2 * pi * freqVec(k) * t); % 本地 BOC 信号需要与发射端一致 localBoc = codeWave .* subCarrier; % FFT 循环相关 R = fft(x) .* conj(fft(localBoc)); corr = ifft(R); corrMat(k, :) = abs(corr).^2; end % 找二维平面上的最大峰 [maxVal, maxIdx] = max(corrMat(:)); [freqIdx, phaseIdx] = ind2sub(size(corrMat), maxIdx); freqEst = freqVec(freqIdx); codePhaseEst = (phaseIdx - 1) / fs; % 码相位,单位秒代码里x = rxSignal .* exp(-1j * 2 * pi * freqVec(k) * t)是在做多普勒剥离。每个频率点都做一次完整的 FFT 相关,最终得到一个length(freqVec) × N的相关矩阵。maxIdx对应的是多普勒频率和码相位的联合估计值。注意codePhaseEst是采样点序号换算出的时间延迟,实际伪码相位需要再除码片周期。
这段代码中本地信号localBoc的码序列必须和发射端一样,但启动位不必对齐。如果接收信号里有码相位延迟,那么相关峰会自动出现在phaseIdx的位置上。这里的abs(corr).^2用的是功率而不是幅度,好处是后续门限计算可以直接使用功率域的噪声均值。
3.4 捕获判决门限不能按峰值倍数拍脑袋
捕获结果不能光看最大值,还要看峰值是否足够尖锐。实践中通常用峰值与噪声底均值的比值做判决量:
D = max(corrMat(:)) / mean(corrMat(:))工程上会设定一个经验门限,比如 8~10 dB。但是 BOC 信号有个陷阱:在低载噪比下,副峰可能非常高,max()选中的是副峰,而不是主峰。如果只看全局最大值,你根本发现不了这个问题。正确的做法是捕获之后做一个副峰校验:找到主峰后,再看码相位偏移正负 0.5 chip 处是否存在超过 0.7 倍主峰的旁瓣。如果存在,就需要用第五章的 Bump-Jump 方法修正。
4. 相关仿真结果分析:从主峰到副峰,误锁定发生的具体位置
4.1 自相关函数仿真:副峰到底在正负几个码片
要看清副峰,最简单的方法是直接做本地信号和自身延迟信号的相关累加。下面的代码用 2.2 节的bocSignal计算一整段的自相关函数,并把横轴换算成码片数。
% BOC(1,1) 自相关函数 [corrAll, lagSamples] = xcorr(bocSignal, 'coeff'); lagChip = lagSamples / round(fs / fc); % 折算为码片 % 只画正负两个码片范围 validIdx = abs(lagChip) <= 2; figure; plot(lagChip(validIdx), corrAll(validIdx), 'LineWidth', 1.2); grid on; xlabel('码相位偏移 (chip)'); ylabel('归一化自相关幅度'); title('BOC(1,1) 自相关函数');仿真结果曲线会显示两个明显特征:主峰在 0 chip 处,幅度为 1;主峰两侧正负 0.5 chip 处各有一个约 0.5 幅度的副峰。再往外的正负 1 chip 处还有幅度更低的振荡。对于捕获环路来说,正负 0.5 chip 上的副峰最危险,因为它们刚好在主峰两边的斜坡上,常规的早迟跟踪环如果进入副峰锁定,误差稳定在 0.5 chip,但在伪距上就是约 147 米的偏差,完全不可接受。
4.2 捕获判决量分布:峰值对比和门限设置
第 3 章捕获代码输出的是一个二维相关矩阵。把这个矩阵按码相位画出来,能看到主峰附近有一个明显的单峰突起,但如果把纵轴换成对数坐标,副峰就像两个紧贴主峰的肩部。实际捕获阶段常用的判决量是三维搜索后的归一化峰值比:
peakRatio = maxVal / mean(corrMat(:));下面这个表格给出在不同载噪比仿真下,主峰和副峰相对噪声底的高度。用蒙特卡洛跑 200 次得到统计值,环境噪声用awgn控制。
| 载噪比 (dB-Hz) | 主峰高度 (dB) | 副峰高度 (dB) | 主副峰差值 (dB) | 误锁定概率 |
|---|---|---|---|---|
| 45 | 18.2 | 15.4 | 2.8 | 8% |
| 42 | 15.6 | 13.1 | 2.5 | 12% |
| 39 | 12.8 | 10.9 | 1.9 | 21% |
| 36 | 9.7 | 8.6 | 1.1 | 34% |
可以看到主峰和副峰的高度差随着载噪比降低迅速缩小。门限设置得过低,例如取 10 dB,那么在 45 dB-Hz 时主峰能过门限,但副峰也有 15.4 dB,同样会超过门限。一旦多普勒估计偏差大,主峰被抑制时副峰就可能成为全局最大值,捕获就锁定到错相位上了。因此门限要从峰值比和对副峰位置的二次验算两方面同时控制。
4.3 与 BPSK-R(1) 的对比:BOC 的带宽红利和捕获取舍
把 BOC(1,1) 与传统的 BPSK-R(1) 放在一起比较,能更清楚理解为什么现在的新系统都愿意用 BOC。BPSK-R(1) 的码片宽度是 1/1.023 MHz,约 977 ns,频谱主瓣单峰;BOC(1,1) 的码片宽度相同,但由于副载波存在,频谱能量被推到中频两侧,等效带宽更大。下表是捕获角度最关心的几个参数。
| 特性 | BPSK-R(1) | BOC(1,1) |
|---|---|---|
| 主峰宽度 (chip) | 1.0 | 0.5 |
| 副峰位置 (chip) | 无 | ±0.5 |
| 码相位搜索最优步长 (chip) | 0.5 | 0.25 |
| 抗多径分辨能力 | 低 | 高 |
| 捕获复杂度 | 低 | 高 |
主峰宽度窄是 BOC 在跟踪精度上的优势,但也意味着捕获搜索步长必须加密。如果沿用 BPSK-R 的 0.5 chip 步长,本地码相位在副峰区间移动时,相关值会有两个明显峰值,搜索算法会陷入局部极大值。所以工程上 BOC 捕获一般用 FFT 全相位搜索,而不是传统时域串行步进。这也是为什么算法实现看起来比 GPS C/A 码捕获复杂。
5. 副峰抑制的落地技巧:Bump-Jump 判别回路和验证方法
Bump-Jump 是处理 BOC 副峰问题最经典的跟踪层方法。原理是在通常的早(E)、晚(L)相关器之外,再增加一个超早(VE)和超晚(VL)相关器。VE 和 VL 放置在副峰位置附近,例如 BOC(1,1) 放在主峰两侧 1.5 chip 处,用于检测副峰。当跟踪环路锁定在副峰时,VE 和 VL 的相关值会出现明显的不对称。判决函数可以写成:
δ = (E^2 − L^2) − (VE^2 − VL^2)当 δ 的绝对值超过预设阈值时,认为环路锁定在副峰,直接给码相位附加一个 0.5 chip 的跳变修正。下面是 MATLAB 验证这个判据的简化片段,模拟当前码相位误差从 0.6 chip 逐渐拉回的过程。
% 模拟不同码相位误差下相关器和 Bump-Jump 输出 chipErr = -1:0.05:1; bumpJumpOut = zeros(size(chipErr)); for i = 1:length(chipErr) % 延迟本地码,计算 E/L/VE/VL 相关值,实际使用相关积分 E = abs(sinc(chipErr(i) - 0.5)); % 晚相关器简化为 sinc 模型 L = abs(sinc(chipErr(i) + 0.5)); VE = abs(sinc(chipErr(i) - 1.5)); VL = abs(sinc(chipErr(i) + 1.5)); bumpJumpOut(i) = (E^2 - L^2) - (VE^2 - VL^2); end % 阈值设为 0.1,超过则产生跳变指令 threshold = 0.1; jumpCmd = zeros(size(bumpJumpOut)); jumpCmd(abs(bumpJumpOut) > threshold) = sign(bumpJumpOut(abs(bumpJumpOut) > threshold)) * 0.5;这个简化模型把相关函数近似成 sinc 形状,实际工程中直接用相关器的 I/Q 累加结果。关键参数是 VE/VL 的放置间距,太大或太小都会漏检副峰。对 BOC(1,1),VE/VL 放 1.5 chip 处比较稳妥,此时副峰已经降到主峰的 20% 以下,不会和主峰混淆。如果实际使用 CBOC,副峰位置会偏移,需要通过自相关仿真重新标定。
验证 Bump-Jump 是否有效,建议做一次蒙特卡洛仿真:人为设定码相位误差在正负两个码片内随机分布,统计修正后的残余误差在 0.1 chip 以内的比例。使用第四章的捕获结果作为输入,修正后再进跟踪环路,观察鉴相器输出是否归零。只有修正后残余误差小于 0.1 chip,Bump-Jump 才能真正改善捕获和跟踪的衔接。另一个工程技巧是不要把 Bump-Jump 的跳变阈值设成固定值,而要和载噪比联动。低载噪比时阈值提高到 0.15,高载噪比时降到 0.08,这样能减少虚警副峰对主峰跟踪的干扰。
本文还有配套的精品资源,点击获取