gusucode.com > wlan工具箱matlab源码程序 > wlan/wlan/+wlan/+internal/ldpcDecodeCore.m

    function [decoded, actualNumIter, finalParityChecks] = ldpcDecodeCore(LLR, rate, N_Iter, varargin)
%LDPCDECODECORE LDPC decoder core
%
%   decoded = ldpcDecodeCore(LLR, rate, N_Iter) decodes the
%   log-likelihood ratios LLR using a WLAN LDPC code at the specified rate
%   (rate).
% 
%   rate must be equal to '1/2', '2/3', '3/4', or '5/6'.
% 
%   N_Iter specifies the number of iterations.
% 
%   Each column of LLR specifies the log-likelihood ratios of a codeword.
%   The number of rows in LLR should be equal to one of the
%   three valid block lengths: 648, 1296, and 1944.
%
%   See http://www.mathworks.com/help/comm/ref/ldpcdecoder.html for
%   the definition of log-likelihood ratios and details about the decoding
%   algorithm.
% 
%   By default, decoded are hard-decision outputs for the information bits
%   of the codewords and ldpcDecodeCore will perform exactly N_Iter
%   iterations.
%
%   The following optional string inputs are accepted in varargin:
%   'whole codeword' - If 'whole codeword' is provided, decoded contains
%                      whole decoded codewords and the number of rows is
%                      equal to the number of rows in LLR; otherwise,
%                      decoded contains the information bits of the
%                      codewords only and the number of rows is equal to
%                      the number of information bits in one codeword.
%   'soft decision'  - If 'soft decision' is provided, each element in
%                      decoded is a log-likelihood ratio for the
%                      corresponding decoded bit and is of type double;
%                      otherwise, each element is either 0 or 1 and
%                      is of type int8.
%   'early exit'     - If 'early exit' is provided, after each iteration,
%                      ldpcDecodeCore will determine independently for
%                      each column of LLR if all parity checks are
%                      satisfied, and will stop for column(s) with all
%                      parity checks satisfied; otherwise, the function
%                      will execute exactly N_Iter iterations.
%
%   [decoded, actualNumIter, finalParityChecks] = ldpcDecodeCore(...)
%   provides optional outputs.
%
%   actualNumIter is a row vector of positive integer(s) whose length is
%   equal to the number of columns of LLR. The i-th element corresponds
%   to the actual number of decoding iterations executed for the i-th
%   column of LLR.
%
%   finalParityChecks is a matrix that holds the final parity checks.
%   The i-th column corresponds to the final parity checks for the i-th
%   codeword. The number of rows is equal to the number of parity-check
%   bits in a codeword. If all elements in finalParityChecks are zeros,
%   decoded corresponds to a valid codeword.
%
%   See also ldpcEncodeCore, ldpcMatrix.

%   Copyright 2015-2016 The MathWorks, Inc.

%#codegen

% Persistent variables for pre-computed data structures for LDPC codes
persistent d_1_2_648    % coding rate = 1/2, block length = 648
persistent d_1_2_1296   % coding rate = 1/2, block length = 1296
persistent d_1_2_1944   % coding rate = 1/2, block length = 1944
persistent d_2_3_648    % coding rate = 2/3, block length = 648
persistent d_2_3_1296   % coding rate = 2/3, block length = 1296
persistent d_2_3_1944   % coding rate = 2/3, block length = 1944
persistent d_3_4_648    % coding rate = 3/4, block length = 648
persistent d_3_4_1296   % coding rate = 3/4, block length = 1296
persistent d_3_4_1944   % coding rate = 3/4, block length = 1944
persistent d_5_6_648    % coding rate = 5/6, block length = 648
persistent d_5_6_1296   % coding rate = 5/6, block length = 1296
persistent d_5_6_1944   % coding rate = 5/6, block length = 1944

[blockLength, numCodewords] = size(LLR);

% When an LDPC code is used for the first time,
% load the corresponding pre-computed data structure and save it in a
% persistent variable
switch blockLength
    case 648
        if strcmp(rate, '1/2') || isequal(rate, 1/2)
            infoLen = blockLength * 1/2;
            if isempty(d_1_2_648)
                H = wlan.internal.ldpcMatrix('1/2', blockLength);
                d_1_2_648 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_1_2_648);
        elseif strcmp(rate, '2/3') || isequal(rate, 2/3)
            infoLen = blockLength * 2/3;
            if isempty(d_2_3_648)
                H = wlan.internal.ldpcMatrix('2/3', blockLength);
                d_2_3_648 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_2_3_648);
        elseif strcmp(rate, '3/4') || isequal(rate, 3/4)
            infoLen = blockLength * 3/4;
            if isempty(d_3_4_648)
                H = wlan.internal.ldpcMatrix('3/4', blockLength);
                d_3_4_648 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_3_4_648);
        else   % case '5/6'
            infoLen = blockLength * 5/6;
            if isempty(d_5_6_648)
                H = wlan.internal.ldpcMatrix('5/6', blockLength);
                d_5_6_648 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_5_6_648);
        end   
    case 1296
        if strcmp(rate, '1/2') || isequal(rate, 1/2)
            infoLen = blockLength * 1/2;
            if isempty(d_1_2_1296)
                H = wlan.internal.ldpcMatrix('1/2', blockLength);
                d_1_2_1296 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_1_2_1296);
        elseif strcmp(rate, '2/3') || isequal(rate, 2/3)
            infoLen = blockLength * 2/3;
            if isempty(d_2_3_1296)
                H = wlan.internal.ldpcMatrix('2/3', blockLength);
                d_2_3_1296 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_2_3_1296);
        elseif strcmp(rate, '3/4') || isequal(rate, 3/4)
            infoLen = blockLength * 3/4;
            if isempty(d_3_4_1296)
                H = wlan.internal.ldpcMatrix('3/4', blockLength);
                d_3_4_1296 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_3_4_1296);
        else   % case '5/6'
            infoLen = blockLength * 5/6;
            if isempty(d_5_6_1296)
                H = wlan.internal.ldpcMatrix('5/6', blockLength);
                d_5_6_1296 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_5_6_1296);
            end 
    otherwise    % case 1944
        if strcmp(rate, '1/2') || isequal(rate, 1/2)
            infoLen = blockLength * 1/2;
            if isempty(d_1_2_1944)
                H = wlan.internal.ldpcMatrix('1/2', blockLength); 
                d_1_2_1944 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_1_2_1944);
        elseif strcmp(rate, '2/3') || isequal(rate, 2/3)
            infoLen = blockLength * 2/3;
            if isempty(d_2_3_1944)
                H = wlan.internal.ldpcMatrix('2/3', blockLength); 
                d_2_3_1944 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_2_3_1944);
        elseif strcmp(rate, '3/4') || isequal(rate, 3/4)
            infoLen = blockLength * 3/4;
            if isempty(d_3_4_1944)
                H = wlan.internal.ldpcMatrix('3/4', blockLength);
                d_3_4_1944 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_3_4_1944);
        else    % case '5/6'
            infoLen = blockLength * 5/6;
            if isempty(d_5_6_1944)
                 H = wlan.internal.ldpcMatrix('5/6', blockLength);
                 d_5_6_1944 = ldpcinit(H);
            end
            [rows, cols, NGrp, grplist] = getldpcparams(d_5_6_1944);
        end   
end

% Parse optional input arguments
[outWholeCodeword, softDecision, earlyExit] = parseInputs(varargin{:});

% Initialize outputs
LLR_out = coder.nullcopy(zeros(blockLength, numCodewords));
finalParityChecks = coder.nullcopy(zeros(blockLength-infoLen, numCodewords));
actualNumIter = coder.nullcopy(zeros(1, numCodewords));

% Decode
if isempty(coder.target) % Simulation
    decoded = zeros(blockLength, numCodewords);
    compFinalParityChecks = (nargout == 3);
    numParityBits = blockLength - infoLen;
    rows = int32(rows-1);
    numRows= length(rows);
    numGrp = size(grplist,2);
    grplist = int32(grplist(:));
    
    for cwIndx = 1:numCodewords
        % C implementation
        [decoded(:,cwIndx), ~, ~, ~, actualNumIter(cwIndx), ...
         finalParityChecks(:,cwIndx)] = mwcomm_ldpcdecode(LLR(:,cwIndx), ...
            N_Iter, blockLength, numParityBits, numRows, numGrp, grplist, ...
            rows, int8(~softDecision), int8(earlyExit), ...
            int8(compFinalParityChecks));
    end
    
    % Format output
    if softDecision
        if ~outWholeCodeword
            decoded = decoded(1:infoLen, :);
        end
    else
        if outWholeCodeword
            decoded = int8(decoded);
        else
            decoded = int8(decoded(1:infoLen, :));
        end
    end
else % codegen
    % Initialize output to fix dimension and data type
    if softDecision
        if outWholeCodeword
             decoded = coder.nullcopy(zeros(blockLength, numCodewords));
        else
            decoded = coder.nullcopy(zeros(infoLen, numCodewords));
        end
    else
        if outWholeCodeword
            decoded = coder.nullcopy(zeros(blockLength, numCodewords,'int8'));
        else
            decoded = coder.nullcopy(zeros(infoLen, numCodewords,'int8'));
        end
    end
    
    % Parity-check matrix for computing final parity checks
    H = zeros(blockLength-infoLen, blockLength);
    for i = 1:length(rows)
        H(rows(i),cols(i)) = 1;
    end

    % The sum-product algorithm
    for cwIndx = 1:numCodewords
        % Key variables inside the for loop:
        % Lq, Lr, LLR_out
        
        Lq = LLR(cols, cwIndx);
        zeroLoc = zeros(size(Lq)); % Stores the location where Lq is zero
        
        numIter = 0;
        for iteration = 1:N_Iter
            numIter = numIter+1;
            
            Lq = tanh(Lq/2);
            prodLq = ones(infoLen,1);
            
            % Variables for handling Lq's that are equal to zero
            NumOfRowsWithZeroTanh = 0;
            ChangedZeroloc = 0;

            % Calculate the product of Lq's
            % May need to handle the situation when some values are zero
            for nn = 1:length(rows)
                if Lq(nn) ~= 0
                    prodLq(rows(nn)) = prodLq(rows(nn)) * Lq(nn);
                else
                % We must make sure that division by zero will not occur.
                % Moreover, we need to compute Lr correctly before
                % calculating LLR_out.
                
                % Strategy:
                %
                % Let j (column index) be fixed.
                %
                % If L(q_{ij}) = 0 for exactly one i (say i0),
                % then L(r_{ji}) = 0 for all i != i0,
                % and for i = i0, L(r_{ji}) will be computed correctly
                % if L(q_{ij}) is changed to any nonzero value.
                %
                % If L(q_{ij}) = 0 for two or more i's,
                % then L(r_{ji}) = 0 for all i.

                % First, change Lq to a nonzero value so that division
                % by zero will not occur.
                      
                    Lq(nn) = 1;
                    % Check if this is the first zero for this particular j
                    if zeroLoc(rows(nn)) == 0
                        % Yes, this is the first zero for this j.
                        % For now, assume that there are no more zeros,
                        % and store nn (which specifies i0),
                        % so that we may set L(r_{ji}) = 0 for all i != i0.
                        zeroLoc(rows(nn)) = nn;
                        
                        % Keep track of the number of rows we need to fix
                        % For each j, NumOfRowsWithZeroTanh may be
                        % increased once only, because zeroLoc(rows(nn)) is
                        % no longer equal to 0.
                        NumOfRowsWithZeroTanh = NumOfRowsWithZeroTanh + 1;
                        
                        % Make sure that zeroLoc will be cleared
                        % for next iteration
                        ChangedZeroloc = 1;
                        
                        % No need to do
                        %   prodLq(rows(nn)) = prodLq(rows(nn)) * Lq(nn);
                        % because Lq(nn) has been changed to 1.
                    else
                        if zeroLoc(rows(nn)) > 0
                            % This is the second zero for this j.
                            % Just set prodLq(rows(nn)) = 0
                            % to force all L(r_{ji}) to 0 for all i.
                            prodLq(rows(nn)) = 0;
                            % Set zeroLoc(rows(nn)) = -1 to record the fact
                            % that there are two zeros already.
                            zeroLoc(rows(nn)) = -1;
                            % Keep track of the number of rows we need to fix
                            NumOfRowsWithZeroTanh = NumOfRowsWithZeroTanh - 1;
                        end
                    end
                end
            end
            
            Lr = 2*atanh(prodLq(rows)./Lq);
            
            % atanh(x) approaches 19.07 as x approaches 1
            % atanh(x) approaches -19.07 as x approaches -1
            % Keep Lr finite to make subsequent summing operations meaningful
            Lr(Lr == Inf) = 2 * (19.07);
            Lr(Lr == -Inf) = 2 * (-19.07);
            
            % Fix those cases with a single zero
            if NumOfRowsWithZeroTanh > 0
                for nn = 1:length(rows)
                    if (zeroLoc(rows(nn)) > 0) && (zeroLoc(rows(nn)) ~= nn)
                        Lr(nn) = 0;
                    end
                end
            end
            
            if ChangedZeroloc
                zeroLoc(:) = 0; % Reset for next iteration
            end
            
            % Initial value of the sums
            LLR_out(:, cwIndx) = LLR(:, cwIndx);

            % Calculate the sums
            offset1 = 0;
            offset2 = 0;
            for g = 1:NGrp  % Loop over all groups
                LLR_out(offset1+(1:grplist(1,g)), cwIndx) = ...
                    LLR_out(offset1+(1:grplist(1,g)), cwIndx) + ...
                    sum(reshape(Lr(offset2+(1:grplist(1,g)*grplist(2,g))), ...
                    grplist(2,g), grplist(1,g)), 1)';
                offset1 = offset1 + grplist(1,g);
                offset2 = offset2 + grplist(1,g)*grplist(2,g);
            end
            
            Lq = LLR_out(cols, cwIndx) - Lr;
            
            if earlyExit
                % Compute the parity checks to see if the decoder can stop early
                hardDecisions = double(LLR_out(:, cwIndx) <= 0);
                finalParityChecks(:, cwIndx) = mod(H*hardDecisions,2);
                if ~any(finalParityChecks(:, cwIndx))
                    break;
                end
            end
        end
        
        % If necessary, compute the final parity checks
        if ~earlyExit && (nargout == 3)
            hardDecisions = double(LLR_out(:, cwIndx) <= 0);
            finalParityChecks(:, cwIndx) = mod(H*hardDecisions,2);
        end
        
        actualNumIter(cwIndx) = numIter;
    end
    
    % Format output
    if softDecision
        if outWholeCodeword
            decoded(:) = LLR_out;
        else
            decoded(:) = LLR_out(1:infoLen,:);
        end
    else
        if outWholeCodeword
            decoded(:) = int8(LLR_out <= 0);
        else
            decoded(:) = int8(LLR_out(1:infoLen,:) <= 0);
        end
    end
end


function d = ldpcinit(H)
[rows, cols] = find(H);
j = [sum(H,1) -1];
x = find(j(2:end)-j(1:end-1));
y = j(x);
dlist = reshape([filter([1 -1],1,x);y],1,[]);
NGrp = length(dlist)/2;
grplist = reshape(dlist, 2, []);
d.rows = rows;       % row indices of nonzero entry in H
d.cols = cols;       % column indices of nonzero entry in H
d.NGrp = NGrp;       % Number of groups in H
d.grplist = grplist; % Each group has the same number of ones in each column


function [rows, cols, NGrp, grplist] = getldpcparams(d)
rows = d.rows;
cols = d.cols;
NGrp = d.NGrp;
grplist = d.grplist;


function [outWholeCodeword, softDecision, earlyExit] = parseInputs(varargin)
outWholeCodeword = false;
softDecision = false;
earlyExit = false;

for i = 1:(nargin)
    if strcmpi(varargin{i}, 'whole codeword')
        outWholeCodeword = true;
    elseif strcmpi(varargin{i}, 'soft decision')
        softDecision = true;
    elseif strcmpi(varargin{i}, 'early exit')
        earlyExit = true;
    end
end