简介:面向蜂窝通信网络建模与仿真人员,这份代码包聚焦泊松点过程随机几何建模与蒙特卡洛模拟,用于基站部署密度分析、覆盖概率与干扰水平评估等场景。包内共三十三个文件,以二十八个MATLAB脚本为主,涵盖泊松点分布生成、不同密度下的平均频谱效率与干扰依赖关系计算、多径及阴影衰落场景模拟、结果绘图;另有三个MATLAB图像窗文件和两张示意图片,便于直接查看与调整仿真结果。压缩包整体约一百三十五KB,文件命名清晰,可按名称快速定位示例函数。目前已有三百四十七人学习下载,适合通信工程方向学生与无线网络研究工程师参考。借助这些脚本,可深入理解泊松点随机几何如何与蒙特卡洛方法结合,并复现覆盖概率、吞吐量等关键指标分析,为蜂窝网络规划与优化提供可量化的实验基础。
1. 蒙特卡洛 PPP 蜂窝仿真:为什么一个泊松点过程就能预测整张网络的覆盖率
做蜂窝网络仿真的人迟早会撞上一个问题:基站位置根本没法用规矩的六边形网格去近似。城区有楼顶铁塔,郊区有山腰宏站,室内有飞基站,它们的分布看起来杂乱无章,但统计规律反而很干净——基站位置可以建模为二维平面上的泊松点过程(PPP),也就是在任意区域里,基站出现的数量服从泊松分布,位置彼此独立均匀散布。把这个随机几何模型和蒙特卡洛仿真结合起来,就是标题里「PPP仿真.zip_蒙特卡洛 PPP_蒙特卡洛ppp_蜂窝仿真_通信 蒙特卡洛_随机 几何」这套东西真正要解决的问题:用随机撒点的方式,快速估计一张网络的覆盖概率、信干噪比分布和用户速率,而不需要搭建昂贵的系统级仿真平台。
这套方法的实用价值非常直接。运营商做预规划时需要回答「在这个密度下部署基站,边缘用户能达到什么体验」,设备商做算法评估时需要知道「某种干扰协调方案在随机拓扑下比现网好多少」,学术界验证论文里的数学推导也需要一条数值曲线来背书。PPP加蒙特卡洛的搭配,恰恰能在半小时内在普通电脑上给出这些答案,精度足以支撑方案对比和参数敏感性分析。本文后面会从PPP的数学定义讲起,给出一个完整的单小区SINR仿真代码,然后扩展到多小区异构网络,最后把边界效应、信道模型选择和收敛判断这些实际工程必踩的坑逐条说清楚。
2. 泊松点过程和蒙特卡洛:这套仿真方法的两个数学支柱
2.1 泊松点过程的密度与分布:为什么基站能看成随机撒点
泊松点过程的核心参数是强度λ,单位为「个/平方米」或「个/平方公里」。它的定义包含两条性质:第一,任意一个区域A内的点数N(A)服从均值为λ|A|的泊松分布;第二,互不相交的区域里,点数彼此独立。这两条性质直接决定了仿真撒点的实现方式——对一块面积S的矩形区域,先按均值为λS的泊松分布随机抽取总点数K,再把K个点均匀独立地撒到区域内。实际代码几乎都是先抽样数量、再抽样坐标,而不是用拒绝采样逐点生成,因为后者要循环很多次,效率低且容易引入相关性。
在蜂窝网络语境下,这个模型对应的是宏基站独立部署的场景。城市规划不会刻意让基站间距保持恒定,反而因为选址受限于楼顶空间、租金和传输资源,出现一定程度的聚集反而更常见。PPP的一个隐含假设是点之间没有排斥力,这跟六边形网格的规则部署是两种极端:真实网络通常介于两者之间。做仿真时心里要有数——用PPP得到的覆盖概率是偏保守的还是偏乐观的,取决于具体比较对象。对于超密集组网和微微站混合部署场景,PPP反而比规则网格更贴近现实,因为小站位置几乎完全由用户热点和物业条件决定。
生成PPP样本点的代码并不复杂,但有一个细节必须注意:常规做法只能生成有限区域内的点,而真实网络里基站是无限的。边缘用户测量的干扰源可能来自仿真区域之外,这个边界效应如果不处理,仿真结果会明显偏离理论值。后面会专门讲边界处理,第5章也会展开。先看最基本的实现。
import numpy as np def generate_ppp(lambda_val, width, height, seed=None): """ 在矩形区域内生成泊松点过程样本。 lambda_val: 强度,单位:个/平方米 width, height: 区域尺寸,单位:米 """ if seed is not None: np.random.seed(seed) area = width * height n_points = np.random.poisson(lambda_val * area) xs = np.random.uniform(0, width, n_points) ys = np.random.uniform(0, height, n_points) return np.column_stack([xs, ys])这段代码的核心逻辑只有三步:先按λ乘面积算出期望点数,再用泊松分布抽样一次得到实际点数K,最后生成K个均匀分布的二维坐标。很多人会漏掉第一步直接均匀撒固定数量的点,那样得到的其实是二项点过程,它的点数在多次仿真之间没有方差,而真实PPP应该有点数的波动。如果lambda_val取值很小,比如每平方公里0.1个基站,而区域只有500米乘500米,期望点数只有0.025,大部分仿真轮次里一个点都没有——这其实是正确的统计行为,但如果你需要在每轮里至少有一个基站,就要换用条件泊松过程,也就是固定点数再均匀撒布。
2.2 蒙特卡洛仿真的收敛逻辑:要跑多少轮才能相信结果
蒙特卡洛仿真的本质是用大量随机样本的平均值去逼近数学期望。对于蜂窝覆盖仿真,每一轮做的事情是:随机生成基站位置、随机生成用户位置、计算用户收到的信号和干扰、判断这条链路是否满足SINR门限。重复几千轮之后,统计「满足门限的轮次占比」,就得到了覆盖概率的估计值。这个过程没有任何高深之处,关键在于两点:样本量要足够大,随机性要真正独立。
收敛速度方面,蒙特卡洛误差按1/√N递减,N是仿真轮数。这意味着想把误差从10%降到5%,需要把轮数从100增到400;想再降到2%,得跑2500轮。实际工程里不看绝对轮数,而是同时跑几个不同随机种子,看结果曲线的抖动幅度。如果两次1000轮的仿真结果覆盖概率差了3个百分点以上,说明轮数不够,密度越低的小概率事件收敛越慢。比如目标要评估的是SINR大于10dB的概率,这个概率如果只有5%左右,可能需要两万轮才能让估计值的变异系数降到可接受范围。
另外一个常被忽视的点是随机数生成器的质量。Python自带的random模块是梅森旋转算法,做几万次抽样没问题,但要生成大量独立的二维坐标时,最好还是用NumPy的随机数生成器并显式传入种子。并行计算时每轮用同一个种子会产生重复样本,看似跑了多轮,实际全是从同一批随机数里取的,统计上等效于只跑了一轮——这是比较容易翻车的地方。通常做法是给每轮分配一个基础种子加轮次偏移,这样既能复现又能保证独立性。
3. 单小区SINR仿真的完整代码:从生成基站到画出覆盖曲线
3.1 路径损耗、阴影衰落和瑞利衰落:三个参数怎么配
信道模型决定了仿真结果是否可信。工程上用得最多的是三部分叠加:路径损耗、阴影衰落、小尺度衰落。路径损耗用对数距离模型,典型宏基站参数是PL(d) = 128.1 + 37.6×log10(d/1000),d单位是米,结果单位是dBm的损耗。频率2GHz、基站高度35米、终端高度1.5米时这个公式比较合适。如果你仿真的是3.5GHz频段,损耗系数要加大,通常取38到40之间的值。
阴影衰落服从对数正态分布,以dB为单位时就是均值为0、标准差为σ的高斯分布。宏基站环境σ取8dB,城区密集环境取10dB,室内场景取12dB。这个参数不能拍脑袋,因为它直接影响覆盖概率曲线的陡峭程度,σ越大,边缘用户的覆盖越差。小尺度衰落如果只关心平均SINR,可以用瑞利分布建模,功率则服从指数分布,均值1。在单天线系统里,这个模型捕捉了深衰落对覆盖的影响,但对波束赋形和多天线系统就需要改用瑞利信道的矩阵版本。
功率控制方面,宏站下行通常以固定功率发送,比如43dBm(20W),不需要逐用户做闭环调节。上行链路因为终端功率受限,功控逻辑会明显影响干扰分布,如果你仿真的是上行,需要在每轮仿真里计算终端发射功率,而不是简单赋固定值。
def compute_sinr(user_pos, bs_pos, bs_power_dbm=43, freq=2.0, shadow_sigma=8.0, noise_dbm=-95): """ 计算单个用户在给定基站位置下的下行SINR。 返回SINR值,单位dB。 """ # 距离不能为0,否则对数会出错 dist = np.linalg.norm(user_pos - bs_pos) dist = max(dist, 1.0) # 路径损耗:宏基站模型,d单位为米 pl_db = 128.1 + 37.6 * np.log10(dist / 1000.0) # 阴影衰落:生成一个高斯随机数 shadow_db = np.random.normal(0, shadow_sigma) # 接收功率:发射功率 + 天线增益 - 路径损耗 - 阴影衰落 rx_power_dbm = bs_power_dbm + 14 - pl_db - abs(shadow_db) # 瑞利衰落:功率服从指数分布,均值1,转换为dB rayleigh_power = np.random.exponential(1.0) rx_power_dbm += 10 * np.log10(rayleigh_power) # 噪声基底:热噪声加接收机噪声系数 noise_power_dbm = noise_dbm + 10 * np.log10(200e6) # 200MHz带宽 sinr_db = rx_power_dbm - noise_power_dbm return sinr_db这段代码是最简版本,只算了单个基站到单个用户的链路。参数上需要注意几点:天线增益14dBi是典型宏站的定向天线增益,如果你仿真的是全向天线小站,这里要改成0到2dBi。带宽200MHz对应5G NR的典型载波带宽,噪声功率按热噪声谱密度-174dBm/Hz加接收机噪声系数5dB计算,最后得到约-95dBm量级。阴影衰落这里取了绝对值,是避免极端深的衰落主导结果——严格做法是用均值0的高斯分布不加绝对值,但两种方式在覆盖概率趋势上差不多,你按统一标准对比方案就行。
3.2 遍历所有候选基站选择服务小区:连接规则决定仿真结果
蜂窝网络里用户选择服务小区,通常按最强接收功率而不是最近距离。这个「最强信号关联」规则在PPP仿真里实现起来很直接:遍历所有基站,计算每个基站的接收功率,选最大的作为服务基站,其余基站全部当作干扰源。注意这里有个微妙之处:如果两个基站信号强度非常接近,用户实际会依据小区重选偏置来选择,但仿真里通常简化成最大功率准则。
如果要做更贴近协议的行为,可以在接收功率上叠加一个小区偏置值,模拟CRE(小区范围扩展)技术。这对异构网络特别重要——微微站的发射功率比宏站低20dB,如果不做偏置,大部分用户仍会连宏站,微微站覆盖形同虚设。下面是完整的多基站SINR计算代码。
def compute_sinr_multi(user_pos, bs_positions, bs_powers_dbm, noise_dbm=-95, shadow_sigma=8.0): """ 计算用户在所有基站配置下的SINR。 bs_positions: [n_bs, 2] 的数组 bs_powers_dbm: [n_bs] 的数组,每个基站的发射功率 返回最优SINR值(dB)和关联的基站编号。 """ n_bs = len(bs_positions) rx_powers = np.zeros(n_bs) for i in range(n_bs): dist = np.linalg.norm(user_pos - bs_positions[i]) dist = max(dist, 1.0) pl_db = 128.1 + 37.6 * np.log10(dist / 1000.0) shadow_db = np.random.normal(0, shadow_sigma) rx_powers[i] = bs_powers_dbm[i] + 14 - pl_db - shadow_db # 选择最强基站 serving_idx = np.argmax(rx_powers) serving_power = rx_powers[serving_idx] # 计算干扰:所有其他基站的接收功率之和(线性域相加) interference_linear = 0.0 for i in range(n_bs): if i != serving_idx: interference_linear += 10 ** (rx_powers[i] / 10) noise_linear = 10 ** (noise_dbm / 10) sinr_linear = (10 ** (serving_power / 10)) / (interference_linear + noise_linear) sinr_db = 10 * np.log10(sinr_linear) return sinr_db, serving_idx这段代码的关键在干扰累加。所有接收功率先保持在dBm域,最后换算成线性功率再求和,因为功率叠加必须在线性域进行,dBm直接相加是错误操作。返回的serving_idx可以用于后续分析,比如统计哪些基站实际承载了最多用户,这能帮你判断部署密度是否合理。需要注意阴影衰落在这个多基站版本里没有加绝对值,这是故意为之——干扰和信号都要经历阴影,如果只对服务信号加绝对值而干扰不加,结果会偏乐观。
3.3 绘制CCDF覆盖曲线:怎样把仿真输出变成决策依据
仿真跑完之后,最常用的呈现方式是互补累计分布函数(CCDF)曲线,横轴是SINR门限(dB),纵轴是SINR大于该门限的用户比例。这条曲线就是通常说的覆盖概率曲线,也是网络规划里「边缘覆盖率」的视觉化表达。画这个图之前,要把所有蒙特卡洛轮次里产生的SINR样本值收集成一个数组,而不是每轮只存一个平均值——CCDF需要逐个样本的分布信息。
def plot_ccdf(sinr_samples, output_path="ccdf.png"): """ sinr_samples: 一个列表/数组,包含所有蒙特卡洛轮次里所有用户的SINR值(dB) 绘制SINR CCDF曲线并保存。 """ import matplotlib.pyplot as plt sorted_sinr = np.sort(sinr_samples) cdf = np.arange(1, len(sorted_sinr) + 1) / len(sorted_sinr) ccdf = 1 - cdf plt.figure(figsize=(8, 5)) plt.plot(sorted_sinr, ccdf, linewidth=2) plt.xlabel("SINR Threshold (dB)") plt.ylabel("P(SINR > Threshold)") plt.grid(True, which="both", alpha=0.3) plt.xlim([-10, 30]) plt.ylim([0, 1]) plt.tight_layout() plt.savefig(output_path, dpi=150)这里有一个经常搞反的逻辑:先把SINR样本从小到大排序,然后构造经验CDF,再转换成CCDF。如果直接从大到小排,后面的概率计算容易出错。另外,单用户每轮只产生一个样本,如果区域里有用户分布,每个用户都要独立计算一次SINR再收集——把用户位置也纳入随机变量,能让覆盖概率的空间分布更平滑,但也意味着每轮仿真里需要生成一批用户而不是一个。
4. 异构蜂窝网络:从单层PPP到多层PPP叠加
4.1 宏站加微微站的双层模型:每层一个密度参数
真实网络很少只有一层基站。宏站覆盖广域,微微站填补热点,中继节点覆盖盲区。每层的发射功率、天线配置、部署密度都不同,随机几何里对应的是多个相互独立的PPP叠加。总过程仍然是PPP,强度是各层强度之和,但每层的属性标签不同——仿真时要记录每个基站属于哪一层,因为路径损耗公式和功率控制行为都不同。
双层模型的典型参数配置是:宏站密度每平方公里5到10个,发射功率43dBm,路径损耗指数3.76;微微站密度每平方公里30到50个,发射功率23到30dBm,路径损耗指数4.2左右(因为站高低,信号衰减更快)。这种不对称性会导致两个结果:一是覆盖空洞区域更容易被宏站兜底,但微微站周边会出现强干扰岛;二是如果微微站密度不够,大部分流量仍被宏站吸收,部署价值大打折扣。
仿真实现上需要区分层来生成基站位置。做法是循环每一层,按各自的密度生成PPP样本,然后合并成一个带层标签的基站列表。连接规则仍然按最强接收功率,但可以给微微站加CRE偏置。下面给出具体实现。
def generate_hetnet_base_stations(): """ 生成双层异构网络的基站位置。 宏站:密度5/km²,功率43dBm 微微站:密度40/km²,功率30dBm 返回带层标签的基站列表。 """ np.random.seed(42) area_km2 = 10 # 10平方公里 width_m = np.sqrt(area_km2) * 1000 height_m = width_m macro_bs = generate_ppp(5 / 1e6, width_m, height_m) # 密度换算成个/平方米 pico_bs = generate_ppp(40 / 1e6, width_m, height_m) macro_layer = np.column_stack([macro_bs, np.full(len(macro_bs), 43.0)]) pico_layer = np.column_stack([pico_bs, np.full(len(pico_bs), 30.0)]) all_bs = np.vstack([macro_layer, pico_layer]) layer_ids = np.array([0] * len(macro_bs) + [1] * len(pico_bs)) return all_bs, layer_ids, width_m, height_m注意密度单位换算:PPP生成函数接受的是个/平方米,而规划习惯用个/平方公里。1平方公里等于1e6平方米,所以每平方公里5个基站要写成5/1e6。这个换算错误会导致仿真结果完全失真——不少人曾经把密度直接传入,结果生成了几百万个基站,程序直接卡死。
4.2 不同层用不同路径损耗模型:一个基站一个参数集
异构网络里各层的信道参数差异很大。宏站天线挂得高、视距概率低,路径损耗指数偏大;微微站通常部署在灯杆或墙面,相对用户有更多视距链路,路径损耗指数反而小,但阴影衰落由于环境复杂而偏大。这就要求计算SINR时不能再用统一的PL公式,要根据layer_id切换参数集。
具体实现上,建议不用现在这种逐个基站循环的写法,而是向量化操作。把所有基站的位置和功率放进矩阵,利用NumPy广播一次性算完所有距离、路径损耗和接收功率,这样性能能提升几十倍,尤其是基站数量达到几百上千时差距非常明显。下面是向量化的双参数集SINR计算。
def compute_sinr_hetnet_vectorized(user_pos, all_bs, layer_ids): """ all_bs: [n_bs, 2] 的位置矩阵 layer_ids: [n_bs] 的层标签,0=宏站, 1=微微站 """ # 距离计算,向量化 dist = np.linalg.norm(all_bs[:, :2] - user_pos, axis=1) dist = np.maximum(dist, 1.0) # 初始化损耗数组 pl_db = np.zeros(len(all_bs)) macro_mask = layer_ids == 0 pico_mask = layer_ids == 1 # 宏站路径损耗 pl_db[macro_mask] = 128.1 + 37.6 * np.log10(dist[macro_mask] / 1000.0) # 微微站路径损耗 pl_db[pico_mask] = 140.7 + 36.7 * np.log10(dist[pico_mask] / 1000.0) # 阴影衰落按层取不同标准差 shadow_db = np.zeros(len(all_bs)) shadow_db[macro_mask] = np.random.normal(0, 8.0, np.sum(macro_mask)) shadow_db[pico_mask] = np.random.normal(0, 10.0, np.sum(pico_mask)) # 接收功率 = 发射功率 + 天线增益 - 损耗 - 阴影 rx_power_dbm = all_bs[:, 2] + 14 - pl_db - shadow_db # 选择服务基站 serving_idx = np.argmax(rx_power_dbm) serving_power = rx_power_dbm[serving_idx] # 干扰累加(线性域) interference_linear = np.sum(10 ** (rx_power_dbm / 10)) - 10 ** (serving_power / 10) noise_linear = 10 ** (-95 / 10) sinr_db = 10 * np.log10((10 ** (serving_power / 10)) / (interference_linear + noise_linear)) return sinr_db, serving_idx这段代码用布尔掩码区分层的路径损耗参数,比循环逐基站计算快得多。引入的代价是代码可读性略差,但当你需要跑几万轮蒙特卡洛时,向量化几乎是必须的。另外注意微微站的发射功率来自all_bs第三列,也就是说生成基站列表时就要把功率作为属性存进去。
4.3 CRE偏置对覆盖和干扰的权衡:偏置加多少才能提升吞吐
CRE(小区范围扩展)通过在接收功率上叠加偏置,让用户更愿意接入微微站。这个偏置值通常取6到15dB,具体取决于微微站功率相对宏站的差距。偏置越大,转移到微微站的用户越多,微微站频谱利用率提升,但那些用户收到宏站强干扰的概率也越大,SINR会下降。如果偏置过头,用户虽然连上了微微站,但干扰远大于有用信号,吞吐和体验反而更差。
在仿真里实现CRE就是一行改动:选择服务基站时,对微微站的接收功率加一个偏置值再做argmax。你可以用不同的偏置值反复跑仿真,画出「平均用户速率vs微站负载」的权衡曲线。典型的结论是:当微微站功率比宏站低20dB时,偏置10dB左右能获得最大增益,再往上加就是纯损失。不过这个最优值受用户分布影响很大,用户越集中在微微站附近,最优偏置就越小,因为负载转移的需求本身不强。
5. 蜂窝PPP仿真的5个避坑清单:收敛、边界、信道和随机性
5.1 边界效应:区域内用户看到的干扰源其实来自区域外
现象:仿真区域的边缘用户SINR明显偏高,覆盖概率在区域边缘出现虚假抬升。原因是边缘用户附近的干扰基站一部分在区域外,而你的仿真里没有生成区域外的基站。解决方式有两种:第一种是扩展区域法,仿真生成基站的范围比用户范围大一圈,用户只在内部采样,基站在更大的范围生成;第二种是周期边界法,把区域复制到四周,相当于把平面卷成环面,干扰计算时取最近副本的距离。工程上首选第一种,扩展范围通常要至少用户区域半径的两倍以上,否则扩展不充分。扩展区域会多生成基站,计算量增大,但这是保证边缘用户结果可信的必要代价。
5.2 随机数种子管理:并行仿真用了同一个种子等于白跑
现象:多核并行跑完几千轮仿真,结果跟只跑几百轮的抖动差不多。原因是每轮仿真调用同一套随机数生成器,种子的设置方式使得每轮生成的基站位置完全相同。解决方式是给每轮分配种子时应把轮次编号混入基础种子,比如seed_base + round_idx * 10007。更稳妥的做法是每轮使用独立的np.random.default_rng(seed)实例,这样既保证轮间独立,又保证整体可复现。并行处理时需要保证各进程的种子互不重叠,否则两路进程生成相同的基站布局,等于浪费一半算力。
5.3 路径损耗公式在近距离发散:距离趋于0时损耗趋于负无穷
现象:用户恰好在基站天线底下,dist取很小值,路径损耗计算得到极低甚至负的损耗,SINR变成异常大的数。原因是37.6×log10(d/1000)在d小于1米时对数为负。解决方式是对距离设置下限,常见做法是钳位到10米或30米,对应基站天线的最低物理距离。这不算精细的建模,但避免了无穷大的出现。如果想要更精确,可以在近距离用另一个损耗公式衔接,但绝大多数覆盖仿真不关心用户贴在基站杆子底下的场景,钳位就够了。
5.4 阴影衰落相关性的误用:同一用户到不同基站应共享阴影值
现象:结果与理论覆盖曲线差异很大,低SINR区间的用户比例远高于理论预测。原因可能是每对用户-基站组合都独立抽样阴影衰落,这相当于增加了额外的随机波动。物理上,阴影衰落主要由用户附近的遮挡物决定,同一个用户看不同基站时,大尺度遮挡是高度相关的。正确做法是每次仿真为用户生成一个阴影偏移值,而这个值对所有基站共享;如果基站和用户同时移动,则阴影还需随位置变化生成相关随机场。常规做法是为每个用户生成一个独立的阴影值,这样复杂度低且结果已经足够贴近实测。
5.5 静默期判断:用户在仿真轮次里被当作静止不动的点
现象:高速移动用户的体验指标和静态用户完全分不开。原因是仿真里用户位置只在每轮开始固定一次,整个SINR计算过程中用户没动过,等于默认用户是静止的。如果关心移动用户,需要在时域上增加抽帧逻辑:在一个较长的仿真时间里,按用户的移动速度逐步更新位置,在每个时间片内重新计算SINR并统计时间占比。注意这与空间上的多次独立撒点是两回事,后者做的是空间平均,不做时间相关性。
5.6 系统盘满与Python环境的连带故障
现象:明明只是跑仿真,结果系统盘突然满了,仿真程序在生成基站时内存申请失败。原因是Anaconda默认把环境和包缓存写在C盘用户目录,而NumPy在计算大规模距离矩阵时会往临时目录写文件,加上仿真中间结果不断累积,系统盘很容易被吃光。解决方式是安装环境时把Anaconda的envs目录挪到D盘,或至少把临时文件目录TEMP和TMP改到非系统盘;再多轮仿真时中间结果按轮次覆写,不要每轮存一份完整副本。
6. 用 K 值检验结果置信度:一个收尾的验证套路
蒙特卡洛仿真的结果如果只有一个平均值,很难判断它是否可信。工程上建议做K值检验:把两万轮仿真产生的SINR样本随机分成10组,每组2000轮统计出一个覆盖概率,看这10个值的极差。如果极差小于0.5个百分点,说明样本量足够;如果极差超过2个百分点,必须增加仿真轮数。这个方法比单纯看标准差更直观,因为它把统计波动换算成了实际操作判断。
另一个从随机几何理论借来的验证思路是:单层同构PPP网络里,覆盖概率只依赖于基站密度、路径损耗指数和SINR门限的组合——具体地,当路损指数为4时,覆盖概率在无阴影衰落下可以写成厂商无关的量。你可以把仿真代码里阴影衰落标准差临时设成0,跑出来的数值曲线与文献中经典曲线放一起对比。通常偏差在1个百分点以内,说明代码实现没有系统性错误;偏差大了,就要检查是不是把dB和线性功率混用了,或者干扰累加写错了,又或者路径损耗公式里距离单位没有统一。
实际设计仿真时,我一般会把验证脚本留在一个单独的文件里,每次改完信道模型或者加了一层基站,先跑一遍验证再跑正式仿真。这个习惯救过我好几次——有一回把高层参数稍微调了个位置,验证曲线直接偏了三个多dB,排查之后发现是把发射功率的单位从dBm误写成了瓦,差了一个数量级的干扰计算。这类问题从覆盖曲线上不容易一眼看出来,但跟理论曲线一对比就暴露了。希望这套验证逻辑和前面的代码框架能帮你把仿真结果真正用起来,而不是纠结于跑数本身。
本文还有配套的精品资源,点击获取