function [rxPSDU,bitErrorRate,eqSymPlot,evm] = heMURx(rx,cfg,userIdx,frameIdx,rxPSDU,cfgUI,SEED,bitErrorRate,eqSymPlot) % [rxPSDU,eqSymUser,csiData/csi,pktFormat,evm,cfoCorrection]=heMURx(rx,cfgMUMIMO,userIdx,cfgPara); % numBitError = 0; % wlan ug %% Setup Waveform Recovery Parameters % Perform synchronization with 11ac components chanBW = cfg.ChannelBandwidth; fs = wlanSampleRate(cfg); % Specify pilot tracking method for recovering the data field. This can be: % 'Joint' - use joint common phase error and sample rate offset tracking % 'CPE' - use only common phase error tracking % When recovering 26-tone RUs only CPE tracking is used as the joint % tracking algorithm is susceptible to noise. pilotTracking = 'Joint'; % Create an HE recovery configuration object and set the channel bandwidth cfgRx = wlanHERecoveryConfig; cfgRx.ChannelBandwidth = chanBW; % Get the field indices for extract fields from the PPDU % ind = wlanFieldIndices(cfg); ind = wlanFieldIndices(cfgRx); % % Setup plots for the example % [spectrumAnalyzer,timeScope,ConstellationDiagram,EVMPerSubcarrier,EVMPerSymbol] = heSigRecSetupPlots(fs); % Minimum packet length is 10 OFDM symbols % lstfLength = double(ind.LSTF(2)); % minPktLen = lstfLength*5; % Number of samples in L-STF rxWaveLen = size(rx,1); %% Front-End Processing searchOffset = 0; % Offset from start of waveform in samples % Packet detection coarsePktOffset = wlanPacketDetect(rx,chanBW,searchOffset,0.8); LSTF = wlanLSTF(wlanNonHTConfig); % if isempty(coarsePktOffset)||(coarsePktOffset + ind.LSIG(2) > rxWaveLen) % If empty no L-STF detected; packet error % numBitError = numBitError+numBits;%%??????????????? % userIdx = userIdx+1; % end % Coarse frequency offset estimation and correction using L-STF if isempty(coarsePktOffset) coarsePktOffset = 0; end rxLSTF = rx(coarsePktOffset+(ind.LSTF(1):ind.LSTF(2)), :); tmp_xcorr = abs(xcorr(LSTF,rxLSTF)); coarseFreqOffset = wlanCoarseCFOEstimate(rxLSTF,chanBW); rx = helperFrequencyOffset(rx,fs,-coarseFreqOffset); % Extract the non-HT fields and determine fine packet offset nonhtfields = rx(coarsePktOffset+(ind.LSTF(1):ind.LSIG(2)),:); finePktOffset = wlanSymbolTimingEstimate(nonhtfields,chanBW); % Determine final packet offset pktOffset = coarsePktOffset+finePktOffset; % if pktOffset>50%%????????????????????????????/// % % numPacketErrors(userIdx) = numPacketErrors(userIdx)+1; % numBitError = numBitError+numBits; % userIdx = userIdx+1; % % continue; % Go to next loop iteration % end % Extract L-LTF and perform fine frequency offset correction rxLLTF = rx(pktOffset+(ind.LLTF(1):ind.LLTF(2)),:); fineFreqOff = wlanFineCFOEstimate(rxLLTF,chanBW); rx = helperFrequencyOffset(rx,fs,-fineFreqOff); % Timing synchronization complete: packet detected fprintf('Packet detected at index %d\n',pktOffset + 1); % Display estimated carrier frequency offset cfoCorrection = coarseFreqOffset + fineFreqOff; % Total CFO fprintf('Estimated CFO: %5.1f Hz\n\n',cfoCorrection); if max(tmp_xcorr)>50 % Scale the waveform based on L-STF power (AGC) gain = 1./(sqrt(mean(rxLSTF.*conj(rxLSTF)))); rx = rx.*gain; %% Packet Format Detection rxLLTF = rx(pktOffset+(ind.LLTF(1):ind.LLTF(2)),:); lltfDemod = wlanLLTFDemodulate(rxLLTF,chanBW); lltfChanEst = wlanLLTFChannelEstimate(lltfDemod,chanBW); noiseVar = helperNoiseEstimate(lltfDemod); rxSIGA = rx(pktOffset+(ind.LSIG(1):ind.HESIGA(2)),:); pktFormat = wlanFormatDetect(rxSIGA,lltfChanEst,noiseVar,chanBW); fprintf(' %s packet detected\n\n',pktFormat); % Set the packet format in the recovery object and update the field indices cfgRx.PacketFormat = pktFormat; ind = wlanFieldIndices(cfgRx); %% L-LTF Channel Estimate lltfDemod = wlanHEDemodulate(rxLLTF,'L-LTF',chanBW); lltfChanEst = wlanLLTFChannelEstimate(lltfDemod,chanBW); %% L-SIG and RL-SIG Decoding % Extract L-SIG and RL-SIG fields rxLSIG = rx(pktOffset+(ind.LSIG(1):ind.RLSIG(2)),:); % OFDM demodulate helsigDemod = wlanHEDemodulate(rxLSIG,'L-SIG',chanBW); % Estimate CPE and phase correct symbols helsigDemod = preHECommonPhaseErrorTracking(helsigDemod,lltfChanEst,'L-SIG',chanBW); % Estimate channel on extra 4 subcarriers per subchannel and create full % channel estimate preheInfo = wlanHEOFDMInfo('L-SIG',chanBW); preHEChanEst = preHEChannelEstimate(helsigDemod,lltfChanEst,preheInfo.NumSubchannels); % Average L-SIG and RL-SIG before equalization helsigDemod = mean(helsigDemod,2); % Equalize data carrying subcarriers, merging 20 MHz subchannels [eqLSIGSym,csi] = preHESymbolEqualize(helsigDemod(preheInfo.DataIndices,:,:), ... preHEChanEst(preheInfo.DataIndices,:,:),noiseVar,preheInfo.NumSubchannels); % Decode L-SIG field [~,failCheck,lsigInfo] = wlanLSIGBitRecover(eqLSIGSym,noiseVar,csi); if failCheck disp(' ** L-SIG check fail **'); else disp(' L-SIG check pass'); end % Get the length information from the recovered L-SIG bits and update the % L-SIG length property of the recovery configuration object lsigLength = lsigInfo.Length; cfgRx.LSIGLength = lsigLength; % Measure EVM of L-SIG symbols EVM = comm.EVM; EVM.ReferenceSignalSource = 'Estimated from reference constellation'; EVM.Normalization = 'Average constellation power'; EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK'); rmsEVM = EVM(eqLSIGSym); evm = 20*log10(rmsEVM/100); fprintf(' L-SIG EVM: %2.2fdB\n\n',20*log10(rmsEVM/100)); % Calculate the receive time and corresponding number of samples in the % packet RXTime = ceil((lsigLength + 3)/3) * 4 + 20; % In microseconds numRxSamples = round(RXTime * 1e-6 * fs); % Number of samples in time %% HE-SIG-A Decoding rxSIGA = rx(pktOffset+(ind.HESIGA(1):ind.HESIGA(2)),:); sigaDemod = wlanHEDemodulate(rxSIGA,'HE-SIG-A',chanBW); hesigaDemod = preHECommonPhaseErrorTracking(sigaDemod,preHEChanEst,'HE-SIG-A',chanBW); % Equalize data carrying subcarriers, merging 20 MHz subchannels preheInfo = wlanHEOFDMInfo('HE-SIG-A',chanBW); [eqSIGASym,csi] = preHESymbolEqualize(hesigaDemod(preheInfo.DataIndices,:,:), ... preHEChanEst(preheInfo.DataIndices,:,:), ... noiseVar,preheInfo.NumSubchannels); % Recover HE-SIG-A bits [sigaBits,failCRC] = wlanHESIGABitRecover(eqSIGASym,noiseVar,csi); % Perform the CRC on HE-SIG-A bits if failCRC disp(' ** HE-SIG-A CRC fail **'); else disp(' HE-SIG-A CRC pass'); end % Measure EVM of HE-SIG-A symbols % release(EVM); % if strcmp(pktFormat,'HE-EXT-SU') % % The second symbol of an HE-SIG-A field for an HE-EXT-SU packet is % % QBPSK. % EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK',[0 pi/2 0 0]); % % Account for scaling of L-LTF for an HE-EXT-SU packet % rmsEVM = EVM(eqSIGASym*sqrt(2)); % else % EVM.ReferenceConstellation = wlanReferenceSymbols('BPSK'); % rmsEVM = EVM(eqSIGASym); % end % fprintf(' HE-SIG-A EVM: %2.2fdB\n\n',20*log10(mean(rmsEVM)/100)); %% Interpret Recovered HE-SIG-A bits cfgRx = interpretHESIGABits(cfgRx,sigaBits); ind = wlanFieldIndices(cfgRx); % Update field indices % disp(cfgRx) %% HE-SIG-B Decoding if strcmp(pktFormat,'HE-MU') if ~cfgRx.SIGBCompression s = getSIGBLength(cfgRx); % Get common field symbols. The start of HE-SIG-B field is known rxSym = rx(pktOffset+(ind.HESIGA(2)+(1:s.NumSIGBCommonFieldSamples)),:); % Decode HE-SIG-B common field [status,cfgRx] = heSIGBCommonFieldDecode(rxSym,preHEChanEst,noiseVar,cfgRx); % CRC on HE-SIG-B content channels if strcmp(status,'Success') fprintf(' HE-SIG-B (common field) CRC pass\n'); elseif strcmp(status,'ContentChannel1CRCFail') fprintf(' ** HE-SIG-B CRC fail for content channel-1\n **'); elseif strcmp(status,'ContentChannel2CRCFail') fprintf(' ** HE-SIG-B CRC fail for content channel-2\n **'); elseif any(strcmp(status,{'UnknownNumUsersContentChannel1','UnknownNumUsersContentChannel2'})) error(' ** Unknown packet length, discard packet\n **'); else % Discard the packet if all HE-SIG-B content channels fail error(' ** HE-SIG-B CRC fail **'); end % Update field indices as the number of HE-SIG-B symbols are % updated ind = wlanFieldIndices(cfgRx); end % Get complete HE-SIG-B field samples rxSIGB = rx(pktOffset+(ind.HESIGB(1):ind.HESIGB(2)),:); fprintf(' Decoding HE-SIG-B user field... \n'); % Decode HE-SIG-B user field [failCRC,cfgUsers] = heSIGBUserFieldDecode(rxSIGB,preHEChanEst,noiseVar,cfgRx); %*********************************03.22修改********************************* for ii = 1:numel(cfgUsers) if cfgUsers{ii}.STAID == userIdx user = cfgUsers{ii}; break; end end % user = cfgUsers{1}; %*********************************03.22修改********************************* % CRC on HE-SIG-B users if ~all(failCRC) fprintf(' HE-SIG-B (user field) CRC pass\n\n'); numUsers = numel(cfgUsers); elseif all(failCRC) % Discard the packet if all users fail the CRC error(' ** HE-SIG-B CRC fail for all users **'); else fprintf(' ** HE-SIG-B CRC fail for at least one user\n **'); % Only process users with valid CRC numUsers = numel(cfgUsers); end else % HE-SU, HE-EXT-SU cfgUsers = {cfgRx}; numUsers = 1; end %% HE-Data Decoding cfgDataRec = trackingRecoveryConfig; cfgDataRec.PilotTracking = pilotTracking; % Get recovery configuration object for each user user = cfgUsers{userIdx}; if strcmp(pktFormat,'HE-MU') fprintf(' Decoding User:%d, STAID:%d, RUSize:%d\n',userIdx,user.STAID,user.RUSize); else fprintf(' Decoding RUSize:%d\n',user.RUSize); end heInfo = wlanHEOFDMInfo('HE-Data',chanBW,user.GuardInterval,[user.RUSize user.RUIndex]); % HE-LTF demodulation and channel estimation rxHELTF = rx(pktOffset+(ind.HELTF(1):ind.HELTF(2)),:); heltfDemod = wlanHEDemodulate(rxHELTF,'HE-LTF',chanBW,user.GuardInterval, ... user.HELTFType,[user.RUSize user.RUIndex]); [chanEst,pilotEst] = heLTFChannelEstimate(heltfDemod,user); % Number of expected data OFDM symbols symLen = heInfo.FFTLength+heInfo.CPLength; numOFDMSym = (ind.HEData(2)-ind.HEData(1)+1)/symLen; numOFDMSym = double(numOFDMSym); % HE-Data demodulation with pilot phase and timing tracking % Account for extra samples when extracting data field from the packet % for sample rate offset tracking. Extra samples may be required if the % receiver clock is significantly faster than the transmitter. maxSRO = 120; % Parts per million Ne = ceil(numRxSamples*maxSRO*1e-6); % Number of extra samples Ne = min(Ne,rxWaveLen-numRxSamples); % Limited to length of waveform numRxSamplesProcess = numRxSamples+Ne; rxData = rx(pktOffset+(ind.HEData(1):numRxSamplesProcess),:); if user.RUSize==26 % Force CPE only tracking for 26-tone RU as algorithm susceptible % to noise cfgDataRec.PilotTracking = 'CPE'; else cfgDataRec.PilotTracking = pilotTracking; end [demodSym,cpe,peg] = heTrackingOFDMDemodulate(rxData,chanEst,numOFDMSym,user,cfgDataRec); % Estimate noise power in HE fields demodPilotSym = demodSym(heInfo.PilotIndices,:,:); nVarEst = heNoiseEstimate(demodPilotSym,pilotEst,user); % Equalize [eqSym,csi] = heEqualizeCombine(demodSym,chanEst,nVarEst,user); % Discard pilot subcarriers eqSymUser = eqSym(heInfo.DataIndices,:,:); csiData = csi(heInfo.DataIndices,:); eqSymPlot = eqSymUser(1:end); % scatterplot % eqSymplot = eqSymUser(1:end); % scatterplot(eqSymplot); % Demap and decode bits rxPSDUbits = wlanHEDataBitRecover(eqSymUser,nVarEst,csiData,user,'LDPCDecodingMethod','layered-bp'); % rxPSDU(:,frameIdx) = RX_CRC32(double(rxPSDUbits)); rxPSDU(:,frameIdx) = rxPSDUbits; % Compare bit error % bitError = sum(txPSDU{userIdx}~=rxPSDU); % numBitError = numBitError+bitError; % Measure EVM of HE-Data symbols release(EVM); EVM.ReferenceConstellation = wlanReferenceSymbols(user); rmsEVM = EVM(eqSymUser(:)); fprintf(' HE-Data EVM:%2.2fdB\n\n',20*log10(rmsEVM/100)); rx = rx(pktOffset+ind.HEData(2)+100:end,:); % && mean(abs(rx)) > mean_power/2 % else % if length(rx) > ind.HEData(2) frameIdx = frameIdx+1; [rxPSDU,bitErrorRate,eqSymPlot] = heMURx(rx,cfg,userIdx,frameIdx,rxPSDU,cfgUI,SEED,bitErrorRate,eqSymPlot); else [~,numPkt] = size(rxPSDU); psduLength = length(rxPSDU(:,1))/8; switch cfgUI.DataType case 'test' txPSDU = DataGenerate(cfgUI,numPkt,SEED,psduLength,0); txPSDUuser = txPSDU{userIdx};% BER计算方式 用收发约定的种子数产生,解5个包确定ACK个数 bitError = sum(txPSDUuser(1:end,:)~=rxPSDU(1:length(txPSDUuser(1:end,:)),:)); bitErrorRate = bitError/length(rxPSDU); ACK = (bitErrorRate == rxPSDU(end)); case 'text' case 'photo' [~,numPkt] = size(rxPSDU); bitstream = reshape(rxPSDU,1,[]); % 恢复比特变比特流 imgLen = bin2dec(num2str(bitstream(1:16))); % bitstream = bitstream(1:len*width*8); % 取图像像素大小 bit_array = reshape(bitstream,8,[])'; byte_array = num2str(bit_array); img = bin2dec(byte_array); % 二进制转十进制 if imgLen+3 > length(img) imgLen = length(img)-3; end rxPSDU = int16(img(1:imgLen+3)); % double转int16 rxCRC = 0; for i = 1:imgLen+2 rxCRC = mod(rxCRC+rxPSDU(i),256); end if rxCRC == rxPSDU(end) disp('Pass RX Sum Check!'); bitErrorRate = zeros(1,numPkt); else disp('Fail RX Sum Check!'); bitErrorRate = ones(1,numPkt); end % img = mat2gray(rxPSDU); % 恢复出的数据按图像大小排列 % imshow(img); % 展示图像 % pause(1); % close; ACK = (rxCRC == rxPSDU(end)); end save(['TXPackets\ACKfeedback_for_User' num2str(userIdx) '.mat'],'ACK'); % scatterplot(eqSymPlot(1:end)); % pause(1); % close; end end