В этом примере показано, как создать моделирование частоты ошибок NB-IoT Narrowband Physical Uplink Shared Channel (NPUSCH) (BLER) в частотно-селективных замираниях и аддитивных белых гауссовых шумах (AWGN) с использованием LTE Toolbox™.
3GPP представил новый радиоинтерфейс Narrowband IoT (NB-IoT), оптимизированный для связи машинного типа с низкой скоростью передачи данных в LTE-Advanced Pro Release 13. NB-IoT обеспечивает улучшение затрат и степени эффективности, поскольку избегает необходимости в сложных служебных данных сигнализации, необходимых для основанных на LTE систем.
Пример генерирует кривую NB-IoT NPUSCH BLER для ряда точек ОСШ и параметров передачи. NPUSCH и узкополосный опорный сигнал демодуляции (DRS) передаются во всех пазах. Работая на базисе за слотом для каждой точки ОСШ, вычисление BLER включает в себя следующие шаги:
Сгенерируйте ресурсную сетку и заполните ее символами NPUSCH
Создайте форму волны основной полосы частот путем SC-FDMA, модулируя сетку
Передайте форму волны через зашумленный канал с замираниями
Выполните операции приемника (демодуляция SC-FDMA, оценка канала и эквализация)
Получите блок CRC путем декодирования уравненных символов
Определите эффективность NPUSCH путем использования блока результата CRC на выходе канального декодера
Длина симуляции составляет 5 транспортных блоков UL-SCH для ряда точек ОСШ SNRdB
для различных повторений simReps
. Для получения значимых результатов пропускной способности следует использовать большее количество транспортных блоков (numTrBlks
). SNRdB
и simReps
может быть заданным в виде скаляра или числового массива.
numTrBlks = 5; % Number of simulated transport blocks SNRdB = [-20 -18 -15 -12.5 -10 -6.4 -3.5 0.7]; % Range of SNR values in dB simReps = [2 16 64]; % Repetitions to simulate
В этом разделе мы конфигурируем параметры, необходимые для генерации NPUSCH. Существует два типа полезной нагрузки, заданные для передачи NPUSCH, формат 1 ('Data') и формат 2 ('Control'). Для формата 1 UE использует комбинацию схемы модуляции и кодирования (MCS) и назначения ресурса, сигнализируемых через DCI, чтобы определить размер транспортного блока из набора, заданного в таблице TS 36.213 16.5.1.2-2 [3]. Для формата 2 NPUSCH содержит 1 бит ACK/NACK. The chs.NPUSCHFormat
параметр задает формат и infoLen
задает длину транспортного блока. Параметры, используемые в этом примере, соответствуют A16-5 FRC, определенным в TS 36.104 Приложение A.16 [4].
Операция HARQ NB-IoT имеет один или два процесса UL HARQ, и операция HARQ является асинхронной для UE NB-IoT, за исключением повторений в пакете. Операция связывания полагается на сущность HARQ для вызова того же процесса HARQ для каждой передачи, которая является частью одного и того же пакета. В пакете повторные передачи HARQ неадаптивны. Они срабатывают, не дожидаясь обратной связи от приема предыдущих повторов. Предоставление восходящей линии связи, соответствующее новой передаче или повторной передаче пакета, принимается только после последнего повторения пакета. Повторная передача пучка также является пучком. Для получения дополнительной информации см. раздел 5.4.2 TS 36.321 [5]. В этом примере повторные передачи пакета не моделируются.
ue = struct(); % Initialize the UE structure ue.NBULSubcarrierSpacing = '15kHz'; % 3.75kHz, 15kHz ue.NNCellID = 10; % Narrowband cell identity chs = struct(); chs.NPUSCHFormat = 'Data'; % NPUSCH payload type ('Data' or 'Control') % The number of subcarriers used for NPUSCH 'NscRU' depends on the NPUSCH % format and subcarrier spacing 'NBULSubcarrierSpacing' as shown in TS 36.211 % Table 10.1.2.3-1. There are 1,3,6 or 12 continuous subcarriers for NPUSCH chs.NBULSubcarrierSet = 0:11; % Range is 0-11 (15kHz); 0-47 (3.75kHz) chs.NRUsc = length(chs.NBULSubcarrierSet); % The symbol modulation depends on the NPUSCH format and NscRU as given by % TS 36.211 Table 10.1.3.2-1 chs.Modulation = 'QPSK'; chs.CyclicShift = 0; % Cyclic shift required when NRUsc = 3 or 6 chs.RNTI = 20; % RNTI value chs.NLayers = 1; % Number of layers chs.NRU = 1; % Number of resource units chs.SlotIdx = 0; % The slot index chs.NTurboDecIts = 5; % Number of turbo decoder iterations chs.CSI = 'On'; % Use channel CSI in PUSCH decoding % RV offset signaled via DCI (See 36.213 16.5.1.2) rvDCI = 0; % Calculate the RVSeq used according to the RV offset rvSeq = [2*mod(rvDCI+0,2) 2*mod(rvDCI+1,2)]; if strcmpi(chs.NPUSCHFormat,'Data') infoLen = 136; % Transport block size for NPUSCH format 1 elseif strcmpi(chs.NPUSCHFormat,'Control') infoLen = 1; % ACK/NACK bit for NPUSCH format 2 end
Структура channel
содержит параметры конфигурации модели канала.
channel = struct; % Initialize channel config structure channel.Seed = 6; % Channel seed channel.NRxAnts = 2; % 2 receive antennas channel.DelayProfile ='ETU'; % Delay profile channel.DopplerFreq = 1; % Doppler frequency in Hz channel.MIMOCorrelation = 'Low'; % Multi-antenna correlation channel.NTerms = 16; % Oscillators used in fading model channel.ModelType = 'GMEDS'; % Rayleigh fading model type channel.InitPhase = 'Random'; % Random initial phases channel.NormalizePathGains = 'On'; % Normalize delay profile power channel.NormalizeTxAnts = 'On'; % Normalize for transmit antennas
В этом примере параметр perfectChannelEstimator
управляет поведением оценщика канала. Допустимые значения true
или false
. Когда установлено значение true
, используется совершенный оценщик канала. В противном случае используется практический оценщик, основанный на значениях полученного DRS NPUSCH.
% Channel estimator behavior
perfectChannelEstimator = true;
Структура cec
конфигурирует практическую оценку канала. Профиль задержки ETU с 1Hz Doppler заставляет канал изменяться медленно с течением времени. Чтобы гарантировать среднее по всем поднесущим для ресурсного блока, установите частотное окно 23 Resource Elements (RE). Переменная channelEstimationLength
настраивает количество пазов, в которых усредняются оценки канала, см. таблицу A.16.1-1 [4] TS 36.104 для предлагаемых значений для различных строений NPUSCH.
% Configure channel estimator cec.PilotAverage = 'UserDefined'; % Type of pilot symbol averaging cec.TimeWindow = 1; % Time window size in REs cec.FreqWindow = 23; % Frequency window size in REs cec.InterpType = 'Cubic'; % 2D interpolation type channelEstimationLength = 1; % Channel estimation length in ms
Для сигналов DRS в формате NPUSCH 1, скачкообразное изменение группы последовательностей может быть включено или отключено параметром для ячеек более высокого слоя groupHoppingEnabled
. Скачкообразное изменение группы последовательностей для конкретного UE может быть отключено через параметр более высокого слоя groupHoppingDisabled
как описано в TS 36.211 Раздел 10.1.4.1.3 [1]. В этом примере мы используем SeqGroupHopping
параметр для включения или отключения скачкообразного изменения группы последовательности
chs.SeqGroupHopping = 'on'; % Enable/Disable Sequence-Group Hopping for UE chs.SeqGroup = 0; % Higher-layer parameter groupAssignmentNPUSCH % Get number of time slots in a resource unit NULSlots according to % TS 36.211 Table 10.1.2.3-1 if strcmpi(chs.NPUSCHFormat,'Data') if chs.NRUsc == 1 NULSlots = 16; elseif any(chs.NRUsc == [3 6 12]) NULSlots = 24/chs.NRUsc; else error('Invalid number of subcarriers. NRUsc must be one of 1,3,6,12'); end elseif strcmpi(chs.NPUSCHFormat,'Control') NULSlots = 4; else error('Invalid NPUSCH Format (%s). NPUSCHFormat must be ''Data'' or ''Control''',chs.NPUSCHFormat); end chs.NULSlots = NULSlots;
Чтобы выполнить NB-IoT NPUSCH ссылки уровня симуляции и построить результаты BLER для ряда уровней повторения, этот пример выполняет следующие шаги:
Для передачи NPUSCH в формате 1 для передачи данных UL:
Сгенерируйте случайный поток бит с размером необходимого транспортного блока
Выполните кодирование CRC, турбокодирование и соответствие скорости, чтобы создать биты NPUSCH
Перемежайте биты на модуль ресурса, чтобы применить первое во времени сопоставление и создать кодовое слово NPUSCH
Для формата NPUSCH 2, используемого для сигнализации обратной связи HARQ для NPDSCH:
Выполните битовое повторение индикатора HARQ, чтобы создать кодовое слово NPUSCH
Затем для любого формата NPUSCH:
Выполните скремблирование, модуляцию, отображение слоя и предварительное кодирование кодового слова, чтобы сформировать комплексные символы NPUSCH
Сопоставьте символы NPUSCH и соответствующий DRS с ресурсной сеткой
Сгенерируйте сигнал временного интервала путем выполнения SC-FDMA модуляции ресурсной сетки
Передайте форму волны через канал с замираниями с AWGN
Восстановите переданную сетку путем синхронизации, оценки канала и эквализации MMSE
Извлечение символов NPUSCH
Восстановите транспортный блок путем демодуляции символов и декодирования в канале полученных оценок бит
Обратите внимание, что если сконфигурирована практическая оценка канала (perfectChannelEstimator = false
), также будет выполнена практическая оценка времени на основе корреляции DRS NPUSCH. Смещение синхронизации инициализируется равным нулю, предназначенному для представления начальной синхронизации после приема NPRACH. Оценка времени затем обновляется, когда пик корреляции DRS NPUSCH является достаточно сильным.
После удаления скремблирования повторяющиеся пазы мягко объединяются перед восстановлением скорости. Вероятность ошибки транспортного блока вычисляется для каждой точки ОСШ. Оценка частоты блочной ошибки основана на допущении, что все пазы в пучке используются для декодирования транспортного блока в UE. Пакет определяется на уровне MAC (см. 3GPP TS 36.321 5.4.2.1 [3]) как NPUSCH.NRU
NPUSCH.NULSlots
NPUSCH.NRep
пазы, используемые для переноса транспортного блока.
% Get the slot grid and number of slots per frame emptySlotGrid = lteNBResourceGrid(ue); % Initialize empty slot grid slotGridSize = size(emptySlotGrid); NSlotsPerFrame = 20/(slotGridSize(1)/12); tSlot = 10e-3/NSlotsPerFrame; % Slot duration symbolsPerSlot = slotGridSize(2); % Number of symbols per slot % Get a copy of the configuration variables ue, chs and channel to create % independent simulation parfor loops ueInit = ue; chsInit = chs; channelInit = channel; for repIdx = 1:numel(simReps) chsInit.NRep = simReps(repIdx); % Number of repetitions of the NPUSCH NSlotsPerBundle = chsInit.NRU*chsInit.NULSlots*chsInit.NRep; % Number of slots in a codeword bundle TotNSlots = numTrBlks*NSlotsPerBundle; % Total number of simulated slots % Initialize BLER and throughput result maxThroughput = zeros(length(SNRdB),1); simThroughput = zeros(length(SNRdB),1); bler = zeros(1,numel(SNRdB)); % Initialize BLER result for snrIdx = 1:numel(SNRdB) % parfor snrIdx = 1:numel(SNRdB) % To enable the use of parallel computing for increased speed comment out % the 'for' statement above and uncomment the 'parfor' statement below. % This needs the Parallel Computing Toolbox (TM). If this is not installed % 'parfor' will default to the normal 'for' statement. % Set the random number generator seed depending on the loop variable % to ensure independent random streams rng(snrIdx,'combRecursive'); ue = ueInit; % Initialize ue configuration chs = chsInit; % Initialize chs configuration channel = channelInit; % Initialize fading channel configuration numBlkErrors = 0; % Number of transport blocks with errors estate = struct('SlotIdx',chs.SlotIdx); % Initialize NPUSCH encoder state dstate = estate; % Initialize NPUSCH decoder state offset = 0; % Initialize overall frame timing offset trblk = []; % Initialize the transport block npuschHest = []; % Initialize channel estimate noiseEst = []; % Initialize noise estimate % Display the number of slots being generated fprintf('\nGenerating %d slots corresponding to %d transport block(s) at %gdB SNR\n',TotNSlots,numTrBlks,SNRdB(snrIdx)); for slotIdx = 0+(0:TotNSlots-1) % Calculate the frame number and slot number within the frame ue.NFrame = fix(slotIdx/NSlotsPerFrame); ue.NSlot = mod(slotIdx,NSlotsPerFrame); % Create the slot grid slotGrid = emptySlotGrid; if isempty(trblk) % Initialize transport channel decoder state dstateULSCH = []; if strcmpi(chs.NPUSCHFormat,'Data') % UL-SCH encoding is performed for the two RV values used for % transmitting the codewords. The RV sequence used is determined % from the rvDCI value signaled in the DCI and alternates % between 0 and 2 as given in TS 36.213 Section 16.5.1.2 % Define the transport block which will be encoded to create the % codewords for different RV trblk = randi([0 1],infoLen,1); % Determine the coded transport block size [~, info] = lteNPUSCHIndices(ue,chs); outblklen = info.G; % Create the codewords corresponding to the two RV values used % in the first and second block, this will be repeated till all % blocks are transmitted chs.RV = rvSeq(1); % RV for the first block cw = lteNULSCH(chs,outblklen,trblk); % CRC and Turbo coding is repeated chs.RV = rvSeq(2); % RV for the second block cw = [cw lteNULSCH(chs,outblklen,trblk)]; %#ok<AGROW> % CRC and Turbo coding is repeated else trblk = randi([0 1],1); % 1 bit ACK % For ACK, the same codeword is transmitted every block as % defined in TS 36.212 Section 6.3.3 cw = lteNULSCH(trblk); end blockIdx = 0; % First block to be transmitted end % Copy SlotIdx for the SCFDMA modulator chs.SlotIdx = estate.SlotIdx; % Set the RV used for the current transport block chs.RV = rvSeq(mod(blockIdx,size(rvSeq,2))+1); % NPUSCH encoding and mapping onto the slot grid txsym = lteNPUSCH(ue,chs,cw(:,mod(blockIdx,size(cw,2))+1),estate); slotGrid(lteNPUSCHIndices(ue,chs)) = txsym; % NPUSCH DRS and mapping on to the slot grid [dmrs,estate] = lteNPUSCHDRS(ue,chs,estate); slotGrid(lteNPUSCHDRSIndices(ue,chs)) = dmrs; % If a full block is transmitted, increment the clock counter so that % the correct codeword can be selected if estate.EndOfBlk blockIdx = blockIdx + 1; end % Perform SC-FDMA modulation to create the time domain waveform [txWaveform,scfdmaInfo] = lteSCFDMAModulate(ue,chs,slotGrid); % Add 25 sample padding. This is to cover the range of delays % expected from channel modeling (a combination of % implementation delay and channel delay spread) txWaveform = [txWaveform; zeros(25, size(txWaveform,2))]; %#ok<AGROW> % Initialize channel time for each slot channel.InitTime = slotIdx*tSlot; % Pass data through channel model channel.SamplingRate = scfdmaInfo.SamplingRate; [rxWaveform,fadingInfo] = lteFadingChannel(channel, txWaveform); % Calculate noise gain SNR = 10^(SNRdB(snrIdx)/20); % Normalize noise power to take account of sampling rate, which is % a function of the IFFT size used in SC-FDMA modulation N0 = 1/(sqrt(2.0*double(scfdmaInfo.Nfft))*SNR); % Create additive white Gaussian noise noise = N0*complex(randn(size(rxWaveform)), ... randn(size(rxWaveform))); % Add AWGN to the received time domain waveform rxWaveform = rxWaveform + noise; %------------------------------------------------------------------ % Receiver %------------------------------------------------------------------ % Perform timing synchronization, extract the appropriate % subframe of the received waveform, and perform SC-FDMA % demodulation if (perfectChannelEstimator) offset = hPerfectTimingEstimate(fadingInfo); else [t,mag] = lteULFrameOffsetNPUSCH(ue, chs, rxWaveform, dstate); % The function hSkipWeakTimingOffset is used to update the % receiver timing offset. If the correlation peak in 'mag' % is weak, the current timing estimate 't' is ignored and % the previous estimate 'offset' is used offset = hSkipWeakTimingOffset(offset,t,mag); end % Synchronize the received waveform rxWaveform = rxWaveform(1+offset:end, :); % Perform SC-FDMA 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 rxSlot = lteSCFDMADemodulate(ue,chs,rxWaveform); [K,L,R] = size(rxSlot); if (L < symbolsPerSlot) rxSlot = cat(2,rxSlot,zeros(K,symbolsPerSlot-L,R)); end % Channel estimation if (perfectChannelEstimator) % Perfect channel estimation ue.TotSlots = 1; % Channel estimate for 1 slot estChannelGrid = lteULPerfectChannelEstimate(ue, chs, channel, offset); noiseGrid = lteSCFDMADemodulate(ue,chs,noise(1+offset:end ,:)); noiseEstSlot = var(noiseGrid(:)); else [estChannelGrid, noiseEstSlot] = lteULChannelEstimateNPUSCH(ue, chs, cec, rxSlot, dstate); end % Get NPUSCH indices npuschIndices = lteNPUSCHIndices(ue,chs); % Get NPUSCH resource elements from the received slot [rxNpuschSymbols, npuschHestSlot] = lteExtractResources(npuschIndices, ... rxSlot, estChannelGrid); % Perform channel estimate and noise estimate buffering in % the case of practical channel estimation if (perfectChannelEstimator) npuschHest = npuschHestSlot; noiseEst = noiseEstSlot; else npuschHest = cat(3,npuschHest,npuschHestSlot); noiseEst = cat(1,noiseEst,noiseEstSlot); if (size(npuschHest,3) > channelEstimationLength) npuschHest = npuschHest(:,:,2:end); noiseEst = noiseEst(2:end); end end % Decode NPUSCH [rxcw,dstate,symbols] = lteNPUSCHDecode(... ue, chs, rxNpuschSymbols, mean(npuschHest,3), mean(noiseEst),dstate); % Decode the transport block when all the slots in a block have % been received if dstate.EndOfBlk % Soft-combining at transport channel decoder [out, err, dstateULSCH] = lteNULSCHDecode(chs,infoLen,rxcw,dstateULSCH); end % If all the slots in the bundle have been received, count the % errors and reinitialize for the next bundle if dstate.EndOfTx if strcmpi(chs.NPUSCHFormat,'Control') err = ~isequal(out,trblk); end numBlkErrors = numBlkErrors + err; % Re-initialize to enable the transmission of a new transport % block trblk = []; end end % Calculate the block error rate bler(snrIdx) = numBlkErrors/numTrBlks; fprintf('NPUSCH BLER = %.4f \n',bler(snrIdx)); % Calculate the maximum and simulated throughput maxThroughput(snrIdx) = infoLen*numTrBlks; % Max possible throughput simThroughput(snrIdx) = infoLen*(numTrBlks-numBlkErrors); % Simulated throughput fprintf('NPUSCH Throughput(%%) = %.4f %%\n',simThroughput(snrIdx)*100/maxThroughput(snrIdx)); end % Plot Block Error Rate vs SNR Results if repIdx == 1 figure; grid on; hold on; xlabel('SNR (dB)'); ylabel('BLER'); legendstr = {['NRep = ' num2str(chsInit.NRep)]}; else legendstr = [legendstr ['NRep = ' num2str(chsInit.NRep)]]; %#ok<AGROW> end plot(SNRdB, bler, '-o'); end % Set figure title title(sprintf(' NPUSCH Carrying %s: NRUsc = %d, NRU = %d, TBS = %d',... chsInit.NPUSCHFormat,chsInit.NRUsc,chsInit.NRU,infoLen)); legend(legendstr);
Generating 20 slots corresponding to 5 transport block(s) at -20dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 20 slots corresponding to 5 transport block(s) at -18dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 20 slots corresponding to 5 transport block(s) at -15dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 20 slots corresponding to 5 transport block(s) at -12.5dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 20 slots corresponding to 5 transport block(s) at -10dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 20 slots corresponding to 5 transport block(s) at -6.4dB SNR NPUSCH BLER = 0.4000 NPUSCH Throughput(%) = 60.0000 % Generating 20 slots corresponding to 5 transport block(s) at -3.5dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 20 slots corresponding to 5 transport block(s) at 0.7dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 160 slots corresponding to 5 transport block(s) at -20dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 160 slots corresponding to 5 transport block(s) at -18dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 160 slots corresponding to 5 transport block(s) at -15dB SNR NPUSCH BLER = 0.6000 NPUSCH Throughput(%) = 40.0000 % Generating 160 slots corresponding to 5 transport block(s) at -12.5dB SNR NPUSCH BLER = 0.2000 NPUSCH Throughput(%) = 80.0000 % Generating 160 slots corresponding to 5 transport block(s) at -10dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 160 slots corresponding to 5 transport block(s) at -6.4dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 160 slots corresponding to 5 transport block(s) at -3.5dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 160 slots corresponding to 5 transport block(s) at 0.7dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 640 slots corresponding to 5 transport block(s) at -20dB SNR NPUSCH BLER = 1.0000 NPUSCH Throughput(%) = 0.0000 % Generating 640 slots corresponding to 5 transport block(s) at -18dB SNR NPUSCH BLER = 0.6000 NPUSCH Throughput(%) = 40.0000 % Generating 640 slots corresponding to 5 transport block(s) at -15dB SNR NPUSCH BLER = 0.2000 NPUSCH Throughput(%) = 80.0000 % Generating 640 slots corresponding to 5 transport block(s) at -12.5dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 640 slots corresponding to 5 transport block(s) at -10dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 640 slots corresponding to 5 transport block(s) at -6.4dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 640 slots corresponding to 5 transport block(s) at -3.5dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 % Generating 640 slots corresponding to 5 transport block(s) at 0.7dB SNR NPUSCH BLER = 0.0000 NPUSCH Throughput(%) = 100.0000 %
Большее количество транспортных блоков, numTrBlks
должны использоваться для получения значимых результатов производительности. Следующий график показывает запуск симуляции с numTrBlks
установите значение 5000 для различных повторений с идеальной оценкой канала.
3GPP ТС 36.211 «Физические каналы и модуляция»
3GPP TS 36.212 «Мультиплексирование и канальное кодирование»
3GPP TS 36.213 «Процедуры физического слоя»
3GPP TS 36.104 «Радиопередача и прием базовой станции (BS)»
3GPP TS 36.321 "Управление доступом к среде (MAC); Спецификация протокола "
3GPP TS 36.331 "Управление радиоресурсами (RRC); Спецификация протокола "
3GPP TS 36.300 "Общее описание; Этап 2 "
О. Либерг, М. Сундберг, Я.-П. Wang, J. Bergman and J. Sachs, Cellular Internet of Things: Technologies, Standards and Performance, Elsevier, 2018.
В этом примере используются следующие вспомогательные функции: