
简介一套基于MATLAB与VPI联合仿真的CO-OFDM通信系统完整工程面向通信工程高年级学生、科研人员以及对硬件在环仿真感兴趣的开发者旨在帮助使用者从OFDM原理出发走通从算法设计到系统级验证的全流程。压缩包共28个文件内含17个mat数据文件用于保存调制映射与信道估计等中间结果9个m脚本覆盖定时同步、频偏估计、信道估计等核心算法另有vtmu与vpa两种VPI工程文件及按Inputs、Outputs、Reports、Resources划分的目录整体仅6.46MB。目前已有2572人浏览学习。通过该资源可以完整复现CO-OFDM系统从基带信号生成、调制、子载波映射、信道模拟到接收端同步与补偿的完整链路其中定时同步涉及基于导频的滑窗相关与MMSE方法频偏估计包含FFT检测和LMMSE方案信道估计也给出LMMSE滤波器或训练序列等多种实现并与MATLAB脚本一一对应便于逐段调试和二次开发。配套的VPI工程还可帮助理解硬件在环仿真流程对课程设计、毕业设计以及通信系统预研均有较强的参考价值。1. 用 MATLAB 和 VPI 仿真整个 CO-OFDM 系统真正的门槛在接口把一套完整的 CO-OFDM 系统放进 MATLAB 和 VPI 里联合仿真真正费时间的往往不是 OFDM 那套 DSP 算法而是两个工具之间的接口怎么定义。MATLAB 擅长数字域QAM 映射、IFFT、加循环前缀几十行代码就能闭环VPI 擅长光域物理层激光器线宽、IQ 调制器非线性、光纤色散与 EDFA 噪声都能按物理量建模。两边拼起来链路才能从发射端比特一路仿真到相干接收机解调输出。这篇内容面向做系统级验证的通信工程师和研究生默认你理解 OFDM 原理但还没完整搭过联合仿真链路。下面给参数表、核心代码、接口方案和排错顺序让你能稳定跑起参数扫描。2. CO-OFDM 联合仿真的架构划分MATLAB 管数字域VPI 管光域CO-OFDM 的仿真链路不算短但如果一开始就把模块归属划清楚后面每个环节的调试范围都是可控的。这一章先把系统怎么切、每个模块归谁、两边的数据以什么格式交接讲明白。2.1 数字域与光域的边界为什么划在 IQ 调制器两端CO-OFDM 本质上是把相干光通信与 OFDM 结合相干接收机用本地振荡器与信号光混频同时恢复幅度和相位因此可以在光域上传高阶 QAMOFDM 再把宽带信道切成几十上百个窄带子载波每个子载波上的信道近似平坦频域用一个复数抽头就能均衡。色散、偏振模色散这类线性损伤理论上都能被一抽头均衡吸收这正是它适合做长距离仿真验证的原因。但理论上简单不等于仿真里好搭。如果全部用 MATLAB 做等效基带仿真光纤就被简化成一个传递函数激光器相位噪声、调制器消光比、接收机热噪声这些物理效应很难真实体现如果全部在 VPI 里搭OFDM 的编解码、帧同步、均衡又会被图形化模块拖慢迭代速度。所以最常见的做法是把系统从 IQ 调制器中间切开调制器之前的比特处理、QAM 映射、IFFT、加 CP 都在 MATLAB 完成光发射机、光纤链路、相干接收机前端留在 VPI解调侧 DSP 再回到 MATLAB。接口只有一对发射端的 I/Q 基带波形以及接收端从相干接收机下来的 I/Q 信号。这个划分还有一个工程上的好处排错时可以只怀疑一个域。比如 EVM 偏高先看 MATLAB 单独闭环的 EVM如果它都在 1% 以上问题在 DSP如果 MATLAB 闭环是干净的接入 VPI 背靠背之后才劣化问题在光域建模或接口。分界清晰联调时就不会两边同时改。2.2 CO-OFDM 三段式参数表发射、光纤、接收下面这张表是整套联合仿真的参数基线后续所有代码都按它来写。FFT 点数取 256、数据子载波 192是因为这个量级在通信仿真里既能容纳足够的频域选择性又不至于让 VPI 光域仿真时间爆炸。阶段模块关键参数典型取值MATLAB 发射OFDM 帧FFT 点数 / 数据子载波 / 导频数256 / 192 / 8MATLAB 发射循环前缀CP 采样点数32MATLAB 发射调制QAM 阶数、星座归一化16QAM单位平均功率MATLAB 发射成型根升余弦滚降、过采样率0.24 倍VPI 光域激光器线宽、中心频率、功率100 kHz、193.1 THz、0 dBmVPI 光域IQ 调制器半波电压、偏置点、消光比4 V、null 点、30 dBVPI 光域光纤与放大色散、衰减、EDFA 噪声指数16.75 ps/nm/km、0.2 dB/km、4.5 dBVPI 光域相干接收LO 功率、PD 带宽10 dBm、40 GHzMATLAB 接收均衡LS 信道估计训练符号取平均参数表里容易被忽视的是星座归一化。MATLAB 里qammod(..., UnitAveragePower, true)保证星座平均功率为 1导频子载波固定为 11i这样 IFFT 之后时域信号的功率量级是稳定的导出给 VPI 时不会因为功率忽大忽小把调制器推向非线性区。激光器线宽和符号周期的乘积直接决定相位噪声预算10 GBd 符号率下 256 点 FFT 对应的 OFDM 符号周期约 25.6 ns线宽 100 kHz 时乘积为 2.56e-316QAM 可以接受线宽放到 1 MHz 后乘积到 2.56e-2EVM 会明显恶化改善手段在第 5 章给。2.3 两种 MATLAB-VPI 接法离线波形文件与引擎协同接法一离线文件交互最稳也最适合第一次搭链路。MATLAB 把 I/Q 波形写进 CSV 或 MAT 文件VPI 里用波形读入模块把它当成电信号源驱动 IQ 调制器这个读入动作相当于一台任意波形发生器在激励光发射机光纤输出后在 VPI 里导出接收端 I/QMATLAB 再读回来做解调。整个流程里 MATLAB 和 VPI 异步执行互不阻塞VPI 算几十公里光纤时也不影响 MATLAB 做下一轮参数整理。代价是每轮迭代都要写盘参数扫描时 I/O 会占时间但换来的是每个中间结果都可回放值得。% save_tx_iq.m 把基带波形导成两列 CSV供 VPI 读入 iq [real(tx_signal), imag(tx_signal)]; writematrix(iq, tx_iq.csv); % 两列分别是 I 路、Q 路 save(tx_signal.mat, tx_signal, fs, N, cp_len);CSV 两列的排布顺序是约定的关键VPI 里两个电端口解复用后第一列接 IQ 调制器的 I 射频口第二列接 Q 射频口。接反了星座图会左右翻转而且这类错误从波形上看不出来只能通过解调结果反推。接法二VPI 内嵌 MATLAB 引擎做协同仿真适合自适应均衡这类需要逐块更新抽头的算法。此时 VPI 每个计算步回调 MATLAB 函数实时性要求高但 MATLAB Engine 的启动和版本匹配是常见坑VPI 是 64 位MATLAB 也必须装 64 位对应版本安装路径不能带空格否则引擎经常无声退出。我一般建议先离线跑通整条链路确认物理层模块没问题再决定要不要上引擎协同否则排错时两个进程互相牵制工作量翻倍。3. 用 MATLAB 把 CO-OFDM 收发端 DSP 先闭环跑通在接触 VPI 之前先把收发端 DSP 在 MATLAB 里单独闭环。这个闭环的意义是建立参考底噪理想信道下 EVM 能做到多少后面每加一段 VPI 光路就多一分 EVM 预算问题出在哪一段才有据可查。3.1 先定稿仿真参数FFT 点数、子载波分配与循环前缀FFT 点数 256 里数据子载波占 192导频 8 个两侧共 56 个子载波置零作保护带。保护带不是浪费光调制器、相干接收机的频响在带外滚降如果没有保护带带外分量会折叠进 FFT 窗造成子载波间干扰。循环前缀长度 32 对应 3.2 ns覆盖色散延展绰绰有余。帧头放 2 个全子载波 BPSK 训练符号既用于帧同步也用于 LS 信道估计一石二鸟。参数取值设计约束FFT 点数256决定子载波间隔与符号周期数据子载波192扣除保护带与导频后的有效载荷导频子载波8频域等间隔便于相位插值循环前缀32 点 / 3.2 ns覆盖色散造成的时延展宽过采样率4与后续 VPI 重采样对齐训练符号2 个LS 信道估计与帧同步共用3.2 发射端 MATLAB 代码QAM 映射、IFFT 与成型滤波% tx_ofdm.m 生成 CO-OFDM 基带 I/Q 波形 N 256; cp_len 32; N_frame 40; M 16; os_rate 4; N_data 192; N_pilot 8; rng(2024); data_idx union(2:N/2, N/22:N); % 数据子载波避开直流与奈奎斯特频点 pilot_idx 26:32:250; % 等间隔 8 个导频 pilot_sym (11i) * ones(N_pilot, 1); % 固定幅度导频 tx_frame zeros(N, N_frame 2); tx_frame(:, 1:2) 1; % 前两个为训练符号全子载波 BPSK data_sym qammod(randi([0 M-1], N_data, N_frame), M, ... gray, UnitAveragePower, true); for k 1:N_frame sym zeros(N, 1); sym(pilot_idx) pilot_sym; % 导频先占位 sym(data_idx) data_sym(:, k); % 数据填入 tx_frame(:, k2) sym; end tx_ifft ifft(tx_frame, N, 1) * sqrt(N); % 归一化保持功率 tx_cp [tx_ifft(end-cp_len1:end, :); tx_ifft]; % 加循环前缀 tx_base reshape(tx_cp, [], 1); % 串并转换 tx_up upsample(tx_base, os_rate); rrc rcosdesign(0.2, 16, os_rate, sqrt); % 根升余弦成型 tx_signal filter(rrc, 1, tx_up); % 4 倍过采样基带波IFFT 后乘sqrt(N)让频域功率为 1 的星座映射成时域均方根为 1 的波形后续给 VPI 的驱动幅度就按这个量级预估。upsample插零后过根升余弦滤波器滚降系数 0.216 个符号长度的滤波器拖尾足够小不会造成帧间重叠。union生成的数据索引避开了直流子载波避免基带信号在零频附近被相干接收机的直流分量干扰。成型滤波一定要在加 CP 之后做。顺序反了 CP 会被滤波器展宽破坏循环卷积假设频域均衡就失效了这是新手最容易忽略的顺序约束。3.3 接收端 MATLAB 代码LS 信道估计与导频相位修正% rx_ofdm.m rx_signal 为 VPI 导出的 I/Q已定时同步 rx_rrc filter(rrc, 1, rx_signal); % 匹配滤波 rx_down downsample(rx_rrc, os_rate); rx_frm reshape(rx_down, Ncp_len, []); rx_frm rx_frm(cp_len1:end, :); % 去 CP rx_fft fft(rx_frm, N, 1) / sqrt(N); H_est mean(rx_fft(:, 1:2), 2); % LS 估计训练符号取平均 rx_eq rx_fft ./ H_est; % 残余频偏与公共相位噪声单值旋转修正 phs angle(mean(mean(rx_eq(pilot_idx, 3:end) .* conj(pilot_sym)))); rx_eq rx_eq .* exp(-1i * phs); rx_data rx_eq(data_idx, 3:end); % 取数据子载波 rx_qam qamdemod(rx_data, M, gray, UnitAveragePower, true);LS 信道估计对两个训练符号取平均等效于把估计阶段接收噪声压低 3 dB代价是每帧多 2 个符号开销。信道估计之后做了一次公共相位旋转这是 VPI 光路仿真里最常被忽略的一步激光器相位噪声对当前 OFDM 符号整体施加同一个旋转角导频子载波的平均相位就是它的估计值。这个单值补偿在 16QAM 下够用QAM 阶数到 64 时单一旋转角不够需要在频域对导频相位做插值第 5 章给完整版。这一段跑通后记下理想信道 EVM作为整个联合仿真链路的底线。理想信道下 16QAM 的 EVM 一般在 1% 以内超过 2% 就要先回头查星座归一化和滤波器的群时延而不是急着接 VPI。4. 在 VPI 中搭光传输链路并与 MATLAB 基带对接MATLAB 侧闭环干净之后开始搭 VPI 光域。这一章把模块选型、接线、以及最容易被卡住的采样率和定时对齐讲清楚。4.1 VPI 光域模块清单与关键参数设置光域链路按发射、传输、接收三段搭。发射端先落激光器再接 IQ 调制器传输段用单模光纤加 EDFA接收端是本地振荡器、90 度光混频器和平衡探测器组成的相干接收机前端。VPI 模块关键参数典型取值设置目的激光器线宽 / 中心频率 / 功率100 kHz / 193.1 THz / 0 dBm控制相位噪声预算IQ 调制器半波电压 / 偏置点 / 消光比4 V / null 点 / 30 dB保证线性电光转换单模光纤色散 / 衰减 / 段长16.75 ps/nm/km / 0.2 dB/km / 80 km引入线性损伤EDFA增益 / 噪声指数按段损耗补 / 4.5 dB维持接收光功率相干接收LO 功率 / PD 带宽10 dBm / 40 GHz完成混频与光电转换IQ 调制器要偏置在 null 点也就是传输曲线的消光点这样输出光场才是基带信号的线性搬移。偏置点一旦偏到 quadrature 点附近输出会混入一个很大的直流光载波解调后表现为整帧直流偏置星座图整体平移而不是旋转很容易误判成信道估计问题。光纤先按 80 km 一段加EDFA 增益补偿该段损耗逐段加的目的是观察色散累积对 EVM 的影响曲线。第一次联调建议做背靠背也就是发射端直接接接收端先确认电光转换和相干探测这两个环节干净。4.2 把 MATLAB 基带波形灌进 VPI 的接线与幅度匹配把第 2 章导出的tx_iq.csv读进 VPI 后两列信号分别接到 IQ 调制器的 I、Q 射频口偏置控制端按 null 点设定。这里最容易出问题的不是接线而是幅度匹配。MATLAB 导出的基带波均方根为 1峰值大约 3.5 左右而 IQ 调制器的半波电压往往在 3 到 5 V。驱动幅度太小调制器工作在传输曲线的低斜率区消光比浪费驱动幅度超过半波电压又会进入非线性区产生高阶边带。常见做法是在 VPI 里加一个电放大器把峰值放大到接近半波电压放大倍数写进电放大器模块不动 MATLAB 导出文件。% read_vpi_out.m 读回 VPI 相干接收机导出的 I/Q 波形 out readmatrix(rx_iq.csv); % 两列I、Q vi out(:, 1); vq out(:, 2); rx_signal complex(vi, vq);读回的时候注意 VPI 导出的时间轴起点。它通常从 0 时刻开始而光纤链路本身有几微秒到几百微秒的时延rx_iq.csv前面会有一段无信号区。这段区域长度和光纤长度、采样率有关不能靠固定偏移裁掉必须用发射端已知的训练序列做定时同步见 4.3 节的滑动相关。4.3 采样率换算与定时同步联合仿真最容易翻车的环节MATLAB 侧是 4 倍过采样符号率 10 GBd 对应 40 GSa/s。VPI 光域计算不一样为了解析调制光信号的频谱计算采样率一般取符号率的 16 倍左右也就是 160 GSa/s。两个采样率不匹配接口处必须重采样。最简单的情况是整数倍降采样160 GSa/s 降到 40 GSa/s 直接按 4 倍抽取即可。% resample_vpi_out.m 把 VPI 导出的光域 I/Q 从 160 GSa/s 降到 40 GSa/s vi resample(vi, 1, 4); vq resample(vq, 1, 4); rx_signal complex(vi, vq); % 用发射端训练序列做滑动相关找帧头 train_seq tx_signal(1:os_rate*(Ncp_len)); % 发射训练段已知 corr filter(conj(flipud(train_seq)), 1, rx_signal); [~, peak] max(abs(corr)); delay peak - length(train_seq) 1; rx_signal rx_signal(delay:end);这里用filter做滑动相关比conv省内存相关峰值对应训练序列的起始位置减去训练序列长度就得到整帧起点。resample自带抗混叠滤波比直接downsample稳后者会引入频谱混叠星座点外圈会散开看起来像噪声太大实际是抽取没带滤波。定时同步做完之后还要丢弃解调后的第一个 OFDM 符号。VPI 仿真启动瞬间存在瞬态激光器和调制器偏置都要经过一个建立过程把这个符号计入 EVM 统计会把结果拉高 1 到 2 个点属于异常仿真场景的典型来源。5. 联调时的仿真发散定位与 EVM 口径校准链路联调阶段最常遇到的就是仿真发散和 EVM 持续偏高。这一章给一套定位顺序和两个能直接落地的处理手段。5.1 仿真发散的定位顺序先闭环、再背靠背、后加光纤仿真发散分两种。MATLAB 侧发散表现是时域波形幅度指数增长或出现 NaN原因集中在归一化错误、滤波器不稳定、循环卷积被破坏VPI 侧发散表现是接收端光功率异常或星座图直接糊掉原因集中在采样率不足、调制器过驱动产生高次边带、EDFA 增益补偿不准进入非线性区。定位顺序固定成三段先跑 MATLAB 闭环确认 EVM再接 VPI 背靠背最后逐段加光纤。每加一段记录一次 EVM哪一段跳变问题就在哪一段不要同时改两处。提示第一次联调阶段VPI 里务必固定随机种子激光器相位噪声和 ASE 噪声都依赖随机数生成种子不定两次仿真结果不可比发散定位就无从谈起。5.2 用 EVM 而不是肉眼星座图做验收口径星座图肉眼看着干净EVM 可能已经超预算。解调后用判决反馈的方式算 EVM口径统一方便前后对比。% calc_evm.m 按判决符号计算 RMS EVM rx_demod qamdemod(rx_data, M, gray, UnitAveragePower, true); ref_data qammod(rx_demod, M, gray, UnitAveragePower, true); num sum(abs(rx_data(:) - ref_data(:)).^2); den sum(abs(ref_data(:)).^2); evm_rms sqrt(num / den) * 100; % 单位 %16QAM 在 7% 硬判决 FEC 门限 BER 约 3.8e-3对应 EVM 约 14%工程上会留 2 个点余量压在 12% 以内。如果背靠背 EVM 超过 10%先检查驱动幅度和偏置点加光纤后 EVM 超过 12%先看 EDFA 增益和入纤功率再怀疑算法。5.3 逐符号导频插值把线宽容忍度放宽一个量级第 3.3 节用的是单值公共相位补偿在 16QAM、线宽 100 kHz 时够用。如果想把激光器线宽放宽到 400 kHz 甚至 1 MHz或者改用 64QAM需要把 8 个导频测到的相位在频域做线性插值逐符号补偿到每个数据子载波上。% pilot_phase_comp.m 逐 OFDM 符号导频相位插值补偿 for k 3:size(rx_eq, 2) % 跳过训练符号 ph angle(rx_eq(pilot_idx, k) .* conj(pilot_sym)); % 导频相位线性插值到数据子载波位置 ph_interp interp1(pilot_idx, ph, data_idx, linear, extrap); rx_eq(data_idx, k) rx_eq(data_idx, k) .* exp(-1i * ph_interp); end插值后的相位补偿能追上线宽变化较快的公共旋转16QAM 下通常把 EVM 改善 2 到 3 dB等效于把可用线宽上限放宽一个量级。配合这个补偿VPI 里激光器线宽参数扫描的布点可以从 50 kHz、100 kHz、200 kHz 稀疏到 100 kHz、400 kHz、1 MHz 三档参数扫描的机时开销随之大幅下降而 EVM 口径仍能守住 12% 的阈值。本文还有配套的精品资源点击获取