374 lines
14 KiB
Matlab
374 lines
14 KiB
Matlab
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
|