Ускорьте измерение BER для турбо декодера HDL LTE

Этот пример показывает рабочий процесс, чтобы измерить BER Турбо Декодера LTE HDL Toolbox с помощью parsim, чтобы параллелизировать симуляции через точки EbNo. Этот подход может использоваться, чтобы ускорить другие симуляции Монте-Карло.

Введение

Реализации HDL примеров готовых узлов являются часто комплексными и занимают много времени, чтобы симулировать. В результате выяснение производительности частоты ошибок по битам (BER) путем выполнения нескольких симуляций в различных точках ОСШ может быть очень трудоемким. Один способ оптимизировать это состоит в том, чтобы параллелизировать симуляции с помощью parsim команды. parsim команда запускает несколько параллельных симуляций, когда названо доступной лицензией Parallel Computing Toolbox™. Этот пример измеряет BER Турбо Декодера HDL LTE. Чтобы достигнуть достаточной статистической точности, приблизительно 100 ошибок должны быть получены в декодере для каждого значения EbNo. Это переводит в 1e8 биты в BER 10e-6. Этот тип симуляции Монте-Карло является подходящим кандидатом, чтобы параллелизировать использование parsim, где BER для каждой точки EbNo выполняется на рабочих параллельно.

Для каждой параллельной симуляции этот пример настраивает входные данные можно следующим образом:

  1. Сгенерируйте системы координат входных данных;

  2. Турбо кодирует;

  3. QPSK модулирует;

  4. Добавьте AWGN на основе значения EbNo;

  5. Демодулируйте шумные символы;

  6. Сгенерируйте мягкие решения.

Мягкие решения становятся входом к Турбо Декодеру HDL LTE в Simulink®. Декодируемые биты турбо сравниваются с переданными битами, чтобы вычислить BER. Каждая параллельная симуляция передает результаты обратно в основной хост.

Сконфигурируйте объекты симуляции и параметры

Общее количество информационных битов для каждого EbNo точка, bitsPerEbNo, разделен по нескольким симуляциям, заданным parsimPerEbNo. Таким образом каждая симуляция запускает bitsPerParsim биты для одного EbNo точка. Общим количеством симуляций является length(EbNo)*parsimPerEbNo. Этот пример сконфигурирован, чтобы запустить только небольшое количество битов в демонстрационных целях. В действительном сценарии необходимо запустить достаточное число выборок через декодер для точной меры BER в более высоком EbNo 'points'. При выборе этих параметров считайте ресурсы памяти доступными на хосте. Большой набор входных данных на симуляцию или большое количество рабочих мог привести к, замедляются или исчерпание памяти. Структура simParam содержит параметры, требуемые для каждой симуляции. Эта структура отправляется в симуляции на более позднем этапе.

EbNo = 0:0.1:1.1;
bitsPerEbNo = 1e5; %1e8;
parsimPerEbNo = 2; %10;
bitsPerParsim = ceil(bitsPerEbNo/parsimPerEbNo);

simParam.blkSize = 6144;
simParam.turboIterations = 6;
simParam.numFrames = ceil(bitsPerParsim/simParam.blkSize); % frames per simulation
simParam.modScheme = 'QPSK';
simParam.bps = 2; % bits per symbol
tailBits = 4; % encoder property
simParam.encoderRate = simParam.blkSize/(3*(simParam.blkSize+tailBits)); % rate 1/3 Turbo code
simParam.samplesizeIn = floor(1/simParam.encoderRate); % 3 samples in at a time
simParam.inframeSize = simParam.samplesizeIn*(simParam.blkSize+tailBits);

model = 'LTEHDLTurboDecoderBERExample';
open_system(model);

Запустите локальный параллельный пул с минимума 1 и максимума maxNumWorkers. Если лицензия Parallel Computing Toolbox™ не будет доступна, симуляции будут сериализированы. Фактический размер пула зависит от количества доступных ядер. Каждый параллельный рабочий присвоен одно ядро, на котором запускается независимый сеанс MATLAB®.

maxNumWorkers = 3;
pool = parpool('local', [1 maxNumWorkers]);
Starting parallel pool (parpool) using the 'local' profile ...
Connected to the parallel pool (number of workers: 3).

Предварительно выделите объект parsim содержать данные, требуемые для каждой симуляции. Объект может также включать указатели на функции, которые модель вызывает прежде или после симуляции. Сеанс MATLAB®, на котором parsim выполняется действия как основной хост. Основной хост ответственен за запуск симуляций на рабочих, отправку необходимых данных каждому рабочему и получения результатов.

parsimIn(1:length(EbNo)*parsimPerEbNo) = Simulink.SimulationInput(model);

Реплицируйте EbNo точки, чтобы настроить parsimPerEbNo симуляции.

repEbNo = repmat(EbNo,parsimPerEbNo,1);
repEbNo = repEbNo(:);

Минимизация передачи данных рабочим улучшает производительность и устойчивость основного хоста. Поэтому этот пример генерирует входные данные в модели, вместо того, чтобы передать большой набор входных данных каждому рабочему. Входные данные сгенерированы с помощью функции перед симуляцией, presimGenInput и вычисление BER также выполняется в функции постсимуляции, postsimOutput. Эти указатели на функцию присвоены каждому SimulationInput объект. Функция постсимуляции присвоена в функции перед симуляцией как показано в разделе Pre-Simulation и Post-Simulation Functions.

for noiseRatio = 1:length(repEbNo)
    % Calculate the noise variance.
    EsNo = repEbNo(noiseRatio) + 10*log10(simParam.bps);
    snrdB = EsNo + 10*log10(simParam.encoderRate);
    noiseVar = 1./(10.^(snrdB/10));

    % Use random but reproducible data.
    seed = noiseRatio;

    % For Rapid Accelerator mode, set the simulation
    % stop time before compilation.
    parsimIn(noiseRatio) = parsimIn(noiseRatio).setModelParameter('StopTime',num2str(simParam.numFrames));

    % Set pre-simulation function.
    parsimIn(noiseRatio) = parsimIn(noiseRatio).setPreSimFcn(@(simIn) presimGenInput(simIn,noiseVar,seed,simParam));
end

Запустите и покажите прогресс симуляций в командном окне. В конце симуляций результаты передают обратно в основной хост в массиве структур, parsimOut, с одной записью, созданной на симуляцию. Если симуляции завершены, закройте параллельный пул.

parsimOut = parsim(parsimIn,'ShowProgress','on','StopOnError','on');
delete(pool);
[07-Mar-2019 14:33:22] Checking for availability of parallel pool...
[07-Mar-2019 14:34:51] Starting Simulink on parallel workers...
[07-Mar-2019 14:35:51] Configuring simulation cache folder on parallel workers...
[07-Mar-2019 14:35:53] Loading model on parallel workers...
[07-Mar-2019 14:36:45] Running simulations...
Analyzing and transferring files to the workers ...done.
[07-Mar-2019 14:39:00] Completed 1 of 24 simulation runs
[07-Mar-2019 14:39:00] Completed 2 of 24 simulation runs
[07-Mar-2019 14:39:00] Completed 3 of 24 simulation runs
[07-Mar-2019 14:39:13] Completed 4 of 24 simulation runs
[07-Mar-2019 14:39:13] Completed 5 of 24 simulation runs
[07-Mar-2019 14:39:13] Completed 6 of 24 simulation runs
[07-Mar-2019 14:39:22] Completed 7 of 24 simulation runs
[07-Mar-2019 14:39:22] Completed 8 of 24 simulation runs
[07-Mar-2019 14:39:22] Completed 9 of 24 simulation runs
[07-Mar-2019 14:39:31] Completed 10 of 24 simulation runs
[07-Mar-2019 14:39:31] Completed 11 of 24 simulation runs
[07-Mar-2019 14:39:31] Completed 12 of 24 simulation runs
[07-Mar-2019 14:39:40] Completed 13 of 24 simulation runs
[07-Mar-2019 14:39:40] Completed 14 of 24 simulation runs
[07-Mar-2019 14:39:40] Completed 15 of 24 simulation runs
[07-Mar-2019 14:39:49] Completed 16 of 24 simulation runs
[07-Mar-2019 14:39:49] Completed 17 of 24 simulation runs
[07-Mar-2019 14:39:49] Completed 18 of 24 simulation runs
[07-Mar-2019 14:39:57] Completed 19 of 24 simulation runs
[07-Mar-2019 14:39:57] Completed 20 of 24 simulation runs
[07-Mar-2019 14:39:57] Completed 21 of 24 simulation runs
[07-Mar-2019 14:40:07] Completed 22 of 24 simulation runs
[07-Mar-2019 14:40:07] Completed 23 of 24 simulation runs
[07-Mar-2019 14:40:07] Completed 24 of 24 simulation runs
[07-Mar-2019 14:40:07] Cleaning up parallel workers...
Parallel pool using the 'local' profile is shutting down.

Постройте BER

Извлеките значения BER из массива структур. Объедините результаты BER для каждого EbNo укажите и найдите средний BER на EbNo точка.

BER = [parsimOut(:).BER];
BER = transpose(reshape(BER,parsimPerEbNo,length(BER)/parsimPerEbNo));
avgBER = mean(BER,2);
semilogy(EbNo,avgBER,'-o');
grid;
xlabel('Eb/No (dB)');
ylabel('Bit Error Rate');

График ниже показов результаты измерения BER с bitsPerEbNo = 1e8.

Предварительная симуляция и функции постсимуляции

Эти функции независимо генерируют входные данные и выходные данные процесса для каждой симуляции, которая избавляет от необходимости основной хост хранить данные в памяти для всех симуляций. presimGenInput функция генерирует входные биты, затем кодирует, модулирует и преобразует их в мягкие решения. Чтобы сделать входные кадры и параметры доступными для модели, они присвоены как переменные в глобальной рабочей области с помощью setVariable функция.

function simIn = presimGenInput(simIn,noiseVar,seed,simParam)

    rng(seed);

    % Preallocate arrays for speed.
    txBits   = zeros(simParam.blkSize,simParam.numFrames,'int8');
    inFrames = zeros(simParam.inframeSize,simParam.numFrames,'single');

    % Generate input frames, turbo encode, modulate and add noise
    % based on noise variance.
    for currentFrame = 1:simParam.numFrames
        txBits(:,currentFrame) = randi([0 1],simParam.blkSize,1);
        codedData = lteTurboEncode(txBits(:,currentFrame));
        txSymbols = lteSymbolModulate(codedData,simParam.modScheme);
        noise = (sqrt(noiseVar/2))*complex(randn(size(txSymbols)),randn(size(txSymbols)));
        rxSymbols = txSymbols + noise;
        inFrames(:,currentFrame) = lteSymbolDemodulate(rxSymbols,simParam.modScheme,'Soft');
    end

    % Set up parameters for Frame to Samples block to serialize data.
    % Leave sufficient gap between frames.
    simParam.idleCyclesBetweenSamples = 0;
    halfIterationLatency = (ceil(simParam.blkSize/32)+3)*32; % window size = 32
    algFrameDelay = 2*simParam.turboIterations*halfIterationLatency+(simParam.inframeSize/simParam.samplesizeIn);
    simParam.idleCyclesBetweenFrames = algFrameDelay;

    % Assign variables to global workspace.
    simIn = simIn.setVariable('inFrames',inFrames);
    simIn = simIn.setVariable('simParam',simParam);

    % Set post-simulation function and send required data.
    simIn =  simIn.setPostSimFcn(@(simOut) postsimOutput(simOut,txBits,simParam));

end

Функция постсимуляции получает выходные параметры симуляции и вычисляет BER. Результаты хранятся в структуре results какой parsim возвращается как parsimOut.

function results = postsimOutput(out, txBits, simParam)
    decodedOutValid = out.decodedOut(out.validOut);

    results.numErrors = sum(xor(txBits(:),decodedOutValid));
    results.BER = results.numErrors/(simParam.numFrames*simParam.blkSize);
end

Заключение

Этот пример показал, как эффективно измерить кривую BER для Турбо Декодера HDL LTE с помощью parsim. Если бы параллельный пул не используется, линейное время, чтобы завершить симуляции составило бы приблизительно 16 часов. В результате распараллеливания время, чтобы запустить все симуляции свелось к 5,4 часам, с помощью 3 рабочих. Это было достигнуто путем выполнения симуляций в Быстром Режиме Accelerator. Этот рабочий процесс может быть применен, чтобы объединить примеры готовых узлов, которые требуют Монте-Карло или других симуляций.