
做多跳收集-传输无线传感器网络WSNs物理层安全仿真时我经常会遇到这样的场景数据源节点要把采集结果通过若干中继一跳一跳送到汇聚节点旁边还有一个窃听者在虎视眈眈更麻烦的是每个节点的射频硬件并不完美存在所谓硬件噪声。这种情况下简单选一条跳数最少或者瞬时SNR最高的路径往往不是最优解。我最近用Matlab完整实现了一套“基于路径选择的多跳WSN性能增强”仿真核心思路很直白在存在窃听者和硬件噪声时把每条候选路径的安全容量算出来再按准则选路最后用蒙特卡洛统计安全中断概率。这篇文章就把系统模型、公式推导、代码框架和踩过的坑一次性讲清楚适合正在做WSN安全路由、物理层安全或者Matlab仿真毕设的同学参考。1. 多跳WSN安全传输问题怎么拆1.1 收集-传输模式与窃听威胁“多跳收集-传输”这个词拆开看就是无线传感器网络最常见的运作方式传感器节点采集数据数据沿着中继节点逐跳转发最终汇聚到sink节点。网络中可能同时存在多条从源到sink的路径比如一个8节点的小型网络从节点1到节点8完全可能有4到5条无环路径。传统路由一般选跳数最少或者链路质量最好的路径但在安全场景下这个准则需要重新审视。窃听者的威胁模型一般是这样他可能部署在某个中继附近或者能够同时监听路径上的多段链路。物理层安全的经典做法是看合法信道和窃听信道之间的容量差。合法接收端能够正确解调的信号越多窃听者偷到的信息越少安全容量就越大。一旦安全容量低于目标速率就认为发生了一次安全中断。我在仿真中采用了最坏情况假设窃听者可以从路径所有跳中选择信道条件最好的一跳进行窃听这样评估出的安全性能偏保守工程上更可靠。多跳带来的问题是“性能累积”。每一跳都会引入噪声、衰减和新的窃听机会。如果单纯追求每跳SNR最大可能把路径引向窃听者附近如果单纯追求跳数最少可能被迫经过一条质量很差的长链路合法接收端自己都解不出来安全容量自然无从谈起。路径选择的本质就是在这个组合空间里找一条“合法传输够好、窃听获取够差”的折中路径。1.2 硬件噪声为什么不能忽略传统仿真通常假设收发机是理想器件接收信号只受加性高斯白噪声影响。但真实节点里存在功率放大器非线性、I/Q不平衡、相位噪声、ADC量化误差等这些统称为硬件损伤。硬件损伤的表现不是恒定噪声而是和信号功率相关的失真噪声。信号功率越大失真也越大最终在信噪比很高的时候仍然限制着实际可达性能。我在模型中采用了最常见的误差矢量幅度EVM建模方式。设理想接收信噪比为$\rho$硬件损伤因子为$\kappa$则实际等效信噪比可以写成[ \gamma \frac{\rho}{1 \kappa^2 \rho} ]当$\rho$趋于无穷大时$\gamma$约等于$1/\kappa^2$。也就是说硬件损伤引入了一个信噪比天花板。我仿真中默认取$\kappa^2 0.1$也就是10%的EVM对应的SNR天花板只有10dB。对多跳网络来说每跳都这么限制一次端到端性能会明显偏离理想模型。这个模型对路径选择影响很大。一条路径如果经过一个硬件损伤很严重的中继哪怕信道增益再高实际贡献也有限。反之一条低损伤节点组成的路径在高SNR区可能反超。因此路径选择不能只看信道SNR必须把每个节点的硬件损伤因子作为路由度量的一部分。1.3 路径选择本质是一个组合优化问题假设网络中有$N$个节点从源到sink的无环路径数量在最坏情况下可以随$N$指数增长。在一个中等规模的WSN中全部枚举并不现实但小规模网络比如10个节点以内完全可以通过深度优先搜索枚举所有路径。这是搞清楚问题机理的最好方式。选路之前要定义“好”的标准。我用的准则不是单一最大化SNR而是最大化端到端安全容量。这里包含两个维度合法链路要足够好窃听链路要足够差。硬件噪声会同时作用于合法接收端和窃听者所以路径选择实际上是在多个约束下做排序这比经典路由协议里的“最短路径”或“最大吞吐路径”复杂但也更贴近真实安全通信需求。2. 端到端性能度量与选路准则2.1 端到端SNR的DF逐跳瓶颈我用译码转发Decode-and-Forward, DF中继作为默认传输方式。DF中继每一跳都先解码再转发因此端到端性能受最差一跳限制。假设路径由$L$跳组成第$l$跳的等效信噪比为$\gamma_l$那么端到端合法信噪比为[ \gamma_D \min_{l1,\dots,L} \gamma_l ]这个“瓶颈模型”非常直观。哪怕其他跳都有20dB只要有一跳只有5dB整条路径的合法速率就被卡在5dB对应的水平。因此凡是做DF多跳研究第一个反应就是看最小跳SNR。路径上的每一跳信道是独立生成的硬件损伤又给每个跳一个独立的天花板所以$\gamma_l$的统计分布并不相同。路径选择在这种情况下更需要对逐跳信息进行综合比较。我还对比过放大转发AF模型但AF的端到端SNR是调和平均形式不像DF那样简单取最小。WSN节点一般算力有限DF比AF更容易实现且可以避免噪声逐跳放大所以本文默认用DF。如果你要做AF只需把评估函数里的$\gamma_D$换成等效端到端SNR公式即可。2.2 窃听端到端SNR的最坏情况建模窃听者不是只盯着一跳。他可以部署在路径经过的任意位置也可以在多个位置布置天线然后选择最好的一个输出。为了不低估窃听能力我采用“最好一跳窃听”模型假设窃听者能从路径所有合法跳中获得信号但最终只选择能够产生最大窃听SNR的那一跳。这是因为窃听者会自适应地选择最容易解码的信号工程上必须做这种最坏假设。于是路径的窃听端到端SNR定义为[ \gamma_E \max_{l1,\dots,L} \gamma_{e,l} ]其中$\gamma_{e,l}$是第$l$跳对应窃听者的等效SNR。窃听者也会受自身硬件噪声影响所以我同样用硬件损伤公式修正$\gamma_{e,l}$。实际仿真中如果窃听者位置固定距离不同跳的远近不同各跳的窃听SNR差异会很大。一旦某跳离窃听者特别近$\gamma_{e,l}$特别高整条路径的安全性能就会被拖垮。路径选择要自觉绕开这类“危险区域”。2.3 安全容量与安全中断有了合法端到端SNR和窃听端到端SNR瞬时安全容量可以写成[ C_s \left[ \log_2(1\gamma_D) - \log_2(1\gamma_E) \right]^ ]这个式子表示合法链路能传输的最大速率与窃听者能解码的最大速率之差。只有$C_s$大于零信息才能不被窃听实际传输还会设定一个目标安全速率$R_s$比如2bit/s/Hz。如果$C_s R_s$就认为发生了安全中断。安全中断概率就是对大量信道实现统计这个事件的发生频率。注意$R_s$设定不同结论可能不同。如果$R_s0$安全中断事件退化为$\gamma_D \le \gamma_E$即“合法信道还不如窃听信道”。如果$R_s$比较大即使$\gamma_D$高于$\gamma_E$也可能达不到目标中断概率会整体抬高。我在仿真里默认$R_s 1$ bit/s/Hz这是一个比较合理的参照。2.4 三种实用的路径选择准则为了说明路径选择的价值我在代码里实现了四种选路方式准则决策方式特点随机路径从候选路径中等概率随机选作为性能下界参照最短跳数选择跳数最少的路径减少暴露机会但可能链路质量差最大最小SNR最大化所有跳中的最小合法SNR均衡链路质量不考虑窃听最大安全容量最大化端到端瞬时安全容量联合考虑合法链路与窃听链路前两种是传统路由常见做法第三种是经典路由与物理层安全的折中第四种是我重点推荐的准则。从理论上说最大安全容量准则在每条信道实现上都选择了理论上限最优的路径其余准则不可能超过它。实际网络如果不能获得瞬时窃听CSI可以用统计CSI替换但趋势仍然一致。我在实验中发现一个很有趣的现象最大最小SNR准则在无窃听者时非常接近最优但一旦加入窃听者它会倾向于选择经过“高SNR危险区”的路径反而让窃听者捡了便宜。这说明安全场景下不能只盯合法链路必须把窃听CSI放进目标函数。3. Matlab仿真架构与关键代码实现3.1 仿真文件与模块划分Matlab代码如果全堆在一个脚本里调试起来非常痛苦。我建议按功能拆成几个文件每个文件只做一件事。我的项目文件结构大致如下main_simulation.m build_topology.m find_all_paths.m evaluate_path.m monte_carlo_run.m plot_results.mmain_simulation.m负责设置参数、调用其他函数、保存结果。build_topology.m生成网络拓扑和邻接矩阵。find_all_paths.m用深度优先搜索枚举所有简单路径。evaluate_path.m针对给定路径计算安全容量和中断标志。monte_carlo_run.m是蒙特卡洛主循环。这样每个函数都能单独测试出了问题也能快速定位。这种模块化设计还有一个好处如果以后要把路径枚举换成K最短路径算法或者把DF改成AF只需要改对应函数接口主流程不用动。我强烈建议做仿真项目时养成这个习惯不要贪图一时方便把所有代码写在循环里。3.2 拓扑生成与路径枚举首先生成一个小型WSN拓扑。节点随机分布在二维平面上设置一个通信距离门限只有距离小于门限的两个节点之间才有链路。为了演示方便我用的是手动指定邻接矩阵的方式保证源节点和sink之间有若干条路径可选。路径枚举我用了深度优先搜索DFS遍历所有无环路径。核心代码如下function paths find_all_paths(adj, s, t) paths {}; path s; dfs(s, path, adj, t, paths); function dfs(cur, path, adj, t, paths) if cur t paths{end1} path; %#okAGROW return; end nbrs find(adj(cur, :)); for nb nbrs if ~ismember(nb, path) dfs(nb, [path, nb], adj, t, paths); end end end end这个函数在小型网络里足够用。但要注意如果网络节点超过15个且比较稠密路径数量会爆炸式增长DFS会很慢。我在实际项目中的解决方式有两种一是限制最大跳数比如超过6跳的直接剪枝二是先计算K条最短路径再在这K条路径里做选择。对于真实WSN这两招比穷举实用得多。3.3 信道与硬件噪声生成信道生成我统一用瑞利衰落模型。为了简化我不直接仿真路径损耗和发射功率的绝对值而是设定“参考平均SNR”$\rho_0$。每一跳的瞬时理想SNR设为[ \rho_l \rho_0 \cdot g_l ]其中$g_l$是服从指数分布的归一化信道功率增益即$g_l \sim \text{Exp}(1)$期望为1。窃听信道同理但它的平均SNR要单独设置用来反映窃听者距离路径的远近。硬件损伤修正函数如下function gamma apply_hwi(rho, kappa2) % rho: 理想信噪比线性值 % kappa2: 硬件损伤因子通常取值0.01到0.2 gamma rho ./ (1 kappa2 .* rho); end这个函数对合法链路和窃听链路都适用。唯一区别是合法节点和窃听者各自的$\kappa^2$可能不同。我在仿真中默认窃听者的硬件损伤较小因为窃听设备通常是专门搭建的射频前端质量可能更好这会让安全性能更差仿真结果也更保守。3.4 路径评估与蒙特卡洛主循环路径评估函数接收一条路径、该路径每一跳的合法SNR、窃听SNR以及目标速率$R_s$返回安全容量和中断标志。实现如下function [Cs, outage] evaluate_path(gamma_l, gamma_e_l, Rs) gammaD min(gamma_l); gammaE max(gamma_e_l); Cs max(log2(1 gammaD) - log2(1 gammaE), 0); outage Cs Rs; end蒙特卡洛主循环需要遍历所有候选路径在当前信道实现下选出最优路径再统计中断事件。伪代码如下rho0 10^(snr_dB / 10); kappa2 0.1; Rs 1; Nmc 20000; outage_count 0; for mc 1:Nmc % 生成每条边的瞬时SNR rho_legit rho0 * exprnd(1, Nedges, 1); rho_eav rho0_eav * exprnd(1, Nedges, 1); gamma_legit apply_hwi(rho_legit, kappa2); gamma_eav apply_hwi(rho_eav, kappa2_eav); % 对所有候选路径计算安全容量 best_Cs -inf; for p 1:length(paths) g_l gamma_legit(paths{p}(1:end-1)); % 每条边对应前一节点 g_e_l gamma_eav(paths{p}(1:end-1)); [Cs, ~] evaluate_path(g_l, g_e_l, Rs); if Cs best_Cs best_Cs Cs; end end [~, outage] evaluate_path(???, ???, Rs); % 实际这里应该在选路径时保留中断标志 if outage outage_count outage_count 1; end end sop outage_count / Nmc;代码里我故意留了一个需要处理的地方更高效的做法是在循环里同时记录选中路径的outage而不是重复调用。实际我建议把evaluate_path返回值直接存在一个数组里然后用max函数找到最优路径和对应中断标志这样逻辑更清晰。3.5 绘图与结果导出仿真结果我一般用两种图展示一是安全中断概率随平均SNR变化的曲线用semilogy画二是特定SNR点下四条选路准则的柱状对比。绘图代码大致如下snr_dB 0:2:30; sop_maxsec zeros(size(snr_dB)); sop_minhop zeros(size(snr_dB)); for k 1:length(snr_dB) % 运行蒙特卡洛记录不同准则下的中断概率 end figure; semilogy(snr_dB, sop_maxsec, -o, LineWidth, 1.5); hold on; semilogy(snr_dB, sop_minhop, -s, LineWidth, 1.5); grid on; xlabel(平均SNR (dB)); ylabel(安全中断概率); legend(最大安全容量, 最短跳数);还要提醒一句Monte Carlo次数不够时安全中断概率曲线会抖动。我建议至少跑20000次尤其是在低中断概率区域否则画出来的图锯齿感很强不方便解释趋势。4. 仿真结果分析与规律总结4.1 安全中断概率随SNR和硬件损伤的变化我跑完一组典型参数后得到的趋势非常明显平均SNR从0dB增加到20dB时最大安全容量准则下的安全中断概率从接近1下降到10^-3量级但继续增加SNR到30dB中断概率下降变缓出现“地板效应”。这个地板正是硬件损伤造成的。理论上如果$\kappa^20$安全中断概率应该一直下降但存在硬件噪声后合法和窃听信道都在高SNR区接近各自天花板两者比值趋于恒定中断概率就趋于一个非零常数。这个结果给工程实践的启示是一味提高发射功率并不是安全传输的有效手段尤其是在硬件质量已经固定的节点上功率提上去只会带来更多失真噪声和能耗。与其增加功率不如在路由层做路径重选绕开损伤严重的节点。这也是本文路径选择方法最直接的增益来源。4.2 路径选择策略之间的差异把四种选路准则放在同一张图上随机路径的性能最差这符合直觉。最短跳数路径在低SNR区和高SNR区的表现有点意思低SNR时它往往因为跳数少而减少累积噪声表现尚可但高SNR时如果最短路径经过窃听者旁路安全中断概率会明显高于最大安全容量准则。最大最小SNR准则在无窃听者时很稳但加入窃听者后就暴露出问题它可能选出一条每跳都很好但恰好被窃听者盯着的那条路。这说明“链路好”和“安全”并不等价。最大安全容量准则始终优于其他准则因为它在每个瞬时信道状态下都直接优化了安全容量相当于一个理想的在线路由上界。实际网络也许无法这么理想但它给出了一个基准。4.3 拓扑与窃听位置的影响我换了三种拓扑验证结论。第一种是线型链式网络路径选择空间很小选路收益不大。第二种是存在两条并行中继链的网络其中一条靠近窃听者结果最大安全容量准则总能避开危险路径。第三种是带有冗余节点的网状网络路径选择空间更大不同准则的差距也更明显。窃听者位置对结果影响极大。当窃听者位于源节点附近时第一跳就完全暴露任何路径选择都很难挽救因为数据已经在第一跳被窃听。当窃听者位于sink附近时最后一跳是瓶颈。路径选择会倾向于从另一侧绕行。这说明在做WSN安全路由设计时必须对窃听者的可能部署位置有先验估计路径选择算法才有发挥空间。4.4 代码可复现性检查为了让结果可复现我把关键参数列成一个表参数默认值说明节点数量8随机生成保证连通平均SNR范围0~30dB合法链路平均信噪比窃听平均SNR0~20dB相对路径位置决定硬件损伤因子$\kappa^2$0.1合法节点窃听硬件损伤因子$\kappa_e^2$0.05窃听设备质量更好目标安全速率$R_s$1 bit/s/Hz可调蒙特卡洛次数20000降低统计波动信道衰落模型瑞利功率增益指数分布如果你直接复现要注意随机数种子。我一般会在main_simulation.m开头加上rng(2025)这样每次跑出来的拓扑和信道一致方便对比算法改进前后的差异。如果没设种子结果会不断变化很难定位是代码问题还是随机性问题。5. 常见问题与调试实录5.1 路径枚举慢怎么办我最初在15个节点的中等稠密网络里做全路径枚举DFS跑了十几秒还能忍受但节点数到20以后直接内存溢出。后来我改成两个办法一是在DFS里加最大跳数限制超过设定值直接剪枝二是先跑Dijkstra得到最短路径再通过删除单条边的方式生成K条备选路径只在这K条路径里做选择。对于WSN这种资源受限场景K取5到10通常足够没必要把所有路径都枚举出来。5.2 安全中断概率永远很高如果你发现安全中断概率在所有SNR下都接近1先别急着改算法。我遇到三次这种情况原因各不相同。第一次是窃听SNR设置太高窃听者离所有路径都太近合法链路再怎么优也没用。第二次是目标速率$R_s$设成了10bit/s/Hz太高当然永远中断。第三次是硬件损伤因子$\kappa^2$设成了1等效SNR天花板只有0dB合法链路完全没有优势。建议先把$\kappa^20$、$R_s0$跑一遍确认结果符合理想模型再逐步加条件。5.3 硬件损伤因子应该怎么取硬件损伤因子的物理含义是失真噪声功率与信号功率之比。实际设备的EVM通常在1%到10%之间对应$\kappa^2$在0.0001到0.01之间。我做仿真时为了突出效应会把$\kappa^2$调到0.1有时候甚至0.2这不是说真实设备这么差而是为了在曲线上清楚看到天花板。如果你要对应真实硬件建议参考芯片手册里的EVM指标再换算成$\kappa^2$。5.4 蒙特卡洛结果抖动如何处理安全中断概率越小需要的蒙特卡洛次数越多。比如要估计10^-4量级的中断概率至少需要10^6次采样才能得到可靠结果。但WSN安全仿真中信道生成和路径枚举都比较耗时跑10^6次会等很久。我的经验是分两步走先用20000次采样找到大致趋势和区分度锁定感兴趣的SNR区间后再单独对那个区间跑更高次数这样既省时间又不影响结论。5.5 硬咬文嚼字不如把“中断事件”和“路径选择”分开调我的调试习惯是先不接路径选择模块固定一条路径跑安全中断概率确认这条路径的理论趋势正确后再把路径选择模块接回去。这样能快速区分问题是出在物理层SNR计算还是出在选路逻辑。最后再分享一个小技巧把每条路径在某个信道样本下的安全容量打出来手动算一遍和代码输出对比这一步能消除几乎所有隐蔽的索引错误。多跳路径的边索引非常容易写错我在项目里至少因为索引错位浪费过半天时间。如果你后续想在这个框架上加东西建议优先尝试不完美CSI下的路径选择因为真实网络里窃听信道信息很难精确获得。也可以把静态拓扑换成动态节点在每一帧重新执行选路观察安全中断概率的时变特性。这些扩展方向都能直接复用本文的代码结构改动量不会太大。