gusucode.com > wlan工具箱matlab源码程序 > wlan/wlan/wlanWaveformGenerator.m

    function txWaveform = wlanWaveformGenerator(dataBits,cfgFormat,varargin)
% wlanWaveformGenerator WLAN waveform generation
%   WAVEFORM = wlanWaveformGenerator(DATA,CFGFORMAT) generates a waveform
%   for a given format configuration and information bits. The generated
%   waveform contains a single packet with no idle time. For OFDM based
%   formats, the data scrambler initial states is 93 and the packet is
%   windowed for spectral controls with a windowing transition time of 1e-7
%   seconds.
%
%   WAVEFORM is a complex Ns-by-Nt matrix containing the generated
%   waveform, where Ns is the number of time domain samples, and Nt is the
%   number of transmit antennas.
%
%   DATA is the information bits including any MAC padding to be coded
%   across the number of packets to generate, i.e., representing multiple
%   concatenated PSDUs. It can be a double or int8 typed binary vector.
%   Alternatively, it can be a scalar cell array or a vector cell array
%   with length equal to number of users. Each element of the cell array
%   must be a double or int8 typed, binary vector. When DATA is a vector or
%   scalar cell array, it applies to all users. When DATA is a vector cell
%   array, each element applies to a single user. For each user, the bit
%   vector applied is looped if the number of bits required across all
%   packets of the generation exceeds the length of the vector provided.
%   This allows a short pattern to be entered, e.g. [1;0;0;1]. This pattern
%   will be repeated as the input to the PSDU coding across packets and
%   users. The number of data bits taken from a data stream for the ith
%   user when generating a packet is given by the ith element of the
%   CFGFORMAT.PSDULength property times eight.
%
%   CFGFORMAT is a format configuration object of type <a href="matlab:help('wlanVHTConfig')">wlanVHTConfig</a>, 
%   <a href="matlab:help('wlanHTConfig')">wlanHTConfig</a>, or <a href="matlab:help('wlanNonHTConfig')">wlanNonHTConfig</a>. The format of the generated waveform 
%   is determined by the type of CFGFORMAT. The properties of CFGFORMAT are
%   used to parameterize the packets generated including the data rate and
%   PSDU length.
% 
%   WAVEFORM = wlanWaveformGenerator(DATA,CFGFORMAT,Name,Value) specifies
%   additional name-value pair arguments described below. When a name-value
%   pair is not specified, its default value is used.
%   
%   'NumPackets'               The number of packets to generate. It must
%                              be a positive integer. The default value is
%                              1.
%   
%   'IdleTime'                 The length in seconds of an idle period
%                              after each generated packet. It must be 0 or
%                              greater than or equal to 2e-6 seconds. The
%                              default value is 0 seconds.
% 
%   'ScramblerInitialization'  Scrambler initial state(s), applied for OFDM
%                              based formats. It must be a double or
%                              int8-typed scalar or matrix containing
%                              integer values between 1 and 127 inclusive.
%                              If a scalar is provided all packets are
%                              initialized with the same state for all
%                              users. Specifying a matrix allows a
%                              different initial state to be used per user
%                              and per packet. Each column specifies the
%                              initial states for a single user. If a
%                              single column is provided, the same initial
%                              states will be used for all users. Each row
%                              represents the initial state of each packet
%                              to generate. Internally the rows are looped
%                              if the number of packets to generate exceeds
%                              the number of rows of the matrix provided.
%                              The default value is 93, which is the
%                              example state given in IEEE Std 802.11-2012
%                              Section L.1.5.2.
% 
%   'WindowTransitionTime'     The windowing transition length in seconds,
%                              applied to OFDM based formats. It must be a
%                              nonnegative scalar and no greater than
%                              16e-6 seconds. Specifying it as 0 turns off
%                              windowing. The default value is 1e-7
%                              seconds.
%   Examples:
%
%   Example 1:
%       %  Generate a time domain signal txWaveform for an 802.11ac VHT
%       %  transmission with 10 packets and 20 microsecond idle period 
%       %  between packets.
%
%       numPkts = 10;                   % 10 packets in the waveform
%      
%       cfgVHT = wlanVHTConfig();       % Create format configuration
%       % Change properties from defaults
%       cfgVHT.NumTransmitAntennas = 2; % 2 transmit antennas
%       cfgVHT.NumSpaceTimeStreams = 2; % 2 spatial streams
%       cfgVHT.MCS = 1;                 % Modulation: QPSK Rate: 1/2 
%       cfgVHT.APEPLength = 1024;       % A-MPDU length in bytes
%
%       % Create bit vector containing concatenated PSDUs
%       numBits = cfgVHT.PSDULength*8*numPkts;
%       dataBits = randi([0 1],numBits,1);
%
%       txWaveform = wlanWaveformGenerator(dataBits, cfgVHT, ...
%           'NumPackets', numPkts, 'IdleTime', 20e-6, ...
%           'WindowTransitionTime', 1e-7);
%
%   Example 2:
%       %  Produce a waveform containing a single 802.11a packet without 
%       %  any windowing.
%          
%       cfgNonHT = wlanNonHTConfig(); % Create format configuration
%
%       psdu = randi([0 1], cfgNonHT.PSDULength*8, 1); % Create a PSDU
%
%       txWaveform = wlanWaveformGenerator(psdu, cfgNonHT, ...
%           'WindowTransitionTime', 0);  % Disable windowing
%
%   See also wlanVHTConfig, wlanHTConfig, wlanNonHTConfig, wlanS1GConfig.

%   Copyright 2015-2016 The MathWorks, Inc.

%#codegen

% Check number of input arguments
coder.internal.errorIf((nargin ~= 3) && mod(nargin, 2) == 1, ...
    'wlan:wlanWaveformGenerator:InvalidNumInputs');

% Validate the format configuration object is a valid type
validateattributes(cfgFormat, ...
    {'wlanVHTConfig','wlanHTConfig','wlanNonHTConfig','wlanS1GConfig'}, ...
    {'scalar'}, mfilename, 'format configuration object');
s = validateConfig(cfgFormat);
inDSSSMode = isa(cfgFormat,'wlanNonHTConfig') && ...
    strcmpi(cfgFormat.Modulation,'DSSS');

% Set maximum limits for windowing transition time based on bandwidth and
% format for the validity check performed later.
maxWinTransitTime = 6.4e-6;         % default
maxWinTransitTimeStr = '6.4e-06';   % string for codegen
switch class(cfgFormat)
    case 'wlanNonHTConfig'
        if strcmpi(cfgFormat.Modulation, 'OFDM')
            switch cfgFormat.ChannelBandwidth
                case 'CBW5'
                    maxWinTransitTime = 6.4e-6; % seconds
                    maxWinTransitTimeStr = '6.4e-06'; 
                case 'CBW10'
                    maxWinTransitTime = 3.2e-6; % seconds
                    maxWinTransitTimeStr = '3.2e-06'; 
                otherwise  % 'CBW20'
                    maxWinTransitTime = 1.6e-6; % seconds
                    maxWinTransitTimeStr = '1.6e-06'; 
            end
        end
    case 'wlanS1GConfig'
        maxWinTransitTime = 16e-6; % seconds
        maxWinTransitTimeStr = '16e-06';
    otherwise % HT/VHT
        maxWinTransitTime = 1.6e-6; % seconds
        maxWinTransitTimeStr = '1.6e-06'; % default
end

if nargin == 3 % wlanGeneratorConfig
    cfgWaveGen = varargin{1};
    % Validate the waveform generator config object is the correct type
    validateattributes(cfgWaveGen, {'wlanGeneratorConfig'}, {'scalar'}, ...
       mfilename, 'waveform generator configuration object');
    numPackets     = cfgWaveGen.NumPackets;
    idleTime       = cfgWaveGen.IdleTime;
    scramblerInit  = cfgWaveGen.ScramblerInitialization;
    winTransitTime = cfgWaveGen.WindowTransitionTime;
    windowing      = (~inDSSSMode) && (cfgWaveGen.Windowing) && (winTransitTime > 0);
    coder.internal.errorIf(windowing && (winTransitTime > maxWinTransitTime), ...
                'wlan:wlanWaveformGenerator:ExceededMaxTransitionTime', ...
                maxWinTransitTimeStr);
else % P-V pairs
    % Define default P-V pair values
    numPackets     = 1;
    idleTime       = 0;
    scramblerInit  = 93;
    winTransitTime = 1e-7;
    
    % Validate each P-V pair
    for i = 3:2:nargin
        prop = varargin{i-2};
        val  = varargin{i-1};
        
        coder.internal.errorIf(~ischar(prop) || ...
            ~any(strcmp(prop, {'NumPackets', 'IdleTime', ...
            'ScramblerInitialization', 'WindowTransitionTime'})), ...
            'wlan:wlanWaveformGenerator:InvalidProperty');
        
        switch prop
          case 'NumPackets'
            validateattributes(val,{'numeric'},{'scalar','integer','>=',0}, ...
                mfilename,'''NumPackets'' value');
            numPackets = val;
          case 'IdleTime'
            validateattributes(val,{'numeric'}, ...
                {'scalar','real','>=',0},mfilename,'''IdleTime'' value');
            coder.internal.errorIf((val > 0) && (val < 2e-6), ...
                'wlan:wlanWaveformGenerator:InvalidIdleTimeValue');
            idleTime = val;
          case 'ScramblerInitialization'
            if ~inDSSSMode
                validateattributes(val,{'double','int8'}, ...
                    {'real','integer','2d','nonempty','>=',1,'<=',127}, ...
                    mfilename,'''ScramblerInitialization'' value');
            end
            scramblerInit = val;
          otherwise % 'WindowTransitionTime'
            if ~inDSSSMode
                validateattributes(val, {'numeric'}, ...
                    {'real','scalar','>=',0,'<=',maxWinTransitTime}, ...
                     mfilename,'''WindowTransitionTime'' value');
            end
            winTransitTime = val;
        end
    end
    windowing = (~inDSSSMode) && (winTransitTime > 0);
end

if isa(cfgFormat,'wlanVHTConfig') || isa(cfgFormat,'wlanS1GConfig')
    numUsers = cfgFormat.NumUsers;
else
    numUsers = 1;
end

% Cross validation
coder.internal.errorIf( ...
    all(size(scramblerInit, 2) ~= [1 numUsers]), ...
    'wlan:wlanWaveformGenerator:ScramInitNotMatchNumUsers');

% Validate that data bits are present if PSDULength is nonzero
if iscell(dataBits) % SU and MU
    % Data must be a scalar cell or a vector cell of length Nu
    coder.internal.errorIf(~isvector(dataBits) || ...
        all(length(dataBits) ~= [1 numUsers]), ...
        'wlan:wlanWaveformGenerator:InvalidDataCell');
    
    for u = 1:length(dataBits)
        if ~isempty(dataBits{u}) && any(cfgFormat.PSDULength > 0) % Data packet
            validateattributes(dataBits{u}, {'double','int8'}, ...
                {'real','integer','vector','binary'}, ...
                mfilename, 'each element in cell data input');
        else
            % Empty data check if not NDP
            coder.internal.errorIf( ...
                any(cfgFormat.PSDULength > 0) && isempty(dataBits{u}), ...
                'wlan:wlanWaveformGenerator:NoData');
        end
    end
    if (numUsers > 1) && isscalar(dataBits) 
        % Columnize and expand to a [1 Nu] cell
        dataCell = repmat({int8(dataBits{1}(:))}, 1, numUsers);
    else % Columnize each element
        dataCell = repmat({int8(1)}, 1, numUsers); 
        for u = 1:numUsers                
            dataCell{u} = int8(dataBits{u}(:));
        end
    end
else % SU and MU: Data must be a vector
    if ~isempty(dataBits) && any(cfgFormat.PSDULength > 0) % Data packet
        validateattributes(dataBits, {'double','int8'}, ...
            {'real','integer','vector','binary'}, ...
            mfilename, 'Data input');

        % Columnize and expand to a [1 Nu] cell
        dataCell = repmat({int8(dataBits(:))}, 1, numUsers);
    else % NDP
        % Empty data check if not NDP
        coder.internal.errorIf(any(cfgFormat.PSDULength > 0) && isempty(dataBits), ...
            'wlan:wlanWaveformGenerator:NoData');

        dataCell = {int8(dataBits(:))};
    end
end

% Number of bits in a PSDU for a single packet (convert bytes to bits)
numPSDUBits = cfgFormat.PSDULength*8;

% Repeat to provide initial state(s) for all users and packets
scramInit = repmat(scramblerInit, 1, ...
    numUsers/size(scramblerInit, 2)); % For all users
pktScramInit = scramInit(mod((0:numPackets-1).', size(scramInit, 1))+1, :);

% Get the sampling rate of the waveform
if inDSSSMode % DSSS format
    sr = 11e6;
    numTxAnt = 1;
    giType = ''; % for codegen
    FFTLen = 0;  % for codegen
    info = wlan.internal.dsssInfo(cfgFormat);
    numPktSamples = info.NumPPDUSamples;

    lstf = []; % for codegen
    lltf = []; % for codegen
    lsig = []; % for codegen
else % OFDM format
    chanBW = cfgFormat.ChannelBandwidth;
    sr = wlan.internal.cbwStr2Num(chanBW)*1e6;
    switch class(cfgFormat)
        case 'wlanNonHTConfig'
            giType = 'Long';  % Always
            FFTLen = 64;
        case 'wlanS1GConfig'
            giType = cfgFormat.GuardInterval;
            FFTLen = (sr/2e6)*64;
        otherwise % For VHT/HT formats
            giType = cfgFormat.GuardInterval;
            FFTLen = (sr/20e6)*64;
    end
    if (strcmp(chanBW, 'CBW10') || strcmp(chanBW, 'CBW5'))
        numTxAnt = 1;  % override and set to 1 only, for 802.11j/p
    else
        numTxAnt = cfgFormat.NumTransmitAntennas;
    end
    numPktSamples = real(s.NumPPDUSamples); % real for codegen

    % Generate the legacy preamble fields for applicable formats
    if ~isa(cfgFormat, 'wlanS1GConfig')
        lstf = wlanLSTF(cfgFormat);
        lltf = wlanLLTF(cfgFormat);
        lsig = wlanLSIG(cfgFormat);
    end
end

if isa(cfgFormat, 'wlanVHTConfig') % VHT format
    % VHT Format
    vhtsiga = wlanVHTSIGA(cfgFormat);
    vhtstf = wlanVHTSTF(cfgFormat);
    vhtltf = wlanVHTLTF(cfgFormat);
    vhtsigb = wlanVHTSIGB(cfgFormat);
    preamble = [lstf; lltf; lsig; vhtsiga; vhtstf; vhtltf; vhtsigb];

elseif isa(cfgFormat, 'wlanHTConfig') % HT-MF format

    htSig = wlanHTSIG(cfgFormat);
    htstf = wlanHTSTF(cfgFormat);
    htltf = wlanHTLTF(cfgFormat);
    preamble = [lstf; lltf; lsig; htSig; htstf; htltf];

elseif isa(cfgFormat, 'wlanNonHTConfig')

    if strcmp(cfgFormat.Modulation, 'OFDM')
        preamble = [lstf; lltf; lsig];
    else % DSSS
        preamble = [wlan.internal.wlanDSSSPreamble(cfgFormat); ...
            wlan.internal.wlanDSSSHeader(cfgFormat)];
    end
    
elseif isa(cfgFormat, 'wlanS1GConfig')
    if isS1G1MConfig(cfgFormat) || isS1GShortConfig(cfgFormat)
        stf = wlan.internal.s1gSTF(cfgFormat);
        [ltf1, ltf2n] = wlan.internal.s1gLTF(cfgFormat);
        sig = wlan.internal.s1gSIG(cfgFormat);
        preamble = [stf; ltf1; sig; ltf2n];
    else % Preamble == 'Long'
        stf = wlan.internal.s1gSTF(cfgFormat);
        ltf1 = wlan.internal.s1gLTF1(cfgFormat);
        siga = wlan.internal.s1gSIGA(cfgFormat);
        dstf = wlan.internal.s1gDSTF(cfgFormat);
        dltf = wlan.internal.s1gDLTF(cfgFormat);
        sigb = wlan.internal.s1gSIGB(cfgFormat);
        preamble = [stf; ltf1; siga; dstf; dltf; sigb];
    end
end

if windowing
    % Calculate parameters for windowing

    % IdleSample offset due to windowing 
    wlength = 2*ceil(winTransitTime*sr/2);
    bLen = wlength/2; % Number of samples overlap at end of packet
    aLen = bLen-1;    % Number of samples overlap at start of packet
    
    windowedPktLength = numPktSamples+wlength-1;
else    
    % Define unused windowing variables for codegen
    wlength = 0;
    windowedPktLength = numPktSamples+wlength-1;
    aLen = 0;
    bLen = 0;
end

% Define a matrix of total simulation length
numIdleSamples = round(sr*idleTime);
pktWithIdleLength = numPktSamples+numIdleSamples;
txWaveform = complex(zeros(numPackets*pktWithIdleLength,numTxAnt));

for i = 1:numPackets
    % Extract PSDU for the current packet
    psdu = getPSDUForCurrentPacket(dataCell, numPSDUBits, i);
    
    % Generate the PSDU with the correct scrambler initial state
    if  isa(cfgFormat, 'wlanVHTConfig')
        if any(cfgFormat.APEPLength > 0)
            data = wlanVHTData(psdu, cfgFormat, pktScramInit(i, :));
        else  % NDP
            data = complex(zeros(0, cfgFormat.NumTransmitAntennas));
        end
    elseif isa(cfgFormat, 'wlanHTConfig') % HT-MF format
        if cfgFormat.PSDULength > 0                    
            data = wlanHTData(psdu{1}, cfgFormat, pktScramInit(i, :));
        else  % NDP or sounding packet
            data = complex(zeros(0, cfgFormat.NumTransmitAntennas));
        end
    elseif isa(cfgFormat, 'wlanNonHTConfig') % NonHT format
        if strcmp(cfgFormat.Modulation, 'OFDM')
            data = wlanNonHTData(psdu{1}, cfgFormat, pktScramInit(i, :));
        else % DSSS
            data = wlan.internal.wlanDSSSData(psdu{1}, cfgFormat);
        end
    elseif isa(cfgFormat, 'wlanS1GConfig') % S1G format
        data = wlan.internal.s1gData(psdu, cfgFormat, pktScramInit(i, :));
    end

    % Construct packet from preamble and data
    packet = [preamble; data]; 

    if windowing
        if isa(cfgFormat, 'wlanS1GConfig') && strcmp(cfgFormat.GuardInterval, 'Short')
            % For S1G the first data symbol is always Long GI
            numSamplesSymbol = 40e-6*sr; %40 us from Table 24.4 IEEE P802.11ah/D5.0
            numSamplesBeforeShortGI = size(preamble,1)+numSamplesSymbol;
        else
            % For other formats short GI begins after the preamble
            numSamplesBeforeShortGI = size(preamble,1);
        end
        
        % Window each packet
         windowedPacket = wlan.internal.wlanWindowing(packet, FFTLen, ...
             wlength, giType, numSamplesBeforeShortGI);

        % Overlap-add the windowed packets
        if numPackets==1 && numIdleSamples==0 % Only one packet which wraps     
            txWaveform = windowedPacket(aLen+(1:numPktSamples), :);
            % Overlap start of packet with end
            txWaveform(1:bLen, :) = txWaveform(1:bLen, :)+ ...
                windowedPacket(end-bLen+1:end, :);
            % Overlap end of packet with start
            txWaveform(end-aLen+1:end, :) = txWaveform(end-aLen+1:end, :)+ ...
                windowedPacket(1:aLen, :);
        else
            if i==1 % First packet (which wraps)
                % First packet wraps to end of waveform
                txWaveform(1:(numPktSamples+bLen), :) = ...
                    windowedPacket(1+aLen:end, :);
                txWaveform(end-aLen+1:end, :) = windowedPacket(1:aLen, :);
            elseif i==numPackets && numIdleSamples==0 % Last packet which wraps
                % Last packet wraps to start of waveform
                startIdx = (i-1)*pktWithIdleLength-aLen+1;
                txWaveform(startIdx:end, :) = txWaveform(startIdx:end, :)+ ...
                    windowedPacket(1:end-bLen, :);
                txWaveform(1:bLen,:) = txWaveform(1:bLen, :)+ ...
                    windowedPacket(end-bLen+1:end, :);
            else % Packet does not wrap
                % Normal windowing overlap between packets
                idx = (i-1)*pktWithIdleLength-aLen+(1:windowedPktLength);
                txWaveform(idx, :) = txWaveform(idx, :)+windowedPacket;
            end
       end
    else
        % Construct entire waveform
        txWaveform((i-1)*pktWithIdleLength+(1:numPktSamples), :) = packet;
    end
end
end

function psdu = getPSDUForCurrentPacket(dataCell, numPSDUBitsPerPacket, ...
    packetIdx)
    numUsers = length(dataCell); % == length(numPSDUBits)
    psdu = repmat({int8(1)}, 1, numUsers); % Cannot use cell(1, numUsers) for codegen
    for u = 1:numUsers
        idx = mod((packetIdx-1)*numPSDUBitsPerPacket(u)+...
            (0:numPSDUBitsPerPacket(u)-1).', length(dataCell{u})) + 1;
        psdu{u} = dataCell{u}(idx);
    end
end

% [EOF]