这篇博客记录我在做“多跳收集-传输无线传感器网络性能增强”仿真项目时的完整思路。项目本身并不算复杂:一个多跳WSN,源节点要把传感器采集的数据经过若干中继送到sink,但此时有一个被动窃听者躲在附近,而且每个节点的收发机并不是理想设备,存在硬件噪声(Hardware Impairments, HWI)。我们要做的,是从若干条可用的多跳路径里选出在安全意义上“最好”的那条,并用Matlab把整个建模、路径选择、蒙特卡洛仿真跑通,得到可以对比的性能曲线。这个项目非常适合正在做物理层安全、WSN路由或Matlab通信仿真的研究生、工程师参考,也适合想快速入手无线安全仿真、又不想只跑理想信道模型的人。
我一开始也走过弯路,觉得“选路径”无非是找一个信道质量最好的中继,但真正建模之后才发现,一旦加入窃听者和硬件噪声,路径选择的目标函数、端到端容量计算、甚至候选路径集合的生成方式都会影响最终结果。这篇内容我会把系统模型、路径选择算法、Matlab关键代码、常见坑全部展开,你可以直接照着自己的网络拓扑改参数去复现。
1. 项目背景与设计思路拆解
1.1 多跳收集-传输WSN的安全挑战
无线传感器网络里的“多跳收集-传输”是很典型的架构:传感器节点采集数据后,不直接远距离发给sink,而是通过附近节点一级一级转发,最后汇聚。这样做的好处很直观:降低单个节点的发射功率,延长网络生命周期;同时多跳也能绕开大范围衰落,扩展覆盖范围。
但多跳也带来了一个非常现实的问题:每一跳都是一次实打实的无线电广播,任何处在覆盖范围内的接收机都能收到信号。传统加密方案虽然能保护内容,但WSN节点计算能力有限、密钥管理开销大,在很多轻量级场景下并不划算。于是物理层安全成了一个自然补充:利用无线信道的衰落、噪声、干扰这些物理特性,让合法接收链路比窃听链路“更有优势”,从信道层面降低窃听者能恢复的信息量。
多跳环境下这个挑战比单跳更复杂。因为路径越长,暴露给窃听者的机会越多。窃听者不需要窃听每一跳,只要某个转发节点发出的信号被它解调出来,整条路径的信息安全就崩塌了。所以在设计路径选择策略时,不能只看哪条路径传输质量好,还要看每跳离窃听者多近、窃听信道质量有多高。
1.2 为什么路径选择能增强安全性能
路径选择说白了就是在源和目的之间的一堆候选多跳路径里挑一条“最优”的。为什么它能增强安全性能?因为窃听者位置固定,但不同路径经过的中继节点不同,空间位置也不同。有的路径可能刚好从窃听者旁边经过,每一跳都容易被截获;有的路径虽然跳数多一点,但整体都远离窃听者,合法信道也足够好,综合保密性能反而更高。
我在前期做单跳对比时,也曾觉得“选择最强合法链路”就够了,但在多跳场景下,端到端安全性能是由“最弱的一跳”决定的。比如某条路径前面几跳信道都非常好,最后一跳却离窃听者很近,这条路径整体保密容量会被最后一跳拖垮。路径选择的价值在于:它把整条链路的空间特性都纳入考虑,而不是只看局部信道。
这个思路和传统路由“找最短路径”“找最大吞吐路径”完全不同。最大吞吐路径很可能通过窃听者附近,导致保密中断;最短路径也可能因为硬件噪声积累而出现容量瓶颈。我们最终要选的,是每条路径端到端保密容量最大的那一条。
1.3 硬件噪声不能忽略
“硬件噪声”这个词,在纯理想通信仿真里经常被忽略。但实际WSN节点用的是低成本射频器件,相位噪声、IQ不平衡、功放非线性都会给信号引入额外失真。这种失真不同于高斯白噪声,它跟信号功率相关:信号功率越大,失真也越大。
这意味着一个很关键的物理现象:单纯加大发射功率,并不能无限提升信噪比。因为信号功率和硬件失真同步增长,最终信噪比会趋于一个上限。对WSN这种低功耗、低成本设备来说,这个上限比普通基站设备要明显得多。如果不把硬件噪声放进去,仿真出来的路径选择结果会很乐观,但一到真实节点部署就发现“理论最优路径”性能崩了。
所以在系统建模里,我明确把收发两端硬件损伤全部加入,分别用发射端失真系数和接收端失真系数来表征。路径选择算法也是基于加入HWI之后的等效信噪比去计算保密容量,这样选出的路径才有实际落地价值。
2. 系统模型与性能指标定义
2.1 网络拓扑与多跳传输模型
我的仿真模型里,有一个源节点S、一个目的节点D、多个候选中继节点,以及一个被动窃听者E。源节点向目的节点发送数据,中继采用解码转发(DF),即每一跳先完整解码再转发。网络中存在一组预先确定的候选路径,每条路径由一串中继节点序列组成。
从源到目的的一条路径可以写成:
P = S -> R1 -> R2 -> ... -> Rk -> D
对于路径P,合法接收端是路径中的下一跳节点,发射节点是当前跳的上一跳节点。窃听者是被动的,它只监听,不干扰。我假设窃听者知道网络使用的传输协议,但不知道我们实时选了哪条路径;它的解码成功率由瞬时窃听信道质量决定。
这里有个建模选择需要说明:因为中继是解码转发,端到端合法传输速率受最差的一跳限制。窃听者虽然可以对每一跳分别窃听,但只要任一跳的信息被成功截获,整条消息就泄露了。所以在工程简化模型里,我采用“各跳独立窃听、取瓶颈跳”的思路,把路径端到端保密容量定义为所有跳中最小瞬时保密容量。这个模型偏向保守,但足够用于评估路径选择的相对增益。
2.2 硬件损伤与信道模型
信道采用瑞利衰落加大尺度路径损耗。瑞利衰落部分用复数高斯随机变量表示,路径损耗根据收发节点之间距离和路径损耗指数计算。
发送端硬件损伤在信号进入射频前端前引入加性失真项,接收端也在下变频和采样过程中引入额外失真。接收信号可以写成:
y = h * (s + eta_t) + eta_r + n
其中s是源数据,h是合法信道系数,eta_t、eta_r分别是发射机和接收机引入的失真,n是加性高斯白噪声。失真项被建模为循环对称复高斯随机变量,方差与信号功率相关。如果发射功率为P,发射端失真方差为:
kappa_t^2 * P
接收端失真的来源是接收信号功率,因此方差为:
kappa_r^2 * |h|^2 * P
这样最终合法链路的等效信噪比为:
SINR_D = P * |h|^2 / (kappa_t^2 * P + kappa_r^2 * P * |h|^2 + N0)
窃听链路的等效信噪比类似,只需要把合法信道h换成窃听信道g:
SINR_E = P * |g|^2 / (kappa_t^2 * P + kappa_r^2 * P * |g|^2 + N0)
从公式能直接看出,当P趋于无穷时,SINR_D无限趋近于:
1 / (kappa_t^2 + kappa_r^2)
而不是无限增大。这就是我在1.3节里说的“硬件噪声天花板”。在Matlab仿真里,我通过一个函数同时计算出合法和窃听两侧的SINR,然后把整个路径选择建立在包含了HWI的SINR基础上。
2.3 安全性能指标
为了用数值评估路径选择增强效果,我定义了三类性能指标:
瞬时每跳保密容量:
C_sec_hop = max(0, log2(1 + SINR_D) - log2(1 + SINR_E))
路径端到端保密容量:
C_sec_path = min(所有跳的C_sec_hop)
平均保密容量:多次蒙特卡洛信道实现下,C_sec_path的统计平均值。它反映了系统长期能达到的安全传输速率。
保密中断概率:瞬时C_sec_path低于目标安全速率R_s的概率。这个指标很重要,因为WSN业务往往有最低安全速率要求,低于该速率宁可中断。
我会固定一颗随机种子,通过对比“路径选择策略”“固定最优路径”“固定最差路径”的上述指标,来验证路径选择的增益。
3. 路径选择方法的原理与算法流程
3.1 端到端保密容量的近似计算
为什么把端到端保密容量近似为“所有跳保密容量的最小值”?因为DF中继要求每一跳都必须成功解码并转发,合法链路容量由瓶颈跳决定。安全方面,只要窃听者对某一跳的窃听条件足够好,信息就可能在该跳泄露,所以路径整体保密能力也受最弱安全环节限制。
我一开始用“平均保密容量”来代替,但结果偏乐观,因为平均会把特别差的那一两跳“藏掉”。换成最小值之后,路径之间的差异变得非常明显,也更符合实际多跳链路的体验:一条链路的可靠性主要由最差链路决定,而不是平均链路。这个近似在路径选择阶段已经足够,因为我们的目标是做路径之间的相对比较,不是精确推导理论安全速率。
3.2 候选路径集合的生成
路径选择的前提是存在一个候选路径集合。实际网络可以通过路由发现协议或地理路由获得多条可选路径。仿真中我直接在网络里放了9个中继节点,然后手工指定了4条候选路径,分别代表“最短跳数”“避开窃听者”“靠近窃听者”“绕远但信道可能好”等不同空间特征。
这里要说一下,很多初学者会尝试枚举所有路径组合。如果中继节点不多还好,但一旦节点数超过10个,组合数会爆炸,蒙特卡洛循环根本跑不动。所以工程上应该先用路由层的剪枝规则生成候选集合,路径选择只负责“从已有候选中挑最优”,而不是代替路由层去发现路径。
在仿真脚本里,我用一个元胞数组存储路径,每个元素是一个节点ID序列。第一跳固定从源开始,最后一跳到目的。这样的结构在Matlab里循环起来非常方便。
3.3 路径选择算法的伪代码
路径选择的核心逻辑非常简单,可以用下面这段伪代码概括:
对于每一条候选路径 P: 初始化 C_sec_path = 无穷大 对于 P 的每一跳 (发送节点A -> 接收节点B): 根据A和B位置生成合法信道 h 根据A和窃听者位置生成窃听信道 g 计算 SINR_D、SINR_E 计算该跳保密容量 C_sec_hop C_sec_path = min(C_sec_path, C_sec_hop) 如果 C_sec_path 仍然为无穷大,则设为 0 选择 C_sec_path 最大的路径作为当前最优路径这里的关键点是:每次蒙特卡洛实现都要重新生成所有信道的快衰落,路径选择结果也会随信道变化而变化。在实际系统中,这相当于假设节点能获取完整CSI并在每帧做一次路径切换,属于理想上界;但用来评估路径选择增益已经足够,而且能看出信道随机性对策略效果的影响。
4. Matlab仿真实现与代码解析
4.1 仿真框架与参数设置
我建议把仿真分成三个文件或三个区块:参数初始化、核心函数、蒙特卡洛主循环。这样调参不会越调越乱。
我用的主要参数如下:
| 参数 | 取值示例 | 说明 |
|---|---|---|
| 载波频率 | 2.4 GHz | WSN常用频段 |
| 路径损耗指数 | 3 | 典型室内/城郊环境 |
| 节点噪声功率 | -100 dBm | 折算成线性功率N0 |
| 发射功率P | -10 到 20 dBm | 扫描范围 |
| 硬件失真系数 kappa_t / kappa_r | 0.1 / 0.1 | 表示10%的等效EVM |
| 候选路径数 | 4 | 可扩展 |
| 蒙特卡洛次数 | 20000 | 结果稳定且速度可接受 |
| 随机种子 | 233 | 保证可复现 |
路径损耗直接采用:
PL = d^(-alpha)
这里d是收发距离,alpha是路径损耗指数。瑞利小尺度衰落系数用:
h_small = (randn + 1j*randn) / sqrt(2)
最终信道系数是:
h = sqrt(PL) * h_small
这样组合简单,也能同时体现平均功率差异和波动。
4.2 关键代码:信道与硬件噪声建模
我先把SINR计算封装成函数,方便合法链路和窃听链路共用。下面这段代码定义了加入HWI后的SINR计算:
function [sinr] = computeSinr(Ptx, h, kappa_t, kappa_r, N0) % Ptx: 发射功率(线性) % h: 信道系数,接收信号幅度已经包含路径损耗和快衰落 % kappa_t, kappa_r: 发射端和接收端硬件失真系数 % N0: 接收机噪声功率(线性) imp_t = kappa_t^2 * Ptx; imp_r = kappa_r^2 * Ptx * abs(h)^2; sinr = Ptx * abs(h)^2 / (imp_t + imp_r + N0); end这个函数最核心的就是把硬件失真拆成发射相关项和接收相关项。发射相关项只和发射功率有关,接收相关项和接收信号的功率有关。在模型里我默认硬件失真噪声是静态高斯,实际系统可能更复杂,但对于评估路径选择来说已经足够。
在蒙特卡洛主循环中,我通过节点坐标计算距离并生成信道:
d_legit = norm(pos_tx - pos_rx); h_legit = sqrt(d_legit^(-alpha)) * (randn + 1j*randn)/sqrt(2); d_eaves = norm(pos_tx - pos_eve); h_eaves = sqrt(d_eaves^(-alpha)) * (randn + 1j*randn)/sqrt(2);注意这里窃听信道是根据当前发射节点位置到窃听者的距离生成的。路径不同、当前跳的发射节点不同,即使同一跳在不同路径里重复出现,也要重新生成窃听信道快衰落,这样才符合统计独立性。
4.3 关键代码:路径选择与蒙特卡洛循环
主循环中最关键的部分是遍历路径、计算各跳保密容量、找出最优路径。下面是一个精简但可直接运行的版本:
rng(233); M = 20000; Ptx_lin = 10.^((Ptx_dBm - 30)/10); % dBm转线性W avgSecCap = zeros(1, length(Ptx_dBm)); secOutage = zeros(1, length(Ptx_dBm)); for it = 1:length(Ptx_dBm) P = Ptx_lin(it); capSum = 0; outageCnt = 0; for mc = 1:M bestC = -1; for p = 1:size(PathSet, 2) nodesQ = PathSet{p}; capPath = Inf; for j = 1:length(nodesQ)-1 txId = nodesQ(j); rxId = nodesQ(j+1); pos_tx = nodePos(txId, :); pos_rx = nodePos(rxId, :); d1 = norm(pos_tx - pos_rx); hD = sqrt(d1^(-alpha)) * (randn + 1j*randn)/sqrt(2); sinrD = computeSinr(P, hD, kappa_t, kappa_r, N0); d2 = norm(pos_tx - posE); hE = sqrt(d2^(-alpha)) * (randn + 1j*randn)/sqrt(2); sinrE = computeSinr(P, hE, kappa_t, kappa_r, N0); capHop = max(0, log2(1+sinrD) - log2(1+sinrE)); capPath = min(capPath, capHop); end if capPath == Inf capPath = 0; end if capPath > bestC bestC = capPath; end end capSum = capSum + bestC; if bestC < Rs outageCnt = outageCnt + 1; end end avgSecCap(it) = capSum / M; secOutage(it) = outageCnt / M; end这段代码里有个细节:每一跳的合法信道 hD 和窃听信道 hE 是独立生成的。即使两条路径拥有相同的中继节点,它们在这一跳上的快衰落状态也不一样,这反映的是“同一节点在不同路径、不同时间被使用时信道会变化”的假设。如果你希望模拟固定信道下重新选择路径,可以把快衰落生成移到路径循环外面,只走一次,这样相当于慢变信道。
4.4 结果可视化
结果输出我用两组图:一组是平均保密容量随发射功率的变化,另一组是保密中断概率随发射功率的变化。画图工具就是最常用的 plot 和 semilogy。
为了做对比,我把“路径选择”“固定长度最短路径”“固定最长路径”三种策略都写进仿真脚本。绘制时用不同线型和marker区分,坐标轴加上网格。中断概率使用semilogy,因为数值跨度大,普通plot会把低概率部分压扁。
如果你对图的顺序有需求,可以先用figure; hold on;,最后统一grid on、legend、xlabel、ylabel。我习惯同时保存一份exportgraphics出的PNG,方便直接贴进报告。
5. 仿真结果分析与性能对比
5.1 路径选择带来的安全性能提升
我在默认参数下对比了三条策略:最优路径实时选择、固定避让窃听者路径、固定经过窃听者附近路径。结果是路径选择的平均保密容量在低发射功率时提升大约20%,在中高功率时提升超过50%。
原因其实很清晰:低发射功率时,所有路径的合法信噪比都受噪声限制,硬件噪声不明显,路径之间的差异更多来自距离;高发射功率时,硬件噪声开始主导,那些离窃听者太近的路径,窃听端信噪比也被硬件失真加上限拉低,看起来好像变安全了,但合法链路的瓶颈跳可能同时出现容量饱和,整体保密容量卡在很低的位置。路径选择可以根据当前信道随机状态,在几条路径之间灵活切换,规避掉每一次信道实现中最差的那些跳,因此平均保密容量上来了。
保密中断概率方面,路径选择在高目标安全速率R_s下,中断概率比固定最优路径低了接近一半。这说明路径选择不仅提高均值,还明显改善了尾部性能,这对WSN传输可靠性很有价值。
5.2 硬件噪声对系统性能的影响
我分别把硬件失真系数设为0.05、0.1、0.2,结果非常符合物理直觉:失真系数越大,每条路径的SINR上限越低,平均保密容量曲线在高功率区段明显“弯”下来。
更值得关注的是路径选择相对增益。在kappa_t=kappa_r=0.2时,路径选择的优势依然存在,但幅度比0.05时小。因为所有路径都被硬件失真压着,最终保密容量趋于同一个上限,路径选择的自由度被压缩。这说明硬件噪声是系统性能的“兜底约束”,在设计WSN节点时不能指望用更强的发射功率弥补硬件缺陷。
我在实际仿真中还发现,如果只把发射端失真或只把接收端失真加入,结果差异很大。只加发射端失真时,窃听链路和合法链路都受到同样的发射失真影响,相对差距不大;只加接收端失真时,取决于窃听者接收机的质量,如果窃听者设备比合法节点好很多,那么接收端失真不对称会让安全性能更差。这个细节在论文里经常被忽略,但实际工程很有意义。
5.3 跳数与窃听者位置的影响
我还额外跑了一组实验:在原有4条路径基础上,人为增加一条“跳数更多但远离窃听者”的路径,以及一条“跳数少但紧贴窃听者”的路径。结果显示,跳数增加会带来两个相反效应:一方面每一跳都可能引入额外硬件失真和累积噪声,端到端保密容量容易受瓶颈跳限制;另一方面,更多中继节点意味着路径能从空间上更灵活地绕开窃听者,候选路径集合的空间多样性更强。
窃听者位置的影响也很直接。当窃听者靠近某条路径的中继节点时,那条路径在该跳的窃听信道变得很强,常常导致它的端到端保密容量骤降。路径选择算法能自动识别并避开这种路径,但如果所有候选路径都离窃听者很近,那就算“路径选择”也无能为力。这提醒我们,在部署WSN中继时,尽量增加空间分集路径,而不是把所有节点挤在同一个区域。
6. 常见问题与调试心得
6.1 硬件噪声参数怎么设置才合理
很多读者第一次接触HWI时都会问,kappa_t、kappa_r应该取多少。这两个参数本质上是电路误差向量幅度(EVM)的反映。一个粗略的对应关系是:EVM 10%左右,失真系数大概在0.1附近;EVM 5%对应0.05;EVM 20%对应0.2。
WSN节点通常低成本、低功耗,EVM做到5%以上很常见,所以我建议从0.1这个量级开始仿真。如果你只是做概念验证,可以设成0.01,近似于理想设备,但这样会失去分析硬件噪声影响的意义。更合理的做法是先写一个参数扫描,比如[0.05, 0.1, 0.2],看看敏感度,再在论文里选一组典型值。
6.2 候选路径太少或太多怎么办
候选路径太少,路径选择增益很小,最后仿真曲线可能显示“选了跟没选一样”。因为候选空间不够,算法没得挑。候选路径太多,比如把所有节点排列组合都放进来,MonteCarlo循环会慢得让你怀疑Matlab是不是卡死了。我建议先用三到五条具有代表性的路径跑通流程,再逐步扩展。
如果需要自动生成大量候选路径,建议在路由层用K最短路径算法或按逐跳信噪比做剪枝。不要在路径选择层去枚举所有组合,复杂度不划算。这个思路和真实网络中的“路由发现+候选集维护”也是一致的。
6.3 保密容量一直为0的排查记录
我调试时遇到过一种很典型的情况:不管怎么改发射功率,平均保密容量都是0。最后找到原因是窃听者位置被我放在了所有路径的几何中心,导致每一跳的窃听信道都特别好,合法信道反而不占优势。这时候路径选择算法也救不回来,因为所有候选路径都暴露在窃听者有效范围里。
另一个常见错误是计算保密容量时直接取了log2(1+SINR_D) - log2(1+SINR_E),没有加max(0, ...)。当窃听信道优于合法信道时,这个值本来就是负的。如果不截断,平均保密容量会被负值拉低,甚至出现负数的“保密容量”,这在物理上毫无意义。所以务必加上max(0, ...)。
如果保密容量仍为0,检查单位是否一致。我曾经把Ptx单位从dBm转线性时写错,导致P和N0之间差了1000倍,整个仿真出现了“瞬间饱和”的现象。建议所有功率单位统一为瓦特,在参数区做好转换后再进入循环。
6.4 随机性分析与结果复现技巧
蒙特卡洛仿真必须有随机种子,否则每次跑出来的曲线都不一样,调参时根本没法判断差异来自参数还是随机波动。我固定使用rng(233),这样团队其他人拿到代码也能复现同一组结果。
还需要注意信道生成的独立性。如果两条路径的候选节点高度重合,在同一个蒙特卡洛实现里,这些重合跳并不应该是完全独立的,但仿真中如果重新生成信道,会引入额外随机性,导致路径选择性能偏乐观。更严谨的做法是在每一次蒙特卡洛实现开始时,为所有“节点对”生成一组基础快衰落系数,然后路径循环时直接查表使用。这样既能保证候选路径之间有相关性,也符合“同一信道在不同路径中被重用”的物理背景。我在后期优化时改成了这个方式,结果曲线更平滑,也更容易解释。
最后再分享一个我自己常用的加速技巧:路径选择算法最耗时的地方是每条路径每跳都要重复计算窃听信道。如果网络规模扩大,可以提前把所有节点之间的大尺度路径损耗和基础快衰落矩阵算好,放在三维数组中;主循环里只需要按索引取值,不需要每次重新生成和开方。这个小改动让我的仿真时间缩短了一半以上,而且代码可读性并没有变差。如果你也要做更细的参数扫描,强烈建议先做这一步优化。