function chanEst = heChannelToChannelEstimate(chan,cfg,varargin)
%heChannelToChannelEstimate Return the perfect channel estimate for HE fields
%   CHANEST = heChannelToChannelEstimate(CHAN,CFGSU) incorporates any
%   precoding applied, and the cyclic shifts per space-time stream to form
%   the perfect channel estimate, CHANEST, as estimated using the HE-LTF
%   fields.
%
%   CHANEST is a Nst-by-Nsym-by-Nsts-by-Nr array where Nst is the number of
%   active (occupied) subcarriers, Nsym is the number of symbols, Nsts is
%   the number of space-time streams, and Nr is the number of receive
%   antennas.
%
%   CHAN is the frequency domain channel response for active subcarriers
%   and is a Nst-by-Nsym-by-Nt-by-Nr array where Nt is the number of
%   transmit antennas.
%
%   CFGSU is a single-user format configuration object of type <a href="matlab:help('wlanHESUConfig')">wlanHESUConfig</a>.
%
%   CHANEST = heChannelToChannelEstimate(CHAN,CFGMU,RUOFINTEREST) returns
%   the perfect channel estimate for the RU of interest index RUOFINTEREST
%   for a multi-user configuration.
%
%   CFGMU is a multi-user format configuration object of type <a href="matlab:help('wlanHEMUConfig')">wlanHEMUConfig</a>.

%   Copyright 2019-2021 The MathWorks, Inc.

%#codegen

W = getPrecodingMatrix(cfg,varargin{:}); % Nst-by-Nsts-by-Ntx

% Apply scaling to match the appied during OFDM modulation and demodulation
% (wlanHEDemodulate)
if isa(cfg,'wlanHEMUConfig')
    allocInfo = ruInfo(cfg);
    ruIdx = varargin{1};
    % The OFDM modulator normalizes the waveform by the total number of
    % active subcarriers in all RUs
    allScalingFactor = sqrt(sum(allocInfo.RUSizes));
    % The OFDM demodulator normalizes the symbols by the number of active
    % subcarriers in the RU of interest
    ruScalingFactor = sqrt(allocInfo.RUSizes(ruIdx));
    W = W*ruScalingFactor/allScalingFactor;
    % getPrecodingMatrix returns the precoding matrix so the power per
    % subcarrier sums to 1 so undo this
    W = W*allScalingFactor;
else
    % getPrecodingMatrix returns the precoding matrix so the power per
    % subcarrier sums to 1 so undo this
    W = W*sqrt(size(W,1));
end

% Apply spatial mapping and cyclic shift
tmp = sum(bsxfun(@times,chan,permute(W,[1 4 3 5 2])),3); % Nst-by-Nsym-by-1-by-Nr-by-Nsts

% Permute to Nst-by-Nsym-by-Nsts-by-Nr
chanEst = permute(tmp,[1 2 5 4 3]);

end