HE/heMURx.m
2024-03-30 16:35:40 +08:00

374 lines
14 KiB
Matlab
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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