프롤로그
802.11be를 시스템 레벨 수준에서 시뮬레이션을 진행하여 내가 원하는 실험을 하거나 결과를 뽑아내내기 위해서는 지금까지 본 바로는 2가지 방법이 존재하는 것 같다.
1. MATLAB의 WLAN Toolbox 이용하기
2. ns-3을 이용하기
시간이 되면 둘 다 다뤄보겠지만, 지금 하고 있는 것은 추후 실험을 위하여 코드들을 분석하고 있다.
802.11be System-Level Simulation Using EMLSR Multilink Operation - MATLAB & Simulink
Simulate an IEEE 802.11be EMLSR MLO between an AP MLD and two STA MLDs.
kr.mathworks.com
위 시뮬레이션대로 진행을 하고 있다가, 이것저것 실험용 파라미터라던지 뜯어보고 있다.
첫번째로 진행할 것은 wlanNode의 생성 부분이다.
https://kr.mathworks.com/help/wlan/ref/wlannode.html
wlanNode - WLAN node - MATLAB
Use the wlanNode object to create and configure a WLAN node.
kr.mathworks.com
블로그 글이 뒤죽박죽 일거라서, 이게 몇 번째로 올라갈지는 모르겠으나, 관련된 다른 글들과 참고해서 이 부분이 필요한 사람들은 도움이 되면 좋겠다.
-MATLAB R2025b 기준
wlanNode 시작
예제 코드대로 실행하다 보면 wlanNode의 시작 위치는
apMLD = wlanNode(Position=[0 0 0],Name="AP",DeviceConfig=apMLDCfg);
staMLD = wlanNode(Position=[0 0 0; 0 10 0],Name=["STA1","STA2"],DeviceConfig=staMLDCfg);
nodes = [apMLD staMLD];
% nodes = 1*3 wlanNode array
위 부분에서 처음 나온다. 디버깅용을 위해서 저기서부터 한줄한줄 뜯어가보자.
코드를 직접 보고 싶다면
edit wlanNode.m
를 입력하면 직접 코드를 확인할 수 있다.
생성 예시로는
% 노드 생성
apMLD = wlanNode(Position=[0 0 0],Name="AP",DeviceConfig=apMLDCfg);
staMLD = wlanNode(Position=[10 0 0; 0 10 0],Name=["STA1","STA2"],DeviceConfig=staMLDCfg);
nodes = [apMLD staMLD];
이렇게 생성한다.
내부 메서드들만 우선 정리를 해보면
노드 구성 및 관리 속성
| 구분 | 속성명 | 설명 |
| 기본 정보 | Name | 사용자가 지정한 노드 이름 (예: "AP", "STA") |
| ID | 시뮬레이터가 자동으로 부여하는 고유 식별 번호 (Read-only) | |
| Position | 노드의 3차원 위치 ($x, y, z$) | |
| Velocity | 노드의 이동 속도 벡터 | |
| 추상화 설정 | MACFrameAbstraction | MAC 프레임을 실제 비트로 생성할지, 구조체로 간소화할지 결정 |
| PHYAbstractionMethod | 물리 계층 모델링 방식 (tgax-evaluation, none 등) | |
| 장치 구성 | DeviceConfig | AP/STA 모드, 전송 포맷 등 장치의 세부 설정 정보 |
| MaxSupportedStandard | 지원 가능한 최대 표준 (802.11a ~ 802.11be) | |
| 내부 객체 | Application | 데이터 트래픽 생성 및 수신을 담당하는 응용 계층 |
| →U-MAC | SharedMAC | MLD(멀티링크) 환경에서 링크 관리 및 시퀀스 번호를 총괄하는 두뇌 |
| →L-MAC | MAC | 개별 링크의 EDCA MAC 상태 머신 및 송수신 동작 관리 |
| PHYTx / PHYRx | 물리 계층의 송신기 및 수신기 객체 | |
| MeshBridge | 메시(Mesh) 네트워크의 경로 포워딩 담당 객체 |
노드 동작 메서드로
| associateStations | AP 노드에 STA들을 연결하고 BSS를 형성하며, MLO 모드를 설정함 |
| addTrafficSource | On-Off, FTP, VoIP 등의 트래픽 소스를 추가하여 통신을 발생시킴 |
| update | 실행 중 CWMin, CWMax, AIFS 등 MAC 계층 파라미터를 동적으로 변경 |
| statistics | 시뮬레이션 종료 후 App/MAC/PHY/Mesh의 모든 통계 데이터를 구조체로 반환 |
| kpi | 처리량(Throughput), 지연(Latency), 패킷 손실률(PLR) 등 핵심 성능 지표 계산 |
| addMeshPath | 메시 네트워크에서 특정 목적지로 가기 위한 다음 홉(Next hop) 경로 지정 |
| run | 시뮬레이션 시간 흐름에 따라 상위/하위 계층의 로직을 순차적으로 실행 |
주요 상태 및 감시 이벤트로
| StateChanged | 노드 상태 변화 감지 (Idle, Sleep, Contention, Transmission, Reception) |
| TransmissionStatus | RTS, MU-RTS, Data 프레임의 전송 성공/실패 여부 결정 시 발생 |
| MPDUDecoded | 수신된 프레임을 MAC 계층에서 성공적으로 해독했을 때 발생 |
| AppDataReceived | 수신 데이터가 최종적으로 응용 계층(Application)에 도달했을 때 발생 |
| MPDUGenerated | MAC 계층에서 전송할 MPDU가 생성되었을 때 발생 |
이렇게 정리가 된다.
| IsMLD | IsMLD해당 장치가 멀티링크 장치(MLD)인지 여부 |
| EnhancedMLMode | 0: STR(동시 송수신 가능), 1: EMLSR(스위칭 모드 동작) |
| NumEMLPadBytes | EMLSR 스위칭 시간 확보를 위해 ICF(Initial Control Frame)에 포함되는 패딩 바이트 수 |
| EnhancedMultilinkPaddingDelay | 스위칭 전 패딩을 위해 필요한 지연 시간 설정값 |
| EnhancedMultilinkTransitionDelay | PHY가 물리적으로 링크를 전환하는 데 걸리는 시간 |
| MU-RTS | EMLSR 스위칭을 유도하는 대표적인 초기 제어 프레임(ICF) 타입 |
이건 참고.

위와같이 여기까지 실행 클릭을 하면

이 상태에서 멈추고, 위쪽에 스탭 인 버튼을 클릭하자.

그러면
methods
function obj = wlanNode(varargin)
% Name-value pair check
coder.internal.errorIf(mod(nargin,2) == 1, 'wlan:ConfigBase:InvalidPVPairs');
% Initialize with defaults, in case user doesn't configure
obj.SharedMAC = wlan.internal.sharedMAC.empty;
obj.MAC = wlan.internal.edcaMAC.empty;
obj.MeshBridge = wlan.internal.meshBridge(obj.MAC);
obj.ReceiveFrequency = zeros(1, 0);
obj.DeviceConfig = wlanDeviceConfig;
obj.FullBufferContext = obj.FullBufferContextTemplate;
% Initialize constant properties
obj.NonHT = wlan.internal.frameFormats.NonHT;
obj.HTMixed = wlan.internal.frameFormats.HTMixed;
obj.VHT = wlan.internal.frameFormats.VHT;
obj.HE_SU = wlan.internal.frameFormats.HE_SU;
obj.HE_EXT_SU = wlan.internal.frameFormats.HE_EXT_SU;
obj.HE_MU = wlan.internal.frameFormats.HE_MU;
obj.HE_TB = wlan.internal.frameFormats.HE_TB;
obj.EHT_SU = wlan.internal.frameFormats.EHT_SU;
obj.PacketTypeEmpty = wlan.internal.networkUtils.PacketTypeEmpty;
obj.DataTypeIQData = wlan.internal.networkUtils.DataTypeIQData;
obj.DataTypeMACFrameBits = wlan.internal.networkUtils.DataTypeMACFrameBits;
obj.DataTypeMACFrameStruct = wlan.internal.networkUtils.DataTypeMACFrameStruct;
...
end
end
초기화 부분이 나온다.
EMLSR에 대한 논문은 많이 읽고 정리하려고 하고 있으나, 아직 시간이 부족하고 할일은 많아서 미뤄두고 있어서..일단 알고 있다라는 가정하게 설명하겠다.
obj.SharedMAC = wlan.internal.sharedMAC.empty;
obj.MAC = wlan.internal.edcaMAC.empty;
이 두 줄. 객체를 SharedMAC부분과 MAC부분각각에
sharedMAC하나와 edcaMAC 하나씩 각각 초기화 하는 것을 확인할 수 있다.
그 밑에 줄에 있는 obj.VHT라던지는 edcaMAC과 관련된 내용이겠구나를 알 수 있다.
중간중간 중요한 부분은
[obj.IsMLDNode] = deal(isa(obj(1).DeviceConfig(1), 'wlanMultilinkDeviceConfig'));
이 부분, MLDMode 설정하는 곳.
매트랩에서는 현재 STR모드와 EMLSR모드 두 개만 지원한다.
appPacketContext = struct(AccessCategory=0, DestinationNodeID=0, DestinationNodeName=""); % App packet context fields
for idx = 1:numNodes
% Application
% Use weak-references for cross-linking handle objects
objWeakRef = matlab.lang.WeakReference(obj(idx));
notificationFcn = @(eventName, eventData) objWeakRef.Handle.triggerEvent(eventName, eventData); % Function handle for event notification
sendPacketFcn = @(packet) objWeakRef.Handle.sendPacketToMAC(packet);
% Function handle for pushing packets from App into MAC
...
init(obj(idx), isCopy);
...
end
end
이부분은 Application 레이어와 MAC 레이어를 연결하는 인터페이스이다.
Application이 생성하는 패킷에 붙붙정보,
AccessCategory는 이제 QoS(VO, VI, BE, BK),목적지 노드, 목적지 이름이 있는 것을 확인할 수 있다. --> edcaMAC과 관련이 있구나 알 수 있다.
notificationFcn 코드 줄은 MAC->Application 방향 통신을 설정해서 ACK수신, TX완료, 패킷 드롭을 수행한다.
가장 중요한
sendPacketFcn = @(packet)
objWeakRef.Handle.sendPacketToMAC(packet);
이 부분에서
U-MAC으로 처음 접근하는 진입점이 된다.
이제 init을 만났다.
wlanNode에서 밑으로 좀 내리다 보면 function init이 보인다.
function init(obj, isCopy)
%init Initialize and setup the node stack
% Extract node ID
nodeIdx = obj.ID;
if ~obj.IsMLDNode
% In case of non-MLD node, devCfg contains per device configuration
devCfg = obj.DeviceConfig;
else
% In case of MLD node, devCfg contains per link configuration
devCfg = obj.DeviceConfig.LinkConfig;
end
validateMACAndPHYAbstraction(obj, devCfg);
% Number of devices in the node in case of non-MLD node. Number of links in
% case of MLD node.
...
non-MLD인 경우 devCfg = 각 device 설정
MLD인 경우 devCfg = 각 link 설정한다.
저기서 MLD모드라면
if obj.IsMLDNode
% Get EMLSR padding delay and transition delay in nanoseconds
emlsrPaddingDelay = round(obj.DeviceConfig.EnhancedMultilinkPaddingDelay*1e9); % in nanoseconds
emlsrTransitionDelay = round(obj.DeviceConfig.EnhancedMultilinkTransitionDelay*1e9); % in nanoseconds
% In case of MLD, create one shared MAC
maxSubframes = max([devCfg(:).MPDUAggregationLimit]);
obj.SharedMAC = wlan.internal.sharedMAC(obj.DeviceConfig.TransmitQueueSize, maxSubframes, ...
ShortRetryLimit=obj.DeviceConfig.ShortRetryLimit, ...
NumLinks=numDevices, IsMLD=obj.IsMLDNode, ...
EMLPaddingDelay=emlsrPaddingDelay, EMLTransitionDelay=emlsrTransitionDelay);
% Store AC to link mapping information in shared MAC
acs = cell(0, numDevices);
% Store band and channel of each link
bandsAndChannels = zeros(numDevices, 2);
primaryChannelNums = zeros(numDevices, 1);
primaryChannelFreqs = zeros(numDevices, 1);
primaryChannelIndices = zeros(numDevices, 1);
% Get the information of AC to link mapping, band and channel and primary
% channel from each link config
for linkIdx = 1:numel(obj.DeviceConfig.LinkConfig)
linkCfg = obj.DeviceConfig.LinkConfig(linkIdx);
acs{linkIdx} = linkCfg.MappedACs;
bandsAndChannels(linkIdx, :) = linkCfg.BandAndChannel;
primaryChannelIndices(linkIdx) = getPrimaryChannelIndex(obj, linkCfg);
[primaryChannelNums(linkIdx), primaryChannelFreqs(linkIdx)] = wlanNode.getPrimaryChannel(linkCfg.BandAndChannel, ...
linkCfg.ChannelBandwidth, primaryChannelIndices(linkIdx));
end
obj.SharedMAC.Link2ACMap = acs;
obj.SharedMAC.BandAndChannel = bandsAndChannels;
obj.SharedMAC.PrimaryChannel = primaryChannelNums; % This information is needed at AP for Beacon fields
sharedMAC = obj.SharedMAC;
% Store the parameters which are applicable per device in case of non-MLD
% and configured common to all links in case of MLD
txQueueSize = obj.DeviceConfig.TransmitQueueSize;
isMeshDevice = obj.DeviceConfig.IsMeshDevice;
isAPDevice = obj.DeviceConfig.IsAPDevice;
end
이 코드가 수행된다.
EnhancedMultiLinkPaddingDelay(AP가 EMLSR STA를 위해 initial control frame 앞뒤로 넣는 패딩 시간 관련)
와 EnhancedMultilinkTransitionDelay(STA가 한 링크에서 다른 링크로 전환하는 데 걸리는 시간)이 설정되고,
sharedMAC을 생성한다.
링크별로 MAC이 따로 있더라도, 그 위에 sharedMAC이 전체를 묶는 상위 제어 구조로 존재한다
즉
SharedMAC
├─ link1 MAC
├─ link2 MAC
└─ link3 MAC
이런구조로 만든거다.
그 다음에
- 링크1 → VO, VI
- 링크2 → BE, BK
이런식으로 각 링크가 담당할 Access Category를 저장한다.
sharedMAC에 링크 정보를 이제 그상태로..쭉 적은 내용을 저장한다.
% Configure and add the devices with MAC and PHY layers
for devIdx = 1:numDevices
isEMLSRSTA = false;
% Get number of space time streams
if obj.IsMLDNode && strcmp(obj.DeviceConfig.Mode, "STA") && ...
strcmp(obj.DeviceConfig.EnhancedMultilinkMode, "EMLSR") % EMLSR STA
isEMLSRSTA = true;
end
% Configure the rate control algorithm at MAC for DL transmissions from the device
if strcmp(devCfg(devIdx).RateControl,'fixed')
% Create a new rate control object for each node and each device/link,
% because rate control is a handle class.
rateControlAlgorithm = wlan.internal.rateControlFixed;
elseif strcmp(devCfg(devIdx).RateControl,'auto-rate-fallback')
% Create a new rate control object for each node and each device/link,
% because rate control is a handle class.
rateControlAlgorithm = wlan.internal.rateControlARF;
else % Custom rate control
if isCopy || isObjectReused(devCfg(devIdx).RateControl)
rateControlAlgorithm = copy(devCfg(devIdx).RateControl);
if ~obj.IsMLDNode
obj.DeviceConfig(devIdx).RateControl = rateControlAlgorithm;
else
linkCfg = obj.DeviceConfig.LinkConfig(devIdx);
linkCfg.RateControl = rateControlAlgorithm;
obj.DeviceConfig = updateLinkConfig(obj.DeviceConfig, devIdx, linkCfg);
end
이제 device/link별로
각 장치 또는 링크에 대해
- rate control
- power control
- scheduler
- MAC
- PHY를 하나씩 만든다.
좀 생략을 하고,
macScheduler = wlan.internal.schedulerRoundRobin;
라운드로빈으로 MAC 스케줄러 설정한다.
MAC 내부 스케줄링 방식의 일부같다.
더 내려가면
% MAC layer
mac = wlan.internal.edcaMAC(NodeID=nodeIdx, ...
DeviceID=devIdx, ...
ChannelBandwidth=devCfg(devIdx).ChannelBandwidth/1e6, ...
TransmissionFormat=wlan.internal.networkUtils.getFrameFormatConstant(devCfg(devIdx).TransmissionFormat), ...
MPDUAggregation=wlan.internal.sls.isMPDUAggregationEnabled(obj, devIdx), ...
DisableAck=devCfg(devIdx).DisableAck, ...
CWMin=devCfg(devIdx).CWMin, ...
CWMax=devCfg(devIdx).CWMax, ...
AIFS=devCfg(devIdx).AIFS, ...
TXOPLimit=devCfg(devIdx).TXOPLimit*32e3, ...
NumTransmitAntennas=numTransmitAntennas, ...
NumReceiveAntennas=numReceiveAntennas, ...
DisableRTS=devCfg(devIdx).DisableRTS, ...
RTSThreshold=devCfg(devIdx).RTSThreshold,...
Use6MbpsForControlFrames=devCfg(devIdx).Use6MbpsForControlFrames, ...
BasicRates=devCfg(devIdx).BasicRates, ...
RateControl=rateControlAlgorithm, ...
PowerControl=powerControlAlgorithm, ...
FrameAbstraction=obj.MACFrameAbstraction, ...
IsMeshDevice=isMeshDevice, ...
IsAPDevice=isAPDevice, ...
SharedMAC=sharedMAC, ...
Scheduler=macScheduler, ...
SharedEDCAQueues=sharedMAC.EDCAQueues, ...
MaxMUStations=maxMUStations, ...
DLOFDMAFrameSequence=dlOfdmaFrameSequence, ...
ULOFDMAEnabled=ulOFDMAEnabled, ...
ULRateControl=ulRateControlAlgorithm, ...
MaxSubframes=devCfg(devIdx).MPDUAggregationLimit, ...
MaxQueueLength=txQueueSize, ...
SIFSTime=16e3, ...
IncludeRxVector=obj.IncludeRxVector, ...
BSSColor=bssColor, ...
OBSSPDThreshold=obssPDThreshold, ...
BeaconInterval=devCfg(devIdx).BeaconInterval, ...
InitialBeaconOffset=devCfg(devIdx).InitialBeaconOffset, ...
IsEMLSRSTA=isEMLSRSTA, ...
NumEMLSRListenAntennas=EMLSRListenAntennas, ...
MaxSupportedStandard=obj.MaxSupportedStandard, ...
PrimaryChannelIndex=primaryChannelIdx);
이 부분이 나온다.
이전까지 초기화하고 설정했던 거 여기서 한 번에 다 설정하는 것인데,
논문에서도 많이 중요하게 보였던 부분은
MPDUAggregation=...,
DisableAck=...,
CWMin=...,
CWMax=...,
AIFS=...,
TXOPLimit=...,
DisableRTS=...,
RTSThreshold=...,
...
좀 많다.
switch devCfg(devIdx).InterferenceModeling
case 'co-channel'
obj.InterferenceFidelity(devIdx) = 0;
case 'overlapping-adjacent-channel'
obj.InterferenceFidelity(devIdx) = 1;
otherwise % 'non-overlapping-adjacent-channel'
obj.InterferenceFidelity(devIdx) = 2;
end
여기서는 간섭 모델링 종류를 저장한다.
자 이제, 전체적인 구조를 정리를 하면..
init()
├─ devCfg 결정 (device or link)
├─ MLD면 sharedMAC 생성
│ ├─ Link2ACMap 저장
│ ├─ Band/channel 저장
│ └─ EMLSR delay 저장
├─ 각 device/link마다
│ ├─ rate/power/scheduler 생성
│ ├─ edcaMAC 생성
│ ├─ PHY 생성
│ ├─ MAC↔PHY↔Node 콜백 연결
│ └─ addDevice
├─ meshBridge 생성
├─ MAC address/버퍼/association 정보 초기화
└─ MLD면 sharedMAC에 모든 MAC 연결
이게 전체 코드를 다 까봤는데...
실제 MAC 인스턴스는 edcaMAC
- sharedMAC이 MAC을 대체하는 게 아님
- edcaMAC 위에 sharedMAC이 얹히는 구조
그리고 sharedMAC이 전체 링크를 통합적으로 관리한다.
- MappedACs
- SharedEDCAQueues
- SharedMAC
아무튼 간에, U-MAC을 예전에
2026.03.24 - [네트워크] - [WiFi] 최신 WIFI 7 (IEEE 802.11 be)에 새로 도입된 Multi-Link Operation(MLO)에 대해 알아보자
[WiFi] 최신 WIFI 7 (IEEE 802.11 be)에 새로 도입된 Multi-Link Operation(MLO)에 대해 알아보자
프롤로그우리가 와이파이를 쓸 때 가장 중요하게 생각하는 요소는 무엇일까?나는 일단 빠른 속도, 끊기지 않는 것이 가장 중요하다고 생각한다. 4GB 프로그램 다운받는데 18시간 걸린다거나(실제
taesan-smj.tistory.com
1. 시퀀스 번호 할당 및 재조립 지원
하나의 데이터 스트림은 여러 링크로 분산되어 전송될 수 있다.
이때 수신 측에서는 각 링크로부터 도착한 데이터를 올바른 순서로 재조립해야 한다.
- U-MAC은 각 데이터에 시퀀스 번호를 부여
- 수신 측에서 순서 보장 및 재조립 가능하도록 지원
2. MSDU 분할 및 결합
전송 효율을 높이기 위해 데이터는 여러 링크로 나뉘어 전달된다.
- 송신 측: 하나의 MSDU를 여러 링크로 분할하여 전송
- 수신 측: 여러 링크에서 수신한 데이터를 다시 하나로 결합
3. TID-to-Link 매핑 (핵심 기능)
U-MAC은 각 트래픽을 어떤 링크로 보낼지 결정한다.
- 트래픽 우선순위(TID)에 따라 링크 선택
- 링크 상태, 혼잡도 등을 고려한 분산
즉, 데이터를 어디로 보낼지 결정하는 스케줄링 역할을 수행한다.
4. 공통 제어 기능
기존 MAC 계층과 동일하게 다음 기능도 담당한다:
- 연결(association)
- 인증(authentication)
이런 역할을 한다고 언급했었는데...
TID-to-Link 매핑 (핵심 기능)
이건 분석하면서 트래픽 우선순위(TID)에 따라 링크 선택하는 건 있었다. 근데 링크 상태를 본다던지, 혼잡도 등을 고려하는 코드는 아직까진 보이진 않는다.
sharedMAC에 데이터가 저장되고, 각 링크의 edcaMAC이 backoff 경쟁을 통해 TXOP를 획득한다. 이때 특정 링크가 TXOP를 획득하면, EMLSR 구조에서는 단일 main PHY가 해당 링크로 전환하여 데이터를 전송하게 된다. 따라서 채널 스위칭은 경쟁 때문이 아니라, 단일 PHY가 여러 링크를 공유하는 구조적 특성에서 발생한다.
다만, 이건 연구 방향에서도 있던 것인데, Dynamic Scheduling은 아니다. 보내야할 데이터를 아무래도 어떤 링크에서는 뭘 보내고, 어떤 링크에서는 뭘 보내고 설정을 정적으로 했기 때문이다.
즉, 이 코드들은 매트랩에서 규칙기반 매핑을 기본으로 구현한 것을 확인할 수 있다.
그래서 추측상, U-MAC의 역할을 sharedMAC에서 수행하고, L-MAC의 역할을 ecdaMAC에서 수행하는 것으로 현재 이해하고 있다.
이제
end
obj.SharedMAC.Link2ACMap = acs;
obj.SharedMAC.BandAndChannel = bandsAndChannels;
obj.SharedMAC.PrimaryChannel = primaryChannelNums; % This information is needed at AP for Beacon fields
sharedMAC = obj.SharedMAC;
이거를 알면, 내가 동적으로 트래픽을 관리하는 코드를 작성하려면 어떻게 해야할지 파악할 수 있을 것이다.
wlanNode 요약
- SharedMAC(U-MAC): 모든 링크를 통합 관리하고 QoS(AC)별로 어느 링크를 쓸지 결정함.
- edcaMAC (L-MAC): 각 링크(2.4/5/6GHz)에서 실제로 공기(Medium)를 점유하기 위해 싸우는 역할.
- EMLSR 특화 파라미터: PaddingDelay와 TransitionDelay가 SharedMAC 초기화 시 주입되어, 물리적인 PHY 스위칭 지연을 시뮬레이션에 반영함.
- 한계점: 현재 MATLAB 기본 구현은 Rule-based(정적) 매핑임. 실시간 채널 상황에 따른 Dynamic Scheduling 로직이 필요
sharedMAC
이 sharedMAC부분부터는 비공개 코드이기 때문에, 코드 함부로 긁어왔다가 디즈니 저작권쇼마냥 소송당할까봐 가져오기는 힘들 거 같고, 한줄씩 뭐뭐 있는지만 확인하는 식으로 가겠다.
which wlan.internal.sharedMAC
/Applications/MATLAB_R2025b.app/toolbox/wlan/netmod/+wlan/+internal/sharedMAC.m % wlan.internal.sharedMAC constructor
edit /Applications/MATLAB_R2025b.app/toolbox/wlan/netmod/+wlan/+internal/sharedMAC.m
그래도 코드를 보려면, 위와같이 which을 이용해서 코드를 볼 수는 있다.
주요 속성 먼저 정리하면
| IsMLD | 해당 장치가 멀티링크 장치(MLD)인지 여부를 나타내는 플래그 |
| NumLinks | MLD 내부에 포함된 총 링크(주파수 대역)의 수 (1~15) |
| MLDMACAddress | MLD 전체를 대표하는 고유 MAC 주소 |
| EMLPaddingDelay | EMLSR 스위칭 시간 확보를 위해 ICF(MU-RTS)에 포함할 패딩 지연 시간 (ns) |
| EMLTransitionDelay | 프레임 교환 종료 후 다시 모든 링크가 수신 대기 상태로 돌아가는 데 걸리는 시간 |
| ShortRetryLimit | 프레임 전송 실패 시 최대 재전송 시도 횟수 (기본값: 7) |
| EDCAQueues | 모든 링크가 공유하는 데이터 대기열(Queue) 관리 객체 |
| Link2ACMap | 각 링크(2.4GHz, 5GHz 등)에 어떤 데이터 타입(AC)이 매핑되어 있는지 나타내는 지도 |
| AssociationInfo | 연결된 상대방의 MLO 모드(STR/EMLSR), 스위칭 패딩(NumEMLPadBytes) 등을 담은 장부 |
| CurrentEMLSRTxSTA | 현재 특정 링크에서 전송 중인 EMLSR 단말의 ID |
| NumPadBytesICF | 스위칭 유도를 위해 MU-RTS 프레임에 실제로 들어갈 패딩 바이트 수 |
| ActiveEMLSRLink | 현재 단말에서 Main PHY가 활성화되어 통신 중인 링크를 표시하는 플래그 |
| SNSQoSDataMLD | MLD 간 통신 시 패킷 순서를 맞추기 위한 시퀀스 번호 카운터 |
| BandAndChannel | 각 링크가 작동하는 주파수 대역과 채널 번호 저장 |
| sharedMAC (생성자) | 객체를 초기화하고, EMLSR 패딩에 필요한 바이트(NumPadBytesICF)를 계산함 |
| assignSequenceNumber | 패킷이 어느 링크로 나가든 순서가 섞이지 않게 통합 번호를 부여함 |
| isQueueFull | 통합 대기열에 데이터를 더 넣을 수 있는지 확인 |
| getQIndexAndExpandContext | 특정 단말을 위한 대기열과 스케줄러 환경이 없으면 새로 생성하고 확장함 |
| addAssociationInfo | 새로운 단말이 연결되었을 때 그 단말의 MLO 정보를 장부에 등록함 |
| turnOffOtherLinks | EMLSR 단말이 한 링크에서 전송을 시작할 때, 다른 링크의 작동을 중단시킴 |
| turnOnOtherLinks | 통신이 종료된 후, 중단되었던 다른 링크들을 다시 수신 대기 상태로 전환함 |
이다.
이 코드의 결론부터 잡으면
sharedMAC은 단순한 공용 큐가 아니라, MLD 전체의 공통 상태, 시퀀스 번호 관리, association 정보, EMLSR 상태, 공용 EDCA queue를 관리하는 상위 MAC 보조 객체다.
공용 queue, 공용 sequence number, 공용 association, 공용 emlsr 상태를 하나의 sharedMAC에서 같이 관리한다.
In the context of a multi-link device (MLD), this object handles shared functionality between the links.
In the context of a non-MLD, this object handles functionality specific to a device.
- MLD에서는 링크 간 공통 기능
- non-MLD에서는 그 디바이스 전용 shared MAC
을 토대로 알 수 있다.
속성으로는 ShortRetryLimit(재전송 횟수), NumLinks(링크 개수), isMLD(MLD여부), MLDMACAddress(MLD전체 대표 맥주소), EMLPaddingDelay(ICF 패딩 지연), EMLTransitionDelay(listening 상태로 가기까지의 지연) 가 있다.
그리고 히든 속성에, 공용 큐, 큐생존시간, 각 링크가 어떤 AC를 담당하는지 나타내는 매핑 Link2ACMap , AssociationInfo(AP와 STA연결 정보), EMLSR 관련 상태들 등이 있다.
일단 동작을 보면
for idx = 1:2:numel(varargin)
obj.(varargin{idx}) = varargin{idx+1};
end
로 전달받은 N-V Pair를 바로 Property에 반영
% Create a WLAN MAC Queue management object
obj.EDCAQueues = wlan.internal.macQueueManagement(maxQueueLength, maxSubframes, ...
NumRetryBuffers=obj.NumLinks, ShortRetryLimit=obj.ShortRetryLimit, ...
MSDUMaxLifetime=obj.MSDUMaxLifetime, DestinationNodeIDs = 0);
로 실제 queue 객체를 생성한다.
- maxQueueLength
- maxSubframes
- NumRetryBuffers=obj.NumLinks
- ShortRetryLimit
- MSDUMaxLifetime
- DestinationNodeIDs = 0
가 매개변수로 넘어간다.
sharedMAC은 queue를 “직접 구현”하는 게 아니라 macQueueManagement라는 별도 queue manager를 들고 관리한다
큐 관리하는 거 보려면...macQueueManagement를 또 봐야할 것 같다. 일단 나중에..
그리고 링크 수만큼 EMLSR 상태 배열 생성을 진행한 후에, ICF Padding을 계산하였다.
그 후
function macQueuePacket = assignSequenceNumber(obj, macQueuePacket, varargin)
를 이용하여 패킷 타입에 따라 적절한 시퀀스 넘버를 선택해서 부여한다.
function pushUpperLayerPacket(obj, upperLayerPacket)
...
% Get access category of the packet
ac = upperLayerPacket.AC;
% Enqueue packet
enqueue(obj.EDCAQueues, upperLayerPacket.ReceiverID, ac+1, upperLayerPacket);
를 보면 상위 계층에서 내려온 패킷을 receiverID와 AC 기준으로 shared EDCA queue에 넣는다
여기까지는 링크 선택이 아니라, receiverID, AC 까지만 보고 enqueue한다.즉 이 시점에서는
- “어느 링크로 갈지”
- “링크 상태가 어떤지”
- “혼잡도가 어떤지”
를 계산하지 않는다.
function turnOffOtherLinks(obj, activeEMLSRLinkID)
% Indicate EDCA MACs of other links to turn off their operations
for idx = 1:numel(obj.MAC)
if (idx ~= activeEMLSRLinkID)
turnOffLink(obj.MAC(idx));
end
end
end
function turnOnOtherLinks(obj, activeEMLSRLinkID)
% Indicate EDCA MACs of other links to turn on their operations
for idx = 1:numel(obj.MAC)
if (idx ~= activeEMLSRLinkID)
turnOnLink(obj.MAC(idx));
end
end
end
이것도 있는데, 하나의 EMLSR링크가 동작하면 나머지 링크들 꺼버리는 코드가 있다.
sharedMAC 요약
1. 공용 EDCA queue 관리
2. receiver별/AC별 sequence number space 관리
3. MLD용 수신 cache 관리
4. association/BSSID/AID 정보 관리
5. EMLSR 상태 및 링크 on/off 관리
6. beacon/EDCA parameter update 상태 관리
sharedMAC은 단순히 여러 링크가 공용으로 사용하는 큐 객체가 아니라, MLD 환경에서 링크 간 공통 상태를 관리하는 상위 MAC 보조 계층에 가깝다. 실제로 이 객체는 공용 EDCA queue뿐 아니라, 시퀀스 번호 공간, MLD 수신 캐시, association 정보, beacon/EDCA 업데이트 상태, 그리고 EMLSR 링크 활성화 상태까지 함께 관리한다.
반면 각 링크에서 실제 contention과 TXOP 획득을 수행하는 것은 edcaMAC이다. 따라서 MATLAB 구현은 sharedMAC과 edcaMAC을 통해 전통적인 U-MAC/L-MAC 기능을 객체적으로 분산해 재구성한 구조로 이해하는 것이 적절하다.
macQueueManagement
which wlan.internal.macQueueManagement
/Applications/MATLAB_R2025b.app/toolbox/wlan/netmod/+wlan/+internal/macQueueManagement.m % wlan.internal.macQueueManagement constructor
앞서 분석한 sharedMAC이 "어느 링크로 보낼지 결정하는 뇌"라면, 지금 macQueueManagement는 "데이터를 쌓아두고 관리하는 창고"이다.
결론부터 말하면
이 객체는 “receiver별 × AC별” 송신 큐와 재전송 버퍼를 관리하는 실제 큐 엔진이다.
그리고 MLD에서는 NumRetryBuffers = NumLinks가 되므로, 링크별 재전송 버퍼까지 함께 관리한다.
1. Tx queue 관리
2. Retry buffer 관리
3. Peek / Dequeue / Discard 처리
4. Receiver별 컨텍스트 확장
핵심역할이 있다.
DestinationNodeID = 수신자 기준
├─ AC0 (BE)
│ ├─ TxQueue
│ └─ RetryBuffers[1..NumRetryBuffers]
├─ AC1 (BK)
│ ├─ TxQueue
│ └─ RetryBuffers
├─ AC2 (VI)
│ ├─ TxQueue
│ └─ RetryBuffers
└─ AC3 (VO)
├─ TxQueue
└─ RetryBuffers
Tx queue 검사애서는 FIFO queue의 맨 앞부터 검사해서 폐기 조건 만족하면 버린다.
여기서 중요한 주석이 있다.
%%FIFO이므로 앞에 있는 패킷이 조건 불만족이면 뒤쪽도 볼 필요 없다
즉 오래된 것부터 정리한다.
더 적을만한 것은 딱히 없어보인다. 그래서 정리를 하면
- 상위 패킷은 sharedMAC.EDCAQueues 안의 macQueueManagement로 들어간다.
- 이 큐는 receiver/AC 기준 FIFO queue다.
- edcaMAC은 contention에서 TXOP를 얻으면, 해당 destination/AC에 대해 peek 또는 dequeue를 수행해 frame을 가져온다.
- 이때 dequeue된 frame은 retry buffer로 옮겨져 추적된다.
- MLD에서는 retry buffer가 링크 수만큼 있으므로, 링크별 전송 중 frame 상태를 구분해서 관리할 수 있다.
이제 실제로 어떤 destination/AC를 골라 peek/dequeue 호출하는지를 보기 위해서는, edcaMAC을 직접 봐야한다.
queue가 어떻게 생겼는지도 봤고, sharedMAC도 봤으니., 그 큐를 누가 어떤 기준으로 집어가느냐를 봐야한다.
edcaMAC
edit /Applications/MATLAB_R2025b.app/toolbox/wlan/netmod/+wlan/+internal/@edcaMAC/edcaMAC.m
을 통해 edcaMAC을 확인할 수 있다.
전체 흐름은
[Application]
↓ (sendPacketFcn)
wlanNode.sendPacketToMAC()
↓
sharedMAC.pushUpperLayerPacket()
↓
macQueueManagement.enqueue()
↓
(shared queue 저장됨)
↓ (시간 흐름 / 이벤트)
edcaMAC (각 링크별)
↓ (backoff 경쟁)
TXOP 획득
↓
scheduler (RoundRobin)
↓
sharedMAC.dequeue()
↓
macQueueManagement.dequeue()
↓
PHY 전송
↓
성공 / 실패
↓
retry buffer or discard
주요 속성 정리하면
| NodeID | Property | 노드 식별자 |
| MACAddress | Property | MAC 주소 |
| IsAPDevice | Property | AP인지 여부 |
| IsAssociatedSTA | Property | STA로 연결된 상태 여부 |
| IsMeshDevice | Property | Mesh STA 여부 |
| BSSID | Property | BSS 식별자 |
| AID | Property | Association ID |
| BasicRates | Property | 지원되는 기본 데이터율 |
| CWMin | Property | 최소 contention window (AC별) |
| CWMax | Property | 최대 contention window (AC별) |
| AIFS | Property | 인터프레임 대기 슬롯 값 |
| RTSThreshold | Property | RTS 사용 기준 패킷 크기 |
| TransmissionFormat | Property | PHY 프레임 형식 |
| ChannelBandwidth | Property | 채널 대역폭 |
| NumTransmitAntennas | Property | 송신 안테나 개수 |
| MPDUAggregation | Property | 프레임 aggregation 사용 여부 |
| MaxSubframes | Property | aggregation 시 최대 서브프레임 수 |
| FrameAbstraction | Property | MAC 프레임 추상화 사용 여부 |
| DisableRTS | Property | RTS 비활성화 여부 |
| DisableAck | Property | ACK 비활성화 여부 |
| Use6MbpsForControlFrames | Property | control frame을 6Mbps로 고정 |
| MaxQueueLength | Property | MAC 큐 최대 크기 |
| MaxMUStations | Property | MU 전송 시 최대 STA 수 |
| DLOFDMAFrameSequence | Property | DL OFDMA 프레임 시퀀스 |
| ULOFDMAEnabled | Property | UL OFDMA 활성화 여부 |
| Scheduler | Property | 스케줄러 객체 |
| RateControl | Property | rate control 객체 |
| PowerControl | Property | 전력 제어 객체 |
| ULRateControl | Property | UL rate control 객체 |
| DeviceID | Property | MAC이 속한 디바이스 ID |
| BeaconInterval | Property | Beacon 주기 |
| InitialBeaconOffset | Property | 첫 beacon 전송 오프셋 |
| HandleReceivePacketFcn | Property | 수신 패킷 처리 함수 핸들 |
| EventNotificationFcn | Property | 이벤트 알림 함수 핸들 |
| SetPHYModeFcn | Property | PHY 모드 변경 함수 핸들 |
| run | Method | MAC layer 실행 |
| pushUpperLayerPacket | Method | 상위 계층 패킷을 MAC 큐에 넣음 |
| isQueueFull | Method | 큐가 꽉 찼는지 확인 |
| statistics | Method | MAC 통계 반환 |
처음에
sendPacketFcn = @(packet) objWeakRef.Handle.sendPacketToMAC(packet);
을 통해 패킷이 생성되면 저기로 들어간다.
노드가
sharedMAC.pushUpperLayerPacket(upperLayerPacket)
를 이용하여
ac = upperLayerPacket.AC;
enqueue(obj.EDCAQueues, upperLayerPacket.ReceiverID, ac+1, upperLayerPacket);
ac기반으로 큐를 선택하고, ReceiverID기준으로 큐를 분리한다.
function enqueue(obj, nodeID, ac, packet)
...
obj.TxQueues(nodeIdx, ac, index) = packet;
obj.TxQueueLengths(nodeIdx, ac) += 1;
로 실제 큐를 저장한다.
그리고 이제부터는 이벤트 기반으로
while(true):
backoff 감소
TXOP 가능 여부 체크
로 EDCA경쟁을 한다.
AC별 독립 경쟁
VO > VI > BE > BK
그러다가 backoff == 0 이되면 TXOP를 획득한다.
그때,
Scheduler = wlan.internal.schedulerRoundRobin;
가 동작한다. 라운드 로빈이라는 단어가 보인다.
밑에서 한 번 더 알아보자.
SharedEDCAQueues = sharedMAC.EDCAQueues
로 연결하고, dequeue로 실제 보낼때 디큐한다.
전송 결과들에 대한 처리는 큐매니지먼트에서 있던 discard, retry buffer등을 이용한다.
이 시스템은 “스마트 스케줄링 기반 MLO”가 아니라
“EDCA 경쟁 기반 MLO 시뮬레이션”
여기서 주목해야할 점은
Link2ACMap이라는 함수가 있다.
function acIndices = getMappedACs(obj)
% Return the AC indices allowed in this link/device for transmission
acIndices = 1:4; % By default, all ACs are allowed
if obj.IsAffiliatedWithMLD
% Get the ACs mapped to this specific link for transmission
acIndices = obj.SharedMAC.Link2ACMap{obj.DeviceID} + 1;
end
end
이건 링크별 허용 AC를 제한한다.
즉
- non-MLD: AC 1~4 전부 허용
- MLD: Link2ACMap{link}에 들어있는 AC만 허용
아 근데 Link2ACMap 설정을 어디서 하나 봤더니, 다시 wlanNode.m에 가보면
% Store AC to link mapping information in shared MAC
acs = cell(0, numDevices);
% Store band and channel of each link
bandsAndChannels = zeros(numDevices, 2);
primaryChannelNums = zeros(numDevices, 1);
primaryChannelFreqs = zeros(numDevices, 1);
primaryChannelIndices = zeros(numDevices, 1);
% Get the information of AC to link mapping, band and channel and primary
% channel from each link config
for linkIdx = 1:numel(obj.DeviceConfig.LinkConfig)
linkCfg = obj.DeviceConfig.LinkConfig(linkIdx);
acs{linkIdx} = linkCfg.MappedACs;
bandsAndChannels(linkIdx, :) = linkCfg.BandAndChannel;
primaryChannelIndices(linkIdx) = getPrimaryChannelIndex(obj, linkCfg);
[primaryChannelNums(linkIdx), primaryChannelFreqs(linkIdx)] = wlanNode.getPrimaryChannel(linkCfg.BandAndChannel, ...
linkCfg.ChannelBandwidth, primaryChannelIndices(linkIdx));
end
obj.SharedMAC.Link2ACMap = acs;
obj.SharedMAC.BandAndChannel = bandsAndChannels;
obj.SharedMAC.PrimaryChannel = primaryChannelNums; % This information is needed at AP for Beacon fields
이러한 코드가 있다. 저거 acs변수 만들고 뭐 설정을 하는데, linkCfg가 보이는가?
아. 그니까 linkCfg가 또 어디서 왔다...DeviceConfig에 있나보다...저기를 가봐야하는데
지금도 너무 뒤죽박죽 섞여있는데 난 모르겠다.
전체 구조 정리
Application
↓
sharedMAC
└─ EDCAQueues = macQueueManagement
├─ receiver별 queue
├─ AC별 queue
├─ retry buffer
└─ dequeue/discard 관리
↓
edcaMAC (link별)
├─ contention
├─ TXOP 획득
└─ shared queue에서 frame 사용
↓
PHY
원래라면 U-MAC에서 혼잡도 계산해서 어떤 링크에다가 보낼지 정하고 순서도 정해주어야하나, 지금 이 매트랩의 코드대로라면, EDCA 경쟁을 해서 각 링크가 해당하는 데이터를 큐에서 뽑아간다.
schedulerRoundRobin
>> which wlan.internal.schedulerRoundRobin
/Applications/MATLAB_R2025b.app/toolbox/wlan/netmod/+wlan/+internal/schedulerRoundRobin.m % wlan.internal.schedulerRoundRobin constructor
>>
edit /Applications/MATLAB_R2025b.app/toolbox/wlan/netmod/+wlan/+internal/schedulerRoundRobin.m % wlan.internal.schedulerRoundRobin constructor
으로 들어가보면
입력으로
primaryAC
txQueueLengths
retryBufferLengths
stationInfo
, 출력으로
obj.DLScheduleInfo.DstStationIDs
obj.DLScheduleInfo.ACs
이걸 받는다. 즉 어떤 STA, 어떤 AC를 쓸지 결정한다.
흐름으로는
전송가능한 STA를 먼저 찾는다.
txBufferedStations = find(~all(txQueueLengths == 0, 2))';
큐에 데이터 있는 STA만 후보로 둔다.
여기서
% Get number of previous chances of transmission for above stations
% and sort them.
numServes = obj.NumDLServes(numDLServesIndices);
[sortedNumServes, sortedIndices] = sort(numServes);
% Rearrange active stations according to ascending order of number
% of chances of transmission.
txBufferedStations = txBufferedStations(sortedIndices);
라운드 로빈을 정렬한다. 그래서 덜쓴 STA를 찾아낸다.
그리고
% Find retry stations with primary AC data and set schedule flags
% to 1.
primaryACRetryStations = find(retryBufferLengths(:, primaryAC))';
scheduleFlags(primaryACRetryStations) = 1;
% Find stations with primary AC data in transmission queues that
% doesn't have primary AC data for retry and set corresponding
% schedule flags to 1.
primaryACStations = find(txQueueLengths(:, primaryAC))';
primaryACStations = primaryACStations(scheduleFlags(primaryACStations) == 0);
scheduleFlags(primaryACStations) = 1;
% Assign weights as -3 for stations with primary AC data in retry
% queues and -2 for stations with primary AC data in transmission
% queues and set their corresponding ACs as primary AC.
AC 우선순위대로 찾아낸다.
재전송 > 일반 primary AC 느낌인 거다.
% Find stations with secondary AC data in retry buffers - Stations with
% non-zero retry buffers, but excluding stations that are already scheduled
% for primary AC.
obj.SecondaryACRetryStations = find((sum(retryBufferLengths(:, acList), 2) ~= 0));
obj.SecondaryACRetryStations = obj.SecondaryACRetryStations(scheduleFlags(obj.SecondaryACRetryStations) == 0);
그리고 2번째 AC 처리도 한다.
% Sort according to weights
[~, tempSortedIndices] = sort(sortedNumServes);
priority 기반으로 최종 STA+AC 선택하고
obj.DLScheduleInfo.DstStationIDs
obj.DLScheduleInfo.ACs
결과를 저장한다.
이 스케줄러는 큐 순서를 안 본다.
그래서 동작은
[EDCA]
↓
AC 승리
↓
[schedulerRoundRobin]
→ (STA, AC 선택)
↓
[macQueueManagement]
→ 해당 STA/AC queue에서 FIFO dequeue
구조가
극 (STA, AC)는 자기 큐를 따로 가진다.
STA1 queue:
[ p1, p2 ]
STA2 queue:
[ p3, p4 ]
이런느낌, 여기서 STA1을 스케줄러가 고르면
p1이 나가는 느낌인 거다.
AP 내부:
AC1
AC2
AC3
AC4
→ 이 4개가 contention
AP에서는 STA별 EDCA 경쟁이 아니라, AP MAC의 AC들끼리 경쟁한다
승리한 AC (primaryAC)
↓
schedulerRoundRobin
↓
그 AC 또는 secondary AC를 가진 STA들 중 대상 선택
AP downlink 기준으로 보면, 먼저 AP 내부의 AC들이 EDCA contention을 수행한다.
이때 TXOP를 획득한 AC가 primary AC가 되며, 이후 schedulerRoundRobin은
각 STA의 queue 상태와 serve 횟수, retry 여부를 고려하여 실제 전송할
STA와 AC 조합을 결정한다. 마지막으로 macQueueManagement가 선택된
(STA, AC) queue에서 FIFO 방식으로 packet을 dequeue하여 전송한다.
즉 schedulerRoundRobin은 queue 내부 packet 순서를 보는 것이 아니라,
어떤 STA와 어떤 AC를 전송 대상으로 고를지를 결정하는 역할을 하며,
packet 단위 선택은 macQueueManagement의 FIFO dequeue가 담당한다.
스케줄러 에서
가중치 부여가
primaryACRetryStations → weight -3
primaryACStations → weight -2
secondaryACRetry → weight -1
이렇게 되기 때문..
전체 흐름 정리
코드대로 가면\
AP에서는
[Application]
↓
sharedMAC.pushUpperLayerPacket()
↓
EDCAQueues (Destination × AC 별 큐)
↓
각 링크의 edcaMAC가 AC별 contention 수행
↓
어떤 링크 + 어떤 AC (primary AC)가 TXOP 획득
↓
schedulerRoundRobin 호출
→ (STA, AC) 선택 (primary + secondary AC 고려)
↓
macQueueManagement.dequeue()
→ 해당 (STA, AC) queue에서 FIFO로 packet 추출
로 된다.
여기서 조금 연구적으로 볼 수 있다면
STA에서는
Application
↓
sharedMAC queue (receiver × AC)
↓
각 링크 edcaMAC
↓
getMappedACs()로 허용 AC 필터
↓
허용 AC만 EDCA contention
↓
winner (link, AC)
↓
retry buffer 우선 / 없으면 FIFO dequeue
↓
전송
차이는 STA을 선택한다는 차이가 있다.
- Application이 packet을 shared queue에 넣음
- 각 링크 edcaMAC은 getMappedACs()로 자기 링크에서 허용된 AC만 후보로 삼음
- 그 허용 AC들에 대해 EDCA/backoff 경쟁
- 어떤 링크와 어떤 AC가 TXOP를 획득
- 해당 (receiver, AC) queue에서 retry-buffer-first, 그다음 FIFO로 dequeue
- 전송
각 링크의 edcaMAC은 먼저 getMappedACs()를 통해 해당 링크에서 허용된 AC 집합을 구하고, 그 허용된 AC들만 대상으로 EDCA/backoff 경쟁을 수행한다.
설명이 그지같을 수 있으니...

그림 하나로...해결이 되길 바란다..
wlanMultilinkDeviceConfig
edit wlanMultilinkDeviceConfig.m
을 입력하면 볼 수 있다.
처음 주석으로
%wlanMultilinkDeviceConfig WLAN multilink device (MLD) configuration
% DEVICECFG = wlanMultilinkDeviceConfig() creates a default WLAN MLD
% configuration object.
%
% DEVICECFG = wlanMultilinkDeviceConfig(Name=Value) creates a WLAN MLD
% configuration object with the specified property Name set to the
% specified Value. You can specify additional name-value arguments in any
% order as (Name1=Value1, ..., NameN=ValueN).
%
% wlanMultilinkDeviceConfig properties:
%
% Mode - Operating mode of the MLD
% ShortRetryLimit - Maximum number of transmission attempts for a frame
% LinkConfig - Link configuration
% EnhancedMultilinkMode - Mode of enhanced multilink operation (MLO)
% EnhancedMultilinkTransitionDelay - Enhanced multilink single radio (EMLSR) transition delay in seconds
% EnhancedMultilinkPaddingDelay - EMLSR padding delay in seconds
% Copyright 2023-2024 The MathWorks, Inc.
값이 보인다.
Mode : MLD냐 아니냐
링크설정도 있고,
EMLSR에서 transitiondelay, paddingdelay를 파악할 수 있다.
여기까지는 기본 값이구나 생각하면 되고,
구조가
wlanMultilinkDeviceConfig ← 지금 보고 있는 코드
└─ LinkConfig (vector)
└─ wlanLinkConfig ← 실제 링크 설정
진짜 200줄내외로 별거 없어서 wrapper로 봐야할 것 같다.
중간 코드에
obj.LinkConfig = wlanLinkConfig;
가 있다. wlanLinkConfig 설정이 있는 것을 알 수 있으니 저기로 넘어가자.
wlanLinkConfig
처음에
밴드 설정을 한다.
[band, channel]
그리고 PrimaryChannelIndex를 설정한다.
내가 관심있게 보지 않는 부분은 그냥 넘어가면...
%CWMin Minimum range of contention window for four ACs
% Specify minimum size of contention window for Best Effort, Background,
% Video, and Voice traffic respectively. This value must be a vector of
% four integers. Each element in the vector must be in the range [1,
% 1023]. The default value is [15 15 7 3].
CWMin (1, 4) {mustBeInteger, mustBeGreaterThanOrEqual(CWMin,1), mustBeLessThanOrEqual(CWMin,1023)} = [15 15 7 3];
%CWMax Maximum range of contention window for four ACs
% Specify maximum size of contention window for Best Effort, Background,
% Video, and Voice traffic respectively. This value must be a vector of
% four integers. Each element in the vector must be in the range [1,
% 1023]. The default value is [1023 1023 15 7].
CWMax (1, 4) {mustBeInteger, mustBeGreaterThanOrEqual(CWMax,1), mustBeLessThanOrEqual(CWMax,1023)} = [1023 1023 15 7];
AC별 contention window
AIFS (1, 4) {mustBeInteger, mustBeGreaterThanOrEqual(AIFS,1), mustBeLessThanOrEqual(AIFS,15)} = [3 7 2 2];
AC별 우선순위 결정
TXOPLimit (1, 4) {mustBeInteger, mustBeGreaterThanOrEqual(TXOPLimit,0), mustBeLessThanOrEqual(TXOPLimit,1023)} = [0 0 0 0];
TXOP duration
%MappedTIDs List of TIDs mapped to this link
% Specify the TID values which can be transmitted on this link as a
% scalar or vector, where each element is in the range [0-7]. By default,
% all the TIDs are mapped to a link. Hence, the default value is 0:7.
MappedTIDs (1, :) {mustBeInteger, mustBeMember(MappedTIDs, 0:7)} = 0:7;
end
이 링크에서 허용된 traffic
properties(Hidden, Constant)
%PowerControl Power control
% A string value indicating the type of power control algorithm
% used.
PowerControl = "FixedPower";
%TID2AC Mapping from TID (values 0 to 7) to AC (values 0 to 3)
% Access Category corresponding to each TID, where TID+1 is the index
TID2AC = [0 1 1 0 2 2 3 3]; % AC 0=BE, 1=BK, 2=Video, 3=Voice
end
MappedACs
function flag = isInactiveProperty(obj, prop)
어떤 property가 "현재 설정에서 무의미한지" 판단
그외에 비콘설정, 물리계층 설정 등등이 있지만
"링크 하나의 PHY + MAC + contention + RF 설정을 전부 들고 있는 객체"
가 본질이다.
MappedTIDs
NumTransmitAntennas
NumSpaceTimeStreams
등등도 있고..
wlanNode에서의 TID/AC의 사용가능 링크 확장
기존에 디폴트값으로 0~7번까지, 즉 모든링크에서 어떤 데이터도 전송할 수 있었다.
왜냐면, wlanLinkConfig때문이었다.
이거 디폴트값이 설정되어있기 때문이다.
이거를 타파하려면
% Link 1 → BE/BK만
linkCfg(1).MappedTIDs = [0 1 2 3];
% Link 2 → Video/Voice만
linkCfg(2).MappedTIDs = [4 5 6 7];
이런식으로 설정해주어야한다.
에필로그
좀 많이 뒤죽박죽 할 것이다.
이것저것 파고파고파고 들어가다 보니...
그리고 분석하면서 적다보니까 잘못된 내용이 있을 수도 있는데...그래도 후반에 마지막 정리부분은 좀 맞을 거다...
다시 한 번 언급하지만, 매트랩 코드보면서 분석한거고, 이 5천줄 넘는거 대충 분석한거라서...틀린 많긴할거다.