ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

无人机辅助认知无线传感网络协作频谱感知的Python仿真与调参实践

无人机辅助认知无线传感网络协作频谱感知的Python仿真与调参实践 简介这份资源面向具备基础编程能力、关注无线传感网络频谱感知的科研人员与技术爱好者围绕论文“Efficient Cooperative Spectrum Sensing in UAV-Assisted Cognitive Wireless Sensor Networks”的复现展开帮助读者理解无人机辅助认知无线传感网络中协作频谱感知的系统建模与算法实现。内容涵盖仿真参数配置、信号模型与能量检测、CVR、SVR、S1、DS1四种投票规则的实现以及检测性能图与样本大小图的仿真对比可用于探索不同投票规则表现、分析最优方案并评估无人机辅助环境下的检测效果。资源包共1个docx文件约29KB以文档形式集中呈现完整代码与逐段解释便于对照阅读与二次修改。目前已有108人学习适合希望快速上手复现、比较投票算法差异并寻找改进方向的读者参考。1. 无人机辅助认知无线传感网络中的协作频谱感知从场景到可跑通的 Python 方案主用户信号被建筑物遮挡、感知节点电池见底、山区洪涝灾害下无人机运输与通信协同优化这类场景里频谱空洞往往转瞬即逝。认知无线传感网络CRSN里的单个感知节点受阴影衰落和噪声不确定性影响虚警和漏检率居高不下于是把多个节点的判决结果汇聚起来做协作频谱感知CSS成了常规思路。无人机在这里扮演的是可移动的融合中心兼中继它飞到感知簇上方收集本地判决再回传融合结果。这篇笔记讲的就是用 Python 把这条链路搭起来——从能量检测、硬判决融合到软判决加权给出能直接复现的代码、参数设置和踩坑记录。适合做无线感知、无人机通信方向的研究生和一线工程师新手能照着跑熟手能直接改参数做对比实验。2. 协作频谱感知的数学骨架与无人机信道建模2.1 能量检测为什么是首选判决统计量怎么算本地感知最常用的就是能量检测原因是它不需要主用户信号的先验信息实现简单对未知调制方式也鲁棒。单个感知节点在观测窗口内采样 N 个点判决统计量就是采样能量和Y Σ |x[n]|²n 从 1 到 N在只有噪声的假设 H0 下Y 服从中心卡方分布在主用户存在 H1 下服从非中心卡方分布。当 N 足够大工程上 N ≥ 100根据中心极限定理可以把 Y 近似为高斯分布这样门限和虚警概率就有闭式解Pf Q((λ - Nσ²) / (σ²√(2N)))其中 σ² 是噪声方差λ 是判决门限。给定目标虚警概率 Pf反解出门限λ σ²(N √(2N)·Q⁻¹(Pf))这一步是整个仿真的地基门限算错后面融合结果全是错的。我一般把 Pf 设在 0.01 到 0.1 之间太低会导致门限过高、漏检严重太高则虚警泛滥浪费频谱机会。2.2 无人机信道的路径损耗与莱斯因子怎么设无人机到地面感知节点的链路和地面节点之间的链路不一样它有很强的直射分量通常用莱斯衰落建模。接收功率写成Pr Pt Gt Gr - PL(d) 10log10(K/(K1)) 衰落项路径损耗用空对地模型视距概率和仰角相关。工程上如果不想引入太复杂的空对地概率模型可以简化为自由空间损耗加一个仰角修正项。莱斯因子 K 是关键参数城区遮挡多K 取 1 到 5开阔农田或水面K 取 10 到 20。K 越大直射越强感知链路越稳融合中心收到的本地判决越可靠。下面这段代码把信道增益和噪声一起生成出来作为后续感知仿真的输入。import numpy as np def generate_channel(num_nodes, distance, fc2.4e9, K_db10, seed42): 生成无人机到各感知节点的信道增益 num_nodes: 感知节点数 distance: 各节点到无人机的距离数组(m) fc: 载波频率(Hz) K_db: 莱斯因子(dB) rng np.random.default_rng(seed) c 3e8 # 自由空间路径损耗 pl_db 20 * np.log10(distance) 20 * np.log10(fc) 20 * np.log10(4 * np.pi / c) # 莱斯衰落直射分量 散射分量 K 10 ** (K_db / 10) los np.sqrt(K / (K 1)) nlos np.sqrt(1 / (K 1)) * (rng.normal(0, 1, num_nodes) 1j * rng.normal(0, 1, num_nodes)) / np.sqrt(2) h los nlos gain_db -pl_db 20 * np.log10(np.abs(h)) return 10 ** (gain_db / 10)逻辑说明先算自由空间路径损耗再叠加莱斯衰落复增益最后转成线性功率增益。参数上 distance 单位是米fc 默认 2.4 GHz 是常见 ISM 频段K_db 控制直射强度。注意 rng 用了固定种子方便复现做蒙特卡洛时把 seed 换成循环变量即可。2.3 硬判决融合与软判决融合的取舍本地判决送到无人机后融合方式分两大类。硬判决是每个节点输出 0/1融合中心做 K 秩准则或多数表决软判决是节点直接上报能量统计量融合中心加权求和。硬判决回传开销小适合无人机带宽受限的场景软判决精度高但要求节点上报浮点数链路负担大。工程上如果无人机回传链路是低速遥测优先硬判决如果节点有本地缓存、可以批量回传软判决的检测概率通常能高出 3 到 8 个百分点。下面这张表把两种方式的参数差异列清楚。维度硬判决融合软判决融合上报内容1 bit 判决能量值或对数似然比融合规则多数表决 / K 秩加权求和 / 似然比回传开销低高典型检测增益基准提升 3~8 个百分点适用场景低速遥测链路有缓存、可批量回传选型时先看无人机回传链路速率再看节点是否有本地处理能力。我一般先用硬判决跑通链路确认门限和信道没问题再切软判决做性能对比。3. 用 Python 搭一套可复现的协作频谱感知仿真3.1 环境准备与依赖安装的最小命令环境用 Python 3.9 以上都行核心依赖只有 numpy 和 matplotlib做加权融合时可选 scipy。如果你还在纠结 python 安装教程或 vscode python 环境配置直接装 Anaconda 最省事它自带 numpy 和 scipy。命令行安装pip install numpy matplotlib scipy装完在终端跑python -c import numpy; print(numpy.__version__)确认没报错。注意别在系统自带的 Python 里乱装库用虚拟环境隔离否则后面 sklearn 之类的库版本冲突会让你查半天。vscode 里选解释器时认准虚拟环境路径别选到全局那个。3.2 单节点能量检测的完整实现先把单节点跑通确认虚警概率和理论值对得上再往上叠协作。下面代码实现能量检测并统计实际虚警率。import numpy as np def energy_detection(samples, noise_var, pf_target): 单节点能量检测 samples: 接收采样序列 noise_var: 噪声方差 pf_target: 目标虚警概率 返回: (判决结果, 统计量, 门限) N len(samples) stat np.sum(np.abs(samples) ** 2) # 由目标虚警概率反解门限 from scipy.stats import norm threshold noise_var * (N np.sqrt(2 * N) * norm.ppf(1 - pf_target)) decision 1 if stat threshold else 0 return decision, stat, threshold # 测试纯噪声下统计虚警率 rng np.random.default_rng(0) pf_target 0.05 N 200 noise_var 1.0 false_alarms 0 trials 10000 for _ in range(trials): noise rng.normal(0, np.sqrt(noise_var), N) d, _, _ energy_detection(noise, noise_var, pf_target) false_alarms d print(f实际虚警率: {false_alarms / trials:.4f}, 目标: {pf_target})逻辑说明统计量是采样能量和门限用高斯近似闭式解。参数 N 是采样点数越大检测越准但感知时间越长pf_target 控制门限高低。跑出来实际虚警率应该在 0.05 附近波动如果差很多检查噪声方差是否和生成时一致。这个验证步骤别省门限公式用错的话后面融合全是错的。3.3 多节点硬判决融合与 K 秩准则硬判决融合里最灵活的是 K 秩准则K 个节点中有 k 个判为主用户存在就判定存在。k1 是或准则检测概率最高但虚警也最高kK 是与准则最保守。多数表决是 kceil(K/2)。下面实现融合并对比不同 k 值的 ROC。def hard_fusion(samples_matrix, noise_var, pf_target, k): 硬判决 K 秩融合 samples_matrix: 形状 (num_nodes, N) k: 触发判决的节点数阈值 num_nodes samples_matrix.shape[0] decisions [] for i in range(num_nodes): d, _, _ energy_detection(samples_matrix[i], noise_var, pf_target) decisions.append(d) return 1 if sum(decisions) k else 0 # 生成含主用户信号的接收数据 def gen_received(num_nodes, N, snr_db, noise_var1.0, seed1): rng np.random.default_rng(seed) signal_power noise_var * 10 ** (snr_db / 10) data [] for _ in range(num_nodes): s rng.normal(0, np.sqrt(signal_power), N) n rng.normal(0, np.sqrt(noise_var), N) data.append(s n) return np.array(data) data gen_received(5, 200, snr_db-8) for k in [1, 3, 5]: d hard_fusion(data, 1.0, 0.05, k) print(fk{k} 融合判决: {d})逻辑说明samples_matrix 每行是一个节点的采样k 是融合阈值。参数 snr_db 设 -8 dB 是低信噪比典型值用来检验融合是否比单节点强。注意 gen_received 里信号和噪声独立生成实际场景中信号可能相关做精确仿真时要引入相关系数。3.4 软判决加权融合与权重怎么定软判决融合把各节点的统计量加权求和权重反映节点可靠性。最简单的是等权进阶用信噪比加权或检测概率加权。下面实现基于估计信噪比的加权融合。def soft_fusion_weighted(samples_matrix, noise_var, pf_target): 软判决加权融合权重正比于各节点估计信噪比 num_nodes, N samples_matrix.shape stats np.sum(np.abs(samples_matrix) ** 2, axis1) # 用统计量减去噪声均值估计信号功率 signal_power np.maximum(stats / N - noise_var, 1e-6) weights signal_power / np.sum(signal_power) fused_stat np.sum(weights * stats) from scipy.stats import norm threshold noise_var * (N np.sqrt(2 * N) * norm.ppf(1 - pf_target)) return 1 if fused_stat threshold else 0, weights d, w soft_fusion_weighted(data, 1.0, 0.05) print(f软判决融合结果: {d}, 权重: {np.round(w, 3)})逻辑说明权重用估计信号功率归一化得到信号强的节点话语权大。参数上 noise_var 必须准确否则权重会偏。注意 fused_stat 的量纲和单节点统计量一致门限可以直接复用。如果节点数很多权重会趋于平均此时软判决相对硬判决的优势会缩小。4. 无人机移动性与感知开销的联合调参4.1 无人机悬停位置对融合性能的影响无人机不是固定基站它的位置直接改变各节点到融合中心的距离和仰角进而改变信道增益和接收信噪比。把无人机放在感知簇几何中心通常不是最优因为边缘节点信噪比太低会拖累融合。我一般用网格搜索找使融合检测概率最大的悬停点。下面代码在二维平面上扫一遍。def evaluate_position(uav_pos, node_pos, snr_ref0, fc2.4e9): 评估给定无人机位置的融合性能简化用平均接收信噪比代替 uav_pos: (x, y) node_pos: 形状 (num_nodes, 2) dist np.linalg.norm(node_pos - np.array(uav_pos), axis1) dist np.maximum(dist, 1.0) gains generate_channel(len(dist), dist, fcfc) snr snr_ref 10 * np.log10(gains) return np.mean(snr) node_pos np.array([[0,0],[50,0],[0,50],[50,50],[25,25]]) best None for x in range(0, 55, 5): for y in range(0, 55, 5): score evaluate_position((x, y), node_pos) if best is None or score best[0]: best (score, x, y) print(f最优悬停点: ({best[1]}, {best[2]}), 平均信噪比: {best[0]:.2f} dB)逻辑说明evaluate_position 用平均接收信噪比作为代理指标实际项目里应该换成融合后的检测概率。参数步长 5 米是精度和耗时的折中要更细就调到 1 米。注意这里没考虑无人机自身功耗和飞行时间真实部署要加约束。4.2 感知时间与回传时间的折中协作频谱感知的总时间 本地感知时间 上报时间 融合时间。感知时间越长采样点数 N 越大单节点检测越准但留给数据传输的时间越少。无人机辅助场景里还要加上飞抵感知区域的时间。工程上常用帧结构每帧前段做感知后段做传输。感知时间占比一般取 10% 到 20%。如果主用户活动频繁感知要更频繁占比就得提高。这个折中没有万能值得根据主用户占空比和业务时延要求调。4.3 节点数增加是收益还是负担直觉上节点越多融合越准但实际有上限。节点数增加融合中心收到的数据量线性增长回传碰撞概率上升而且距离远的节点信噪比低贡献的是噪声而不是信息。我做过对比5 到 10 个节点时检测概率提升明显超过 15 个后边际收益很小甚至因为低质量节点拖累而下降。选节点数时优先选信噪比高于门限的把太差的节点剔除比硬塞进去更有效。5. 避坑与排查协作频谱感知仿真里最容易翻车的五件事5.1 虚警概率理论值和实测对不上现象跑单节点能量检测设 Pf0.05实测出来 0.15 甚至更高。原因通常是噪声方差和门限公式里的 σ² 不一致或者采样点数 N 太小导致高斯近似失效。解决先确认生成噪声用的方差和传入 energy_detection 的 noise_var 是同一个值N 至少 100最好 200 以上如果还不对检查 norm.ppf 的参数是不是 1-pf_target写成 pf_target 就反了。5.2 融合后检测概率反而比单节点低现象多个节点融合检测概率不升反降。原因多半是融合阈值 k 选得太大或者有节点信噪比极低把整体拉垮。解决先用多数表决 kceil(K/2) 跑一遍再扫 k 值看 ROC把信噪比低于 -12 dB 的节点剔除后重跑。另外确认各节点采样是独立生成的如果误用了同一组噪声融合等于没融合。5.3 莱斯因子设太大导致结果过于乐观现象仿真检测概率接近 1和文献差距大。原因是 K_db 设成了 20 以上直射分量过强信道几乎无衰落。解决城区场景 K_db 取 1 到 5郊区取 5 到 10开阔地才用 10 到 20。做对比实验时把 K_db 作为扫描变量别固定一个值就下结论。5.4 权重计算出现负值或除零现象软判决融合权重里出现负数或者归一化时除零报错。原因是 signal_power 估计时 stats/N - noise_var 可能为负没做截断。解决用 np.maximum(..., 1e-6) 兜底如 3.4 节代码所示。另外如果所有节点信号都很弱权重会退化成均匀分布这是正常的不是 bug。5.5 蒙特卡洛次数不够导致曲线抖动现象ROC 曲线锯齿严重结论不可信。原因是每个信噪比点只跑了几百次。解决虚警概率 0.01 量级时至少跑 10000 次才能让统计误差可控。跑之前把随机种子固定方便复现跑的时候用向量化代替循环速度能快一个数量级。6. 把仿真推到可用ROC 对比与参数扫描的实操技巧最后一章说一个我常用的验证习惯任何融合算法写完先画 ROC 曲线和单节点基准对比再扫关键参数。ROC 是检测概率对虚警概率的曲线横轴虚警、纵轴检测曲线越靠左上越好。下面这段代码把硬判决和软判决的 ROC 画在一起方便你判断融合到底有没有用。import numpy as np import matplotlib.pyplot as plt from scipy.stats import norm def roc_curve(samples_h0, samples_h1, noise_var, pf_list): 简化 ROC对每个目标虚警概率算检测概率 samples_h0/h1: 形状 (num_nodes, N, trials) pd_hard, pd_soft [], [] for pf in pf_list: # 这里用统计量直接比较省略逐次判决循环 stat_h0 np.sum(np.abs(samples_h0) ** 2, axis1).mean(axis1) stat_h1 np.sum(np.abs(samples_h1) ** 2, axis1).mean(axis1) thr noise_var * (samples_h0.shape[1] np.sqrt(2 * samples_h0.shape[1]) * norm.ppf(1 - pf)) pd_hard.append(np.mean(stat_h1 thr)) pd_soft.append(np.mean(stat_h1 thr * 0.9)) # 软判决门限略低示意 return pd_hard, pd_soft pf_list np.logspace(-3, -0.5, 10) # 实际使用时替换成你的仿真数据 print(把真实仿真数据代入后画图横轴虚警、纵轴检测)逻辑说明这段是骨架真实使用时把 samples_h0 和 samples_h1 换成你的蒙特卡洛数据。参数 pf_list 用对数间隔扫覆盖三个数量级。注意软判决门限这里用 0.9 倍示意实际要按加权统计量的分布重新推导别直接抄这个系数。参数扫描我一般固定三个变量节点数、信噪比、莱斯因子每次只动一个其余固定。这样出的图能直接放进论文或报告也方便定位是哪个参数在起作用。扫描时把结果存成 npz 文件别每次重跑省时间。血泪经验仿真代码一定要版本管理我吃过亏改了一版权重公式后没留记录结果复现不出之前的曲线查了两天才发现是噪声种子变了。现在我的习惯是每次实验把参数、种子、代码 commit 一起存出图脚本单独放数据和绘图分离。这个习惯比任何调参技巧都值钱。希望帮到你。本文还有配套的精品资源点击获取
返回列表