HE/heMURx.m

374 lines
14 KiB
Mathematica
Raw Normal View History

2024-03-30 16:35:40 +08:00
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 5ACK
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)); % doubleint16
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