
简介面向通信专业学生、研究人员以及正在开展课程设计或毕业设计的开发者这套 MATLAB 与 VPI 联合仿真资源围绕 CO-OFDM 通信系统完整展开。内容涵盖定时同步、频偏估计、信道估计等核心环节源码覆盖基带信号生成、调制映射、信道模拟到接收端算法验证的全流程可作为 CO-OFDM 系统学习与二次开发的基础工程。压缩包共 28 个文件其中 17 个 mat 文件用于保存信道响应和信号中间结果9 个 m 脚本实现关键算法另有 vtmu/vpa 工程文件面向 VPI 硬件在环仿真环境整体仅 6.46MB结构清晰便于快速下载和对照学习。项目兼顾理论验证与实际部署目前已有 2572 人学习下载参考价值较高。通过运行代码读者可以直观理解帧结构设计、载波同步策略与信道补偿方法并基于现有模块展开自己的实验。1. 为什么 CO-OFDM 仿真要把 MATLAB 和 VPI 拆开各管一半CO-OFDM 是把 OFDM 的正交子载波放到相干光链路上传输的方案200G/400G 波分系统基本都在走这条路线。真要仿真整个系统最常见的误区是在一个工具里全干纯 MATLAB 做到光层只能用近似公式代替色散、非线性和激光器相位噪声很难还原真实器件行为纯 VPI 搭激光器、调制器、光纤很容易却要拿一堆模块去拼 QAM 映射、IFFT、信道均衡和相位恢复改一个子载波数就得重拖一遍图迭代效率极低。项目里通用的解法是让 MATLAB 管发射和接收两端的 DSPVPI 管中间那段光学传输两个软件用 I/Q 基带文件交接。这个分工决定了整套通信仿真能跑多快、参数能改多快。下文按发射端 DSP、VPI 光路建模、接收端 DSP、结果验证四段展开适合正在搭相干光通信仿真平台的工程师和光通信方向的研究生。代码基于 MATLAB 的 Communications Toolbox交接方式不依赖两个软件的具体版本。2. 搭 CO-OFDM 发射端MATLAB 里生成 I/Q 基带信号再交给 VPI先想清楚边界。整个 CO-OFDM 系统按功能切成五块信源与调制映射、OFDM 调制、电光转换与光传输、光电转换、OFDM 解调。头两块和最后一块放 MATLAB中间两块放 VPI。判断依据就一条这个模块的数学模型是否封闭、能否用离散公式精确表达。DSP 环节是离散数学MATLAB 的表达成本和修改成本都低光器件环节包含带宽受限、偏置漂移、偏振串扰这类难以用简单公式覆盖的物理效应交给 VPI 的器件库更可靠。两个软件的模块归属对照如下。模块放哪个软件理由信源、QAM 映射、IFFT、加 CP、导频插入MATLAB改调制格式和子载波分配只动几行代码激光器、IQ 调制器、光纤、EDFA、相干接收前端VPI色散、非线性、线宽、偏振由器件模型给出同步、频偏补偿、均衡、相位恢复、BER 统计MATLAB算法迭代快统计脚本好写2.1 发射端 DSP 链路QAM 映射、IFFT 与循环前缀CO-OFDM 发射端至少包含四步比特映射到 QAM 符号、子载波分配、IFFT 得到时域波形、加循环前缀。实际工程里还会加两个增强步骤在子载波里插导频用于接收端的公共相位误差估计在帧头放两段训练序列用于时频同步。下面这段代码把这些都做了输出sI和sQ两个向量就是后面要交给 VPI 的基带 I/Q 信号。% CO-OFDM 发射端基带 DSP生成 I/Q 双路信号供 VPI 光路仿真使用 Nfft 256; % IFFT 长度即总子载波数 Nused 192; % 有效子载波数其余位置挂零做保护带 Ncp Nfft / 4; % 循环前缀长度需大于信道时延扩展 M 16; % 16-QAM Nsym 100; % 数据符号个数 deltaF 39.0625e6; % 子载波间隔决定信道栅格 Fs Nfft * deltaF; % 采样率 10 GHzVPI 端必须用同一个值 % 随机比特 - 16-QAM 符号平均功率归一为 1 pilotIdx 1:24:Nused; % 导频子载波在有效载波中的位置 dataNoPilot setdiff(1:Nused, pilotIdx); % 数据子载波位置 bitsTx randi([0 1], numel(dataNoPilot)*Nsym*log2(M), 1); symTx qammod(bitsTx, M, InputType, bit, UnitAveragePower, true); symTx reshape(symTx, numel(dataNoPilot), Nsym); % 每列一个 OFDM 符号 % 子载波映射直流与频带边缘留空避开器件频响边缘 dataPos [2:97, 160:255]; % 共 192 个有效位置 X zeros(Nfft, Nsym); X(dataPos(dataNoPilot), :) symTx; % 导频子载波填入已知 QPSK幅度与数据星座平均功率相当 pilotSeq (sign(randn(numel(pilotIdx),1)) 1j*sign(randn(numel(pilotIdx),1)))/sqrt(2); X(dataPos(pilotIdx), :) repmat(pilotSeq, 1, Nsym); % IFFT 变到时域加循环前缀后按符号串行化 x ifft(X, Nfft, 1); % 每列一个时域 OFDM 符号 xcp [x(end-Ncp1:end, :); x]; % 符号尾部复制到头部 % 帧结构时频同步前导 信道估计前导 数据段 ts (sign(randn(Nfft/2,1)) 1j*sign(randn(Nfft/2,1)))/sqrt(2); preamble1 [ts; ts]; % 两段重复用于同步与频偏估计 XpreKnown zeros(Nfft,1); XpreKnown(dataPos) (sign(randn(Nused,1)) 1j*sign(randn(Nused,1)))/sqrt(2); preamble2 ifft(XpreKnown, Nfft); % 已知频域响应逐子载波估计信道 txFrame [preamble1; preamble2; xcp(:)]; % 归一化到 ±3.5 V匹配 VPI 中 IQ 调制器的半波电压 drivePk 3.5; normFac drivePk / max(abs(txFrame)); sI real(txFrame) * normFac; sQ imag(txFrame) * normFac; pilotSub dataPos(pilotIdx); % 导频在 256 点频域中的绝对位置 Xpilot X(pilotSub, 1); % 第一个符号的导频参考值 save(cofdm_tx.mat, sI, sQ, Fs, deltaF, Nfft, Ncp, ... dataPos, XpreKnown, pilotSub, Xpilot);逻辑说明qammod的UnitAveragePower选项把 16-QAM 星座平均功率归一为 1后面按峰值归一化到驱动电压时就有确定的比例关系不会因为星座缩放不同导致调制深度忽大忽小。子载波映射里[2:97, 160:255]把直流和频带边缘留空光电器件的频率响应在边缘最不平坦留空可以避免均衡器去补偿不现实的边缘增益。dataNoPilot单独剔除导频位置保证后面 BER 统计时不会把 QPSK 导频当 16-QAM 数据解调。参数说明Nfft256、Ncp64 意味着每个符号总长 320 个采样点10 GHz 采样率下 OFDM 符号周期 3.2 µsCP 时长 6.4 ns。发射信号峰峰值如果超过调制器驱动范围在 VPI 里主要表现为调制器过驱动和非线性失真所以归一化这一步不要省略。2.2 VPI 端光路模块IQ 调制器、光纤与相干接收机VPI 里的系统按下面的信号流搭建顺序不要反两个电信号源分别读入sI、sQ用 VPI 库里的Matlab2VPI组件或文件源取决于版本CW 激光器波长 1550 nm功率 3 dBm线宽 100 kHzIQ 调制器I 路、Q 路各接一个 MZM偏置点设置在 null无驱动时输出为零SSMF 光纤长度 80 km色散系数 16.75 ps/(nm·km)衰减 0.2 dB/km可选加一级 EDFA噪声系数 4~5 dB增益补偿光纤衰减相干接收前端90° 光混频器加两个平衡探测器本振激光器1550 nm线宽 100 kHz与发射端激光器分开建模示波器或文件输出组件把两路电信号存成cofdm_rx.mat这套结构对应的是直接检测做不到的线性场检测相干接收把光场线性映射到 I/Q 两路电信号上后续 DSP 才能对复信号做 FFT。光电转换环节最常见的错误是漏设平衡探测器的带宽——带宽小于信号带宽时高频子载波被低通滤波接收端看到的等效信噪比随子载波频率升高而恶化。基带仿真里探测器和 ADC 的带宽一般设成 0.7 到 1 倍采样率先用 1 倍采样率跑通再收紧到 0.75 倍看代价。2.3 MATLAB 与 VPI 的数据交接采样率对齐与文件握手两个软件交接的点有两个发射端cofdm_tx.mat进 VPI接收端cofdm_rx.mat回 MATLAB。两个方向都必须对齐三件事采样率、信号时长、I/Q 两路的对应关系。采样率不一致是最常见的坑VPI 的信号源组件通常有自己的默认采样率必须显式改成 Fs10 GHz时长对齐则检查 VPI 的仿真时间窗至少覆盖2*Nfft Nsym*(NfftNcp)个采样点对应的 3.25 µs否则信号被截断接收端同步位置就会落在数据段中间。文件交接的替代方案是 VPI 的 Co-Simulation 组件在运行时直接调 MATLAB 引擎省去读写文件但调试可见性差接收端 DSP 一旦出问题很难判断是光路仿真发散还是数据被截断。我一般建议先跑通文件方式算法验证完再考虑换成实时协同仿真。如果 VPI 导出的是 CSV 或文本格式而不是 .mat在 MATLAB 里用readmatrix读入即可但要确认列顺序是[I, Q]而不是[Q, I]——读反了整条链路都会给出错误结果而且波形图上很难看出来。交接方向常见格式必须核对的项目发射信号 MATLAB 到 VPI.mat / .bin / CSV采样率、I/Q 顺序、信号总时长接收信号 VPI 到 MATLAB.mat / .bin / CSV采样率、是否含直流偏置、时域起点运行时 Co-SimMATLAB engine软件版本匹配、数组生命周期、内存释放3. VPI 光层建模参数色散、激光线宽与 IQ 调制器偏置光路部分决定整个系统仿真真实性的上限。MATLAB 里的高斯白噪声模型给不出系统性的光纤损伤VPI 的价值在于把色散、非线性、相位噪声这些效应按物理机制叠加在一起。参数设置建议从最简光路起步单跨 SSMF、无中间放大、不做偏振复用先拿到参考误码率再逐项打开复杂机制。每改一个参数只重跑一个短帧确认方向对了再跑全帧。3.1 光纤参数色散系数、衰减与非线性取舍CO-OFDM 的一个核心优势是用循环前缀吸收色散引起的符号间干扰。色散在 OFDM 里表现为不同子载波经历不同累积相位符号在时域被展宽。判断 CP 够不够可以用下面这段代码快速核算% 核算循环前缀是否能包住色散的时延扩展 D 16.75; % SSMF 色散系数ps/(nm·km) L 80; % 光纤长度km lam 1550e-9; % 中心波长m Bw Nused * deltaF; % 信号带宽约 7.5 GHz dLam Bw * lam^2 / 2.998e8 * 1e9; % 带宽折算成波长宽度nm tauPs D * L * dLam; % 最大群时延差ps cpPs Ncp / Fs * 1e12; % CP 时长ps fprintf(色散时延扩展 %.1f psCP 时长 %.1f ps\n, tauPs, cpPs);80 km、7.5 GHz 带宽下计算出的色散时延扩展只有约 80 ps远小于 6.4 ns 的 CP说明 NcpNfft/4 余量很大工程上可以降到 Nfft/8 来减少开销。真正让 CO-OFDM 仿真变难的不是色散本身而是色散和非线性的耦合光纤非线性会引入子载波之间的交叉调制这种损伤是随机的CP 吸收不了只能靠提高有效信噪比来缓解。VPI 里对应参数是光纤的非线性系数和有效纤芯面积扫描发射光功率时两者保持常数观察星座图外圈是否出现向内收缩即可判断非线性是否进入影响区。3.2 激光器与本振线宽决定 CO-OFDM 相位噪声地板相干系统里发射激光器和本振激光器各贡献一份相位噪声两者合起来在接收端表现为 OFDM 符号内各子载波共享的随机相位旋转外加少量高频抖动。慢变部分是公共相位误差可以用导频估计并补偿快变部分补偿不掉最终表现为星座点云变厚、误码率抬高。VPI 里线宽参数默认值往往偏乐观建议从 100 kHz 起步逐步加到 1 MHz 观察代价。线宽每放大一个量级高 OSNR 区的误码率平台就会上移一截这是判断相位噪声是否成为瓶颈的最直接信号。参数推荐起始值调偏后的典型现象排查方向发射与本振激光线宽各 100 kHz1 MHz 以上时星座点成环状云先归零跑一次确认损伤消失发射光功率3 dBm功率过高时外圈星座向内收缩逐 dB 扫描找误码率拐点光纤长度80 km过长时 CP 失效误码率出平台缩短长度对照区分色散与非线性EDFA 噪声系数4~5 dB噪声系数愈大OSNR 代价愈高同时记录 OSNR别只看入纤功率本振频偏0 或小偏置超过半倍子载波间隔时子载波错位先在 MATLAB 同步算法中清零验证这里单独提一下本振频偏现实中收发激光器波长不可能完全一致仿真里故意加一个 5 MHz 左右的频偏可以验证接收端频偏估计算法是否工作正常。频偏超过半倍子载波间隔约 19.5 MHz时子载波会整体错位频偏估计结果跳变一个整数子载波这是正常现象不是算法 bug。3.3 IQ 调制器偏置点与 VPI 仿真的常见坑IQ 调制器的偏置点决定载波抑制程度。CO-OFDM 工作在 null 点无驱动时输出光功率为零频谱上不残留载波分量偏置一旦偏离 null输出中会出现一个与信号相干的光载波接收端表现为星座图整体偏移。VPI 的 MZM 模型允许直接设偏置电压验证方法是看发射光谱null 点下光谱中心没有尖锐的载波线。另一个高频坑是 VPI 仿真发散。常见诱因有三个驱动信号幅度超过调制器允许范围导致数值振荡、光纤分步长设置过大、信号源采样率与系统采样率不一致导致插值尖峰。遇到发散先别急着调光纤参数而是把sI、sQ的峰峰值打印出来看是否超过半波电压再用更细的光纤分步长重跑一次确认发散与步长无关后才值得怀疑器件设置本身。多数发散从头几步就发生原因就是数值设置问题。另外相干接收机的平衡探测器如果有直流偏置没清零导出的rI、rQ会带着直流分量接收端 FFT 后直流子载波上的残留会污染邻近子载波遇到这种情况在 MATLAB 里先减掉均值再进 DSP。4. 接收端 MATLAB 解调符号同步、频偏补偿、CPE 与 BER接收端 DSP 的处理顺序是固定的时域同步找帧起点、频偏补偿、去 CP、FFT、信道均衡、公共相位误差补偿、QAM 解映射、统计 BER。顺序不能乱特别是频偏补偿必须在 FFT 之前做否则子载波之间的正交性被破坏均衡器无法修复。下面按这个顺序给出一段可直接运行的接收端代码与 2.1 节发射端的变量一一对应。%% CO-OFDM 接收端 DSP读回 VPI 仿真结果并解调 load(cofdm_rx.mat, rI, rQ); % VPI 导出的两路电信号 r rI 1j*rQ; % 合成复基带信号 % 1) 延迟相关同步与频偏估计利用两段重复的时频前导 L Nfft / 2; % 重复段长度128 个采样点 corr r(1:end-L) .* conj(r(1L:end)); Mcorr movmean(corr, L); % 滑动窗平均压制噪声 [~, d] max(abs(Mcorr)); % 粗同步点前导起始位置附近 cfo angle(Mcorr(d)) / pi; % 归一化频偏单位是子载波间隔 % 2) 频偏补偿逐采样点旋转相位 n (0:length(r)-1).; r2 r .* exp(-1j * 2 * pi * cfo * n / Nfft); % 3) 帧内截取信道估计前导与数据段 rPreamble r2(d Nfft 1 : d 2*Nfft); % 信道估计前导 rData r2(d 2*Nfft 1 : d 2*Nfft Nsym*(NfftNcp)); rxMat reshape(rData, Nfft Ncp, Nsym); rxMat rxMat(Ncp1:end, :); % 去掉循环前缀 R fft(rxMat, Nfft, 1); % 每列一个频域符号 % 4) 用已知前导做 LS 信道估计再做零迫均衡 Rpre fft(rPreamble, Nfft); Hest Rpre ./ XpreKnown; % 逐子载波相除得到信道频响 Rdat R ./ Hest; % 单抽头均衡子载波间互不影响 % 5) CPE 补偿用各符号内的导频子载波估计公共相位误差 Yp Rdat(pilotSub, :); % 导频处的接收值 Hp Hest(pilotSub, :); % 导频处的信道频响 cpe angle( sum( Yp .* conj(Xpilot(:) .* Hp), 1) ); % 每符号一个相位 Rc Rdat .* exp(-1j * cpe); % 整符号相位回旋 % 6) QAM 解映射与 BER 统计只统计数据子载波 symRx Rc(dataPos(dataNoPilot), :); bitsRx qamdemod(symRx, M, OutputType, bit, UnitAveragePower, true); ber mean(bitsRx(:) ~ bitsTx(:));4.1 训练序列与符号同步接收端同步有两种常见做法。一种是这里用的延迟相关法利用两段完全相同的重复结构对相距 L 个采样点的样本做共轭相乘真实信号段的相位是固定的噪声段的相关值随机起伏滑动平均后峰值位置就是帧起点。另一种是互相关法用本地存储的训练序列与接收信号逐点相关峰值更尖锐但计算量大而且对频偏敏感频偏稍大相关峰就会被抹平。延迟相关法对频偏不敏感适合先做粗同步。同步点 d 有正负十几个采样点的偏差没有关系。循环前缀会吸收这部分定时误差星座图不会有明显恶化如果偏差超过 NcpFFT 窗口跨越符号边界子载波间干扰会显著上升星座图出现规律性旋转这时要回到 d 的搜索范围上找原因。4.2 载波频偏估计与补偿延迟相关的相位差公式是 Δφ 2π·f_off·L/Fs。这里 L Nfft/2Fs Nfft·Δf代进去得到 Δφ π·f_off/Δf。所以angle(Mcorr(d))除以 π 就得到以子载波间隔为单位的频偏取值范围是 [-1, 1)。如果实际频偏超过一个子载波间隔估计结果会折叠表现为子载波整体移位可以用后续均衡后的导频残差做整数倍频偏修正。代码里频偏补偿用exp(-1j*2*pi*cfo*n/Nfft)这是把cfo以子载波间隔为单位折算回每个采样点的相位旋转量。补偿必须在 FFT 之前否则 OFDM 子载波的正交性已经被破坏频域的均衡器只能做幅度和相位修正救不回跨子载波的泄漏。4.3 信道均衡与公共相位误差补偿信道估计用第二个前导做 LS 估计发射端已知该前导在所有有效子载波上的复数值XpreKnown接收端对其做 FFT 得到Rpre两者逐点相除即得信道频响Hest。CO-OFDM 的均衡是典型的单抽头频域均衡每个子载波独立乘一个复数因子复杂度低且没有稳定性问题。注意前导符号两段重复结构只在偶数子载波上有能量所以信道估计必须用独立的第二个前导不能拿时频同步前导来估计信道。公共相位误差的来源是激光器线宽它在每个 OFDM 符号内表现为所有子载波共享的一个随机相位。估计公式是 φ angle(Σ Y_p·conj(H_p·X_p))其中 p 遍历导频子载波。这个估计量在高 OSNR 下接近无偏但导频数量太少时估计方差大实际系统里导频子载波数一般要占到有效子载波的 4%~8%。代码里每隔 24 个子载波放一个导频共 8 个占 192 个有效子载波的 4.2%属于偏保守的配置如果相位噪声严重可以加密到每隔 16 个子载波放一个。4.4 BER 统计口径BER 统计有一个容易被忽略的细节统计窗口必须排除导频子载波、保护带和空子载波。代码里用dataPos(dataNoPilot)才取到真正的数据位置如果直接取dataPos导频的 QPSK 符号会被当成 16-QAM 解调BER 会偏低。统计时还要保证比特样本量足够100 个符号、184 个数据子载波、16-QAM 共产生 73600 个比特只够在 BER 高于 1e-3 时给出参考值要看到 1e-4 以下的曲线需要把 Nsym 加大到 1000 以上或者多个 OSNR 点重复跑取平均。统计项建议口径统计范围剔除保护带、导频后的有效数据子载波最小比特样本至少 1e6 比特BER 曲线才平滑有效下限累计至少 100 个错误比特否则用置信区间估算OSNR 扫描2 dB 粗扫定位区间0.5 dB 细扫画曲线5. 验证 CO-OFDM 仿真结果是否可信的三个技巧5.1 先跑背靠背把光路代价和 DSP 自身代价分开第一步不接光纤把cofdm_tx.mat的sI、sQ在 MATLAB 里直接叠加高斯白噪声OSNR 从 8 dB 扫到 20 dB运行完整的接收端 DSP画出一条 BER-OSNR 曲线。这条背靠背曲线要和理论 AWGN 信道下的 16-QAM 误码率对照MATLAB 里直接用berawgn(16,qam,EbNodB)就能得到参考线注意把 OSNR 按 12.5 GHz 参考带宽折算到每比特信噪比再对齐。如果背靠背曲线和理论线在 1e-3 处差距超过 0.5 dB问题出在 DSP 实现本身先检查同步偏差、CP 长度和均衡器实现不要急着调光路。只有背靠背对齐了VPI 光路测出来的代价才有解释意义。5.2 判断误码率平台的来源用逐项剥离代替盲调VPI 全链路仿真后如果高 OSNR 区出现误码率平台不要直接归因于光纤非线性。按下面的顺序逐项剥离每一步只改一项、跑一个短帧就能判断先把发射端和本振线宽归零平台消失说明是相位噪声再把入纤功率降到 -10 dBm 压住非线性平台移动说明有非线性贡献然后把光纤长度砍半若平台依旧存在问题在色散残余或均衡器本身都试完平台仍在回到背靠背检查接收机 DSP。这个剥离过程是定位系统瓶颈最省时间的办法比一次性把参数全开再猜原因可靠得多。5.3 波形重叠对比快速定位同步偏差和幅度异常把发射帧txFrame和频偏补偿后的接收信号r2画在同一张时间轴上接收信号做幅度归一后两者应该在前导部分高度重合。互相关峰值位置和同步点 d 的差值就是定时偏差量偏差在 ±Ncp/2 以内属正常接近 Ncp 时必须校正 d否则高频子载波先开始恶化星座图会带规律性旋转。这一步还能发现幅度异常VPI 端如果 EDFA 增益设得过大接收信号会被削顶波形顶部出现平切这种失真在星座图上表现为外圈点向内收缩和 SPM 非线性很像但波形重叠图一眼就能区分。观察每个 OSNR 点的星座 EVMEVM 应该随 OSNR 提高单调下降若某一点 EVM 突然跳变优先怀疑帧同步跳变而不是光路问题。本文还有配套的精品资源点击获取