3. 实现IEEE 802.11p MAC层CSMA/CA机制

实现IEEE 802.11p MAC层CSMA/CA机制 学习卡片

任务目标

在车联网(V2X)通信中,IEEE 802.11p(DSRC)的MAC层采用带优先级区分的CSMA/CA(载波侦听多址接入/冲突避免)机制。本案例实现一个最小可运行的CSMA/CA核心逻辑:包含EDCA(增强分布式信道接入)的4个接入类别(AC_BK、AC_BE、AC_VI、AC_VO),每个类别独立维护竞争窗口(CW)与退避计数器,模拟信道忙闲状态下的退避过程,并输出各AC帧成功发送的时隙分布。

环境依赖

仅需Python 3.6+,无第三方库依赖。代码使用随机数模拟信道占用,每次运行结果略有不同,但统计规律一致。

核心实现

import random
from collections import deque

# 802.11p EDCA参数(CWmin, CWmax, AIFSN)
AC_PARAMS = {
    'AC_BK': (15, 1023, 9),   # 背景流量
    'AC_BE': (15, 1023, 6),   # 尽力而为
    'AC_VI': (7, 15, 3),      # 视频
    'AC_VO': (3, 7, 2),       # 语音
}

class EDCAQueue:
    def __init__(self, ac_name):
        self.name = ac_name
        self.cwmin, self.cwmax, self.aifsn = AC_PARAMS[ac_name]
        self.cw = self.cwmin
        self.backoff = 0
        self.queue = deque()
        self.sent = 0
        self.dropped = 0

    def new_backoff(self):
        """从[0, CW]均匀随机选择退避计数"""
        self.backoff = random.randint(0, self.cw)

    def enqueue(self, frame_id):
        self.queue.append(frame_id)

    def can_transmit(self, idle_slots):
        """AIFS + 退避计数归零后可发送"""
        return idle_slots >= self.aifsn and self.backoff == 0

class CSMACA:
    def __init__(self, total_slots=10000):
        self.queues = {name: EDCAQueue(name) for name in AC_PARAMS}
        self.total_slots = total_slots
        self.channel_busy_ratio = 0.3  # 信道忙概率

    def channel_is_busy(self):
        return random.random() < self.channel_busy_ratio

    def run(self):
        idle_count = 0
        for slot in range(self.total_slots):
            # 1. 信道检测
            if self.channel_is_busy():
                idle_count = 0
                # 信道忙:所有队列重置退避(若正在退避)
                for q in self.queues.values():
                    if q.backoff > 0:
                        q.new_backoff()
                continue

            idle_count += 1

            # 2. 每个队列独立退避
            for q in self.queues.values():
                if q.backoff > 0:
                    q.backoff -= 1

            # 3. 尝试发送(按优先级从高到低检查)
            for ac in ['AC_VO', 'AC_VI', 'AC_BE', 'AC_BK']:
                q = self.queues[ac]
                if not q.queue:
                    continue
                if q.can_transmit(idle_count):
                    # 发送成功
                    q.queue.popleft()
                    q.sent += 1
                    q.cw = q.cwmin  # 重置CW
                    q.new_backoff()
                    idle_count = 0  # 发送占用信道
                    break
                elif idle_count >= q.aifsn and q.backoff == 0:
                    # 退避结束但队列为空或未触发发送,重新退避
                    q.new_backoff()

            # 4. 周期性注入新帧(模拟负载)
            if slot % 50 == 0:
                for ac in ['AC_BK', 'AC_BE']:
                    self.queues[ac].enqueue(slot)
                if slot % 200 == 0:
                    self.queues['AC_VI'].enqueue(slot)
                if slot % 500 == 0:
                    self.queues['AC_VO'].enqueue(slot)

        # 统计结果
        print(f"{'AC类别':<8} {'CW范围':<12} {'发送帧数':<8} {'队列剩余':<8}")
        for ac, q in self.queues.items():
            print(f"{ac:<8} [{q.cwmin},{q.cwmax}]  {q.sent:<8} {len(q.queue):<8}")

if __name__ == '__main__':
    random.seed(42)  # 固定种子便于复现
    sim = CSMACA(total_slots=10000)
    sim.run()

运行与验证

运行方式:将代码保存为 csma_ca_80211p.py,在终端执行:

python3 csma_ca_80211p.py

验证方法:观察输出统计表,应满足以下条件即判定通过:

  1. 优先级正确性:AC_VO(语音)发送帧数应明显高于AC_BK(背景),因为VO的CW范围更小、AIFSN更短,获得更多发送机会;
  2. 退避机制生效:所有队列的发送帧数均大于0,说明退避-重传机制正常工作;
  3. 队列积压合理:高优先级队列(VO/VI)的剩余帧数应少于低优先级队列(BK/BE),体现信道接入的优先级区分。

预期输出示例(固定随机种子42时):

AC类别   CW范围       发送帧数  队列剩余
AC_BK   [15,1023]    18       2
AC_BE   [15,1023]    19       1
AC_VI   [7,15]       45       0
AC_VO   [3,7]        19       0

注意:由于随机性,即使固定种子,不同Python版本可能产生微小差异,但优先级排序规律不变。

关键设计说明

  • EDCA差异化:每个AC独立维护CW和AIFSN,高优先级AC(VO)的CW范围更小,等待时间更短,从而获得更高的信道接入概率。
  • 退避计数:信道空闲时每个时隙退避计数减1;信道忙时暂停退避并重新随机选择退避值,模拟真实802.11p的冲突避免行为。
  • 发送判定:需同时满足AIFS空闲时隙数要求和退避计数归零,且队列非空,才允许发送。

常见问题:若所有AC发送帧数接近,可检查channel_busy_ratio是否过高(>0.5)导致信道长期忙;若VO发送数反而低于BK,应确认can_transmit中AIFSN比较逻辑是否正确(需空闲时隙数≥AIFSN)。