MJ GALLERY
목록으로
조회 46 좋아요 0
[wifi] WiFi 7 Puncturing 기능에 대해서 알아보자
Tech Published

[wifi] WiFi 7 Puncturing 기능에 대해서 알아보자

IEEE 802.11BE에서 PHY 핵심 기능인 Puncturing 가기까지에 대한 개념과 과정

작성자 서민재 · 2026.06.15 10:59 (수정됨) · 댓글 0

프롤로그


이제 Wifi 7(802.11be)에서 PHY의 핵심기능인 Puncturing에 대해서 좀 자세히 알아보고, 코드로 구현까지 해보자.

MRU(Multi Resource Unit)


이전 글에서 RU라는 개념에 대해서 적었다.

🔗 https://smjgallery.kr/blog/post/wi-fi-ofdm-mimo-mu-mimo-ofdma%EB%A1%9C-%EB%B3%B4%EB%8A%94-wi-fi-%EA%B8%B0%EC%88%A0%EC%9D%98-%EC%A7%84%ED%99%94/

RU는 OFDMA 환경에서 사용자에게 할당되는 주파수 자원의 단위라고 볼 수 있다.

OFDMA에서는 하나의 채널을 여러 개의 RU로 나누고, 각 RU를 사용자에게 할당하여 여러 사용자가 동시에 통신할 수 있도록 한다.

하지만 이러한 구조는 사용자가 많을 때는 효율적이지만, 사용자가 적거나 특정 사용자가 많은 데이터를 전송해야 하는 상황에서는 한계가 존재한다.

예를 들어 채널이 여러 개의 RU로 나누어져 있다고 가정해보자.

사용자가 많다면 각 사용자에게 서로 다른 RU를 할당하여 효율적으로 통신할 수 있다. 하지만 사용자가 적거나 특정 사용자가 많은 데이터를 전송해야 하는 상황에서는 일부 RU가 비어 있는 채로 남을 수 있다.

기존 OFDMA에서는 하나의 사용자에게 하나의 RU만 할당하는 경우가 많았기 때문에, 사용 가능한 주파수 자원이 남아 있음에도 이를 충분히 활용하지 못하는 상황이 발생할 수 있었다.

이를 개선하기 위해 Wi-Fi 7에서는 MRU(Multi Resource Unit)가 도입되었다.

MRU는 하나의 사용자가 여러 개의 RU를 동시에 할당받을 수 있도록 하는 기술이다.

Puncturing


그런데 여기서 또 하나의 문제가 발생한다.

만약 여러 개의 RU 중 일부 구간에 강한 간섭이 존재한다면 어떻게 될까?

기존 방식에서는 간섭이 있는 구간 때문에 넓은 채널 전체를 사용하지 못하거나, 더 좁은 채널로 대역폭을 낮춰 통신해야 했다.

이를 해결하기 위해 Wi-Fi 7에서는 Puncturing이라는 기술이 도입되었다.

Wi-Fi는 더 높은 속도를 제공하기 위해 80MHz, 160MHz, 320MHz와 같은 넓은 채널 대역폭을 사용한다.

하지만 넓은 채널을 사용할수록 특정 주파수 구간에 간섭이 발생할 가능성도 높아진다.

예를 들어 160MHz 채널을 사용하고 있는데, 그중 일부 20MHz 구간에 레이더 신호나 다른 Wi-Fi AP의 강한 간섭이 존재한다고 가정해보자.

기존 방식에서는 전체 160MHz 채널을 사용할 수 없어 더 좁은 대역폭인 80MHz 또는 40MHz로 전환해야 했다.

즉, 일부 구간에만 문제가 발생했음에도 불구하고 정상적으로 사용할 수 있는 나머지 주파수 자원까지 포기해야 하는 비효율이 존재했다.

이를 해결하기 위해 등장한 기술이 Puncturing이다.

Puncturing은 간섭이 발생한 특정 주파수 구간만 비우고(Puncture), 나머지 정상적인 주파수 구간은 계속 사용하는 기술이다.

즉, 일부 주파수 자원만 포기하고 나머지 주파수 자원을 계속 활용함으로써 전체 전송 성능을 유지할 수 있게 된다.

Wi-Fi 7에서는 이러한 Puncturing 기술이 더욱 확장되었으며, 다양한 RU(Resource Unit)와 MRU(Multi Resource Unit) 조합을 활용하여 간섭 환경에서도 높은 처리량(Throughput)을 유지할 수 있도록 설계되었다.

결과적으로 Puncturing은 “간섭이 있는 일부 주파수만 버리고, 나머지는 계속 사용하자”는 아이디어를 기반으로 하는 Wi-Fi 7의 핵심 PHY 기술 중 하나라고 볼 수 있다.

즉, Puncturing의 성능은 “간섭이 어느 위치에 존재하는가”, “몇 개의 서브채널을 비워야 하는가”, “Bandwidth Fallback 대비 얼마나 높은 Throughput을 유지하는가”에 의해 결정된다. 따라서 Wi-Fi 7에서는 간섭 환경에서 언제 Puncturing을 적용하는 것이 유리한지가 중요한 연구 주제가 된다.

Non-OFDMA에서 Wave만들기

OFDMA가 아니기 때문에, 하나의 RU에 여러 명의 사용자가 빔포밍을 이용하여 들어갈 수 있다.

우선 초기 환경설정 파라미터 부터 만들자

clc;
clear;
close all;
rng(1);

으로 먼저 초기화를 하고

%% Parameters
bandwidth = 320;


numRUs = 1; % Define the number of Resource Units
numTx =8; % Number of transmit antennas
numUsers = 2; %Number of Users


SNR_dB = 1;
SNR_linear = 10.^(SNR_dB/10); %Signal Power


guardInterval = 3.2;
EHTLTFType = 4;


osf = 1.5;
channelCoding = "LDPC";
MCS = 12;
payloadLength = 1024; %byte
numPackets = 1;

이렇게 파라미터 값을 설정하였다. 아 물론 나중을 위해서 미리 만들어놓은 것도 있어서 지금은 필요없는 변수값도 존재할 수 있을 수 있다.

여기서 guardInterval = 3.2라던지, MCS=12라던지는 이전 글

https://smjgallery.kr/blog/post/wifi-ofdm%EA%B8%B0%EB%B0%98-wi-fi-phy-%EA%B8%B0%EC%B4%88/

https://smjgallery.kr/blog/post/wifi-ofdm%EA%B8%B0%EB%B0%98-wi-fi-phy-%EA%B8%B0%EC%B4%88/

에서 이게 무슨 내용인지 정리하였으니 확인이 가능하다.

그 다음

%% Initial
cbw = getCBW(bandwidth);

%% function
function cbw = getCBW(bandwidth)
    if bandwidth == 320
        cbw = "CBW320"; % Assign the corresponding channel bandwidth
    elseif bandwidth == 160
        cbw = "CBW160";
    elseif bandwidth == 80
        cbw = "CBW80";
    elseif bandwidth == 40
        cbw = "CBW40";
    elseif bandwidth == 20
        cbw = "CBW20";
    else
        error('Invalid bandwidth specified');
    end
end

이 함수를 만들고

%% Initial
cbw = getCBW(bandwidth);


%% 통합 CFG 생성
cfg = wlanEHTMUConfig(cbw, "NumUsers", numUsers);
cfg.NumTransmitAntennas = numTx;
cfg.GuardInterval = guardInterval;
cfg.EHTLTFType = EHTLTFType;



% 할당 정보 확인
allocInfo = ruInfo(cfg);
disp('Allocation info:')
disp(allocInfo)

이렇게 wlanEHTMUConfig를 이용해서 cfg 변수를 만들자.

MATLAB WLAN Toolbox에서는 IEEE 802.11 계열 패킷을 생성하기 위해 다양한 Configuration 객체를 제공한다.

여기서 각 이름의 의미는 다음과 같다.

  • wlan : WLAN(Wireless Local Area Network, 무선 LAN)
  • EHT : Extremely High Throughput (802.11be, Wi-Fi 7)
  • MU : Multi-User
  • Config : PHY/MAC 설정 정보를 저장하는 객체

즉, wlanEHTMUConfig는 Wi-Fi 7(802.11be) 환경에서 Multi-User 패킷을 생성하기 위한 설정 객체라고 볼 수 있다.

이 객체 내부에는 채널 대역폭(Channel Bandwidth), RU(Resource Unit), MCS(Modulation and Coding Scheme), 공간 스트림(Spatial Stream), Puncturing 패턴 등 다양한 PHY 계층 파라미터들이 저장된다.

여기까지 하고 실행을 하면

Allocation info:
                    NumUsers: 2
                      NumRUs: 1
                   RUIndices: {[1]}
                     RUSizes: {[3984]}
               NumUsersPerRU: 2
    NumSpaceTimeStreamsPerRU: 2
       PowerBoostFactorPerRU: 1
                   RUNumbers: 1
                  RUAssigned: 1

>> 

이것만 보면 각각이 무엇을 의미하는지 알 수 없으므로, 다른 예시도 하나 보여주겠다.

%% 통합 CFG 생성
% cfg = wlanEHTMUConfig(cbw, "NumUsers", numUsers);
cfg = wlanEHTMUConfig(cbw, "NumUsers", numUsers, "PuncturedChannelFieldValue", 3);
cfg.NumTransmitAntennas = numTx;
cfg.GuardInterval = guardInterval;
cfg.EHTLTFType = EHTLTFType;



% 할당 정보 확인
allocInfo = ruInfo(cfg);
disp('Allocation info:')
disp(allocInfo)

를 이용해서 출력하면 아래와 같이 나온다.

Allocation info:
                    NumUsers: 2
                      NumRUs: 1
                   RUIndices: {[1 4 3 4]}
                     RUSizes: {[996 484 996 996]}
               NumUsersPerRU: 2
    NumSpaceTimeStreamsPerRU: 2
       PowerBoostFactorPerRU: 1
                   RUNumbers: 1
                  RUAssigned: 1

일단 위에거 부터 보자.

242-tones가 20MHz 정도 된다. 근데 RUSize가 3984라는 뜻은, 242*16을 해서 20MHz*16 = 320MHz 사이즈의 RU 큰 덩어리라는 의미이다. 실제로 우리가 파라미터에 

bandwidth = 320;

를 하였기 때문에 해당 결과가 나왔다.

그리고, 이 RU 큰 덩어리 하나에 유저 2명이 사용하게 된다. 즉 빔포밍을 이용하여 해당 RU덩어리를 두 명의 유저가 나눠쓴다라는 의미이다.

그 밑에 것을 봐보자.

이번에도 역시나 NumRUs는 1개다. 근데, 여기에 인덱스는 1 4 3 4 가 있고, 사이즈는 996 484 996 996이 있다.

996-tone(약 80MHz) RU 세 개와 484-tone(약 40MHz) RU 한 개를 결합하여 하나의 MRU를 구성한 형태이다. 즉 여러 개의 서로 다른 RU를 하나의 사용자 또는 사용자 그룹이 동시에 사용할 수 있도록 묶어놓은 구조라고 볼 수 있다. MATLAB에서는 이러한 RU 집합을 하나의 MRU로 취급하기 때문에 NumRUs 값은 1로 표시된다.

다만 최종적으로 왜 하필 [1 4 3 4]가 선택됐는지 는 설정한 Puncturing 패턴을 봐야 알 수 있다.

996-tones(약 80MHz)로 4등분이 되었다.

여기서 #1, #3, #4번은 그대로 사용이 가능하다. 왜냐하면 간섭이 없기 때문이다.

그러나 #2번에서 간섭이 존재하므로, 해당 부분은 RU로 사용할 수 없다.

그래서 해당 부분을 다시 484-tone로 쪼갠다.

이렇게 쪼갰을 때 #1번과 #2번은 996로 통합되어서 #1번으로 사용하기 때문에, 신경 써도 된다.

484-tones #4를 이제 간섭이 없기때문에 사용이 가능하다.

[1 4 3 4] 인덱스로 나타나는 이유가 바로 이것이다.

즉, 996-tone RU 기준으로는 1번, 3번, 4번 위치를 사용하고, 간섭이 포함된 2번 996-tone RU 영역에서는 전체 80MHz를 버리는 대신 그 안에서 사용 가능한 484-tone RU 4번 위치만 선택하여 하나의 MRU로 묶은 것이다.

결과적으로 이 구성은 320MHz 전체를 하나의 3984-tone RU로 사용하는 것이 아니라, 간섭이 있는 일부 구간을 제외하고 사용 가능한 RU들만 묶어 하나의 MRU를 구성한 형태라고 볼 수 있다.

여기서 의문이 존재할 수 있다.

뒤쪽 996-tones#3과 996-tones#4는 한 번에 이어붙여서 약 160MHz를 통째로 다루게 1992-tones#2로 이용해도 될텐데, 왜 996tones로 나뉘었을까?

표준문서 802.11be 에서 36.3.2.2.3.1 섹션에 가면, 가능한 조합이 나온다.

1992라는 표현보다는 

996을 합쳐서 사용한다.

그리고 Table 9033d-ELA Control Subfileds에서 PS160 칸에서

다음과 같은 내용이 나온다. MAC 제어 프레임 비트제한과 시그널링 한계 때문에, 제한된 비트수 때문에 996으로 이용한다.

정리하면

연속된 160MHz 대역을 1992로 부르지 않고 996 + 996으로 풀어서 표시하는 이유는,  PHY 계층에서 대형 MRU 구조를 80MHz 기반 모듈 단위로 규격화했기 때문이며, MAC 계층의 PS160 서브필드를 확장 인덱스로 활용하여 제한된 제어 비트 안에 복잡한 주파수 할당 정보를 효율적으로 우겨넣기 위한(Signaling 효율성) 표준 기구의 하드웨어적 약속 때문이다.

좀 길이 많이 샜는데...(이거 waveform 만들기였다) 유저를 등록 하고, 이제 RU가 실제 주파수에서 어떻게 할당되었는지 확인해보자.

cfg.User{1}.NumSpaceTimeStreams = 4;
cfg.User{1}.APEPLength = payloadLength;
cfg.User{1}.MCS = 12;

cfg.User{2}.NumSpaceTimeStreams = 4;
cfg.User{2}.APEPLength = payloadLength;
cfg.User{2}.MCS = 13;

%% 전체 할당 그래프 보기
showAllocation(cfg);

여기서 각 파라미터는 사용자별 전송 설정을 의미한다.

  • NumSpaceTimeStreams : 사용자에게 할당되는 Spatial Stream의 개수
  • MCS : Modulation and Coding Scheme으로 변조 방식 및 코딩률을 결정
  • APEPLength : 전송할 데이터의 크기(Byte)

APEP(Aggregated MAC Protocol Data Unit End Payload)는 PHY 계층에서 실제로 전송할 사용자 데이터 길이를 의미하며, 이 값이 커질수록 생성되는 PPDU(Packet)의 길이도 길어진다.[단위는 바이트]

그리고 실행해보면

이렇게 나온다.

왼쪽에 서브캐리어 인덱스는 320MHz대역은 약 3984개의 서브캐리어(tone)이 존재해서 나온 것이다.

큰 네모 노란색 2개를 합친 게 하나의 996 사이즈인 셈이고, 작은 거 2개 합치면 484가 된다.

이거 하나가 Ru#1인 셈이다.

User # 1-2는 이 하나의 MRU에 유저 2명이 같이 사용하기 때문이다.

만약에 puncturing이 되어있지 않으면

이렇게 출력된다.

이제 각 할당되는 정보는 알았으니, 실제 wave폼을 만들어보자.

%% 웨이브폼 생성
psduLen = psduLength(cfg);
psdu = cell(1,allocInfo.NumUsers);
for i = 1:allocInfo.NumUsers
    psdu{i} = randi([0 1],psduLen(i)*8,1,'int8');
end


tx = wlanWaveformGenerator(psdu, cfg, NumPackets=numPackets, OversamplingFactor=osf);
fs = wlanSampleRate(cfg) * osf;

fig = plotSpectrumAndSpectrogram(tx, cfg, osf, "3x996+484-tone MRU with punctured 40 MHz subchannel in 320 MHz channel");


function fig = plotSpectrumAndSpectrogram(tx, cfg, osf, titleText)

    if nargin < 4
        titleText = "EHT Waveform Spectrum and Spectrogram";
    end

    %% tx shape 보정
    if isvector(tx)
        tx = tx(:);
    end

    %% 기본 정보
    fs = wlanSampleRate(cfg) * osf;
    [numSamples, numChannels] = size(tx);

    %% Spectrogram / PSD 파라미터
    winLen = min(4096, numSamples);
    win = hamming(winLen, "periodic");

    noverlap = floor(0.75 * winLen);

    % 높은 frequency resolution
    nfft = 65536;

    %% 채널 색상
    colors = [
        0.0000    0.4470    0.7410
        0.8500    0.3250    0.0980
        0.9290    0.6940    0.1250
        0.4940    0.1840    0.5560
        0.4660    0.6740    0.1880
        0.3010    0.7450    0.9330
        0.6350    0.0780    0.1840
        0.0000    0.4470    0.7410
    ];

    %% Figure 생성
    fig = figure( ...
        "Name", titleText, ...
        "Color", "w", ...
        "Position", [100 80 1300 750]);


    % PSD
    ax1 = subplot(2,1,1);

    hold(ax1, "on");

    set(ax1, ...
        "Color", "w", ...
        "XColor", "k", ...
        "YColor", "k", ...
        "GridColor", [0.75 0.75 0.75], ...
        "MinorGridColor", [0.85 0.85 0.85], ...
        "GridAlpha", 0.7, ...
        "Box", "on");

    for ch = 1:numChannels

        [pxx, f] = pwelch( ...
            tx(:,ch), ...
            win, ...
            noverlap, ...
            nfft, ...
            fs, ...
            "centered");

        plot( ...
            ax1, ...
            f/1e6, ...
            10*log10(pxx + eps), ...
            "LineWidth", 1.0, ...
            "Color", colors(ch,:), ...
            "DisplayName", "Channel " + ch);
    end

    title(ax1, ...
        titleText, ...
        "FontWeight", "bold", ...
        "Color", "k", ...
        "Interpreter", "none");

    xlabel(ax1, "Frequency (MHz)", ...
        "Color", "k");

    ylabel(ax1, "Power/Frequency (dB/Hz)", ...
        "Color", "k");

    xlim(ax1, [-fs/2 fs/2]/1e6);

    grid(ax1, "on");

    lgd = legend(ax1, ...
        "show", ...
        "Location", "northoutside", ...
        "Orientation", "horizontal");

    set(lgd, ...
        "Color", "w", ...
        "TextColor", "k");

    hold(ax1, "off");

    % Spectrogram
    ax2 = subplot(2,1,2);

    set(ax2, ...
        "Color", "w", ...
        "XColor", "k", ...
        "YColor", "k", ...
        "GridColor", [0.8 0.8 0.8], ...
        "GridAlpha", 0.5, ...
        "Box", "on");

    % 채널별 spectrogram power 합산
    totalPower = [];

    for ch = 1:numChannels

        [s, fSpec, tSpec] = spectrogram( ...
            tx(:,ch), ...
            win, ...
            noverlap, ...
            nfft, ...
            fs, ...
            "centered");

        p = abs(s).^2;

        if isempty(totalPower)
            totalPower = p;
        else
            totalPower = totalPower + p;
        end
    end

    %% dB 변환
    specDb = 10*log10(totalPower + eps);

    %% 핵심
    % spectrogram output:
    % rows = frequency
    % cols = time
    %
    % imagesc(x=freq, y=time)이므로 transpose 필요
    imagesc( ...
        fSpec/1e6, ...
        tSpec, ...
        specDb.');

    axis(ax2, "xy");

    %% colormap
    colormap(ax2, turbo);

    cb = colorbar(ax2);

    cb.Color = "k";

    ylabel(cb, "dB", ...
        "Color", "k");

    %% dynamic range
    maxVal = max(specDb(:));

    clim(ax2, [maxVal-80 maxVal]);

    %% labels
    xlabel(ax2, ...
        "Frequency (MHz)", ...
        "Color", "k");

    ylabel(ax2, ...
        "Time (s)", ...
        "Color", "k");

    title(ax2, ...
        "Spectrogram", ...
        "FontWeight", "bold", ...
        "Color", "k");

    %% 축 범위
    xlim(ax2, [-fs/2 fs/2]/1e6);

    grid(ax2, "on");

end

펑쳐링이 없으면

이렇게 나오고

펑처링을 하면

둘이 차의가 느껴지는가???
아래 그림은 40MHz Subchannel Puncturing을 적용한 결과이다. PSD(Power Spectral Density)를 보면 약 -80MHz ~ -40MHz 구간의 전력이 크게 감소하여 해당 주파수 자원이 사용되지 않음을 확인할 수 있다. 또한 스펙트로그램에서도 동일한 구간이 파란색으로 나타나는데, 이는 해당 주파수 영역에 에너지가 존재하지 않음을 의미한다. 즉, 간섭이 발생한 40MHz 구간만 제외하고 나머지 주파수 자원은 계속 사용하고 있는 Wi-Fi 7 Puncturing의 특성을 확인할 수 있다.

OFDMA에서 Wave 만들기


이번에는 OFDMA를 만들자. 똑같이 config할 때, 이번에는 숫자를 입력한다.

%% 통합 CFG 생성
% cfg = wlanEHTMUConfig(cbw, "NumUsers", numUsers);
cfg = wlanEHTMUConfig(47);
cfg.NumTransmitAntennas = numTx;
cfg.GuardInterval = guardInterval;
cfg.EHTLTFType = EHTLTFType;



% 할당 정보 확인
allocInfo = ruInfo(cfg);
disp('Allocation info:')
disp(allocInfo)

여기서

cfg = wlanEHTMUConfig(47);

이 47번은 표준 문서를 봐야하는데, 802.11be Table 36-34 : RU Allocation subfield에 나와있다.

47번의 경우 106+26, 52, 52인데, 무슨 의미냐면

주파수 쪼개기 구조: 20MHz 대역 하나를 [52-tone RU] + [106+26-tone MRU] + [52-tone RU] 형태로 쪼갠다.

사용자 수 (Number of Users): 각각의 RU/MRU 마다 정확히 1명(Single User)씩 할당한다. (Total Users = 3명)

라는 의미이다.

여기서 한 가지 흥미로운 점은 106+26-tone MRU 이다.

“그냥 132-tone RU를 하나 만들면 되는 것 아닌가?” 라는 의문이 생길 수 있다.

하지만 IEEE 802.11ax와 IEEE 802.11be 표준에서 독립적인 RU 크기로 정의된 것은 다음과 같다.

  • 26-tone RU
  • 52-tone RU
  • 106-tone RU
  • 242-tone RU

즉, 132-tone RU 라는 규격 자체는 존재하지 않는다.

대신 Wi-Fi는 여러 개의 RU를 하나의 사용자에게 동시에 할당할 수 있는 MRU(Multi Resource Unit) 기능을 제공한다.

를 구성한다.

즉, 106+26-tone MRU는 새로운 크기의 RU가 아니라, 두 개의 표준 RU를 하나의 사용자에게 묶어서 할당한 형태라고 이해하면 된다.

MRU는 새로운 주파수 블록을 만드는 기술이 아니라, 이미 존재하는 여러 RU를 하나의 사용자에게 동시에 할당하기 위한 기술이라고 볼 수 있다

아무튼, 47 하나만 하면 20MHZ를 분할하는 방식이기에, 320을 나누기 위해서는

cfg = wlanEHTMUConfig([47 47 47 47 47 47 47 47 47 47 47 47 47 47 47 47]);

이렇게 사용하면 된다.

일단 지금은 47을 하나만 넣는다라고 가정하고 실행을 누르면

showAllocation(cfg);

위 그림과

Allocation info:
                    NumUsers: 3
                      NumRUs: 3
                   RUIndices: {[1 5]  [3]  [4]}
                     RUSizes: {[106 26]  [52]  [52]}
               NumUsersPerRU: [1 1 1]
    NumSpaceTimeStreamsPerRU: [1 1 1]
       PowerBoostFactorPerRU: [1 1 1]
                   RUNumbers: [1 2 3]
                  RUAssigned: [1 1 1]

이 결과값이 나온다.

이 47에 9비트 자원 할당 인덱스에서는 주파수 쪼개기 모양뿐만 아니라, 각 자원에 몇 명의 유저가 들어가야하는지 까지 강제(고정)되어 있다.

47번 인덱스의 하드웨어 약속: 20MHz 대역을 [52] + [106+26] + [52] 자원으로 쪼갠다.

MATLAB의 wlanEHTMUConfig(47) 함수는 해당 OFDMA 구조를 생성하면서 각 RU(MRU)에 대응되는 사용자 객체도 함께 생성한다.

따라서 별도로 사용자 수를 지정하지 않아도

cfg = wlanEHTMUConfig(47);

만으로 총 3명의 사용자가 자동 생성된다. 따로 변수 설정을 안 해줘도 된다.

  • User #1 → 52-tone RU
  • User #2 → 106+26-tone MRU
  • User #3 → 52-tone RU

와 같은 구조가 자동으로 구성된다.

실제로 allocationInfo(cfg) 결과를 확인하면 NumUsers = 3으로 표시되는 것을 확인할 수 있다.

그 다음 User 설정을 등록해보자.

cfg.RU{1}.SpatialMapping = "Fourier";
cfg.User{1}.NumSpaceTimeStreams = 1;
cfg.User{1}.APEPLength = 5000;
cfg.User{1}.MCS = 4;
cfg.User{1}.ChannelCoding = "LDPC";

cfg.RU{2}.SpatialMapping = "Fourier";
cfg.User{2}.NumSpaceTimeStreams = 1;
cfg.User{2}.APEPLength = 1;
cfg.User{2}.MCS = 9;
cfg.User{2}.ChannelCoding = "LDPC";

cfg.RU{3}.SpatialMapping = "Fourier";
cfg.User{3}.NumSpaceTimeStreams = 1;
cfg.User{3}.APEPLength = 1;
cfg.User{3}.MCS = 12;
cfg.User{3}.ChannelCoding = "LDPC";

SpatialMapping 설정할 떄 Direct와 Fourier를 설정하는 것을 확인할 수 있다.

Direct는 가장 직관적으로

NumTransmitAntennas = 4
NumSpaceTimeStreams = 4

가 있다라고 한다면, 

위와같이 행렬이 정렬된다.

  • Stream1 -> 안테나 1
  • Stream2 -> 안테나 2
  • Stream3 -> 안테나 3
  • Stream4 -> 안테나 4

이 되는 셈이다.

즉, 스트림 수 = 안테나 수가 강제가 되는 것.

반면에 Fourier는 DFT Matrix기반 매핑이다.

Stream하나가 여러 안테나에 분산되는 방식인데, 내가 보낼려고 하는 메시지가 

0.1a + 0.2b + 0.3c + 0.4d 해서 1을 4개의 안테나에 나눠서 보내는 방식인 셈이다.

조금 OFDMA가 어떻게 그래프상에서 표현되는지 확인해보자.

RU1 (106+26 MRU)

≈ -9.5 MHz ~ +1.25 MHz

RU2 (52)

≈ +1.33 MHz ~ +5.31 MHz

RU3 (52)

≈ +5.47 MHz ~ +9.45 MHz

를 쓰고 있단 건 아까 위 그래프로 확인하였었다.

OFDMA에서는 사용자마다 서로 다른 RU를 할당받지만, 하나의 MU PPDU 안에서 전송되기 때문에 전체 패킷의 시간 길이는 사용자별로 따로 끝나지 않는다. 특정 사용자의 데이터 길이가 짧더라도, 가장 긴 사용자 또는 전체 PPDU 구조에 맞추기 위해 padding이 삽입될 수 있다. 따라서 스펙트로그램에서는 데이터가 적은 사용자의 RU도 패킷이 끝날 때까지 에너지가 존재하는 것처럼 보일 수 있다.

그래서 아무리 출력을 해도

구분이 되지는 않았다.

안테나1

= User1 신호

+ User2 신호

+ User3 신호

안테나2

= User1 신호

+ User2 신호

+ User3 신호

안테나3

= User1 신호

+ User2 신호

+ User3 신호

이기 때문에 셋다 합쳐져 보인다.

스펙트로그램에서 시간축 방향으로 나타나는 세로 패턴의 변화는 RU 할당 변화가 아니라 OFDM 심볼마다 서로 다른 데이터가 매핑되기 때문으로 해석할 수 있다. 즉, 사용되는 주파수 대역(RU)은 유지되지만 각 OFDM 심볼에서 서브캐리어에 매핑되는 QAM 심볼의 진폭과 위상이 계속 변하면서 시간에 따라 서로 다른 에너지 분포가 나타난다.

따라서 스펙트로그램에서 관찰되는 세로 줄무늬의 변화는 RU 재할당이 아니라, 동일한 RU 내에서 전송되는 데이터 심볼 조합이 시간에 따라 변화하는 OFDM/OFDMA의 특성으로 이해할 수 있다.

다른 식으로는 이렇게도 그려지기도 한다.

Large MRU, 즉, MRU가 너무 커지면 EHT-SIG로 사용자 정보를 어떻게 전달해야할까에 대한 정보도 나온다.

AP는 사용자들에게 각각

  • 어떤 RU를 써라
  • 어떤 MCS를 써라
  • NSS 몇개 써라
  • 등을 각각 전달해줘야하는데, 그 정보가 들어있는 필드가 EHT-SIG이다.

공식 예제에서 든 설명은

  • A large 996+484-tone MRU (RU #1) with eight users (user #1-8)
  • A 242-tone RU (RU #2) with one user (user #9)
  • A 242-tone RU (RU #3) with one user (user #10)

전체 160중에 120까지에는 1~8번 유저가 있고, 20에는 9번, 또 20크기의 10번 유저가 존재하고 있다.

그리고 각각에 총 10명의 유저에게 EHT-SIG가 설명해야한다.

여러가지 조합법이 있을 수 있다.
https://kr.mathworks.com/help/wlan/ug/802-11be-waveform-generation.html

여기서 조합C를 이용해서 코드를 짜면

cfgLMRU = wlanEHTMUConfig([145 145 145 145 64 64 29 29]); % 1 MRU (996+484) with 8 users and two 242-tone RUs with one user each
cfgLMRU.NumTransmitAntennas = 8;

userSTS = [1 1 1 1 1 1 1 1 8 8]; % Number of space time streams per user
allocInfo = ruInfo(cfgLMRU); % Get details of the RU/MRU in the configuration
for u=1:allocInfo.NumUsers
    cfgLMRU.User{u}.NumSpaceTimeStreams = userSTS(u);
    cfgLMRU.User{u}.MCS = 12;
    cfgLMRU.User{u}.APEPLength = randi([100 500],1,1);
end

tx = wlanWaveformGenerator([1 0 1 0],cfgLMRU);

showAllocation(cfgLMRU)

하면

이렇게, 유저 1~8이 사용될 RU1(약 120), 9, 10 각각 20씩 차지하게 된다.

여기서

펑쳐링 코드까지 해서 출력해보면\

cfgPuncture = wlanEHTMUConfig([64 26 64 64 64 26 26 64]);
for u=1:numel(cfgPuncture.User)
    cfgPuncture.User{u}.APEPLength = 1000;
end

osf = 1.5;
txPuncture = wlanWaveformGenerator([1 0 1 0],cfgPuncture,'OversamplingFactor',osf);

sa = plotSpectrumAndSpectrogram(txPuncture,cfgPuncture,osf,'160 MHz EHT MU Transmission with Punctured 20 MHz Channels');


function fig = plotSpectrumAndSpectrogram(tx, cfg, osf, titleText)

    if nargin < 4
        titleText = "EHT Waveform Spectrum and Spectrogram";
    end

    %% tx shape 보정
    if isvector(tx)
        tx = tx(:);
    end

    %% 기본 정보
    fs = wlanSampleRate(cfg) * osf;
    [numSamples, numChannels] = size(tx);

    %% Spectrogram / PSD 파라미터
    winLen = min(4096, numSamples);
    win = hamming(winLen, "periodic");

    noverlap = floor(0.75 * winLen);

    % 높은 frequency resolution
    nfft = 65536;

    %% 채널 색상
    colors = [
        0.0000    0.4470    0.7410
        0.8500    0.3250    0.0980
        0.9290    0.6940    0.1250
        0.4940    0.1840    0.5560
        0.4660    0.6740    0.1880
        0.3010    0.7450    0.9330
        0.6350    0.0780    0.1840
        0.0000    0.4470    0.7410
    ];

    %% Figure 생성
    fig = figure( ...
        "Name", titleText, ...
        "Color", "w", ...
        "Position", [100 80 1300 750]);


    % PSD
    ax1 = subplot(2,1,1);

    hold(ax1, "on");

    set(ax1, ...
        "Color", "w", ...
        "XColor", "k", ...
        "YColor", "k", ...
        "GridColor", [0.75 0.75 0.75], ...
        "MinorGridColor", [0.85 0.85 0.85], ...
        "GridAlpha", 0.7, ...
        "Box", "on");

    for ch = 1:numChannels

        [pxx, f] = pwelch( ...
            tx(:,ch), ...
            win, ...
            noverlap, ...
            nfft, ...
            fs, ...
            "centered");

        plot( ...
            ax1, ...
            f/1e6, ...
            10*log10(pxx + eps), ...
            "LineWidth", 1.0, ...
            "Color", colors(ch,:), ...
            "DisplayName", "Channel " + ch);
    end

    title(ax1, ...
        titleText, ...
        "FontWeight", "bold", ...
        "Color", "k", ...
        "Interpreter", "none");

    xlabel(ax1, "Frequency (MHz)", ...
        "Color", "k");

    ylabel(ax1, "Power/Frequency (dB/Hz)", ...
        "Color", "k");

    xlim(ax1, [-fs/2 fs/2]/1e6);

    grid(ax1, "on");

    lgd = legend(ax1, ...
        "show", ...
        "Location", "northoutside", ...
        "Orientation", "horizontal");

    set(lgd, ...
        "Color", "w", ...
        "TextColor", "k");

    hold(ax1, "off");

    % Spectrogram
    ax2 = subplot(2,1,2);

    set(ax2, ...
        "Color", "w", ...
        "XColor", "k", ...
        "YColor", "k", ...
        "GridColor", [0.8 0.8 0.8], ...
        "GridAlpha", 0.5, ...
        "Box", "on");

    % 채널별 spectrogram power 합산
    totalPower = [];

    for ch = 1:numChannels

        [s, fSpec, tSpec] = spectrogram( ...
            tx(:,ch), ...
            win, ...
            noverlap, ...
            nfft, ...
            fs, ...
            "centered");

        p = abs(s).^2;

        if isempty(totalPower)
            totalPower = p;
        else
            totalPower = totalPower + p;
        end
    end

    %% dB 변환
    specDb = 10*log10(totalPower + eps);

    %% 핵심
    % spectrogram output:
    % rows = frequency
    % cols = time
    %
    % imagesc(x=freq, y=time)이므로 transpose 필요
    imagesc( ...
        fSpec/1e6, ...
        tSpec, ...
        specDb.');

    axis(ax2, "xy");

    %% colormap
    colormap(ax2, turbo);

    cb = colorbar(ax2);

    cb.Color = "k";

    ylabel(cb, "dB", ...
        "Color", "k");

    %% dynamic range
    maxVal = max(specDb(:));

    clim(ax2, [maxVal-80 maxVal]);

    %% labels
    xlabel(ax2, ...
        "Frequency (MHz)", ...
        "Color", "k");

    ylabel(ax2, ...
        "Time (s)", ...
        "Color", "k");

    title(ax2, ...
        "Spectrogram", ...
        "FontWeight", "bold", ...
        "Color", "k");

    %% 축 범위
    xlim(ax2, [-fs/2 fs/2]/1e6);

    grid(ax2, "on");

end

이렇게 나온다.

에필로그


양이 너무 많아서 다시 정리해서 나중에 따로 올리겠다.

참고자료


  • DEMBELE, Hamidou; CHOU, Sih-Yu. Physical layer implementation analysis of ieee 802.11 be preamble puncturing in su transmission. 2024.
  • https://kr.mathworks.com/help/wlan/ug/802-11be-waveform-generation.html

댓글 0

내 생각을 남겨주세요

로그인 후 글 작성합니다

로그인하기

아직 댓글이 없습니다.