D2D信道仿真:从链路到系统的资源分配与干扰建模
简介面向无线通信方向的学习者与研究人员这份 MATLAB 仿真资料聚焦 D2D 通信的信道建模与资源分配问题适合已具备一定 MATLAB 基础、希望动手复现启发式算法求解频谱分配的中高级读者。资源包共 22 个文件以 20 个 .m 脚本为主体辅以 2 个 .asv 自动备份文件压缩包约 16KB体积轻量但结构完整。代码覆盖信道建模、路径损耗计算、用户与 D2D 对生成、干扰距离与干扰量统计、随机算法与启发式算法实现、最优方案求解及主流程调度等模块可支撑从信道仿真到资源分配对比实验的完整链路。已有 1214 人学习下载说明其在 D2D 仿真入门与课程设计场景中具有一定参考价值。读者可据此理解瑞利衰落、阴影衰落等信道条件下的性能评估思路对比随机分配与启发式算法的吞吐量、干扰表现并在此基础上改写参数、扩展算法或验证自己的资源分配策略。1. D2D 信道仿真为什么“链路能通”和“系统能跑”是两回事很多人第一次做 D2D 信道仿真都会掉进同一个坑单条链路的误码率曲线画得漂漂亮亮信噪比一拉高就乖乖往下掉看起来一切正常可一旦把几十对 D2D 用户塞进同一个小区加上资源分配系统吞吐不升反降甚至比不用 D2D 还差。这不是代码写错了而是链路级仿真和系统级仿真根本是两套东西。链路级关心的是“这一对收发之间给定信道模型误码率是多少”系统级关心的是“多对用户共享频谱时干扰怎么叠加、资源怎么分、谁该复用谁该退让”。D2D 信道仿真的价值恰恰在于把这两层接起来用 MATLAB 把路径损耗、阴影衰落、小尺度衰落的信道建模做扎实再把资源分配策略放进去跑才能看出复用增益到底被干扰吃掉了多少。搞懂这套机制你才知道自己画的曲线为什么“好看但没用”。2. 信道建模的底层逻辑从大尺度到小尺度的叠加顺序2.1 为什么必须先算路径损耗再叠衰落D2D 信道不是单一模型而是三层增益的乘积大尺度路径损耗、阴影衰落、小尺度快衰落。常见的实现思路是先把距离相关的路径损耗算出来再乘上对数正态分布的阴影项最后叠上瑞利或莱斯分布的小尺度项。顺序不能乱因为小尺度衰落的归一化功率是 1它只改变瞬时幅度不改变平均功率如果你先叠衰落再算路径损耗平均接收功率就会被错误缩放后面算信干噪比时全盘偏移。% 大尺度路径损耗D2D 常用近距离模型距离单位米 d max(dist, 1); % 避免 log(0) PL_dB 38.46 20*log10(d) 18.4*log10(fc/1e9); % 视距近似 % 阴影衰落对数正态标准差 sigma_sf shadow_dB sigma_sf * randn(size(d)); % 小尺度瑞利衰落复高斯功率归一化 h_small (randn(size(d)) 1j*randn(size(d))) / sqrt(2); % 总信道增益线性 gain_linear 10.^(-(PL_dB shadow_dB)/10) .* abs(h_small).^2;这段代码里fc是载频sigma_sf一般取 4 到 8 dB取决于场景。关键点在最后一行路径损耗和阴影是 dB 域相加后转线性小尺度衰落是线性域直接乘。很多人把h_small也转成 dB 再相加结果功率对不上误码率曲线整体平移几个 dB排查半天以为是调制解调写错了。我一般会在这里加一句断言检查mean(abs(h_small).^2)是否接近 1作为仿真前的自检。2.2 小尺度衰落为什么用瑞利而不是直接给个随机数瑞利衰落的物理含义是“没有直射径、多径散射充分”的场景D2D 在遮挡较多的环境下正好符合。它的复高斯实现之所以被广泛采用是因为两个独立高斯变量的模服从瑞利分布相位均匀分布这跟多径叠加的统计特性一致。如果你图省事直接rand()一个幅度分布是均匀的深衰落出现的概率被严重低估系统级仿真里干扰的尾部特性就失真了。莱斯衰落则用于存在直射径的情况用K因子控制直射分量占比K越大越接近高斯信道。D2D 近距离视距场景下K取 3 到 10 dB 是常见做法。2.3 阴影衰落的相关性为什么不能忽略独立同分布的阴影假设在链路级没问题但系统级仿真里同一对 D2D 用户在不同资源块上的阴影是相关的不同用户之间的阴影也可能相关。忽略相关性会让干扰的方差被高估资源分配算法显得“过于保守”。常见的处理是给阴影项加一个空间相关矩阵用 Cholesky 分解生成相关随机变量。这一步在 MATLAB 里就是chol加矩阵乘法但很多人直接跳过导致后面调度算法的性能对比失去意义。3. 资源分配放进仿真干扰怎么算、复用怎么判3.1 信干噪比的完整计算链路系统级仿真的核心是每个资源块上每个接收端的 SINR。D2D 复用蜂窝上行资源时D2D 接收端受到两类干扰复用同一资源块的蜂窝用户以及其他复用同一块的 D2D 对。计算顺序是先确定资源分配矩阵再逐块累加干扰功率最后算 SINR。% alloc: N_user x N_rb 的 0/1 分配矩阵 % P_tx: 发射功率向量, gain: 信道增益矩阵 (tx, rx) SINR zeros(N_user, N_rb); for rb 1:N_rb active find(alloc(:, rb)); for rx active signal P_tx(rx) * gain(rx, rx); interference 0; for tx active if tx ~ rx interference interference P_tx(tx) * gain(tx, rx); end end SINR(rx, rb) signal / (interference noise_power); end end这里gain(tx, rx)是发射端tx到接收端rx的信道增益注意索引方向别写反否则干扰算成了有用信号。noise_power用kTB加噪声系数算别直接拍一个常数。这段循环在用户数多时会慢常见的优化是把干扰项写成矩阵乘法但初版用循环更不容易出错先跑通再优化。3.2 复用判据距离门限还是干扰门限资源分配里最常见的复用判据是“D2D 对之间的距离大于某个门限才允许复用”这个门限来自干扰容限的推导。但更严谨的做法是直接算干扰门限如果 D2D 对复用某蜂窝用户资源后蜂窝用户的 SINR 下降不超过某个阈值才允许复用。距离门限是干扰门限的简化版实现简单但保守。仿真里两种都值得跑一遍对比你会看到距离门限在用户分布不均匀时明显吃亏。3.3 调度算法为什么不能只看瞬时 SINR比例公平调度在 D2D 场景下要同时考虑蜂窝用户和 D2D 用户的历史吞吐。只按瞬时 SINR 排序会让边缘用户饿死系统总吞吐好看但公平性崩盘。常见的实现是维护每个用户的平均吞吐用瞬时速率除以平均速率作为优先级。这个平均值的更新系数决定了“记忆长度”系数太小调度抖动大太大则响应慢。仿真里这个参数要跟资源分配周期匹配否则对比不同算法时结论不可靠。4. 仿真避坑那些让曲线“看起来对但实际错”的细节4.1 现象误码率曲线在高信噪比处出现平台原因通常是干扰被当成了噪声或者小尺度衰落的样本数不够。瑞利衰落的深衰落需要足够多的独立样本才能统计出来如果每个信噪比点只跑几百个符号高信噪比处的误码率会被少数深衰落样本主导曲线出现平台。解决方法是每个点至少跑 1e5 个符号或者用解析的瑞利误码率公式做交叉验证。4.2 现象系统吞吐随 D2D 对数增加先升后降但降得太早原因多半是干扰计算里漏了 D2D 对之间的相互干扰只算了蜂窝对 D2D 的干扰。D2D 对密集时彼此之间的干扰才是主要矛盾。检查interference累加循环是否覆盖了所有同资源块的发射端别只遍历蜂窝用户。4.3 现象不同随机种子下结论翻转原因是样本数不足或阴影相关性没处理。系统级仿真的随机性来源多单次蒙特卡洛的方差很大。常见做法是每个配置跑至少 50 次独立拓扑取平均并给出置信区间。如果两次种子结果差很多先加样本数再检查阴影生成是否每次重新抽样。4.4 现象资源分配矩阵出现全零行或全零列原因是分配算法的约束没写全比如每个 D2D 对最多复用一个资源块但代码里允许了一个对占多个块导致其他用户无块可用。在分配后加一行检查all(sum(alloc, 2) 0)不满足就报错比事后看吞吐异常再回头找快得多。5. 设计取舍仿真精度和跑得动之间怎么选信道仿真里最贵的不是公式是样本数和循环层数。链路级要精度就得堆符号数系统级要统计显著性就得堆拓扑数两者乘起来很容易让一次仿真跑上几个小时。我的经验是分层验证先用少量样本确认信道生成和 SINR 计算的逻辑正确比如单用户单资源块的手算对比再放大样本跑性能曲线。小尺度衰落用解析模型生成而不是逐个符号仿真能省一个数量级的時間代价是失去符号级定时细节但对资源分配的性能对比影响很小。另一个取舍是阴影相关性的建模复杂度。全相关矩阵最准但构造麻烦简化为同一用户跨资源块相关、用户间独立在多数对比场景下够用。关键是在报告结论时写清楚用了哪种假设否则别人复现不出来血泪经验就是曾经因为没写阴影假设被追问到重新跑了一遍全部仿真。取舍点高精度做法跑得动的做法适用场景小尺度衰落符号级逐样本生成解析分布直接抽样资源分配对比阴影相关性全相关矩阵用户内相关、用户间独立中等规模拓扑蒙特卡洛次数200 次以上50 次加置信区间初步筛选算法从那以后我每次搭 D2D 仿真都强制先跑一个“单链路手算对比”的小脚本确认路径损耗、阴影、衰落的叠加顺序和功率归一化没问题再往上叠资源分配。这个习惯帮我省掉了无数次“曲线不对但不知道错在哪”的排查。希望帮到你。本文还有配套的精品资源点击获取