メインコンテンツ

チャネル状態情報フィードバックを使用した NR PDSCH のスループット

この参照シミュレーションでは、5G new radio (NR) リンクの物理ダウンリンク共有チャネル (PDSCH) のスループットを測定します。シミュレーションでは、チャネル状態情報 (CSI) フィードバックを使用して、ダウンリンク共有チャネル (DL-SCH) および PDSCH 送信パラメーター (ターゲット符号化率、変調、レイヤー数、および多入力多出力 (MIMO) プリコーディング行列) を調整します。

はじめに

以下の図は、この参照シミュレーションにおける PDSCH スループット推定の手順を示しています。送信機 (gNodeB) には、トランスポート チャネル符号化のステージ (DL-SCH) と PDSCH の生成が含まれます。送信パラメーターは、受信機 (UE) によって実行され、送信機にフィードバックされる CSI 測定に基づきます。このメカニズムの目的は、送信パラメーターをチャネル条件に適応させることです。シミュレーションでは、CSI フィードバック遅延も制御します。人工知能に基づく CSI 圧縮手法を利用できる 5G NR シミュレーションについては、Test AI-based CSI Compression Techniques for Enhanced PDSCH Throughputの例を参照してください。

Block diagram of the PDSCH throughput simulation that uses CSI feedback

このシミュレーションは、NR PDSCH スループットの例に基づいていますが、受信機からの CSI フィードバックを使用して送信パラメーターを調整する部分が追加されています。

5G NR における CSI フィードバックとリンク適応

ユーザー端末 (UE) は、チャネル状態情報基準信号 (CSI-RS) を使用してダウンリンク チャネル応答を推定し、一連の CSI 指標を報告します。CSI レポートには、TS 38.214 の Section 5.2.2 で定義されている次の指標が含まれます。

  • ランク指標 (RI)

  • プリコーディング行列指標 (PMI)

  • チャネル品質指標 (CQI)

gNodeB は報告された CSI を使用し、構成可能な遅延の後に続く PDSCH 送信で、ターゲット符号化率、変調、レイヤー数、および MIMO プリコーディング行列を構成します。通常、gNodeB は UE が報告する送信パラメーターとは異なる送信パラメーターを選択できます。しかし、このシミュレーションでは、gNodeB は UE からの推奨に厳密に従います。UE が RI、PMI、および CQI を選択する方法の詳細については、5G NR ダウンリンク CSI レポートの例を参照してください。

シミュレーションでは、次の条件を想定しています。

  • アップリンク送信なし。CSI フィードバックは、UE から gNodeB にエラーなく送信される。

  • シミュレーションの長さに対する PDSCH PRB の割り当ては固定。割り当てをチャネル条件に適応させるスケジューラは存在しない。

  • FDD 処理。

  • HARQ サポートなし。

シミュレーションの長さと SNR 点

シミュレーションの長さを 10 ms のフレームの数で設定します。統計的に有意なスループットの結果を生成するには、フレーム数 (NFrames) を大きな数に更新しなければなりません。シミュレーションする S/N 比 (SNR) の点を設定します。各レイヤーの SNR はリソース エレメント (RE) ごとに定義され、すべてのアンテナにおける信号とノイズの影響が含まれます。この例で使用している SNR 定義の説明については、リンク シミュレーションで使用する SNR の定義の例を参照してください。

simParameters = struct();       % Clear simParameters variable to contain all key simulation parameters 
simParameters.NFrames = 2;      % Number of 10 ms frames
simParameters.SNRIn = [-10 10]; % SNR range (dB)

チャネル推定器の構成

logical 変数 PerfectChannelEstimator は、チャネル推定と同期の動作を制御します。この変数を true に設定すると、シミュレーションでは完全なチャネル推定と同期が使用されます。この変数を false に設定すると、シミュレーションでは受信した PDSCH 復調基準信号 (DM-RS) の値に基づいて実用的なチャネル推定と同期が使用されます。

simParameters.PerfectChannelEstimator = true;

シミュレーション診断

変数 DisplaySimulationInformation は、シミュレーション情報の表示を制御します。

simParameters.DisplaySimulationInformation = true;

DisplayDiagnostics フラグを使用すると、レイヤーごとにエラー ベクトル振幅 (EVM) をプロットできるようになります。このプロットは、イコライズ後の受信信号の品質を監視します。レイヤーごとの EVM の Figure は以下を表示します。

  • スロット単位でのレイヤーごとの EVM。これは時間とともに変化する EVM を表示します。

  • リソース ブロック単位でのレイヤーごとの EVM。これは EVM の周波数を示します。

この Figure はシミュレーションとともに変化し、スロットごとに更新されます。通常、低い SNR またはチャネル フェージングは、信号品質の低下 (高 EVM) につながる可能性があります。チャネルは各レイヤーに異なる影響を与えます。したがって、EVM 値はレイヤーごとに異なる場合があります。

simParameters.DisplayDiagnostics = false;

キャリアと PDSCH の構成

波形タイプ、PDSCH numerology (サブキャリア間隔 (SCS) およびサイクリック プレフィックス (CP) タイプ)、およびその他の送信構成パラメーターを設定します。

% SCS carrier parameters
simParameters.Carrier = nrCarrierConfig;         % Carrier resource grid configuration
simParameters.Carrier.NSizeGrid = 52;            % Bandwidth in number of resource blocks
simParameters.Carrier.SubcarrierSpacing = 15;    % 15, 30, 60, 120 (kHz)
simParameters.Carrier.CyclicPrefix = 'Normal';   % 'Normal' or 'Extended' (Extended CP is relevant for 60 kHz SCS only)
simParameters.Carrier.NCellID = 1;               % Cell identity

全帯域スロット単位の PDSCH 送信を指定し、最初の 2 つの OFDM シンボルを予約します。

simParameters.PDSCH = nrPDSCHConfig;      % This PDSCH definition is the basis for all PDSCH transmissions in the simulation

% Define PDSCH time allocation in a slot
simParameters.PDSCH.MappingType = "A"; % PDSCH mapping type ("A" (slot-wise), "B" (nonslot-wise))
symAlloc = [2 simParameters.Carrier.SymbolsPerSlot-2];  % Starting symbol and number of symbols of each PDSCH allocation
simParameters.PDSCH.SymbolAllocation = symAlloc;

% Define PDSCH frequency resource allocation per slot to be full grid 
simParameters.PDSCH.PRBSet = 0:simParameters.Carrier.NSizeGrid-1;

% Scrambling identifiers
simParameters.PDSCH.NID = simParameters.Carrier.NCellID;
simParameters.PDSCH.RNTI = 1;

TS 38.211 の Section 7.4.1.1 で定義されている DM-RS 構成を指定します。この例では、CSI フィードバック (RI) と DM-RS 構成に基づいて DM-RS ポート セットを動的に設定します。有効な DM-RS ポート セット構成の詳細については、DMRSPortSetオブジェクトのプロパティまたは TS 38.211 の Table 7.4.1.1.2-5 を参照してください。

simParameters.PDSCH.DMRS.DMRSTypeAPosition       = 2; % Mapping type A only. First DM-RS symbol position (2, 3)
simParameters.PDSCH.DMRS.DMRSLength              = 2; % Number of front-loaded DM-RS symbols (1 (single symbol), 2 (double symbol))
simParameters.PDSCH.DMRS.DMRSAdditionalPosition  = 1; % Additional DM-RS symbol positions (max range 0...3)
simParameters.PDSCH.DMRS.DMRSConfigurationType   = 2; % DM-RS configuration type (1, 2)
simParameters.PDSCH.DMRS.NumCDMGroupsWithoutData = 3; % CDM groups without data (1, 2, 3)

DL-SCH および PDSCH の追加のシミュレーション パラメーターを指定します。TS 38.214 の Section 5.1.2.3 で定義されている MIMO プリコーダーの周波数粒度、TS 38.214 の Section 5.1.3.1 で定義されている変調および符号化スキーム テーブル、およびトランスポート ブロックのサイズ計算のオーバーヘッドを設定します。CSI-RS に割り当てられた RE に基づいて自動的に選択させるには、XOverhead を空 ([]) に設定します。この例では、CSI-RS 送信が行われるスロットに適した XOverhead の値が選択されます。

simParameters.PDSCHExtension = struct();
simParameters.PDSCHExtension.PRGBundleSize = 4; % 2, 4, or [] to signify "wideband"
simParameters.PDSCHExtension.MCSTable      = 'Table1'; % 'Table1', ..., 'Table4'
simParameters.PDSCHExtension.XOverhead     = [ ]; % 0, 6, 12, 18, or [] for automatic selection.

LDPC 復号化のアルゴリズムと LDPC の最大反復回数を構成します。使用可能な復号化アルゴリズムは、'Belief propagation'、'Layered belief propagation'、'Normalized min-sum'、および 'Offset min-sum' です。

simParameters.PDSCHExtension.LDPCDecodingAlgorithm = "Normalized min-sum";
simParameters.PDSCHExtension.MaximumLDPCIterationCount = 6;

アンテナ パネルの構成

アンテナ パネルの数 (Ng) とその次元 (N1N2) を指定して、アンテナ パネルの形状を構成します。N1N2 は、それぞれ各パネルの水平方向と垂直方向の交差偏波アンテナ素子の数であり、Ng は列アレイ パネルの数です。次の図は、アンテナ パネルの配置とその次元を示しています。

Diagram of multipanel antenna arrangement

TS 38.214 の Section 5.2.2.2 で定義されている MIMO プリコーディング コードブックは、5G NR がサポートする NgN1、および N2 の値を制限します。単偏波アンテナ素子を使用して単入力単出力 (SISO) 送信を構成するには、パネルの次元を [1 1] に設定し、偏波の数を 1 に設定します。受信機パネルの次元はコードブックによって制限されません。

simParameters.TransmitAntennaArray.NumPanels        = 1; % Number of transmit panels in horizontal dimension (Ng)
simParameters.TransmitAntennaArray.PanelDimensions  = [2 2]; % Number of columns and rows in the transmit panel (N1, N2)
simParameters.TransmitAntennaArray.NumPolarizations = 2; % Number of transmit polarizations
simParameters.ReceiveAntennaArray.NumPanels         = 1; % Number of receive panels in horizontal dimension (Ng)
simParameters.ReceiveAntennaArray.PanelDimensions   = [2 1];                % Number of columns and rows in the receive panel (N1, N2)
simParameters.ReceiveAntennaArray.NumPolarizations  = 2; % Number of receive polarizations

複数の素子をもつ送信アンテナ アレイが 2 つの異なる偏波で構成されていることを確認します。

simParameters.TransmitAntennaArray = validateAntennaPolarization(simParameters.TransmitAntennaArray);

アンテナの総数は Np×N1×N2×Ng です。ここで、Np は偏波の数です。

simParameters.NTxAnts = numAntennaElements(simParameters.TransmitAntennaArray);
simParameters.NRxAnts = numAntennaElements(simParameters.ReceiveAntennaArray);

disp("Number of transmit antenna elements: " + simParameters.NTxAnts)
Number of transmit antenna elements: 8
disp("Number of receive antenna elements: " + simParameters.NRxAnts)
Number of receive antenna elements: 4

CSI-RS 構成

シミュレーションでは、送信パネルの各アンテナ素子にマッピングされる 8 ポートの CSI-RS が構成されます。CSI-RS ポートの数は、シングルパネルの場合は TS 38.214 の Table 5.2.2.2.1-2、マルチパネル コードブックの場合は Table 5.2.2.2.2-1 で定義されている送信アレイ パネルの次元と一致しなければなりません。次の表は、選択したアレイ パネルの次元と互換性がある CSI-RS 行番号を示しています。CSI-RS 行番号については、TS 38.211 の Table 7.4.1.5.3-1 で定義されています。

Tables that contain single panel and multipanel antenna dimensions

送信周期や周波数密度などの CSI-RS パラメーターを設定します。この例では、指定されたキャリア、PDSCH、および送信アンテナ パネルの構成に基づいて、CSI-RS の帯域幅、行番号、サブキャリア位置、およびシンボル位置が自動的に設定されます。これらのパラメーターは手動で指定することもできます。

simParameters.CSIRS = nrCSIRSConfig;
simParameters.CSIRS.CSIRSPeriod = [10 0];
simParameters.CSIRS.Density = "one";

% Set CSI-RS allocation parameters
simParameters.CSIRS.NumRB = simParameters.Carrier.NSizeGrid;
[rowNumber, subcarriers, symbols, density] = csirsAllocationParameters(simParameters);
simParameters.CSIRS.RowNumber = rowNumber;
simParameters.CSIRS.SubcarrierLocations = subcarriers;
simParameters.CSIRS.SymbolLocations = symbols;
simParameters.CSIRS.Density = density;

disp(['Number of CSI-RS ports: ' num2str(simParameters.CSIRS.NumCSIRSPorts) '.'])
Number of CSI-RS ports: 8.
csirsCDMLengths = getCSIRSCDMLengths(simParameters.CSIRS);

% Check that the number of CSI-RS ports and transmit antenna elements match
% and the consistency of multiple CSI-RS resources
validateCSIRSConfig(simParameters.Carrier,simParameters.CSIRS,simParameters.NTxAnts);

CSI のフィードバック構成

CSI フィードバック モードを、'RI-PMI-CQI'、または 'Perfect CSI' として指定します。どちらのモードでも、UE は CSI-RS を使用して完全なチャネル推定または実用的なチャネル推定を実行できます。

  • RI-PMI-CQI: UE は適切な RI、PMI、および CQI を定期的に選択して報告します。gNodeB は報告された CSI に従い、構成可能な遅延の後に続く PDSCH 送信で、ターゲット符号化率、変調、レイヤー数、および MIMO プリコーディング行列を構成します。

  • Perfect CSI: UE は定期的にチャネル推定値を gNodeB に報告します。gNodeB は、選択された MIMO プリコーダーに応じて、チャネル推定値の固有ベクトルから MIMO プリコーディング行列を、TS 38.214 の Table 5.1.3.1-1 から適切な変調および符号化スキーム (MCS) を選択します。その後、gNodeB は、構成可能な遅延の後に続く PDSCH 送信で、選択された構成を適用します。

simParameters.CSIReportMode = 'RI-PMI-CQI'; % 'RI-PMI-CQI', 'Perfect CSI'

CSI レポート構成を指定します。CSI レポート構成の詳細については、5G NR ダウンリンク CSI レポートの例を参照してください。

simParameters.CSIReportConfig = struct();
simParameters.CSIReportConfig.Period = [5 0];  % Periodicity and offset of the CSI report in slots
simParameters.CSIReportConfig.CQITable          = "Table1"; % 'Table1', 'Table2', 'Table3'
simParameters.CSIReportConfig.CQIMode           = 'Wideband'; % 'Wideband', 'Subband'
simParameters.CSIReportConfig.PMIMode           = 'Subband'; % 'Wideband', 'Subband'
simParameters.CSIReportConfig.CodebookType      = 'Type1SinglePanel'; % 'Type1SinglePanel', 'Type1MultiPanel', 'Type2', 'eType2'
simParameters.CSIReportConfig.SubbandSize       = 4; % Subband size in RB (4, 8, 16, 32)
simParameters.CSIReportConfig.CodebookMode      = 1; % 1, 2
simParameters.CSIReportConfig.RIRestriction     = [];                   % Empty for no rank restriction
simParameters.CSIReportConfig.NumberOfBeams     = 2; % 2, 3, 4. Only for Type II codebooks
simParameters.CSIReportConfig.PhaseAlphabetSize = 8; % 4, 8. Only for Type II codebooks
simParameters.CSIReportConfig.SubbandAmplitude  = true;                  % true, false. Only for Type II codebooks
simParameters.CSIReportConfig.ParameterCombination = 1;             % 1...8. Only for Enhanced Type II codebooks
simParameters.CSIReportConfig.NumberOfPMISubbandsPerCQISubband = 1; % 1, 2. Only for Enhanced Type II codebooks
simParameters.CSIReportConfig.NStartBWP         = [];                                  % Empty to signal the entire carrier
simParameters.CSIReportConfig.NSizeBWP          = [];                                  % Empty to signal the entire carrier

% Configure the CSI report with the antenna panel dimensions specified
simParameters.CSIReportConfig = updateCSIReportPanelInfo(simParameters.CSIReportConfig,simParameters.TransmitAntennaArray);

% Adjust the rank restriction based on the number of ports supported by
% the DM-RS configuration, as defined in TS 38.211 Table 7.4.1.1.2-5.
simParameters.CSIReportConfig.RIRestriction = updateRankRestriction(simParameters.PDSCH.DMRS,simParameters.CSIReportConfig);

スロット内の CSI 処理遅延を構成します。UE の場合、この遅延は CSI-RS の受信と CSI フィードバックの可用性との間のタイム スロット数です。gNodeB の場合、遅延は CSI レポートの受信と推奨 CSI を使用した送信との間のタイム スロット数です。

simParameters.UEProcessingDelay = 7;
simParameters.BSProcessingDelay = 1;

伝播チャネル構成

シミュレーションの伝播チャネルの遅延プロファイル、遅延スプレッド、および最大ドップラー シフトを構成します。CDL と TDL の両方のチャネル モデルをサポートしています。アンテナ パネルの構成で指定したパネル次元と交差偏波素子は、CDL チャネルのアンテナ アレイの形状を定義します。

simParameters.DelayProfile = 'CDL-C';   % 'CDL-A', ..., 'CDL-E', 'TDL-A', ..., 'TDL-E'
simParameters.DelaySpread = 300e-9;     % s
simParameters.MaximumDopplerShift = 5;  % Hz

simParameters.Channel = createChannel(simParameters);

処理ループ

各 SNR 点の PDSCH スループットを決定するために、シミュレーションでは次の手順を実行します。

  1. DL-SCH と PDSCH の送信パラメーター (ターゲット符号化率、レイヤー数、変調、および MIMO プリコーディング行列) を更新します。この手順は、新しい CSI レポートが利用可能な場合にのみ適用されます。

  2. CSI-RS 信号をリソース グリッドにマッピングします。

  3. チャネル符号化 (DL-SCH) と PDSCH 符号化を実行します。PDSCH および PDSCH DM-RS をリソース グリッドにマッピングします。

  4. 生成されたグリッドを OFDM 変調します。

  5. AWGN を使用するフェージング チャネルを通して信号を渡します。

  6. 同期と OFDM 復調を実行します。

  7. PDSCH DM-RS ベースのチャネル推定を実行します。

  8. イコライゼーションを実行します。

  9. PDSCH と DL-SCH を復号化し、PDSCH スループットを測定します。

  10. CSI-RS ベースのチャネル推定を実行します。

  11. CSI レポートを作成します。

  12. CSI レポートを適切な遅延とともに送信機にフィードバックします。

シミュレーションの合計時間を短縮するために、Parallel Computing Toolbox™ を使用して SNR ループを並列に実行できます。for ステートメントをコメントアウトし、parfor ステートメントのコメントを解除します。Parallel Computing Toolbox がインストールされていない場合、parfor は既定で通常の for ステートメントになります。parfor ループによる反復は非確定的な順序で並列に実行されるため、各 SNR 点に対応するシミュレーション情報が混在して表示される可能性があります。シミュレーション情報の表示をオフにするには、上記の displaySimulationInformation 変数を false に設定します。

% Array to store the maximum throughput for all SNR points
maxThroughput = zeros(length(simParameters.SNRIn),1); 
% Array to store the simulation throughput for all SNR points
simThroughput = zeros(length(simParameters.SNRIn),1);

% Cell array to store CSI reports per SNR point
CSIReport = {};

for snrIdx = 1:numel(simParameters.SNRIn)
% parfor snrIdx = 1:numel(simParameters.SNRIn)
% To reduce the total simulation time, you can execute this loop in
% parallel by using the Parallel Computing Toolbox. Comment out the 'for'
% statement and uncomment the 'parfor' statement.
    
    % Reset the random number generator for repeatability
    rng(0,"twister");

    % Display simulation information at this SNR point
    displaySNRPointProgress(simParameters,snrIdx);

    % Take full copies of the simulation-level parameter structures so that
    % they are not PCT broadcast variables when using parfor
    simParamLocal = simParameters;

    % Extract CSI feedback configuration parameters
    csiFeedbackOpts = getCSIFeedbackOptions(simParamLocal);

    % Set up the transmitter, propagation channel, and receiver
    [carrier,encodeDLSCH,pdsch,pdschextra,csirs,wtx] = setupTransmitter(simParamLocal);
    [channel,maxChDelay] = setupChannel(simParamLocal);
    [decodeDLSCH,timingOffset,N0,noiseEst,csiReports,csiSlots] = setupReceiver(simParamLocal,channel,snrIdx,csiFeedbackOpts);

    % Total number of slots in the simulation period
    NSlots = simParamLocal.NFrames * carrier.SlotsPerFrame;

    % Loop over the entire waveform length
    for nslot = 0:NSlots-1

        % Update the carrier slot numbers for new slot
        carrier.NSlot = nslot;

        % Use new CSI report to configure the number of layers and
        % modulation of the PDSCH and target code rate of the DL-SCH if
        % there is a new report available.
        [isNewReport,repIdx] = ismember(nslot,csiSlots);
        if isNewReport
            [pdsch.Modulation,pdschextra.TargetCodeRate,wtx] = hCSIDecode(carrier,pdsch,pdschextra,csiReports(repIdx),csiFeedbackOpts);
            pdsch.NumLayers = size(wtx,1);
            encodeDLSCH.TargetCodeRate = pdschextra.TargetCodeRate;
        end

        % Create an OFDM resource grid for a slot
        dlGrid = nrResourceGrid(carrier,csirs.NumCSIRSPorts);

        % CSI-RS mapping to the slot resource grid
        [csirsInd,csirsInfo] = nrCSIRSIndices(carrier,csirs);
        csirsSym = nrCSIRS(carrier,csirs);
        dlGrid(csirsInd) = csirsSym;
        csirsTransmission = ~isempty(csirsInd);

        % PDSCH reserved REs for CSI-RS
        pdsch.ReservedRE = csirsInd-1; % 0-based indices
        
        % PDSCH generation
        % Calculate the transport block sizes for the transmission in the slot
        [pdschIndices,pdschIndicesInfo] = nrPDSCHIndices(carrier,pdsch);
        trBlkSizes = nrTBS(pdsch.Modulation,pdsch.NumLayers,numel(pdsch.PRBSet),pdschIndicesInfo.NREPerPRB,pdschextra.TargetCodeRate,pdschextra.XOverhead);

        % Transport block generation
        for cwIdx = 1:pdsch.NumCodewords
            % New data for current codeword then create a new DL-SCH transport block
            trBlk = randi([0 1],trBlkSizes(cwIdx),1);
            setTransportBlock(encodeDLSCH,trBlk,cwIdx-1);
            resetSoftBuffer(decodeDLSCH,cwIdx-1);
        end

        % Encode the DL-SCH transport blocks
        RV = zeros(1,pdsch.NumCodewords);
        codedTrBlocks = encodeDLSCH(pdsch.Modulation,pdsch.NumLayers, ...
            pdschIndicesInfo.G,RV);

        % PDSCH modulation and precoding
        pdschSymbols = nrPDSCH(carrier,pdsch,codedTrBlocks);
        [pdschAntSymbols,pdschAntIndices] = nrPDSCHPrecode(carrier,pdschSymbols,pdschIndices,wtx);
        dlGrid(pdschAntIndices) = pdschAntSymbols;        

        % PDSCH DM-RS precoding and mapping
        dmrsSymbols = nrPDSCHDMRS(carrier,pdsch);
        dmrsIndices = nrPDSCHDMRSIndices(carrier,pdsch);
        [dmrsAntSymbols,dmrsAntIndices] = nrPDSCHPrecode(carrier,dmrsSymbols,dmrsIndices,wtx);
        dlGrid(dmrsAntIndices) = dmrsAntSymbols;

        % Warn if CSI-RS and PDSCH DM-RS resources overlap
        if any(ismember(dmrsIndices,csirsInd))
            warning("CSI-RS and PDSCH DM-RS resources overlap in the resource grid. This can result in decoding failures.")
        end

        % OFDM modulation
        txWaveform = nrOFDMModulate(carrier,dlGrid);

        % Pass data through channel model. Append zeros at the end of the
        % transmitted waveform to flush channel content. These zeros take
        % into account any delay introduced in the channel.
        txWaveform = [txWaveform; zeros(maxChDelay,size(txWaveform,2))]; %#ok<AGROW>
        [rxWaveform,ofdmResponse,tOffset] = channel(txWaveform,carrier);
        
        % Add AWGN to the received time-domain waveform
        noise = N0*randn(size(rxWaveform),"like",1i);
        rxWaveform = rxWaveform + noise;

        if simParamLocal.PerfectChannelEstimator
            % For perfect synchronization, use the timing offset obtained
            % from the channel
            timingOffset = tOffset;
        else
            % Practical synchronization. Correlate the received waveform
            % with the PDSCH DM-RS to obtain the timing offset and
            % correlation magnitude. The receiver updates the timing offset
            % only when the correlation magnitude is high.
            [t,mag] = nrTimingEstimate(carrier,rxWaveform,dmrsIndices,dmrsSymbols); 
            timingOffset = hSkipWeakTimingOffset(timingOffset,t,mag);
            % Display a warning if the estimated timing offset exceeds the
            % maximum channel delay
            if timingOffset > maxChDelay
                warning(['Estimated timing offset (%d) is greater than the maximum channel delay (%d).' ...
                    ' This can result in a decoding failure. This issue can be caused by low SNR' ...
                    ' or not enough DM-RS symbols for successful synchronization.'],timingOffset,maxChDelay);
            end
        end
        rxWaveform = rxWaveform(1+timingOffset:end,:);

        % Perform OFDM demodulation on the received data to recreate the
        % resource grid, including padding in the event that practical
        % synchronization results in an incomplete slot being demodulated
        rxGrid = nrOFDMDemodulate(carrier,rxWaveform);
        [K,L,R] = size(rxGrid);
        if (L < carrier.SymbolsPerSlot)
            rxGrid = cat(2,rxGrid,zeros(K,carrier.SymbolsPerSlot-L,R));
        end

        if simParamLocal.PerfectChannelEstimator
            % For perfect channel estimate, use the OFDM channel response
            % obtained from the channel
            Hest = ofdmResponse;

            % Get PDSCH resource elements from the received grid and 
            % channel estimate
            [pdschRx,pdschHest,~,pdschHestIndices] = nrExtractResources(pdschIndices,rxGrid,Hest);

            % Apply precoding to channel estimate
            pdschHest = nrPDSCHPrecode(carrier,pdschHest,pdschHestIndices,permute(wtx,[2 1 3]));
        else
            % Practical channel estimation between the received grid and
            % each transmission layer, using the PDSCH DM-RS for each
            % layer. This channel estimate includes the effect of
            % transmitter precoding
            aw = channelEstimateAveragingWindow(pdsch);
            [Hest,noiseEst] = nrChannelEstimate(carrier,rxGrid,dmrsIndices,dmrsSymbols,...
                PRGBundleSize = pdschextra.PRGBundleSize,CDMLengths = pdsch.DMRS.CDMLengths,AveragingWindow = aw);

            % Average noise estimate across PRGs and layers
            noiseEst = mean(noiseEst,'all');
            
            % Get PDSCH resource elements from the received grid and
            % channel estimate
            [pdschRx,pdschHest] = nrExtractResources(pdschIndices,rxGrid,Hest);
        end

        % Equalization
        [pdschEq,eqCSIScaling] = nrEqualizeMMSE(pdschRx,pdschHest,noiseEst);

        % Decode PDSCH physical channel
        [dlschLLRs,rxSymbols] = nrPDSCHDecode(carrier,pdsch,pdschEq,noiseEst);
        
        % Display EVM per layer, per slot and per RB
        if (simParamLocal.DisplayDiagnostics)
            plotLayerEVM(NSlots,nslot,pdsch,size(dlGrid),pdschIndices,pdschSymbols,pdschEq);
        end
        
        % Scale LLRs
        eqCSIScaling = nrLayerDemap(eqCSIScaling); % CSI scaling layer demapping
        for cwIdx = 1:pdsch.NumCodewords
            Qm = length(dlschLLRs{cwIdx})/length(rxSymbols{cwIdx});        % bits per symbol
            eqCSIScaling{cwIdx} = repmat(eqCSIScaling{cwIdx}.',Qm,1);      % expand by each bit per symbol
            dlschLLRs{cwIdx} = dlschLLRs{cwIdx} .* eqCSIScaling{cwIdx}(:); % scale LLRs
        end
        
        % Decode the DL-SCH transport channel
        decodeDLSCH.TransportBlockLength = trBlkSizes;
        decodeDLSCH.TargetCodeRate = pdschextra.TargetCodeRate;
        [decbits,blkerr] = decodeDLSCH(dlschLLRs,pdsch.Modulation,pdsch.NumLayers,RV);

        % Store values to calculate throughput
        simThroughput(snrIdx) = simThroughput(snrIdx) + sum(~blkerr .* trBlkSizes);
        maxThroughput(snrIdx) = maxThroughput(snrIdx) + sum(trBlkSizes);

        % CSI measurements and encoding 
        if csirsTransmission
            
            if ~simParamLocal.PerfectChannelEstimator
                % Consider only the NZP-CSI-RS symbols and indices for CSI-RS based
                % channel estimation
                nzpind = (csirsSym ~= 0);
                
                % Calculate practical channel estimate based on CSI-RS. Use
                % a time-averaging window that covers all of the
                % transmitted CSI-RS symbols.
                [Hest,noiseEst] = nrChannelEstimate(carrier,rxGrid, ...
                    csirsInd(nzpind),csirsSym(nzpind),'CDMLengths',csirsCDMLengths);
            end

            % Generate CSI report. Store the report for use at the
            % transmitter. The CSI feedback is subject to a delay that
            % depends on the CSI report periodicity and the UE processing
            % delay. The slot in which the CSI is available to use at the
            % transmitter depends on the BS processing delay as well.
            csiReport = hCSIEncode(carrier,csirs,Hest,noiseEst,csiFeedbackOpts);
            feedbackSlot = nextCSISlot(csiFeedbackOpts.CSIReportPeriod,1+nslot+simParamLocal.UEProcessingDelay);
            csiSlots(end+1) = 1+feedbackSlot+simParamLocal.BSProcessingDelay; %#ok<SAGROW>
            csiReports(end+1) = csiReport; %#ok<SAGROW>

            csiReports = reduceCSIReports(csiReports,csiSlots,carrier.NSlot,simParamLocal.CSIReportMode);
        end

        % Print slot-wise information
        if simParamLocal.DisplaySimulationInformation
            printSlotInfo(NSlots,carrier,pdsch,pdschextra,blkerr,trBlkSizes./pdschIndicesInfo.G,csirsTransmission,csiReports,repIdx)
        end
    end

    % Store CSI report for each SNR point
    CSIReport{snrIdx} = csiReports; %#ok<SAGROW>
    
    % Display the results dynamically in the command window
    if simParamLocal.DisplaySimulationInformation
        fprintf('\n');
    end
    fprintf('\nThroughput(Mbps) for %d frame(s) = %.4f\n',simParamLocal.NFrames,1e-6*simThroughput(snrIdx)/(simParamLocal.NFrames*10e-3));

end
Simulating transmission scheme 1 (8x4) and SCS=15kHz with CDL-C channel at -10dB SNR for 2 10ms frame(s)
Using RI, PMI, and CQI as CSI feedback.
( 5.00%) NSlot= 0: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.462). Using initial CSI. CSI-RS transmission. 
(10.00%) NSlot= 1: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(15.00%) NSlot= 2: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(20.00%) NSlot= 3: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(25.00%) NSlot= 4: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(30.00%) NSlot= 5: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(35.00%) NSlot= 6: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(40.00%) NSlot= 7: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(45.00%) NSlot= 8: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(50.00%) NSlot= 9: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(55.00%) NSlot=10: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.462). CSI-RS transmission. 
(60.00%) NSlot=11: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(65.00%) NSlot=12: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423). Using CSI from NSlot= 0.
(70.00%) NSlot=13: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(75.00%) NSlot=14: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(80.00%) NSlot=15: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(85.00%) NSlot=16: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(90.00%) NSlot=17: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(95.00%) NSlot=18: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
(100.00%) NSlot=19: Transmission succeeded (Layers=1, Mod=16QAM, TCR=0.479, CR=0.423).
Throughput(Mbps) for 2 frame(s) = 8.4560
Simulating transmission scheme 1 (8x4) and SCS=15kHz with CDL-C channel at 10dB SNR for 2 10ms frame(s)
Using RI, PMI, and CQI as CSI feedback.
( 5.00%) NSlot= 0: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.622). Using initial CSI. CSI-RS transmission. 
(10.00%) NSlot= 1: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(15.00%) NSlot= 2: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(20.00%) NSlot= 3: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(25.00%) NSlot= 4: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(30.00%) NSlot= 5: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(35.00%) NSlot= 6: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(40.00%) NSlot= 7: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(45.00%) NSlot= 8: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(50.00%) NSlot= 9: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(55.00%) NSlot=10: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.622). CSI-RS transmission. 
(60.00%) NSlot=11: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(65.00%) NSlot=12: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570). Using CSI from NSlot= 0.
(70.00%) NSlot=13: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(75.00%) NSlot=14: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(80.00%) NSlot=15: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(85.00%) NSlot=16: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(90.00%) NSlot=17: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(95.00%) NSlot=18: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
(100.00%) NSlot=19: Transmission succeeded (Layers=3, Mod=64QAM, TCR=0.650, CR=0.570).
Throughput(Mbps) for 2 frame(s) = 51.2160

結果

測定したスループットを SNR の関数として表示します。

figure;
plot(simParameters.SNRIn,1e-6*simThroughput/(simParameters.NFrames*10e-3),'o-.')

xlabel('SNR (dB)'); ylabel('Throughput (Mbps)'); grid on;
title(sprintf('%s (%dx%d) / NRB=%d / SCS=%dkHz / CSI: %s', ...
              simParameters.DelayProfile,simParameters.NTxAnts,simParameters.NRxAnts, ...
              simParameters.Carrier.NSizeGrid,simParameters.Carrier.SubcarrierSpacing,...
              char(simParameters.CSIReportMode)));

Figure contains an axes object. The axes object with title CDL-C (8x4) / NRB=52 / SCS=15kHz / CSI: RI-PMI-CQI, xlabel SNR (dB), ylabel Throughput (Mbps) contains an object of type line.

if simParameters.CSIReportMode == "RI-PMI-CQI"
    perc = 90;
    plotCQI(simParameters,CSIReport,perc)
end

Figure contains 2 axes objects. Axes object 1 with title Median CQI and (5,95) Percentiles, ylabel CQI value contains an object of type errorbar. Axes object 2 with title CQI not in set {median CQI - 1 , median CQI, median CQI + 1 }, xlabel SNR (dB), ylabel % contains an object of type line.

% Bundle key parameters and results into a combined structure for recording
simResults.simParameters = simParameters;
simResults.simThroughput = simThroughput;
simResults.maxThroughput = maxThroughput;
simResults.CSIReport = CSIReport;

ローカル関数

function [carrier,eDLSCH,pdsch,pdschextra,csirs,wtx] = setupTransmitter(simParameters)
% Extract channel and signal-level parameters, create DL-SCH encoder, and
% initialize MIMO precoding matrix.

    carrier = simParameters.Carrier;
    pdsch = simParameters.PDSCH;
    pdschextra = simParameters.PDSCHExtension;
    csirs = simParameters.CSIRS;

    % Select XOverhead for TBS calculation if required
    if isempty(pdschextra.XOverhead)
        pdschextra.XOverhead = getXOverhead(carrier,csirs);
    end
    
    % Create DL-SCH encoder system object to perform transport channel
    % encoding
    eDLSCH = nrDLSCH;

    % Initialize MIMO precoding matrix
    wtx = 1;
    
end

function [decodeDLSCH,timingOffset,N0,noiseEst,csiReports,csiAvailableSlots] = setupReceiver(simParameters,channel,snrIdx,csiFeedbackOpts)
% Create and configure DL-SCH decoder. Obtain noise related quantities and
% initial CSI feedback from perfect channel knowledge.

    % Create DL-SCH decoder system object to perform transport channel
    % decoding
    decodeDLSCH = nrDLSCHDecoder;
    decodeDLSCH.LDPCDecodingAlgorithm = simParameters.PDSCHExtension.LDPCDecodingAlgorithm;
    decodeDLSCH.MaximumLDPCIterationCount = simParameters.PDSCHExtension.MaximumLDPCIterationCount;

    % Calculate noise standard deviation. Normalize noise power by the IFFT
    % size used in OFDM modulation, as the OFDM modulator applies this
    % normalization to the transmitted waveform.
    carrier = simParameters.Carrier;
    waveInfo = nrOFDMInfo(carrier);
    SNRdB = simParameters.SNRIn(snrIdx);
    SNR = 10^(SNRdB/10);    
    N0 = 1/sqrt(double(waveInfo.Nfft)*SNR);

    % Also normalize by the number of receive antennas if the channel
    % applies this normalization to the output
    chInfo = info(channel);
    if channel.NormalizeChannelOutputs
        if contains(simParameters.DelayProfile,'CDL')
            N0 = N0/sqrt(chInfo.NumOutputSignals);
        else
            N0 = N0/sqrt(chInfo.NumReceiveAntennas);
        end
    end

    % Initial channel estimate
    [Hest,timingOffset] = getInitialChannelEstimate(carrier,channel,chInfo.MaximumChannelDelay);

    % Initial noise variance
    noiseEst = N0^2*double(waveInfo.Nfft);

    % Obtain an initial CSI report based on perfect channel estimates that
    % the Tx can use to adapt the transmission parameters.
    csirs = simParameters.CSIRS;

    % Initial CSI report using initial channel estimate
    csiFeedbackOpts.PerfectChannelEstimator = true;
    csirs.CSIRSPeriod = 'on';
    csiReports = hCSIEncode(carrier,csirs,Hest,noiseEst,csiFeedbackOpts);
    csiAvailableSlots = 0;

end

function channel = createChannel(simParameters)
% Create and configure the propagation channel. If the number of antennas
% is 1, configure only 1 polarization, otherwise configure 2 polarizations.
    
    if contains(simParameters.DelayProfile,'CDL')

        % Create CDL channel
        channel = nrCDLChannel;

        % Tx antenna array configuration in CDL channel. The number of antenna
        % elements depends on the panel dimensions. The size of the antenna
        % array is [M,N,P,Mg,Ng]. M and N are the number of rows and columns in
        % the antenna array. P is the number of polarizations (1 or 2). Mg and
        % Ng are the number of row and column array panels respectively. Note
        % that N1 and N2 in the panel dimensions follow a different convention
        % and denote the number of columns and rows, respectively.
        txArray = simParameters.TransmitAntennaArray;
        M = txArray.PanelDimensions(2);
        N = txArray.PanelDimensions(1);
        Ng = txArray.NumPanels;
        P = txArray.NumPolarizations;

        channel.TransmitAntennaArray.Size = [M N P 1 Ng];
        channel.TransmitAntennaArray.ElementSpacing = [0.5 0.5 1 N/2]; % Element spacing in wavelengths
        channel.TransmitAntennaArray.PolarizationAngles = [-45 45];  % Polarization angles in degrees
        
        % Rx antenna array configuration in CDL channel
        rxArray = simParameters.ReceiveAntennaArray;
        M = rxArray.PanelDimensions(2);
        N = rxArray.PanelDimensions(1);
        Ng = rxArray.NumPanels;
        P = rxArray.NumPolarizations;

        channel.ReceiveAntennaArray.Size = [M N P 1 Ng];
        channel.ReceiveAntennaArray.ElementSpacing = [0.5 0.5 1 N/2];  % Element spacing in wavelengths
        channel.ReceiveAntennaArray.PolarizationAngles = [0 90];     % Polarization angles in degrees

    elseif contains(simParameters.DelayProfile,'TDL')

        channel = nrTDLChannel;
        channel.NumTransmitAntennas = simParameters.NTxAnts;
        channel.NumReceiveAntennas = simParameters.NRxAnts;

    else

        error('Channel not supported.')

    end

    % Configure common channel parameters: delay profile, delay spread, and
    % maximum Doppler shift
    channel.DelayProfile = simParameters.DelayProfile;
    channel.DelaySpread = simParameters.DelaySpread;
    channel.MaximumDopplerShift = simParameters.MaximumDopplerShift;

    % Configure the channel to return the OFDM response
    channel.ChannelResponseOutput = 'ofdm-response';

    % Get information about the baseband waveform after OFDM modulation step
    waveInfo = nrOFDMInfo(simParameters.Carrier);

    % Update channel sample rate based on carrier information
    channel.SampleRate = waveInfo.SampleRate;
    
end

function [channel,maxChannelDelay] = setupChannel(simParameters)
% Reset propagation channel and obtain the maximum channel delay

    % Extract carrier and channel
    channel = simParameters.Channel;
    channel.reset();

    % Get the channel information
    chInfo = info(channel);
    maxChannelDelay = chInfo.MaximumChannelDelay;

end

function [ofdmResponse,toffset] = getInitialChannelEstimate(carrier,channel,maxChannelDelay)
% Obtain OFDM channel response and timing offset before first transmission.
% This can be used to obtain initial transmission parameters.

    % Clone channel and configure channel to get OFDM channel response for
    % one slot
    channel = clone(channel);
    release(channel);
    channel.ChannelFiltering = false;
    ofdmInfo = nrOFDMInfo(carrier);
    channel.NumTimeSamples = (ofdmInfo.SampleRate*1e-3/carrier.SlotsPerSubframe) + maxChannelDelay;
    [ofdmResponse,toffset] = channel(carrier);
    
end

function aw = channelEstimateAveragingWindow(pdsch)

    % Use an auto averaging window by default ([0 0])
    aw = [0 0];
    if pdsch.DMRS.DMRSLength == 2
        % Increase time averaging for double-symbol DM-RS to avoid
        % extrapolation errors in the channel estimator
        aw = [0 7]; 
    end
    
end

function XOverhead = getXOverhead(carrier,csirs)
% Calculate XOverhead for transport block size determination based on
% CSI-RS resource grid occupancy

    [~,csirsInfo] = nrCSIRSIndices(carrier,csirs);
    csirsRE = length(csirsInfo.KBarLBar{1})*length(csirsInfo.KPrime{1})*length(csirsInfo.LPrime{1});
    [~,XOverhead] = quantiz(csirsRE,[0 6 12],[0 6 12 18]);
    
    if csirsRE > XOverhead
        warning("The CSI-RS RE overhead is higher than the maximum 18. This can result in decoding failures.")
    end

end

function cdmLengths = getCSIRSCDMLengths(csirs)
%   CDMLENGTHS = getCSIRSCDMLengths(CSIRS) returns the CDM lengths given
%   the CSI-RS configuration object CSIRS.

    CDMType = csirs.CDMType;
    if ~iscell(csirs.CDMType)
        CDMType = {csirs.CDMType};
    end
    CDMTypeOpts = {'noCDM','fd-CDM2','CDM4','CDM8'};
    CDMLengthOpts = {[1 1],[2 1],[2 2],[2 4]};
    cdmLengths = CDMLengthOpts{strcmpi(CDMTypeOpts,CDMType{1})};

end

function csiFeedbackOpts = getCSIFeedbackOptions(simParameters)
% Create a CSI feedback algorithmic options structure

    csiFeedbackOpts = struct();
    csiFeedbackOpts.CSIReportMode = simParameters.CSIReportMode;
    csiFeedbackOpts.CSIReportPeriod = simParameters.CSIReportConfig.Period;
    csiFeedbackOpts.CSIReportConfig = simParameters.CSIReportConfig;
    csiFeedbackOpts.PerfectChannelEstimator = simParameters.PerfectChannelEstimator;
    csiFeedbackOpts.DMRSConfig = simParameters.PDSCH.DMRS;

end

function csiReportConfig = updateCSIReportPanelInfo(csiReportConfig,antennaArray)
% Update the antenna array dimensions according to TS 38.214 Section
% 5.2.2.2 as a vector [N1,N2] for single-panel arrays and a vector
% [Ng,N1,N2] for multi-panel arrays. Also, adjust the codebook type
% according to the number of panels.

    if antennaArray.NumPanels > 1 && csiReportConfig.CodebookType ~= "Type1MultiPanel"
        csiReportConfig.CodebookType = "Type1MultiPanel";
        warning("For transmit antenna arrays with more than one panel, the codebook type in the CSI report configuration must be 'Type1MultiPanel'. The codebok type is set to 'Type1MultiPanel'.");
    end

    % Configure CSI report config panel dimensions. Add number of panels if
    % codebook type is multi-panel
    if strcmpi(csiReportConfig.CodebookType,'Type1MultiPanel')
        csiReportConfig.PanelDimensions = [antennaArray.NumPanels antennaArray.PanelDimensions];
    else
        csiReportConfig.PanelDimensions = antennaArray.PanelDimensions;
    end    
    
end

function csislot = nextCSISlot(period,nslot)
% Return the slot number of the first slot where CSI feedback can be
% reported according to the CSI report periodicity

    p = period(1); % Slot periodicity
    o = period(2); % Slot offset

    csislot = p*ceil((nslot-o)/p)+o;

end

function csiReports = reduceCSIReports(csiReports,csiAvailableSlots,nslot,csiMode)
% Reduce size of CSI reports to minimize memory usage

    prevSlots = csiAvailableSlots < nslot;
    if csiMode == "RI-PMI-CQI"
        % Empty old precoding matrices
        [csiReports(prevSlots).W] = deal([]);
    else
        % Empty old channel estimates
        [csiReports(prevSlots).H] = deal([]);
    end
end

function txArray = validateAntennaPolarization(txArray)
% Ensure transmit antenna arrays with more than one element specify 2
% polarizations
    
    numTxElements = numAntennaElements(txArray);
    if numTxElements > 1 && txArray.NumPolarizations == 1
        txArray.NumPolarizations = 2;
        warning("For transmit antenna arrays with more than one element, the number of polarizations must be 2. The number of polarizations is set to 2.")
    end

end

function numElemenets = numAntennaElements(antArray)
% Calculate number of antenna elements in an antenna array

    numElemenets = antArray.NumPolarizations*antArray.NumPanels*prod(antArray.PanelDimensions);
    
end

function ranks = updateRankRestriction(dmrsConfig,CSIReportConfig)
% Restrict ranks unsupported by the DM-RS configuration
    ranks = CSIReportConfig.RIRestriction;
    
    if ~dmrsConfig.DMRSEnhancedR18 && (dmrsConfig.DMRSLength == 1) && strcmpi(CSIReportConfig.CodebookType, 'Type1SinglePanel')
        if (dmrsConfig.DMRSConfigurationType == 1)
            % Up to rank 4 for DM-RS configuration type 1
            dmrsRankRestriction = [ones(1,4) zeros(1,4)];
        else
            % Up to rank 6 for DM-RS configuration type 2
            dmrsRankRestriction = [ones(1,6) zeros(1,2)];
        end

        if isempty(ranks)
            ranks = ones(1,8);
        end

        ranks = ranks.*dmrsRankRestriction;

        fprintf('The PDSCH DM-RS configuration limits the maximum number of layers to %d. \n',find(dmrsRankRestriction,1,'last'));
    end
end

function validateCSIRSConfig(carrier,csirs,nTxAnts)
% validateCSIRSConfig(CARRIER,CSIRS,NTXANTS) validates the CSI-RS
% configuration, given the carrier specific configuration object CARRIER,
% CSI-RS configuration object CSIRS, and the number of transmit antennas
% NTXANTS.

    % Validate the number of CSI-RS ports
    if ~isscalar(unique(csirs.NumCSIRSPorts))
        error('nr5g:InvalidCSIRSPorts',...
            'All the CSI-RS resources must be configured to have the same number of CSI-RS ports.');
    end

    % Validate the CSI-RS and TX antenna array configuration
    if any(csirs.Ports_Options(csirs.RowNumber) ~= nTxAnts)
        rn = num2str(find(csirs.Ports_Options == nTxAnts),'%3d,');
        str = 'The number of CSI-RS ports must be equal to the number of Tx antenna elements. ';
        str = [str sprintf('For the Tx antenna array size configured, valid CSI-RS row numbers are (%s).',rn(1:end-1))];
        error(str)
    end

    % Validate the CDM lengths
    if ~iscell(csirs.CDMType)
        cdmType = {csirs.CDMType};
    else
        cdmType = csirs.CDMType;
    end
    if (~all(strcmpi(cdmType,cdmType{1})))
        error('nr5g:InvalidCSIRSCDMTypes',...
            'All the CSI-RS resources must be configured to have the same CDM lengths.');
    end
    if nTxAnts ~= csirs.NumCSIRSPorts(1)
        error('nr5g:InvalidNumTxAnts',['Number of transmit antennas (' num2str(nTxAnts)...
            ') must be equal to the number of CSI-RS ports (' num2str(csirs.NumCSIRSPorts(1)) ').']);
    end

    % Check for the overlap between the CSI-RS indices
    csirsInd = nrCSIRSIndices(carrier,csirs,"OutputResourceFormat",'cell');
    numRes = numel(csirsInd);
    csirsIndAll = cell(1,numRes);
    ratioVal = csirs.NumCSIRSPorts(1)/prod(getCSIRSCDMLengths(csirs));
    for resIdx = 1:numRes
        if ~isempty(csirsInd{resIdx})
            grid = nrResourceGrid(carrier,csirs.NumCSIRSPorts(1));
            [~,tempInd] = nrExtractResources(csirsInd{resIdx},grid);
            if numel(tempInd)/numel(csirsInd{resIdx}) ~= ratioVal
                error('nr5g:OverlappedCSIRSREsSingleResource',['CSI-RS indices of resource '...
                    num2str(resIdx) ' must be unique. Try changing the symbol or subcarrier locations.']);
            end
            csirsIndAll{resIdx} = tempInd(:);
            for idx = 1:resIdx-1
                overlappedInd = ismember(csirsIndAll{idx},csirsIndAll{resIdx});
                if any(overlappedInd)
                    error('nr5g:OverlappedCSIRSREsMultipleResources',['The resource elements of the '...
                        'configured CSI-RS resources must not overlap. Try changing the symbol or '...
                        'subcarrier locations of CSI-RS resource ' num2str(idx) ' and resource ' num2str(resIdx) '.']);
                end
            end
        end
    end
end

function displaySNRPointProgress(simParameters,snrIdx)
% Print SNR point progress

    str = ['\nSimulating transmission scheme 1 (%dx%d) and '...  
          'SCS=%dkHz with %s channel at %gdB SNR for %d 10ms frame(s)\n' ...
          'Using %s as CSI feedback.\n'];

    if strcmpi(simParameters.CSIReportMode,'RI-PMI-CQI')
        modeText = 'RI, PMI, and CQI';
    else
        modeText = 'channel estimates';
    end

    SNRdB = simParameters.SNRIn(snrIdx);
    fprintf(str,simParameters.NTxAnts,simParameters.NRxAnts,simParameters.Carrier.SubcarrierSpacing, ...
        simParameters.DelayProfile,SNRdB,simParameters.NFrames,modeText);

end

function printSlotInfo(NSlots,carrier,pdsch,pdschextra,blkerr,ECR,csirsTransmission,csiReports,reportIndex)
% Print information about the current slot transmission

    ncw = pdsch.NumCodewords;
    cwLayers = floor((pdsch.NumLayers + (0:ncw-1)) / ncw);
    infoStr = [];
    for cwIdx = 1:ncw
        if blkerr(cwIdx)
            infoStrCW = "Transmission failed";
        else
            infoStrCW = "Transmission succeeded";
        end
        infoStrCW = sprintf("%22s (Layers=%d, Mod=%5s, TCR=%.3f, CR=%.3f).",infoStrCW,cwLayers(cwIdx),pdsch.Modulation{cwIdx},pdschextra.TargetCodeRate(cwIdx),ECR(cwIdx));
        if (ncw>1)
            infoStr = sprintf('%s\n%s%s',infoStr,sprintf('CW%d: %s',cwIdx-1),infoStrCW);
        else
            infoStr = infoStrCW;
        end
    end
    
    csirsInfoStr = [];
    if csirsTransmission
        csirsInfoStr = "CSI-RS transmission. ";
    end

    csifbInfoStr = [];
    if carrier.NSlot == 0
        csifbInfoStr = 'Using initial CSI.';
    elseif reportIndex > 0
        csifbInfoStr = sprintf("Using CSI from NSlot=%2d.",csiReports(reportIndex).NSlot);
    end

    nslot = carrier.NSlot;
    fprintf('\n(%5.2f%%) NSlot=%2d: %s',100*(nslot+1)/NSlots,nslot,join([infoStr,csifbInfoStr,csirsInfoStr]));

end

function plotLayerEVM(NSlots,nslot,pdsch,siz,pdschIndices,pdschSymbols,pdschEqSymbols)
% Plot EVM information

    persistent slotEVM;
    persistent rbEVM
    persistent evmPerSlot;
    persistent numLayers;
    
    maxNumLayers = 8;
    if (nslot==0)
        slotEVM = comm.EVM;
        rbEVM = comm.EVM;
        evmPerSlot = NaN(NSlots,maxNumLayers);
        numLayers = pdsch.NumLayers;
        figure;
    else
        % Keep the maximum number of layers in the legend
        numLayers = max(numLayers,pdsch.NumLayers);
    end
    [Ns,P] = size(pdschEqSymbols);
    pdschEqSym = zeros(Ns,maxNumLayers);
    pdschSym = zeros(Ns,maxNumLayers);
    pdschEqSym(:,1:P) = pdschEqSymbols;    
    pdschSym(:,1:P) = pdschSymbols;
    evmPerSlot(nslot+1,:) = slotEVM(pdschSym,pdschEqSym);
    subplot(2,1,1);
    plot(0:(NSlots-1),evmPerSlot,'o-');
    xlabel('Slot number');
    ylabel('EVM (%)');
    legend("layer " + (1:numLayers),'Location','EastOutside');
    title('EVM per layer per slot');

    subplot(2,1,2);
    [k,~,p] = ind2sub(siz,pdschIndices);
    rbsubs = floor((k-1) / 12);
    NRB = siz(1) / 12;
    evmPerRB = NaN(NRB,maxNumLayers);
    for nu = 1:pdsch.NumLayers
        for rb = unique(rbsubs).'
            this = (rbsubs==rb & p==nu);
            evmPerRB(rb+1,nu) = rbEVM(pdschSym(this),pdschEqSym(this));
        end
    end

    plot(0:(NRB-1),evmPerRB,'x-');
    xlabel('Resource block');
    ylabel('EVM (%)');
    legend("layer " + (1:numLayers),'Location','EastOutside');
    title(['EVM per layer per resource block, slot #' num2str(nslot)]);
    
    drawnow;
    
end

function plotCQI(simParameters,CSIReport,perc)
% Plot CQI median and percentiles 

    % Calculate median and percentiles
    med = cellfun(@(x) median([x.CQI]), CSIReport);
    p1 = cellfun(@(x) prctile([x.CQI],50-perc/2), CSIReport);
    p2 = cellfun(@(x) prctile([x.CQI],50+perc/2), CSIReport);
    
    % Calculate the percentage of CQI not in the set {median CQI -1, median CQI, median CQI +1} 
    cqiPerc = cellfun(@(x,y) sum(abs([x.CQI]-y)>1)/length(x),CSIReport,num2cell(med));
    
    figure;
    subplot(211)
    errorbar(simParameters.SNRIn,med,p2-p1,'o-.')
    ylabel('CQI value')
    title(sprintf('Median CQI and (%g,%g) Percentiles',50-perc/2,50+perc/2));
    grid

    subplot(212)
    plot(simParameters.SNRIn,cqiPerc,'o-.')
    xlabel('SNR (dB)')
    ylabel('%')
    title('CQI not in set \{median CQI -1, median CQI, median CQI +1\}');
    grid   

end

function [rowNumber, subcarriers, symbols, density] = csirsAllocationParameters(simParameters)
% Select CSI-RS row number, subcarrier and symbol locations that are
% suitable for the input carrier, PDSCH, and transmit antenna array
% specified in simParameters. See TS 38.211 Table 7.4.1.5.3-1 and TS 38.214
% Table 5.2.2.2.1-2.

    carrier = simParameters.Carrier;
    pdsch = simParameters.PDSCH;

    % Select row number from number of ports
    numPorts   = [1 2 4 8 12 16 24 32];
    rowNumbers = [2 3 4 6  9 11 13 16];
    userNumPorts = numAntennaElements(simParameters.TransmitAntennaArray);
    rowNumber = rowNumbers(userNumPorts==numPorts);
    
    % CSI-RS subcarriers
    kiLengths = [1 1 1 1 1 4 2 2 6 3 4 4 3 3 3 4 4 4]; % Number of subcarriers for each row 
    numSubcarriers = kiLengths(rowNumber);
    scStep = 12./numSubcarriers;
    subcarriers = 0:scStep:11; %#ok<BDSCI>
    
    % CSI-RS OFDM symbols
    dmrsind = nrPDSCHDMRSIndices(carrier,pdsch,"IndexStyle","subscript");
    dmrssym = unique(dmrsind(:,2))-1; % 0-based indices
    slotSymbolSet = 2:carrier.SymbolsPerSlot-2;
    slotSymbolSet = setdiff(slotSymbolSet,dmrssym);     
    nsyms = [1 1 1 1 1 1 1 1 1 1 1 1 2 2 1 2 2 1]; % Number of symbols for each row 
    nsym = nsyms(rowNumber);
    symbols = slotSymbolSet(1:2:2*nsym);

    density = simParameters.CSIRS.Density;
    if (density ~= "one" ) && any(rowNumber == (4:10))
        density = "one";
        warning("For the transmit array panel dimensions, the CSI-RS density must be 'one'. The density is set to 'one'.");
    end

end

参考

トピック