%scaleCDLAngles TR 38.901 Section 7.7.5.1 Scaling of angles

%   Copyright 2017-2022 The MathWorks, Inc.

%#codegen

function phi = scaleCDLAngles(model,pdp,phi,AS_field,mu_field)

    [AS_model,mu_model] = calculateAngleParameters(pdp,phi);

    AS_desired = getfieldordefault(model,AS_field,AS_model);
    mu_desired = getfieldordefault(model,mu_field,mu_model);
    
    if (any(strcmpi(mu_field(end-2:end),{'AoA','AoD'})))
        postfn = @(x)mod(x,360); % wrap to 0...360
    else % {'ZoA','ZoD'}
        postfn = @(x)max(min(x,180),0); % clip to 0...180
    end
    
    if (AS_model==0)
        phi = postfn(phi - mu_model + mu_desired);
    else
        phi = postfn((AS_desired / AS_model * (phi - mu_model)) + mu_desired);
    end

end

% TR 38.901 Annex A: Further parameter definitions
function [AS,mu_phi] = calculateAngleParameters(pdp,phi)

    % named column subscripts
    [~,power] = wireless.internal.channelmodels.namedDelayProfileColumns();

    % linear cluster powers
    P = 10.^(pdp(:,power)/10);
    
    % establish ray powers from cluster powers
    P = repmat(P,1,size(phi,2))/size(phi,2);
    
    % calculate power weighted sum of rays
    weightedRaySum = sum(exp(1i*phi(:)/180*pi).*P(:));

    % Annex A.1 Calculation of angular spread
    AS = sqrt(-2*log(abs(weightedRaySum/sum(P(:)))))/pi*180;
    
    % Annex A.2 Calculation of mean angle
    mu_phi = angle(weightedRaySum)/pi*180;
    
end

% get field s.(f) or default value 'v' is 'f' is not a field of 's'
function v = getfieldordefault(s,f,v)
    
    if (isfield(s,f))
        v = s.(f);
    end
    
end
