☰
DCO-OFDM可见光通信MATLAB仿真与误码率分析
2026/10/26 3:37:50 网站建设 项目流程

简介:围绕OFDM可见光通信系统仿真整理的MATLAB工程,面向刚接触可见光通信与OFDM调制的初学者,也可作为课程设计、毕业设计前的参考样例。内容以朗伯模型可见光无线信道为基础,串起发送端、接收端与OFDM完整链路,并配有较详细的中文注释,可直接运行观察误码率与星座图等结果。压缩包共10个文件,以9个m脚本和1个mat数据文件为主,脚本分别承载信道建模、QAM/QPSK调制解调、加窗与根升余弦处理、OFDM演示等环节,mat文件用于保存信噪比相关数据;整体约10KB,体积轻便,便于逐文件阅读和二次修改。已有1978人学习下载,说明其在同类入门资料中具有一定参考度。读者可据此理解可见光信道增益计算、子载波映射、循环前缀与加窗对频谱的影响,并借助现成脚本快速复现实验、排查参数设置问题,减少从零搭建链路的时间。

1. 从一次“发不出去的光”说起

答辩前一周,A 同学把跑了一学期的 OFDM 可见光通信系统仿真交给导师,算法全对,误码率曲线也漂亮,唯独时域波形是复数——LED 根本发不出去。可见光通信走的是强度调制/直接检测,光功率非负、信号必须是实数,这两条物理约束决定了它跟射频 OFDM 不是同一套东西。这套 MATLAB 仿真要解决的就是把比特流一路推到 LED 光功率、再经光电二极管收回来的完整闭环:Hermitian 对称、直流偏置、削波、朗伯信道、均衡与误码统计,每一环都要和物理量对得上。它适合正在做通信方向毕设、课设,或者要给实验室搭一套可复现仿真基线的人。下面按需求、设计、实现、验收的顺序展开,参数和代码都能直接改。

2. 链路总体设计:从比特到光功率的六段划分

把整条链路摊开看,一共六段:信源与 QAM 映射、频域子载波分配、OFDM 调制(IFFT 加 CP)、光域适配(直流偏置与削波)、可见光信道、接收端解调与评估。这六段在代码里对应六个函数,好处是任何一段出问题都能单独拿示波器式的中间变量去看,而不是在一个两百行的脚本里靠disp猜。

很多同学喜欢把所有逻辑塞进一个main.m,跑通很快,改参数就崩。我带过的几届里,凡是最后能顺利答辩的,基本都把发射、信道、接收拆成了独立函数,主脚本只负责扫 SNR 和画图。这个习惯看着麻烦,实际上省下来的调试时间远大于前期投入。

2.1 为什么选 DCO-OFDM,而不是把射频 OFDM 原样搬过来

射频 OFDM 的时域信号是复基带,实部和虚部分别上正交载波,这在电路上靠 IQ 调制器实现。可见光链路里没有 IQ 调制器,LED 的瞬时光功率只能是标量且非负,光电二极管也只响应光强不响应相位。把射频代码直接改个变量名就当成 VLC 仿真,是这类课题最常见的翻车起点。

工程上有三条主流路线,各自的取舍很明确:

方案时域是否实数非负处理方式频谱效率主要代价
DCO-OFDM是(Hermitian 对称)叠加直流偏置后硬削波N/2−1 个数据子载波削波噪声、直流功耗
ACO-OFDM是(只用奇数子载波)非对称削波,负半轴直接置零N/4 个数据子载波频谱效率减半
PAM / 单载波是直接加偏置单路无多载波抗多径增益,均衡器复杂

这套仿真选 DCO-OFDM,理由有三个。第一,它和射频 OFDM 的框架最接近,IFFT/FFT、CP、导频、均衡这些模块能直接复用,对毕设来说工作量可控且讲得清。第二,频谱效率是 ACO-OFDM 的两倍,同样的子载波数能跑出更高的净速率。第三,直流偏置和削波这两个环节本身就带出一个很有讲头的研究点——削波比怎么选,答辩时被追问的概率很高,答得好是加分项。

提示:如果你的课题要求对比多种方案,别另起三个工程。把子载波映射和削波这两处写成可切换的配置项,主脚本里换个cfg.scheme就能跑出三条曲线,工作量和代码量都省一半。

2.2 参数表:把物理量和仿真量对齐

仿真最容易出问题的地方不是算法,是量纲。采样率、子载波间隔、光功率、响应度、噪声功率密度这几组量一旦混着用,曲线形状可能还是对的,数值却完全站不住。我在动手写第一行代码之前会先把这张表填满,后面所有函数都从同一个cfg结构体取参数,杜绝散落在各处的魔法数字。

参数符号取值说明
IFFT 点数N2562 的幂,便于 FFT 与索引对齐
循环前缀Ncp16占符号长度 6.25%
调制阶数M1616-QAM,每符号 4 bit
采样率fs20 MHz满足奈奎斯特,覆盖 LED 带宽
子载波间隔Δf78.125 kHzfs / N
数据子载波数Nd127N/2 − 1,去掉 DC 与 Nyquist
占用带宽B9.92 MHzNd × Δf
OFDM 符号周期T12.8 μsN / fs
CP 时长Tcp0.8 μsNcp / fs
净速率Rb≈37.4 Mbps127×4 / 13.6 μs
削波比CR10 dB常用 7~13 dB
收发距离d2.15 m典型室内吸顶灯到桌面
PD 有效面积A_pd1e-4 m²1 cm²
PD 响应度R0.53 A/W对应 550 nm 附近
LED 半功率角φ½60°决定朗伯阶数 m
接收视场角Ψc60°超出即无接收

这张表里有两个数值得单独说。一个是净速率 37.4 Mbps,它是 127 个数据子载波乘 4 bit 再除以含 CP 的符号周期,不是拿带宽直接乘频谱效率——答辩时被问到“你这速率怎么算的”,能当场推出来和背不下来是两回事。另一个是 CP 只占 6.25%,看着偏短,后面第 5 章会讲为什么在室内 10 MHz 量级带宽下它其实够用。

2.3 数据流方向与模块划分

信号从比特到光功率要经过五次形态变化,每一次都有明确的中间变量可以截取:bits(列向量)、sym(复星座点)、Xf(频域帧,共轭对称)、x(实数时域样本)、x_led(非负光功率样本)。接收端反过来走一遍,最后落到Xhat和ber。

我一般把工程切成这几个文件:main.m负责参数装配和 SNR 扫描,tx_dco_ofdm.m负责发射,vlc_channel.m负责信道增益与时延,rx_dco_ofdm.m负责接收,plot_result.m统一画图。主脚本里只出现cfg和函数调用,不出现任何常数。这样做还有个隐性好处:写论文时的系统框图,基本就是把函数名连起来,图上的每一个方框在代码里都找得到对应位置,不会出现“图画得比代码复杂”的尴尬。

数据流的方向也要在代码里体现出来。发射端所有数组按列组织,每一列是一个 OFDM 符号,这样fft(X, N, 1)沿第一维做变换,天然就是逐符号处理,不需要写循环。nSym取 2000 以上,误码率才能统计到 1e-4 量级——一个符号只有 508 bit,2000 个符号才一百万比特,10⁻⁴ 的误码率意味着大约一百个错误,置信度勉强够用。想画到 10⁻⁵,nSym至少得翻十倍,这是笔不小的时间开销,提前规划好。

3. 发射端实现:Hermitian 对称、IFFT 与削波的三个关键点

发射端是整套仿真里唯一需要“造”出物理约束的地方。射频链路里,信号是复数是天经地义的;光链路里,实数是物理强制的,非负是器件强制的。这两个强制条件必须在发射端完成,接收端只能被动接受结果,所以这里错一步,后面全盘皆错。

3.1 子载波映射:哪些位置能放数据

N 点 IFFT 输出为实数的充要条件,是输入频域序列满足共轭对称:X[k] = conj(X[N-k])。这条约束直接决定了三个位置的特殊处理——索引 1 的直流分量、索引 N/2+1 的奈奎斯特分量,这两个位置必须为实数(通常直接置零,不携带信息),剩下的正频率 2 到 N/2 承载数据,负频率镜像取共轭。所以 N = 256 时,可用数据子载波是 127 个,不是 128 个,也不是 256 个。

function [x_led, bits, Xf] = tx_dco_ofdm(nSym, cfg) %TX_DCO_OFDM 生成 DCO-OFDM 可见光发射信号 % nSym : OFDM 符号数 % cfg : 参数结构体(N / Ncp / M / CR / Popt) N = cfg.N; % IFFT 点数,取 2 的幂 Ncp = cfg.Ncp; % 循环前缀长度 M = cfg.M; % QAM 阶数 Nd = N/2 - 1; % 可用数据子载波:去掉 DC 与 Nyquist bits = randi([0 1], Nd*log2(M)*nSym, 1); sym = qammod(bits, M, 'InputType', 'bit', 'UnitAveragePower', true); X = reshape(sym, Nd, nSym); % 每列一个 OFDM 符号 Xf = zeros(N, nSym); Xf(2:Nd+1, :) = X; % 正频率:承载数据 Xf(N:-1:N-Nd+1,:) = conj(X); % 负频率:共轭镜像 % 索引 1(DC)与索引 N/2+1(Nyquist)保持 0,保证时域为实数 end

索引关系值得在纸上画一遍。MATLAB 从 1 开始计数,所以正频率占用 2 到 128,负频率占用 130 到 256,镜像关系是k ↔ N+2-k:索引 2 的镜像是 256,索引 128 的镜像是 130。代码里Xf(N:-1:N-Nd+1,:) = conj(X)展开就是Xf(256:-1:130,:) = conj(X),正好和Xf(2:128,:)一一对应。写成Xf(Nd+2:N,:) = conj(X)是错的,那会把 129 这个奈奎斯特点也覆盖掉,时域立刻冒出虚部。

qammod的UnitAveragePower参数也别漏。默认情况下 16-QAM 的星座平均功率是 10,不同阶数还不一样,扫 SNR 的时候曲线会整体平移,看起来像算法有问题,实际是功率没归一。

3.2 IFFT 与循环前缀的落地写法

IFFT 之后要做一个功率归一化。MATLAB 的ifft自带 1/N 因子,不同 N 下时域幅度差别很大,直接拿去和噪声功率比较会得到毫无意义的 SNR。常见的处理是乘sqrt(N),让频域总功率和时域总功率在 Parseval 意义下对齐。

x = ifft(Xf, N, 1) * sqrt(N); % 归一化 IFFT,时域为实数 x = real(x); % 抹掉 1e-17 量级的浮点虚部 x_cp = [x(N-Ncp+1:N, :); x]; % 尾部 Ncp 个样本复制到头部

第三行的real(x)不是可有可无的装饰。理论上共轭对称保证虚部为零,实际数值计算会残留 1e-17 量级的虚部,某些版本的函数在遇到复数输入时会走完全不同的分支,报错信息还特别隐晦。加这一行,等于给后面所有模块买了个保险。

循环前缀的复制方向也要注意:是把尾巴搬到头上,不是把头搬到尾巴。写成[x; x(1:Ncp,:)]就成了补零后缀,形式上也能跑,但多径下起不到保护作用,而且符号长度对不上,接收端去 CP 的位置全错。这种错误不会立刻报错,只会让误码率曲线莫名其妙地差一截,很难查。

注意:x_cp的行数是N + Ncp,接收端去 CP 时要按y(Ncp+1:end,:)截取,索引差一位就会把 CP 的最后一个样本当成数据,星座图上会出现一圈弥散的干扰点。

3.3 直流偏置与削波比:非负约束怎么满足

到这里x_cp还是个零均值双极性信号,正负都有,LED 只能发非负光功率。DCO-OFDM 的做法是整体抬一个直流电平,抬完还剩下的负值直接削掉。

sigma = std(x_cp(:)); % 时域标准差 Bdc = sigma * 10^(cfg.CR/20); % 削波比 CR(dB) 换算成偏置电平 x_ac = x_cp + Bdc; % 抬到正半轴 x_ac = max(x_ac, 0); % 硬削波,负值归零 x_led = x_ac / mean(x_ac(:)) * cfg.Popt; % 标定平均光功率为 Popt

削波比 CR 的定义是直流偏置电平与时域标准差之比,取 10 dB 意味着Bdc ≈ 3.16σ。这个数值不是随便拍的:高斯分布下 3σ 之外的概率约 0.27%,削掉的样本很少,削波噪声可控;CR 降到 6 dB 只有 2σ,削掉的样本接近 5%,削波噪声会明显抬高误码率平台;CR 提到 13 dB,削波几乎消失,但直流功耗占比太大,光功率利用率低,实际系统里不划算。

这段代码的最后一行做了平均光功率标定。因为削波之后mean(x_ac)会小于Bdc(负半轴被砍掉了),如果不重新归一,不同 CR 下的平均光功率不一样,扫出来的曲线就没法横向比较。归一化到Popt之后,无论 CR 取多少,进入信道的光功率都是同一个值,比较才有意义。

还有一个容易忽略的细节:std要在加 CP 之后的x_cp上算,不是在x上算。CP 是复制出来的样本,会改变整体的统计特性,虽然差异不大,但既然要做可复现的仿真,就该统一口径。

3.4 PAPR 统计:为后面的削波分析留一手

DCO-OFDM 的峰均比问题和射频 OFDM 一样严重,而且因为要留直流余量,实际可用的动态范围更紧。仿真里顺手把 PAPR 的 CCDF 算出来,答辩时是一条很有说服力的辅助曲线。

papr_dB = 10*log10(max(abs(x).^2,[],1) ./ mean(abs(x).^2,1)); gamma = 0:0.5:12; ccdf = arrayfun(@(g) mean(papr_dB(:) > g), gamma); semilogy(gamma, ccdf, 'LineWidth', 1.2); grid on; xlabel('PAPR_0 (dB)'); ylabel('CCDF');

这里没用ecdf,因为那个函数依赖统计工具箱,换台机器可能就跑不了。arrayfun加逻辑索引是最朴素的写法,不依赖任何工具箱,谁拿去都能复现。16-QAM、256 点 IFFT 的 PAPR 在 0.1% 概率处大约是 9~10 dB,正好对应 CR 取 10 dB 时削掉的那一小撮峰值——两条曲线放在一起讲,逻辑是自洽的。

4. 信道与接收端:朗伯模型、均衡与误码统计

接收端看着是把发射端倒着走一遍,实际有两个发射端没有的麻烦:一是信道增益必须算对,二是噪声功率的定义必须和 SNR 的定义严格一致。这两处一旦含糊,曲线形状对、数值全错,评审老师一眼就能看出来。

4.1 可见光信道怎么建模才不算“假”

室内 VLC 的直射路径用朗伯辐射模型描述,直流增益的经典表达式是:

function [H0, h] = vlc_channel(cfg) %VLC_CHANNEL 朗伯直射信道 + 单抽头冲激响应 m = -log(2)/log(cosd(cfg.phi_half)); % 朗伯阶数 d = cfg.d; % 收发距离 A_pd = cfg.A_pd; H0 = (m+1)*A_pd/(2*pi*d^2) ... * cosd(cfg.phi)^m * cosd(cfg.psi); % 滤光片与聚光器增益取 1 tau = d / 3e8; % 直射径传播时延 h = zeros(1, cfg.Ncp); h(max(1, round(tau*cfg.fs))) = H0; % 折算到采样点 end

m 由半功率角决定,φ½ = 60° 时 m ≈ 1,接近理想朗伯分布;φ½ = 30° 时 m ≈ 4.8,光束更集中,同样距离下 H0 更大但覆盖范围更小。这两个参数在论文里经常被写反,半功率角越小 m 越大,别搞混。

真正需要说清楚的是时延那一行。d = 2.15 m 时 τ ≈ 7.2 ns,采样率 20 MHz 对应采样周期 50 ns,round(7.2e-9 × 20e6) = 0,所以直射径落在第 0 个抽头上,信道在 10 MHz 带宽内基本是平的。这不是建模偷懒,是物理事实——室内几米距离的直射时延远小于采样周期。CP 真正要对付的是墙面反射带来的多径,一次反射的路径差通常 1~3 m,折算 3~10 ns,在这个采样率下同样不足一个样本。

想在仿真里看到 ISI,只有两条路:把采样率提到 100 MHz 以上,或者人为在h里塞几个间隔 3~5 个样本的抽头当作强反射。前者更真实但计算量大,后者更可控且便于做参数扫描。我一般两种都备着,默认跑平坦信道看理论曲线,答辩演示时切到多径版本,说明 CP 的作用,两条曲线一对比,说服力比讲十分钟原理强。

4.2 去直流、去 CP 与频域均衡

接收端的顺序不能乱:先去 CP,再去直流,然后 FFT。去直流必须在时域做,因为直流偏置是一个叠加在波形上的常数,频域上看它就是索引 1 的那一个点,等到 FFT 之后再处理已经晚了。

function Xhat = rx_dco_ofdm(y, cfg, H0, R) %RX_DCO_OFDM 去CP -> 去直流 -> FFT -> ZF 均衡 N = cfg.N; Ncp = cfg.Ncp; Nd = N/2 - 1; y = y(Ncp+1:end, :); % 去循环前缀 y = y - mean(y(:)); % 扣除直流(实际系统用高通滤波或长序列均值) Y = fft(y, N, 1) / sqrt(N); % 归一化 FFT,与发射端对称 Yd = Y(2:Nd+1, :); % 取出数据子载波 Hd = R * H0 * ones(Nd, 1); % 平坦信道频响;多径时改用 fft(h,N) 取子载波 W = 1 ./ Hd; % ZF 均衡,直接除掉信道增益 Xhat = Yd .* W; end

mean(y(:))这个估计方式只有在符号数足够多、QAM 星座零均值的前提下才成立。符号数少于 50 时估计偏差明显,星座图会整体偏移。真实系统里用高通滤波器或者专门的直流估计序列,仿真里用均值是为了少写一个模块,这一点在论文里要交代清楚,别被当成疏漏。

均衡器给了 ZF 版本,因为它是无偏的,解调时不需要额外补偿。MMSE 的形式是W = conj(Hd)./(abs(Hd).^2 + nvar),误码率在低 SNR 下更好看,但输出带偏置,星座幅度会被压缩,配合qamdemod的单位功率假设必须再补一步幅度校正。很多同学抄了 MMSE 的公式没做补偿,曲线在低 SNR 段反而比 ZF 差,回头怀疑公式抄错了,其实是尺度没对齐。

Hd那行写成R * H0 * ones(Nd,1)是把响应度和信道增益合在一起了。严格说响应度属于光电转换环节,信道增益属于光传播环节,物理上应该分开。代码里合并是为了少传一个参数,注释里要写明白,不然过两个月自己都看不懂。

4.3 误码率曲线与星座图:评估脚本怎么写

主脚本负责把 SNR 从 0 扫到 24 dB,每个点重新加噪、接收、解调、统计误码。噪声方差不是拍出来的,是由接收端电信号平均功率除以线性 SNR 得到的,这样 SNR 的定义才和横轴标签一致。

cfg.N = 256; cfg.Ncp = 16; cfg.M = 16; cfg.CR = 10; cfg.Popt = 1; % 平均光功率归一化为 1 W nSym = 2000; [x_led, bits, ~] = tx_dco_ofdm(nSym, cfg); [H0, ~] = vlc_channel(cfg); R = 0.53; % PD 响应度 A/W SNRs = 0:2:24; ber = zeros(size(SNRs)); for i = 1:numel(SNRs) Ps = mean((R*H0*x_led(:)).^2); % 接收电信号平均功率 nvar = Ps / 10^(SNRs(i)/10); % 由 SNR 反推噪声方差 y = R*H0*x_led + sqrt(nvar)*randn(size(x_led)); Xhat = rx_dco_ofdm(y, cfg, H0, R); bh = qamdemod(Xhat(:), cfg.M, 'OutputType','bit','UnitAveragePower',true); ber(i) = mean(bh ~= bits(1:numel(bh))); end semilogy(SNRs, ber, 'o-', 'LineWidth', 1.2); grid on; xlabel('电域 SNR (dB)'); ylabel('BER');

x_led是矩阵,R*H0*x_led是逐元素乘,randn(size(x_led))保证噪声维度一致。这里如果用randn(nSym,1)会触发隐式扩展,MATLAB 不报错,但每个符号加的是同一列噪声,统计上不独立,误码率会偏低——这种错误特别隐蔽,因为曲线依然平滑。

理论对照线也建议加上。AWGN 下 16-QAM 的 BER 近似式是3/8 * erfc(sqrt(0.4*Eb/N0)),把仿真参数折算成 Eb/N0 画在同一张图上,两条线在中等 SNR 段应该贴合,高 SNR 段仿真会因削波噪声出现平台。平台高度和 CR 直接相关,CR 从 10 dB 降到 7 dB,平台大概会抬高半个数量级,这个对比本身就是论文里很漂亮的一节。

星座图用plot(real(Xhat(:)), imag(Xhat(:)), '.')就行,不要用scatterplot,那个需要工具箱。16-QAM 在 SNR = 15 dB 左右应该能看到清晰的 16 个点簇,簇间的弥散程度直接反映噪声水平;如果簇心整体偏移或旋转,说明均衡增益没对齐;如果簇是四团而不是十六团,说明子载波映射或者比特顺序错了。

5. 常见问题排查:五处最容易翻车的地方

仿真跑不通的原因,九成集中在这五处。每一条我都按现象、原因、解决三段写,因为光看结论记不住,知道现象长什么样才能在下次第一时间反应过来。

5.1 时域信号出现虚部,后面全崩

现象:x的虚部不是 1e-17 量级,而是和实部同一个数量级,max(abs(imag(x)))能到 0.1 以上。后面加噪、削波、画图全带着复数,有的函数直接报错,有的默默取实部,结果全错。

原因:共轭对称没写对。三种典型错法——负频率索引写成Nd+2:N覆盖了奈奎斯特点;正负频率的共轭关系搞反,写成了conj(Xf(...)) = X;或者数据子载波个数按 N/2 算,多塞了一个。

解决:单独写一个断言函数,在 IFFT 之前检查max(abs(Xf - conj(Xf([1, N:-1:2], :))))是否小于 1e-12,在 IFFT 之后检查max(abs(imag(x)))是否小于 1e-10。这两个检查加起来不到十行,能省掉后面几小时的排查。

5.2 误码率曲线在 1e-2 附近压不下去

现象:低 SNR 段曲线正常下降,到 15 dB 之后开始变平,怎么加 SNR 都停在 1e-2 到 1e-3 之间,画到 30 dB 依然是这个平台。

原因:削波噪声。CR 取得太低,时域峰值被大量削掉,削波引入的失真在接收端表现为额外的噪声底,这个底与 SNR 无关,所以曲线必然出现平台。CR = 7 dB 时平台在 1e-2 附近,CR = 10 dB 时能压到 1e-3 以下。

解决:先把 CR 提到 13 dB 重跑一遍。如果平台消失,就确认是削波问题,再回头做 CR 的扫描,找出误码率和光功率效率的平衡点——这个扫描本身就是论文里的一节内容,别当bug处理掉。

5.3 信噪比定义与实际不符,曲线整体平移

现象:曲线形状对,斜率也对,就是和理论线差了好几 dB,或者两条不同参数的曲线对不齐。

原因:SNR 定义不统一。有的地方按符号功率算,有的按比特能量算;有的把 CP 的功率算进去了,有的没算;有的加了sqrt(N)归一化,有的没加。定义一混,横轴就是错位的。

解决:在代码里固定一条链——Ps = mean((R*H0*x_led(:)).^2)算接收电功率,nvar = Ps / 10^(SNR/10)反推噪声方差,全篇只用这一处定义。理论线折算 Eb/N0 时,Eb/N0 = SNR × (N+Ncp)/N / log2(M)再乘上 CP 开销和子载波利用率,把这两项算进去,仿真和理论才对得上。

5.4 CP 长度与信道时延不匹配

现象:平坦信道下一切正常,一换成多径信道,误码率在中等 SNR 就出现平台,而且平台高度随反射抽头的时延增大而升高。

原因:CP 长度小于信道最大时延扩展。CP 的作用是把前一个符号的拖尾挡在 FFT 窗口之外,一旦时延超过 CP,符号间干扰无法消除,就会形成错误地板。

解决:CP 时长至少取最大时延扩展的两到四倍。20 MHz 采样下 Ncp = 16 对应 800 ns,折算光程 240 m,任何室内反射都远小于这个值,所以这套参数在室内场景非常安全。真要构造多径测试,把反射抽头放在 5~15 个样本之间,正好在 CP 覆盖范围内,可以看到 CP 有效性的验证效果。

5.5 归一化与均衡增益失配,星座图整体缩放

现象:误码率异常高,但星座图上的点分布是清晰的十六团,只是整体偏大、偏小或者偏移,qamdemod一直判错。

原因:发射端的sqrt(N)归一化和接收端的1/sqrt(N)没配上,或者均衡器里多除/少除了一次信道增益,导致Xhat的平均功率不是 1,而qamdemod的UnitAveragePower假设它是 1。

解决:在rx_dco_ofdm返回之前打一行mean(abs(Xhat(:)).^2),正常情况下应该接近 1。如果不是,往前逐级查:Yd的功率、Hd的量级、Xf的功率,哪一级和预期差了一个常数因子,问题就在那。我习惯在每一级后面加一行功率打印,跑一次就能定位,比盲猜快得多。

6. 验收与答辩:把曲线讲成一条能自证的链

验收这套仿真不需要复杂工具,一个能跑通的脚本加四条曲线就够。关键是每条曲线都能回答一个具体问题,而不是堆图。

验收项检查方法合格标准
时域实数性max(abs(imag(x)))小于 1e-10
非负性min(x_led(:))不小于 0
功率标定mean(x_led(:))等于设定的 Popt
平坦信道 BER15 dB 处低于 1e-3
理论对照仿真线与 erfc 理论线中 SNR 段贴合,偏差小于 2 dB
削波分析CR 扫描 7/10/13 dB平台高度单调下降
星座图15 dB 处16 个清晰点簇,无整体偏移
PAPR 分布CCDF 曲线0.1% 概率处 9~10 dB

答辩时最常见的追问是“你这个 SNR 是怎么定义的”和“为什么曲线在高 SNR 会出现平台”。前一个问题照 5.3 那条链答,后一个问题照 5.2 答,两个都能顺着讲到 CR 的取舍,节奏就起来了。反过来,如果只贴一张 BER 曲线不说平台成因,评委很容易认为你没跑过高 SNR 点,只是画了个形状。

还有个细节值得提前准备:把nSym从 2000 提到 20000,看误码率统计是否稳定。如果两次跑的 10⁻⁴ 点差了三四倍,说明样本量不够,这时候要么加大nSym,要么在论文里注明统计置信度。我带过的一个课设,A 同学就是因为没做这一步,答辩现场被要求重跑,十分钟跑不完,场面很难看。

从那以后我每次交付仿真,都强制走一遍“断言检查 → 单点复现 → 曲线对照 → 加大样本量”这四步,任何一步过不去就不往下走。这套流程看着笨,但它把“跑通了”和“跑对了”分开,前者靠运气,后者靠证据。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询