
简介面向Galileo卫星导航系统BOC码产生与捕获的MATLAB仿真资源提供了一套可运行的脚本集合。适合通信导航领域的算法研究人员、MATLAB使用者以及卫星定位专业学生用于理解BOC调制原理、验证捕获算法、评估不同参数下的接收性能。压缩包共30个文件以16个m脚本为核心完整覆盖码序列生成、载波模拟、加噪处理、捕获搜索等仿真环节另有11个asv自动保存文件、2个bak备份文件和1个fig图形文件包体仅33KB结构清晰便于查阅和修改。已有181人学习浏览。脚本从BOC码参数设定出发依次构建模拟信号、加入多径与噪声利用滑动相关和FFT运算完成捕获搜索输出相关峰值与信噪比等关键结果读者可按需调整码率、偏移载波频率及噪声条件深入观察不同环境下的捕获性能为Galileo接收机算法设计与工程实现提供直接可复用的代码参考。1. 从Galileo的BOC调制说起为什么捕获代码比想象中麻烦Galileo 系统在 E1 频段使用了 BOCBinary 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 MHzBOC(10,5) 则是副载波 10.23 MHz、码速率 5.115 MHz。工程上最直观的区别在主瓣宽度和副峰位置下面这张表列出常用配置的差异。参数符号BOC(1,1)BOC(10,5)副载波频率f_s1.023 MHz10.23 MHz码速率f_c1.023 MHz5.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 MHzsqrt(10/11)主瓣贡献大BOC(6,1)6.138 MHzsqrt(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)误锁定概率4518.215.42.88%4215.613.12.512%3912.810.91.921%369.78.61.134%可以看到主峰和副峰的高度差随着载噪比降低迅速缩小。门限设置得过低例如取 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.00.5副峰位置 (chip)无±0.5码相位搜索最优步长 (chip)0.50.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 chipBump-Jump 才能真正改善捕获和跟踪的衔接。另一个工程技巧是不要把 Bump-Jump 的跳变阈值设成固定值而要和载噪比联动。低载噪比时阈值提高到 0.15高载噪比时降到 0.08这样能减少虚警副峰对主峰跟踪的干扰。本文还有配套的精品资源点击获取