CSMA/CA与802.11 DCF原理及MATLAB仿真工程解析
2026/9/15 22:13:58 网站建设 项目流程

简介:针对无线网络协议学习中 CSMA/CA 机制抽象、不易观察的问题,这份 MATLAB 仿真资源提供了可直接运行的脚本与可视化展示,适合通信工程、计算机网络方向的学生或研究人员用来理解 802.11 DCF 分布式协调功能下的信道访问流程。压缩包共20个文件,其中19个为 .m 仿真脚本,另含1个 txt 文档,用于说明程序模块功能;整体仅22KB,轻量且结构清晰,便于逐文件阅读与二次修改。资源目前已吸引456人学习下载。脚本覆盖载波监听、随机退避、RTS/CTS 握手、ACK 确认以及 DIFS/SIFS 帧间隔等关键机制,通过图形化界面直观展示数据发送与冲突避免过程,同时配套的代码注释能帮助读者快速掌握各函数模块的作用。对正在完成无线网络课程设计、协议仿真实验或希望加深 CSMA/CD 与 CSMA/CA 对比理解的读者而言,是一份简洁实用的参考资料。

1. 无线网络放弃 CSMA/CD,为什么反而更复杂:CSMA/CA 与 802.11 DCF 的由来

以太网收发共用一根线,发送时可以同时读回电平,所以CSMA/CD能边发边检测冲突。Wi-Fi是半双工射频,发送信号会淹没接收信号,根本实现不了“边发边听”。于是IEEE 802.11把碰撞解决思路从“检测”改成“避免”,这就有了CSMA/CA和作为核心机制的分布式协调功能DCF。这份Csmaca_wifi压缩包用MATLAB完整搭了一套802.11 DCF仿真工程,里面不仅有csma_ca.m主模型,还有Display1.m、FramePop.m、SetBackoffTime.m、RecordSend.m等配套模块,并附带“程序模块功能详解.txt”。如果你在做无线网络课程设计,或者想把wifi协议里的载波监听、退避窗口、RTS/CTS、ACK这些概念跑成可观察的曲线,这套代码值得拆一拆。

2. DCF 的四道防线:载波监听、帧间间隔、退避窗口与 RTS/CTS 协调

DCF 设计的核心目标是在分布式无中心环境下,让多个节点公平共享无线信道。它不像集中调度那样由AP统一分配,而是每个节点在发送前自己判断信道是否“干净”。这四道防线缺一不可。

2.1 物理载波监听与网络分配向量

节点在发起传输前必须先检测信道。物理层CCA(Clear Channel Assessment)判断接收功率是否超过-82 dBm的门限;超过则信道忙。DCF在MAC层还维护一个网络分配向量NAV,记录未来一段时间信道将被占用,即使物理层暂时空闲,只要NAV没到0,就视为信道忙。这份工程里的GetFreeze.m,对应的就是因为“监听忙而冻结退避计数”的动作。

function [busy, nav_count] = channel_busy(cca_power, thresh, nav_count) % 根据接收信号功率和NAV状态判断信道忙闲 if cca_power > thresh || nav_count > 0 busy = 1; else busy = 0; end if nav_count > 0 nav_count = nav_count - 1; % 每个时隙递减一次 end end

这个函数里的cca_power是物理层采样到的接收功率,thresh是载波侦听门限,nav_count是虚拟载波监听计数器。判断逻辑是物理和虚拟任意一路说忙就算忙。注意nav_count要在主循环的每个时隙只减一次,不能在几个分支里重复减,否则DIFS计算会出错。

2.2 SIFS、DIFS 与 EIFS:不同帧的优先级从间隔时间开始

802.11 DCF之所以能区分ACK、普通数据帧和恢复帧,靠的是不同的帧间间隔,而不是优先级标记。下表是基本参数。

帧间间隔时长(802.11a典型值)主要用途
SIFS16 μsACK、CTS确认
PIFS25 μs点协调控制信号
DIFS34 μs数据帧/管理帧发送前等待
EIFS约 92 μs收到坏帧后额外等待

SIFS 最短,所以接收端回ACK时能比其它要发数据的节点优先抢到信道。DIFS比PIFS长,保证有PCF时数据不会压过控制。EIFS在解码失败时启用,避免一个坏帧之后大家盲目竞争。仿真中如果发现ACK占用率不对,先检查SIFS是否比DIFS短,很多初版代码把两者写反。

2.3 二进制指数退避:冲突避免的数学基础

即使每个节点都等DIFS,仍可能同时发送。DIFS之后每个节点从 [0, CW] 均匀取一个退避数,每过一个空闲时隙递减1,信道忙时冻结。连续碰撞会让CW翻倍(CW = CW_min × 2^c),直到CW_max。

function backoff = SetBackoffTime(cw) % 802.11 DCF: 从竞争窗口内均匀随机选取退避时隙数 persistent rng_state; if isempty(rng_state) rng_state = rng('shuffle'); end raw = round(rand * cw); backoff = raw; % 单位是时隙:aSlotTime end

竞争窗口cw的单位不是微秒而是时隙数。802.11a中一个时隙是9 μs,初始CW_min = 15,CW_max = 1023。rand产生 [0,1) 均匀随机数,乘以cw再取整,覆盖0到cw-1,退避计数从0开始即可。实际工程中应使用独立同分布的随机数流,不要在每个节点里共享同一个随机数生成器的状态而不做跳步,否则大量节点会同时选中同一个退避值,仿真中会出现不现实的碰撞峰。

2.4 RTS/CTS/ACK:解决隐藏节点与确认收包

隐藏节点是无线网络特有的问题:A和C都能与B通信,但互相听不到,所以A发数据时C也可能发,B处冲突。DCF提供RTS/CTS短帧预约信道。发送方先发RTS,里面对应NAV时长覆盖整个数据+ACK阶段;接收方回CTS,所有听到CTS的节点(包括A和C)都会更新NAV。数据帧发出后,接收方再回ACK表示成功。这个机制不是必选的,小于RTSThreshold的短帧直接发数据即可。仿真中可以把RTSThreshold设成0观察开销,再设成大片包观察吞吐量下降,体会“越短帧RTS/CTS越亏”。

3. MATLAB 仿真工程拆解:从 main.m 到 SetBackoffTime、FramePush 的数据流

压缩包一共20个文件,初看很乱。把职责理清后,实际只有三类:控制主程序、协议逻辑模块和可视化模块。下文按一个可复现的主循环来分析。

3.1 文件职能划分与调用关系

文件类型作用
main.m / main1.m主程序搭建仿真场景,控制时间推进
csma_ca.m / Csmaca.m / csma_ca1.m / CSMA_CA_test.mCSMA/CA模型主协议逻辑入口
csma_cd.m / Csmacd.m对比模型CSMA/CD有线以太网仿真,用于对比
AddNode.m节点模块动态添加节点并分配ID
Increase.m条件更新更新节点状态/计数器
SetBackoffTime.m退避算法生成退避时隙数
FramePush.m / FramePop.m队列模块模拟发送队列和接收队列
GetFreeze.m状态判断决定是否冻结退避计数
RecordSend.m统计模块记录每次发送的时间、节点、结果
Display.m / Display1.m可视化绘图展示信道占用、发送过程
mysphere.m / my.m辅助工具绘制三维场景/自定义绘图辅助

Csmacd.m不是CSMA/CA的错误拼写,它是同一个作者做的CSMA/CD有线网络模型。建议先跑csma_cd再用csma_ca对比,能直观看出碰撞率差异:有线模型检测到冲突后立即停止,无线模型只能等ACK超时重传。

3.2 main.m 主循环:时间步进还是事件驱动

从包名和文件结构推断,工程采用的是固定时隙时间步进:每个循环代表一个aSlotTime,节点状态和计数器逐时隙更新。时间步进代码简单,但步长必须严格等于协议时隙,否则退避递减和NAV递减会失去同步。一个可执行的主循环骨架如下:

nodes(1) = AddNode(1, 0.2); % 节点1 信道占用强度参数0.2 nodes(2) = AddNode(2, 0.2); nav = zeros(1, length(nodes)); % 每个节点的NAV backoff = zeros(1, length(nodes)); for t = 1:10000 % 10000个离散时隙 for i = 1:length(nodes) % 1. 检查是否要产生新帧 if rand < nodes(i).arrival_rate nodes(i).frame_num = nodes(i).frame_num + 1; nodes(i).state = 'wait_difs'; end % 2. DIFS已结束且退避为0则发送 if nodes(i).state == 'ready' && backoff(i) == 0 [result, busy_channel] = csma_ca1(nodes(i), t); RecordSend(t, i, result); backoff(i) = SetBackoffTime(15); end % 3. 退避递减/冻结 if GetFreeze(channel_busy, nav(i)) == 0 backoff(i) = max(backoff(i) - 1, 0); end end % 更新NAV nav = max(nav - 1, 0); end Display(main_output);

这里把csma_ca1.m当作实际发送处理函数调用。循环内每个时隙都要经过“产生帧→处理DIFS/退避→发送→更新NAV”的顺序。若把NAV更新放在发送处理前,会导致同一时隙内新设的NAV立刻被减掉,等效于缩短了预约时长。AddNode返回结构体,其中arrival_rate表示每个时隙产生新帧的概率,0.2意味着每5个时隙约产生1帧,对应网络负载较高。

注意:上面的主循环中,NAV更新必须放在所有节点的发送处理之后;如果放在前面,同一次发送设置的NAV会在同一时隙被减一,等于把RTS/CTS预约时长人为缩短了一个时隙。

3.3 FramePush 与 FramePop 的责任边界

FramePush.m负责把待发送帧压入发送队列,FramePop.m在发送成功后弹出帧并记录完成时间。许多初学MATLAB的人会把队列和信道状态混在一起,实际上应该分开:信道忙不忙是物理层判断的,队列里积压多少是链路层判断的。改进方法是在每个节点结构里维护一个tx_queue向量,容量上限可以设成10,超过上限后新帧丢弃,模拟802.11 MAC层的队列溢出。

3.4 容易混淆的 CSMA/CD 与 CSMA/CA 实现

压缩包里Csmacd.mCsmaca.m并存,命名很容易搞混。CSMA/CD在读回冲突后立刻结束发送,而CSMA/CA从来不会在发送中途放弃,它只能通过超时未收到ACK来感知冲突。如果你把csma_cd的分支逻辑套用到csma_ca上,最明显的错误是发送时长为0、碰撞检测时间被算进信道占用。这类问题可以从RecordSend的结果类别看出:CD模型会出现“collision_abort”记录,CA模型只能出现“send_ok”和“ack_timeout”。

4. 参数怎么调、图形怎么读:Display 系列与 RecordSend 结果可视化

仿真输出不是只看一条漂亮曲线。必须通过参数扫描找到“网络从稳定到饱和”的拐点,再对照Display图检查节点行为是否符合DCF定义。

4.1 影响吞吐量与延迟的关键参数

参数典型值变化趋势
节点数2~64节点越多,碰撞概率越高
分组到达率0.01~0.30到达率越高,重传积压越大
CWmin15越小延迟越低但碰撞越频繁
CWmax1023越大重传时越稳定但退避越久
SIFS16 μs变长会拖慢ACK反馈
DIFS34 μs变长会降低信道利用率

对于Wi-Fi联网场景,如果一台AP带很多设备,实际感受就是“wifi上网慢”。从仿真角度看,慢的根源往往不是带宽,而是节点数增大后DIFS+退避+重传占用的空口时间成倍增加。你可以把节点数从10改成50,观察RecordSend中的总发送次数和有效payload比例,数据会快速下降。

4.2 RecordSend 统计:冲突率与吞吐量计算

RecordSend.m 应该维护一个矩阵,每行是[时间, 节点ID, 发送结果]。读取这些记录后,按节点聚合统计:

rec = RecordSend_history; % 每行: [时间(us), 节点ID, 结果(1:成功,2:超时)] send_ok_cnt = sum(rec(:, 3) == 1); coll_cnt = sum(rec(:, 3) == 2); total_send = size(rec, 1); collision_rate = coll_cnt / total_send; payload_bits = send_ok_cnt * 1500 * 8; % 假设每帧固定1500字节 payload total_time_s = max(rec(:, 1)) * 1e-6; throughput_mbps = payload_bits / total_time_s / 1e6;

写入统计时建议把时间戳统一用微秒表示,避免后续吞吐量换算出现数量级错误。collision_rate超过0.2时说明网络已经工作在饱和区,继续提高到达率只会让排队时延无限增大,与DCF的二进制指数退避能否收敛关系不大。

4.3 Display 系列图怎么读

Display.m 通常画信道占用状态图,横轴是时间时隙,纵轴是节点ID,每个矩形表示一次发送。如果看到两个节点在同一条竖线上有重叠矩形,说明仿真里出现了同一次发送的帧占用冲突,要先检查是不是时序推进问题。Display1.m一般绘制队列长度或退避计数值随时间的折线。正常DCF仿真的退避曲线应是锯齿状:建帧后退避随机下降到0,若因忙冻结则出现平台期,冻结越频繁说明信道竞争越激烈。若所有节点退避长期停在0,说明代码里没有调用SetBackoffTime初始化,或者DIFS判断条件写错,导致所有节点争先发送。

5. 模型验证与边界:从 802.11 DCF 到 802.11ax 的进阶调试技巧

5.1 用 Bianchi 模型校验饱和吞吐量

想确认仿真实现不是“看起来合理”,可以跑一个单饱和场景,让每个节点永远有包可发,然后对比Bianchi的马尔可夫模型理论值。饱和吞吐量S可近似为:

S = (P_tr * P_s * payload) / ((1-P_tr)slot + P_trP_sT_s + P_tr(1-P_s)*T_c)

其中P_tr是至少一个节点发送的概率,P_s发送成功概率,T_s成功传输耗时,T_c碰撞耗时。仿真参数与理论公式必须采用相同的时隙、帧长和头开销。实测误差在5%以内说明主循环和SetBackoffTime随机数生成正确。性能偏差太大的话,优先排查GetFreeze——冻结逻辑一旦错误,退避计数会在信道上提前递减,P_idle变小,吞吐量虚高。

5.2 调试DCF时该抓什么“log”

实际Wi-Fi问题诊断中,工程师遇到“wifi上网慢”时抓空口日志看信道占用、返回异常和CCA状态。仿真模型同理。建议在csma_ca1.m的入口处增加一个事件日志开关:

if enable_log fprintf('t=%d node=%d type=%s state=%s backoff=%d nav=%d\n', ... t, node.id, evt_type, node.state, backoff, nav_count); end

这个log在验证RTS/CTS时序时尤其有用。正确的CTS应答顺序应该是“RTS发射→SIFS→CTS发射→SIFS→数据→SIFS→ACK”,任何一行日志里出现了连续两次DIFS,就说明SIFS优先权没实现。把EnableLog设成1后跑2000个时隙,直接看波形图里的顺序,比看曲线收敛快得多。

5.3 从DCF迁移到802.11ax MU-OFDMA

这套模型的核心是单信道半双工竞争,而802.11ax引入了OFDMA多用户并行传输,DCF不再是唯一接入方式。但你并不需要推翻整个模型,只需把每个节点当作一个RU资源单元,在发送前先由AP触发多用户帧,再让节点复用退避机制竞争上行资源。你可以把AddNode的返回值扩展为包含ru_index的struct,FramePush处增加frame_type = 'trigger_based'的分支。这样原有退避、冻结、ACK记录全部保留,你只需要新增一个AP调度器,就能对比802.11 DCF和802.11ax两种模式下的延迟表现。第一件要做的事是给每个节点的退避状态增加freeze_count字段,记录冻结前后计数器的差值,用来评估并行传输消除竞争后的收益,避免模型迁移后又回到冲突避免的老套路上。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询