gusucode.com > wlan工具箱matlab源码程序 > wlan/wlan/wlanVHTDataRecover.m
function [bits, CRCBits, eqDataSym, varargout] = wlanVHTDataRecover( ... rxVHTData, chanEst, noiseVarEst, cfgVHT, varargin) %WLANVHTDATARECOVER Recover bits from VHT Data field signal % % [BITS, CRCBITS] = wlanVHTDataRecover(RXVHTDATA, CHANEST, NOISEVAREST, % CFGVHTSU) recovers the bits in the VHT-Data field for a VHT format % single-user transmission. % % BITS is an int8 column vector of length 8*CFGVHT.PSDULength containing % the recovered information bits. % % CRCBITS is an int8 column vector of length 8 containing the VHT-Data % field checksum bits. % % RXVHTDATA is the received time-domain VHT Data field signal, specified % as an Ns-by-Nr matrix of real or complex values. Ns represents the % number of time-domain samples in the VHT Data field and Nr represents % the number of receive antennas. Ns can be greater than the VHT Data % field length; in this case additional samples at the end of RXVHTDATA % are not used. % % CHANEST is the estimated channel at data and pilot subcarriers based on % the VHT-LTF. It is an array of size Nst-by-Nsts-by-Nr, where Nst % represents the total number of occupied subcarriers, Nsts represents % the total number of space-time streams used for the transmission and Nr % is the number of receive antennas. % % NOISEVAREST is the noise variance estimate. It is a nonnegative scalar. % % CFGVHTSU is the format configuration object of type <a % href="matlab:help('wlanVHTConfig')">wlanVHTConfig</a>, which % specifies the parameters for the single-user VHT format. % % [BITS, CRCBITS] = wlanVHTDataRecover(RXVHTDATA, CHANEST, NOISEVAREST, % CFGVHTMU, USERNUMBER) recovers the bits in the VHT-Data field of a VHT % format multi-user transmission for an individual user of interest. % % CFGVHTMU is the VHT format configuration for a multi-user transmission, % specified as a <a href="matlab:help('wlanVHTConfig')">wlanVHTConfig</a> object. % % USERNUMBER is the user of interest, specified as an integer between 1 % and NumUsers, where NumUsers is the number of users in the % transmission. % % [BITS, CRCBITS] = wlanVHTDataRecover(RXVHTDATA, CHANEST, NOISEVAREST, % CFGVHTSU, USERNUMBER, NUMSTS) recovers the bits in the VHT-Data field % of a VHT format multi-user transmission for an individual user of % interest. % % CFGVHTSU is the VHT format configuration for the user of interest, % specified as a <a href="matlab:help('wlanVHTConfig')">wlanVHTConfig</a> object. % % NUMSTS is the number of space-time streams, specified as a % 1-by-NumUsers vector. Element values specify the number of space-time % streams per user. % % [BITS, CRCBITS] = wlanVHTDataRecover(..., CFGREC) allows different % algorithm options for data recovery via the input CFGREC, which is a % <a href="matlab:help('wlanRecoveryConfig')">wlanRecoveryConfig</a> configuration object. When the CFGREC input is not % specified, the default property values of the <a href="matlab:help('wlanRecoveryConfig')">wlanRecoveryConfig</a> object % are adopted in the recovery. % % [..., EQDATASYM, CPE] = wlanVHTDataRecover(...) also returns the % equalized subcarriers and common phase error. % % EQDATASYM is a complex Nsd-by-Nsym-by-Nss array containing the % equalized symbols at data carrying subcarriers. Nsd represents the % number of data subcarriers, Nsym represents the number of OFDM symbols % in the VHT-Data field, and Nss represents the number of spatial % streams assigned to the user. % % CPE is a column vector of length Nsym containing the common phase error % between each received and expected OFDM symbol. % % Example: % % Recover bits in VHT Data field via channel estimation on VHT-LTF % % over a 2 x 2 quasi-static fading channel % % % Configure a VHT configuration object % chanBW = 'CBW160'; % cfgVHT = wlanVHTConfig('ChannelBandwidth', chanBW, ... % 'NumTransmitAntennas', 2, 'NumSpaceTimeStreams', 2, ... % 'APEPLength', 512); % % % Generate VHT-LTF and VHT Data field signals % txDataBits = randi([0 1], 8*cfgVHT.PSDULength, 1); % txVHTLTF = wlanVHTLTF(cfgVHT); % txVHTData = wlanVHTData(txDataBits, cfgVHT); % % % Pass through a 2 x 2 quasi-static fading channel with AWGN % H = 1/sqrt(2)*complex(randn(2, 2), randn(2, 2)); % rxVHTLTF = awgn(txVHTLTF * H, 10); % rxVHTData = awgn(txVHTData * H, 10); % % % Perform channel estimation based on VHT-LTF % demodVHTLTF = wlanVHTLTFDemodulate(rxVHTLTF, cfgVHT, 1); % chanEst = wlanVHTLTFChannelEstimate(demodVHTLTF, cfgVHT); % % % Configure a recovery object using ZF equalization % cfgRec = wlanRecoveryConfig('EqualizationMethod', 'ZF'); % % % Recover information bits in VHT Data % rxDataBits = wlanVHTDataRecover(rxVHTData, chanEst, 0.1, ... % cfgVHT, cfgRec); % % % Compare against original information bits % disp(isequal(txDataBits, rxDataBits)); % % See also wlanVHTConfig, wlanRecoveryConfig, wlanVHTData, wlanVHTLTF, % wlanVHTLTFDemodulate, wlanVHTLTFChannelEstimate. % Copyright 2015-2016 The MathWorks, Inc. %#codegen %#ok<*EMCA> narginchk(4,7); nargoutchk(0,4); % Calculate CPE if requested if nargout>3 calculateCPE = true; else calculateCPE = false; end % VHT configuration input self-validation validateattributes(cfgVHT, {'wlanVHTConfig'}, {'scalar'}, ... mfilename, 'VHT format configuration object'); % Optional parameter and case determination - with cfgRec last if nargin == 7 % (..., cfgVHTSU, userNum, numSTS, cfgRec) cfgRecSpec = true; cfgRec = varargin{3}; muSpec = 2; userNum = varargin{1}; numSTSVec = varargin{2}; elseif nargin == 6 if isa(varargin{2}, 'wlanRecoveryConfig') % (..., cfgVHTMU, userNum, cfgRec) cfgRecSpec = true; cfgRec = varargin{2}; muSpec = 1; userNum = varargin{1}; else % (..., cfgVHTSU, userNum, numSTS) cfgRecSpec = false; muSpec = 2; userNum = varargin{1}; numSTSVec = varargin{2}; end elseif nargin == 5 if isa(varargin{1}, 'wlanRecoveryConfig') % (..., cfgVHTSU, cfgRec) cfgRecSpec = true; cfgRec = varargin{1}; muSpec = 0; else % (..., cfgVHTMU, userNum) cfgRecSpec = false; muSpec = 1; userNum = varargin{1}; end else % 4 (..., cfgVHTSU) cfgRecSpec = false; muSpec = 0; end % Validate optional inputs if muSpec==2 % SU CFGVHT validateattributes(userNum, {'numeric'}, ... {'real','integer','scalar','>=',1,'<=',4}, mfilename, 'USERNUMBER'); wlan.internal.validateParam('NUMSTS', numSTSVec, mfilename); % If UserNum>1, numSTSVec must be a vector coder.internal.errorIf(userNum > length(numSTSVec), ... 'wlan:wlanVHTDataRecover:InvalidUserNum', length(numSTSVec)); propIdx = 1; % Have a SU cfgVHT object numSTSu = numSTSVec(userNum); elseif muSpec==1 % MU CFGVHT validateattributes(userNum, {'numeric'}, ... {'real','integer','scalar','>=',1,'<=',cfgVHT.NumUsers}, ... mfilename, 'USERNUMBER'); % Have a MU cfgVHT object as input numSTSVec = cfgVHT.NumSpaceTimeStreams; propIdx = userNum; numSTSu = numSTSVec(propIdx); else % not specified, set defaults % Single-user case userNum = 1; propIdx = 1; numSTSVec = cfgVHT.NumSpaceTimeStreams; numSTSu = numSTSVec(propIdx); end if cfgRecSpec validateattributes(cfgRec, {'wlanRecoveryConfig'}, {'scalar'}, ... mfilename, 'recovery configuration object'); symOffset = cfgRec.OFDMSymbolOffset; pilotPhaseTracking = cfgRec.PilotPhaseTracking; eqMethod = cfgRec.EqualizationMethod; maxLDPCIterationCount = cfgRec.MaximumLDPCIterationCount; earlyTermination = cfgRec.EarlyTermination; else % set defaults symOffset = 0.75; pilotPhaseTracking = 'PreEQ'; eqMethod = 'MMSE'; maxLDPCIterationCount = 12; earlyTermination = false; end cfgInfo = validateConfig(cfgVHT, 'MCS'); mcsTable = wlan.internal.getRateTable(cfgVHT); chanBW = cfgVHT.ChannelBandwidth; % NDP only for SU, so idx is (1) if cfgVHT.APEPLength(1) == 0 bits = zeros(0, 1, 'int8'); CRCBits = zeros(0, 1, 'int8'); eqDataSym = zeros(mcsTable.NSD(1), 0, mcsTable.Nss(1)); if calculateCPE==true varargout{1} = []; % CPE end return; end % All optional params: parsed and validated numSTSTotal = sum(numSTSVec); % Signal input self-validation validateattributes(rxVHTData, {'double'}, {'2d','finite'}, ... 'rxVHTData', 'VHT-Data field signal'); validateattributes(chanEst, {'double'}, {'3d','finite'}, ... 'chanEst', 'channel estimation'); validateattributes(noiseVarEst, {'double'}, ... {'real','scalar','nonnegative','finite'}, ... 'noiseVarEst', 'noise variance estimation'); % Set up some implicit configuration parameters numBPSCS = mcsTable.NBPSCS(propIdx); % Number of coded bits per single carrier numCBPS = mcsTable.NCBPS(propIdx); % Number of coded bits per OFDM symbol numDBPS = mcsTable.NDBPS(propIdx); rate = mcsTable.Rate(propIdx); numES = mcsTable.NES(propIdx); % Number of encoded streams numSS = mcsTable.Nss(propIdx); % Number of spatial streams numSeg = strcmp(chanBW, 'CBW160') + 1; % Number of coded bits per OFDM symbol, per spatial stream, per segment numCBPSSI = numCBPS/numSS/numSeg; numRx = size(rxVHTData, 2); % Get OFDM configuration [cfgOFDM, dataInd, pilotInd] = wlan.internal.wlanGetOFDMConfig(chanBW, ... cfgVHT.GuardInterval, 'VHT', numSTSTotal); % Set channel coding coder.varsize('channelCoding',[1,4]); channelCoding = getChannelCoding(cfgVHT); % Cross-validation between inputs if muSpec==2 coder.internal.errorIf(cfgVHT.NumSpaceTimeStreams(1) ~= numSTSu, ... 'wlan:wlanVHTDataRecover:InvalidNumSTS', numSTSu, cfgVHT.NumSpaceTimeStreams(1)); end coder.internal.errorIf(cfgVHT.STBC && muSpec > 0, ... 'wlan:wlanVHTDataRecover:InvalidSTBCMU'); numST = numel([dataInd; pilotInd]); % Total number of occupied subcarriers coder.internal.errorIf(size(chanEst, 1) ~= numST, ... 'wlan:wlanVHTDataRecover:InvalidChanEst1D', numST); coder.internal.errorIf(size(chanEst, 2) ~= numSTSTotal, ... 'wlan:wlanVHTDataRecover:InvalidChanEst2D', numSTSTotal); coder.internal.errorIf(size(chanEst, 3) ~= numRx, ... 'wlan:wlanVHTDataRecover:InvalidChanEst3D'); % Extract data and pilot subcarriers from channel estimate chanEstData = chanEst(dataInd,:,:); chanEstPilots = chanEst(pilotInd,:,:); % Cross-validation between inputs numOFDMSym = cfgInfo.NumDataSymbols; minInputLen = numOFDMSym*(cfgOFDM.FFTLength+cfgOFDM.CyclicPrefixLength); coder.internal.errorIf(size(rxVHTData, 1) < minInputLen, ... 'wlan:wlanVHTDataRecover:ShortDataInput', minInputLen); numOFDMSym = length(rxVHTData)/(cfgOFDM.FFTLength+cfgOFDM.CyclicPrefixLength); % OFDM demodulation [ofdmDemodData, ofdmDemodPilots] = wlan.internal.wlanOFDMDemodulate( ... rxVHTData, cfgOFDM, symOffset); % Index into streams for the user of interest stsIdx = sum(numSTSVec(1:(userNum-1)))+(1:numSTSu); % Pilot phase tracking if calculateCPE==true || strcmp(pilotPhaseTracking, 'PreEQ') % Get reference pilots, from Eqn 22-95, IEEE Std 802.11ac-2013 % Offset by 4 to allow for L-SIG, VHT-SIG-A, VHT-SIG-B pilot symbols n = (0:numOFDMSym-1).'; z = 4; refPilots = wlan.internal.vhtPilots(n, z, chanBW, sum(numSTSVec)); % Estimate CPE and phase correct symbols cpe = wlan.internal.commonPhaseErrorEstimate(ofdmDemodPilots, ... chanEstPilots(:,stsIdx,:), refPilots(:,:,stsIdx)); if strcmp(pilotPhaseTracking, 'PreEQ') ofdmDemodData = wlan.internal.commonPhaseErrorCorrect(... ofdmDemodData, cpe); end if calculateCPE==true varargout{1} = cpe.'; % Permute to Nsym-by-1 end end % Equalization if cfgVHT.STBC % Only SU [eqDataSym, dataCSI] = wlan.internal.wlanSTBCCombine(ofdmDemodData, ... chanEstData, numSS, eqMethod, noiseVarEst); else % Both SU and MU [eqDataSym, dataCSI] = wlan.internal.wlanEqualize(ofdmDemodData, ... chanEstData(:,stsIdx,:), eqMethod, noiseVarEst); end % Segment deparsing % [Nsd/Nseg Nsym Nss Nseg] parserOut = wlan.internal.wlanSegmentDeparser(eqDataSym, chanBW, 'Rx'); % [Nsd/Nseg 1 Nss Nseg] csiParserOut = wlan.internal.wlanSegmentDeparser( ... reshape(dataCSI, [], 1, numSS), chanBW, 'Rx'); deintlvrOut = zeros(numCBPSSI*numOFDMSym, numSS, numSeg); chBW = wlan.internal.cbwStr2Num(chanBW); % Constellation demapping and deinterleaving per segment for segIdx = 1 : numSeg if strcmp(channelCoding{propIdx},'LDPC') mappingIndicesLDPC = wlan.internal.getToneMappingIndices(chanBW); % Tone derotation in LDPC parserOut(mappingIndicesLDPC,:,:,segIdx) = parserOut(:,:,:,segIdx); end qamDemodOut = wlan.internal.wlanConstellationDemodulate( ... parserOut(:,:,:,segIdx), numBPSCS, noiseVarEst); % [Nbpscs*Nsd/Nseg Nsym Nss] qamDemodOut = bsxfun(@times, ... reshape(qamDemodOut, numBPSCS, [], numOFDMSym, numSS), ... reshape(csiParserOut(:,:,:,segIdx), 1, [], 1, numSS)); % [Nbpscs Nsd/Nseg Nsym Nss] if strcmp(channelCoding{propIdx}, 'BCC') for symIdx = 1:numOFDMSym deintlvrOut((symIdx-1)*numCBPSSI+(1:numCBPSSI), :, segIdx) = ... wlan.internal.wlanBCCDeinterleave( ... reshape(real(qamDemodOut(:,:,symIdx,:)), [], numSS), ... 'VHT', numCBPSSI, numBPSCS, chBW, numSS); end else % Deinterleaving is not required for LDPC deintlvrOut(:, :, segIdx) = reshape(real(qamDemodOut), [], numSS); end end % Segment parsing segDeparserOut = wlan.internal.wlanSegmentParser(deintlvrOut, chanBW, ... numBPSCS, numCBPS, numES, 'Rx'); % Stream deparsing streamDeparserOut = wlan.internal.wlanStreamDeparser(segDeparserOut, ... numES, numBPSCS); if strcmp(channelCoding{propIdx}, 'BCC') % Channel decoding for BCC chanDecOut = zeros(round(size(streamDeparserOut, 1)*mcsTable.Rate(propIdx)), ... numES, 'int8'); numTailBits = 6; for nesIdx = 1 : numES chanDecOut(:, nesIdx) = wlan.internal.wlanBCCDecode(streamDeparserOut(:, nesIdx), ... mcsTable.Rate(propIdx)); end preDescramBits = reshape(chanDecOut(1:end-numTailBits,:)', [], 1); else % Channel decoding for LDPC % Calculate numSymMaxInit as specified in IEEE Std 802.11ac-2013, % Section 22.3.10.5.4, Eq 22-65 and Section 22.3.21, Eq 22-107 numSym = cfgInfo.NumDataSymbols(1); % Estimate number of OFDM symbols as specified in IEEE Std % 802.11ac-2013, Section 22.3.21, Eq 22-107. mSTBC = (cfgVHT.NumUsers == 1)*(cfgVHT.STBC ~= 0) + 1; numSymMaxInit = numSym - mSTBC*cfgInfo.ExtraLDPCSymbol; % Compute the number of payload bits as specified in IEEE Std % 802.11ac-2013, Section 22.3.10.5.4, Eq 22-61 and Eq 22-66. numPLD = numSymMaxInit*numDBPS; % LDPC decoding parameters as per IEEE Std 802.11-2012, Section % 20.3.11.17.4 and IEEE Std 802.11ac-2013, Section 22.3.10.5.4. cfg = wlan.internal.getLDPCparameters(numDBPS, rate, mSTBC, numPLD, numOFDMSym); preDescramBits = wlan.internal.wlanLDPCDecode(streamDeparserOut, cfg, ... maxLDPCIterationCount, earlyTermination); end % Descrambling with derived initial state scramInit = mod([preDescramBits(3:-1:1) + preDescramBits(7:-1:5); ... preDescramBits(4:-1:2) + preDescramBits(3:-1:1) + ... preDescramBits(7:-1:5); sum(preDescramBits([1 3 4 7]))]', 2); descramBits = wlan.internal.wlanScramble( ... preDescramBits(1:16+8*cfgVHT.PSDULength(propIdx)), scramInit); % Outputs CRCBits = descramBits(9:16); bits = descramBits(17:end); end % [EOF]