资讯动态

OPNET中ALOHA与CSMA随机接入协议仿真对比

发布时间:2026/10/26 11:46:33 来源:尧图企业网站定制
第一次在 OPNET 里把 ALOHA 和 CSMA 摆进同一个场景跑对比是接一个链路层协议分析任务的时候。当时手上就一句需求——“给出两种随机接入协议在不同负载下的性能差异”没有参考模型、没有既定参数、也没有人说清楚“性能”到底指吞吐还是时延。我最初的想法很单纯摆几个节点、发点包、挂两个统计量一两天怎么也能出图。结果从工程建起来到曲线敢拿去汇报前后拖了将近三周中间踩的坑比写的代码还多。这篇就把这套 ALOHA 和 CSMA 的 OPNET 仿真实验从头到尾拆一遍包括协议本身的数学底子、OPNET 里进程模型和节点模型怎么分工、统计量怎么注册和采集、参数扫描怎么组织以及那几次结果离谱到怀疑人生的排查过程。不管你是刚接触网络仿真、要赶一份实验报告还是已经用过 OPNET 但没做过共享信道类的协议对比下面这些内容应该都能直接拿去改改用。1. 先把实验目标想清楚这两组协议到底在比什么动手建模之前有件事必须先定下来——这个仿真到底要回答什么问题。很多人包括当年的我一上来就急着摆节点、连线、点运行跑到一半发现不知道该看哪个统计量最后导出一堆曲线却讲不出结论。ALOHA 和 CSMA 的对比实验本质上是在回答同一个问题多个节点共享一条信道时随着业务量上升把信道资源“抢”着用的效率如何衰减。所有的参数设计、统计量选择都应该围绕这个核心问题展开。1.1 从“想说就说”到“先听后说”协议演进的驱动力ALOHA 的思路极其朴素有帧就发发完等确认超时没收到确认就随机等一段时间再重发。它诞生于早期无线分组网络那个年代终端算力有限、链路速率低能省掉协调开销比提高信道利用率更重要。代价是明显的——两个节点只要发送时间有任意重叠整帧就废了而且冲突双方都不知道对方存在只能靠超时重传“碰运气”。CSMA 加了一个动作发之前先听。信道忙就等信道闲再发。这一听就把大量本可以避免的冲突消灭在发送之前。但“听”这件事本身有物理限制——信号在介质上传播需要时间A 节点开始发送的瞬间B 节点可能还没收到这个信号于是 B 也判定信道空闲照样撞上。这就是所谓的传播延迟窗口也是 CSMA 永远无法做到零冲突的根本原因。把这两条路线放在一起仿真价值不在于证明“CSMA 比 ALOHA 好”——这是课本上的定论不用仿真是个人都知道。真正的价值在于量化在给定的帧长、速率、节点数、传播距离下两者的吞吐差距到底有多大、时延拐点分别在什么负载位置、差距随哪个参数变化最敏感。这些数字才是仿真能给出的东西也是后面写报告时真正有分量的部分。1.2 为什么选 OPNET 而不是自己写脚本打表有人会问纯 ALOHA 和分槽 ALOHA 的吞吐公式就那么两个CSMA 的经典分析结果也查得到为什么还要费劲跑仿真直接画公式曲线不是五分钟的事这里有个很实际的区分。解析公式大多建立在强假设之上——无限节点数、泊松到达、帧长恒定、忽略捕获效应、重传无限次。一旦节点数变成有限的 10 个、20 个一旦加入最大重传次数限制一旦帧长有分布公式就不准了。而 OPNET 这类离散事件仿真器的强项恰恰是处理这种“假设被打破”的场景你可以精确控制每个节点的行为、记录每一个事件的时刻、观察瞬态过程。至于为什么是 OPNET 而不是别的工具从我做这类实验的体会看主要三条。一是三层建模体系分得清——网络域管拓扑、节点域管内部结构、进程域管状态机做协议对比时改一层不影响另外两层改起来心里有底。二是自带统计采集框架op_stat_reg注册一下就能自动进结果库不用自己写 CSV 拼装。三是参数化研究Parametric Study是内建功能把负载、帧长、节点数设成可扫描参数一次配置跑一组场景最后直接比对曲线这个流程比手动改参数重跑省太多事。1.3 实验变量的三层设计负载、节点数、帧长变量设计这件事看起来简单其实决定了整个实验有没有说服力。我的做法是分成三层主变量、控制变量、验证变量。主变量是归一化负载 G也就是单位时间内到达的信道业务量与信道容量之比。它不能直接设要通过“到达率 × 帧传输时间”换算出来。控制变量是帧长和信道速率这两个决定了单帧传输时间 T进而决定传播延迟比 a 的大小是影响 CSMA 表现的关键量。验证变量是节点数 N它不影响解析公式公式里基本假设无限节点但会显著影响仿真结果用来检验模型和理论之间的偏差是否合理。下面这张表是我常用的一组基准参数各组实验在这套基准上做单变量调整参数基准值扫描范围说明信道速率1 Mbps固定决定 T 的量级帧长1024 bit512 / 1024 / 2048T 随帧长线性变化传播延迟20 us5 / 20 / 100控制 a 延迟/T节点数105 / 10 / 30检验有限节点效应归一化负载 G0.1 至 2.0步长 0.1主变量最大重传次数8固定影响高负载区时延仿真时长每点 1e5 帧时固定保证统计稳定把这套参数先定死后面所有建模细节才有参照。反过来如果参数边做边改最后你会发现自己收集的一堆数据互相之间不可比白跑。2. ALOHA 部分的建模细节与参数推导ALOHA 看起来是两种协议里简单的那个但真要在 OPNET 里跑出和理论吻合的曲线细节上一个都不能马虎。尤其是分槽 ALOHA 的时隙对齐写不好就会出现“理论值 0.368仿真跑出 0.29”这种让人抓狂的偏差。2.1 纯 ALOHA 和分槽 ALOHA 的吞吐公式自己推一遍才踏实先把这个推导过程过一遍因为后面调参、看曲线全靠它。设帧传输时间为 T全网总到达率为 λ帧/秒定义归一化负载G λT表示“每个帧时内平均到达的帧数”。信道容量归一化为 1吞吐 S 就是“每帧时内成功传输的帧数”。纯 ALOHA 的脆弱期是 2T。为什么是 2T 而不是 T因为一个帧要想成功它开始发送之前的 T 时间内不能有别的帧开始发否则那帧会覆盖到它它开始之后的 T 时间内也不能有别的帧开始发否则它覆盖到别人。前后各 T总共 2T 的窗口内必须“干净”。泊松到达下这个概率是 e^(-2G)于是S_pure G · e^(-2G)对 G 求导令其为 0得 G 0.5此时 S 1/(2e) ≈ 0.184。分槽 ALOHA 把发送时刻强制对齐到时隙边界时隙长度等于 T。这样帧要么整体落在某个时隙里要么不发生脆弱期从 2T 缩短到 T。成功概率变成 e^(-G)S_slotted G · e^(-G)G 1 时取最大值 1/e ≈ 0.368。这两个数字0.184 和 0.368就是我在仿真里首先要验证的靶子。如果纯 ALOHA 的峰值吞吐跑出来偏离 0.18 太远说明模型里有问题必须先停下来查而不是急着加 CSMA。2.2 泊松到达在 OPNET 里的落地方式理论公式假设泊松到达仿真里也必须用泊松到达否则两条曲线没有可比性。OPNET 的进程模型里对应的是指数分布的到达间隔op_dist_exponential(mean)其中 mean 是平均间隔。这里有个容易写错的地方——mean 填的是间隔均值不是速率。如果目标到达率是 λ 帧/秒mean 应该是 1/λ 秒。我见过把 λ 直接填进去的写法结果负载小了一个数量级曲线整体左移还以为是模型精度问题查了半天。具体做法是在进程模型的初始化状态里为每个节点调度第一个到达自中断/* 进程模型init 状态的进入代码 */ double lambda_node; /* 从仿真属性读取全局到达率再按节点数均分 */ lambda_node op_ima_sim_attr_get_double(global_lambda) / (double) num_nodes; /* 调度第一个包到达事件 */ op_intrpt_schedule_self(op_sim_time() op_dist_exponential(1.0 / lambda_node), ARRIVAL_CODE);然后在处理到达事件的状态里先发包再调度下一个到达/* 进程模型处理 ARRIVAL_CODE 的转移条件分支 */ op_intrpt_schedule_self(op_sim_time() op_dist_exponential(1.0 / lambda_node), ARRIVAL_CODE);这里的关键是先把下一个到达调度好再去处理发包逻辑。因为发包过程中可能涉及重传、退避等待如果放到后面调度容易在退避期间漏掉新的到达事件导致实际到达率偏低。注意op_dist_exponential的参数必须是秒且必须严格大于 0。如果扫描参数时把 λ 设成了 0 想代表“无业务”这个函数会返回无穷大或者报错得单独处理这个边界。2.3 分槽机制的实现时间槽对齐是个体力活分槽 ALOHA 的实现比纯 ALOHA 麻烦不少因为它引入了全局时间参考。所有节点必须共享同一个时隙边界否则“分槽”就退化成纯 ALOHA 了。我的做法是在初始化时统一计算时隙长度slot_len等于帧传输时间 T然后每个节点的发送时刻强制取整到最近的时隙边界/* 计算下一个可用时隙的起点 */ double now op_sim_time(); double next_slot ceil(now / slot_len) * slot_len; /* 如果在时隙边界上往后推一个槽避免和当前槽冲突 */ if (next_slot now 1e-12) next_slot slot_len; op_intrpt_schedule_self(next_slot, TX_CODE);这段代码里那个1e-12的容差必须加。浮点数在做除法取整时会有精度误差ceil(now / slot_len) * slot_len算出来的结果可能比now小那么一点点不加容差就会调度到过去的时间点OPNET 会直接把事件丢弃或者报“调度时间早于当前时间”的错误。还有一个隐蔽问题时隙长度必须和帧传输时间严格相等。如果节点发包耗时因为加了处理延迟而略大于 T帧就会跨槽分槽的假设就破了。我的做法是把帧长度和信道速率设成整数比比如 1024 bit / 1 Mbps 1.024 ms然后把所有处理延迟设成 0 或者远小于 T 的值保证单帧传输严格落在槽内。3. CSMA 部分监听逻辑比想象中难写从 ALOHA 切到 CSMA代码量大概翻一倍难点全部集中在“监听”这个动作怎么建模上。共享信道在真实世界里是物理介质在仿真里必须显式实现一个“信道状态”的共享变量否则每个节点都以为自己独占信道。3.1 三种坚持策略的取舍与实现位置CSMA 有三个常见变种选哪个直接决定了曲线形状策略信道忙时的行为实现难度特点1-坚持持续监听一空闲立即发低冲突概率高高负载下性能塌陷快非坚持随机退避一段时间再听中冲突少但空闲期浪费多p-坚持以概率 p 发送1-p 延迟一个槽中高分槽系统里表现最好参数敏感我的建议是先做 1-坚持再补非坚持。1-坚持逻辑最简单——信道忙就等着一空闲马上发不需要额外的退避状态机跑通了能快速拿到一条基准曲线。之后加非坚持只需要在“信道忙”分支里插入一段op_dist_uniform的随机等待改动量很小。p-坚持不建议第一次就上。它需要分槽、需要为每个等待节点维护一个“已等待槽数”、还要处理多个节点在同一槽内以概率 p 同时决定发送导致的二次冲突状态机复杂度直接上一个台阶。等前两种跑稳了再考虑。3.2 传播延迟与 0 延迟假设的后果共享信道状态怎么实现这里有个分岔路口很多人第一次做会选错。做法一零延迟全局状态。在进程模型里维护一个全局变量channel_busy任何节点发包时置 1发完置 0其他节点读这个变量判断。实现简单但等于把传播延迟设成了 0CSMA 退化成完美监听——冲突率接近 0曲线好看到不真实。做法二带延迟的信道状态传播。每个节点在 t 时刻发出的信号要在 t τ 之后才能被其他节点感知到τ 是传播延迟。实现上发包节点在发出后调度一个自中断延迟 τ 后才把全局channel_busy置 1结束时再延迟 τ 后置 0。这样别的节点在 τ 窗口内仍然认为信道空闲冲突就自然产生了。选做法二这是让仿真结果有说服力的前提。具体到代码/* 节点开始发送立即置忙本地感知无延迟 */ op_intrpt_schedule_self(op_sim_time() prop_delay, BUSY_ON_CODE); /* 发送结束时延迟 τ 后再释放 */ op_intrpt_schedule_self(op_sim_time() frame_time prop_delay, BUSY_OFF_CODE);这样就自然产生了“A 已经开始发B 还没感知到于是 B 也发”的冲突窗口和真实物理过程一致。传播延迟 τ 的取值直接决定冲突率——τ 越大冲突越多这也是为什么 CSMA 在长距离链路上表现明显不如短距离局域网。3.3 冲突判定、退避与重传上限冲突判定逻辑要单独说。当一个节点准备发包时除了检查信道忙闲还要检查是否已经有别的节点正在发送。在带延迟的信道模型下这两个判断是分开的信道上可能已经有信号在传播别的节点刚发但本节点还没感知到。我的实现方式是给每个帧打一个“发送起始时刻”的标签冲突判定发生在帧接收端如果接收期间检测到有另一个帧的发送区间与自己重叠就标记为冲突两个帧都丢弃。这比在发送端判断更准确也更接近物理过程。退避策略方面二进制的指数退避BEB是常用选择第 n 次冲突后从[0, 2^n - 1]个时隙中随机选一个等待。但要注意n 要有上限一般取 8 到 10。如果不设上限高负载下退避窗口会指数膨胀到几千个时隙仿真事件数爆炸跑一晚上出不来结果——这个坑我在第 6 节会详细讲。重传上限同样要设。超过上限就丢帧丢帧率本身也是个有意义的统计量能反映系统在高负载下的稳定性。4. OPNET 工程搭建全流程实录前面讲的是协议逻辑这一节讲怎么把它落到 OPNET 的三层模型里。整个流程我按实际操作顺序走一遍中间的关键设置标注清楚。4.1 从新建工程到网络域摆节点新建工程时选“空场景”不要用自带的模板场景模板里预置的节点和流量配置会干扰实验。工程建好后先设场景尺度——这个参数很多人忽略但它决定了坐标单位和传播延迟的换算方式。共享信道实验里节点摆得越开传播延迟越大如果尺度设错了实际延迟和你以为的差好几个数量级。节点摆放有两种思路。一是星型/总线型物理拓扑所有节点连到一个中心节点或者一条总线上用 OPNET 自带的链路对象建模共享介质。二是逻辑共享、物理独立节点之间不连线共享信道的忙闲状态完全靠进程模型里的全局变量维护。做协议对比实验我推荐第二种因为第一种的链路对象自带一套信道接入逻辑会和你要实现的 CSMA 打架调起来极其难受。节点数量直接影响仿真时间。10 个节点跑 1e5 帧时的仿真在普通工作站上大概几分钟30 个节点的事件数差不多是 3 倍以上因为每多一个节点就多一路到达流和一套监听判断。做参数扫描时节点数一般不超过 30再多就得考虑并行或者简化模型。网络域的属性设置里有几个仿真属性必须提前定义好global_lambda全局到达率、frame_len帧长、prop_delay传播延迟、max_retry最大重传次数。用**仿真属性Simulation Attribute**而不是硬编码是为了后面做参数化扫描时能直接扫描这些值不用改代码重编译。4.2 节点模型与进程模型的分工OPNET 三层模型的分工用一句话概括节点模型管“有什么”进程模型管“怎么动”。节点模型里放的是模块一个source模块负责产生业务一个sink模块负责收包统计一个processor模块挂载协议进程。模块之间用包流packet stream连成数据通路用统计线stat wire连成统计通路。做共享信道实验时我的节点模型一般就三个模块app_gen产生帧、mac_proc协议主体挂进程模型、sink接收并统计。进程模型是状态机。我的状态划分是这样的状态含义主要动作init初始化读仿真属性、注册统计量、调度首个到达idle空闲等待等待到达事件或信道空闲事件sense监听判断检查信道状态决定发送或退避tx发送中占用信道等待发送完成backoff退避等待定时器到期后回到sense状态转移用转移条件宏控制每个状态有进入代码enter和离开代码exit。这套结构写熟了很顺手但第一次搭的时候容易把“事件类型”和“状态”搞混——op_intrpt_type()返回的是事件类型码自中断、流中断、统计中断等不是状态。我早期写错过把到达事件的处理逻辑写在了流中断分支里结果永远进不去。4.3 统计量的注册、采集与导出统计量是仿真结果的全部来源注册错了等于白跑。OPNET 的统计量分两类标量scalar和矢量vector。标量是仿真结束时的一个汇总值适合记录“总吞吐”“平均时延”这种一次性结果。矢量是随时间变化的采样序列适合观察瞬态过程比如“时延随仿真时间的变化”用来判断系统是否进入稳态。注册方式是在进程模型的函数块里调用/* 进程模型注册全局统计量 */ stat_thru_handle op_stat_reg(channel.throughput (bits/sec), OPC_GLOBAL, OPC_STAT_INDEX);OPC_GLOBAL表示全局作用域所有节点写同一个统计量自动累加。这一点很关键——如果误用了节点作用域每个节点各写各的最后导出来是 N 条曲线还要自己手动求和。写统计的时机也有讲究。吞吐量建议每成功接收一帧就写一次增量/* 帧成功接收后累加吞吐 */ op_stat_write(stat_thru_handle, (double) op_pk_total_size_get(pk));而时延建议在帧接收时记录一个样本值/* 计算端到端时延并写入 */ double delay op_sim_time() - op_pk_creation_time_get(pk); op_stat_write(stat_delay_handle, delay);采集配置在“配置/运行离散事件仿真”对话框里把需要的统计量勾选上指定结果文件名。这里有个必须注意的点结果文件是二进制格式不能直接拿 Excel 打开得先用结果查看器导出成 CSV 或者直接看曲线。我见过有人到处找“结果文件打不开”的原因其实就是格式问题。4.4 参数扫描与结果比对单点仿真只能得到一个数据点画不出一条曲线。要画吞吐-负载曲线至少得跑 15 到 20 个负载点。手动改参数跑 20 次累且容易出错用参数化研究功能可以一次配置完。配置方式在参数化研究对话框里把global_lambda设成扫描变量给定起始值、步长、点数。OPNET 会自动生成一组场景每个场景一个参数值依次运行。跑完之后用“比较结果”功能把多个场景的同名统计量画在同一张图上。这里有两个实操细节。一是扫描点的间隔要合理。负载从 0.1 扫到 2.0如果均匀取 20 个点间隔 0.1在低负载区0.1 到 0.5分辨率太低而 ALOHA 的峰值恰恰在 0.5 附近容易错过峰值位置。我的做法是在 0.3 到 0.8 区间加密到 0.05 的步长两头可以粗一点。二是每个负载点要用不同的随机种子。如果用同一个种子跑所有点随机数序列相同不同负载下的结果之间存在人为相关性做统计推断时置信区间会偏窄。种子一般设在仿真属性里每个场景给一个不同的整数值。5. 结果曲线怎么读才有意义曲线出来只是开始读不懂等于没做。这一节讲三个关键观察点都是我在反复对比之后才慢慢有感觉的。5.1 吞吐-负载曲线的三个关键点一条标准的吞吐-负载曲线至少要看三个位置。峰值位置和峰值高度。纯 ALOHA 的峰值应该在 G ≈ 0.5 处高度 0.18 附近分槽 ALOHA 在 G ≈ 1.0 处高度 0.36 附近1-坚持 CSMA 在低 a 值下峰值能到 0.5 甚至更高。如果仿真跑出来的峰值位置整体偏移八成是负载换算出了问题——比如到达率是按“每帧时”还是“每秒”算的没统一。下降段的斜率。过了峰值之后吞吐随负载上升而下降。下降越快说明协议在高负载下的“自我调节”能力越差。ALOHA 的下降段很陡因为冲突后的重传又制造了新冲突形成正反馈。分槽 ALOHA 下降稍缓。1-坚持 CSMA 在高负载下反而可能出现吞吐断崖式下跌因为所有节点都在同步监听、同步发送退避窗口不够大时冲突集中爆发。曲线右端的渐近行为。负载继续加大吞吐趋近于某个稳定值还是继续下探到 0反映了重传上限设置的影响。有限重传次数会让系统在高负载下“丢帧自保”吞吐稳定在一个低水平而不是无限恶化。5.2 时延曲线的拐点才是真正的分水岭吞吐曲线好看但真正能说明问题的往往是时延曲线。在负载低于某个阈值时时延基本稳定在一个小值因为大部分帧一次发送成功。过了阈值之后时延急剧上升因为重传次数增加、排队变长。这个拐点的位置就是系统的实际可用容量。纯 ALOHA 的时延拐点大概在 G 0.3 到 0.4 之间比吞吐峰值位置0.5更靠左——这意味着如果按峰值吞吐来设计负载实际时延已经很难接受了。这个结论在课本上往往只是一句话但自己跑出来看到两条曲线的相对位置印象会深得多。CSMA 的时延拐点通常比 ALOHA 更靠右在中低负载区时延明显更低。但当负载接近饱和时CSMA 的时延上升更陡——因为退避窗口指数增长等待时间突然拉长。两条时延曲线在高负载区交叉的现象我见过好几次这个交叉点在不同参数下位置不同很值得单独做一组扫描。5.3 仿真时间、预热期和随机种子这三个东西决定了结果可不可信但新手最容易忽略。仿真时长。太短的话统计样本量不够曲线抖动严重。我的经验是每个负载点至少跑 1e5 个帧传输时间如果帧传输时间是 1 ms模型时间就是 100 秒。这个时长下G 0.5 时的平均到达帧数约 5 万够统计用了。预热期。仿真刚开始时所有节点都处于初始状态系统还没进入稳态前一段时间的统计会拉低平均值。做法是设一个预热时长比如总时长的 10%在预热期内收集统计量但预处理时把这段时间的数据丢弃。OPNET 里可以通过统计过滤或者后处理实现。不做这一步低负载区的吞吐会系统性偏低。随机种子。单个种子的结果带有随机性严格来说应该跑多个种子取平均并给出置信区间。做课程实验可以简化但至少要用 3 个不同种子跑一遍看看结果的波动范围。如果三个种子的吞吐峰值差了 20% 以上说明样本量不够得加长仿真时间。6. 排查实录那几次结果离谱的仿真这一节是整篇里我最想写的部分。前面讲的都是“应该怎么做”这里讲“做错了会怎样”。6.1 吞吐曲线全为 0 的三种可能第一次跑通工程满怀期待地看结果曲线是一条贴着横轴的水平线。当时排查的顺序是这样的第一种可能统计量根本没注册成功。op_stat_reg调用时的名字必须和结果采集配置里勾选的名字完全一致包括大小写和空格。名字对不上统计量就写到了一个没人采集的地方结果文件里自然什么都没有。第二种可能包根本没发出去。在发包状态里插入调试打印看op_pk_send有没有被调用。我遇到过一次是包格式packet format没在包的创建函数里注册op_pk_create_fmt返回空指针后面的发送直接跳过也不报错。第三种可能包发了但接收端全判成冲突。这个最隐蔽。如果冲突判定逻辑写错比如把“任何两个帧”都判成冲突而不是时间重叠才冲突那所有帧都会被丢弃吞吐自然是 0。排查方法是在接收端加一个计数器分别统计“收到”“冲突”“格式错误”三种情况看比例。6.2 曲线出现人为天花板的两个来源有一次跑出来的吞吐曲线在 G 超过 1.0 之后完全水平最大值恰好是某个整数。这个“整数天花板”一眼就是人为的不是物理规律。来源之一是统计量单位错。如果吞吐量的统计单位是“包/秒”而不是“比特/秒”而每包的比特数又恰好被当成了 1那算出来的数值就是包数看起来像封顶了。检查方法是把同一个统计量同时用两种单位写一遍对比数值。来源之二是重传上限卡死。重传次数设成 8意味着一个帧最多尝试 9 次。在高负载下大部分帧都在 9 次内失败被丢弃吞吐就不再随负载变化了。这个天花板本身是真实存在的有限重传系统确实会饱和但它掩盖了协议本身的性能差异做对比实验时应该把重传上限设得足够大让系统在高负载区能充分体现拥塞行为。6.3 仿真跑一晚上没跑完的根因这是最让人崩溃的情况点运行进度条爬得极慢一晚上过去还在 20%。根因基本都是事件数爆炸。常见触发点有三个一是退避窗口没有上限。第 n 次冲突后从2^n个时隙里选n 长到 20 就是百万级时隙每个时隙都要调度一个定时器事件事件数直接失控。加个n min(n, 10)就解决了。二是监听逻辑形成了忙等循环。如果“信道忙”分支里没有退避而是调度一个极短的定时器立刻回来重查比如每次只等 1 us那系统会以极高的频率产生自中断。正确的做法是退避一个随机时长或者等信道释放事件而不是高频轮询。三是统计量写得过于频繁。如果吞吐统计在每次事件里都写一次而不是每帧写一次矢量数据量会大到 IO 成为瓶颈。改成按帧写之后运行时间能缩短一个数量级。6.4 常见问题速查表把上面这些整理成一张表方便对照现象最可能的原因处理方式吞吐恒为 0统计名不匹配 / 包未发出 / 冲突判断过严逐项加调试计数定位吞吐封顶在整数单位换算错 / 重传上限太小统一单位调大重传上限峰值位置整体左移或右移负载换算的 λ 和 T 不匹配复核 G λT 的量纲分槽 ALOHA 表现接近纯 ALOHA时隙未对齐或槽长不等于 T检查取整逻辑和容差设置CSMA 冲突率接近 0传播延迟被设成 0改为带延迟的信道状态传播时延曲线抖动剧烈仿真时间太短 / 样本不足加长仿真多跑几个种子仿真进度极慢退避无上限 / 忙等轮询 / 统计过频对应加限、改事件驱动、降采样低负载区吞吐系统性偏低未设预热期丢弃前 10% 仿真数据7. 跑了这么多组之后的一点体会这套实验做下来最深的感受是仿真最容易骗人的地方不是算错而是把假设不小心简化掉了。零延迟的共享信道、无上限的退避、忽略预热期——每一个单独看都是“合理简化”合起来就让曲线变得漂亮但不真实。当你发现仿真结果比理论预期还好看的时候先别高兴多想想是不是哪个假设被悄悄抹平了。另一个体会是关于参数扫描的耐心。我一开始总想用最少的点画出最完整的曲线结果峰值附近的数据点太少曲线形状完全变形。后来固定做法峰值区加密、两端放粗宁可多跑十几个点也不让关键区域留空白。这套参数表我后来复用到了好几个类似的信道接入仿真里改改帧长和速率就能直接用省下的重复劳动比想象中多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑