www.gusucode.com > wlan工具箱matlab源码程序 > wlan/wlan/+wlan/+internal/ChannelBase.m

    classdef (Hidden) ChannelBase < matlab.System & matlab.system.mixin.Propagates
%ChannelBase Filter input signal through a TGn and TGac fading channel
%   The implementation is based on TGn and TGac channel model, as specified
%   by the IEEE 802.11 Wireless LAN Working group [1,2]. The power delay
%   profile, spatial correlation and Doppler filter coefficients values are
%   based on TGn Implementation note version 3.2 - May 2004.
%
%   %   References:
%   [1] Erceg, V. et al. "TGn Channel Models."  Doc. IEEE802.11-03/940r4.
%   [2] Briet, G. et al. "TGac Channel Model Addendum." Doc. IEEE 802.11-09/0308r12

% Copyright 2015 The MathWorks, Inc.

%#codegen
%#ok<*EMCLS>

properties (Nontunable)
    %DelayProfile Channel propagation condition
    %   Specify the Delay profile model of WLAN multipath fading channel as
    %   one of 'Model-A' | 'Model-B' | 'Model-C' | 'Model-D' | 'Model-E' |
    %   'Model-F'. The default is 'Model-B'.
    DelayProfile = 'Model-B';
    % CarrierFrequency Carrier frequency (Hz) 
    %   Specify the carrier frequency of the input signal in Hz. The
    %   default is 5.25e9 Hz.
    CarrierFrequency = 5.25e9;
    %LargeScaleFadingEffect Large scale fading effect
    %   Specify the large scale fading effect in WLAN multipath fading
    %   channel as one of 'None' | 'Pathloss' | 'Shadowing' | 'Pathloss and
    %   shadowing'. The default is 'None'.
    LargeScaleFadingEffect = 'None';
    %TransmitReceiveDistance Distance between transmitter and receiver (m)
    %   Specify the separation between transmitter and receiver in meters.
    %   Used to compute the path loss, and to determine whether the channel
    %   has LOS or NLOS condition. The path loss and standard deviation of
    %   shadow fading loss is dependent on the separation between the
    %   transmitter and the receiver. The default is 3.
    TransmitReceiveDistance = 3;
    %PowerLineFrequency Power line frequency (Hz)
    %   Specify the power line frequency as one of '50Hz' | '60Hz'. The
    %   power line frequency is 60Hz in US and 50Hz in Europe. This
    %   property only applies when DelayProfile is set to Model-D or
    %   Model-E. The default is 60Hz.
    PowerLineFrequency = '60Hz';
    %RandomStream Source of random number stream
    %   Specify the source of random number stream as one of 'Global
    %   stream' | 'mt19937ar with seed'. If RandomStream is set to 'Global
    %   stream', the current global random number stream is used for
    %   normally distributed random number generation, in which case the
    %   reset method only resets the filters. If RandomStream is set to
    %   'mt19937ar with seed', the mt19937ar algorithm is used for normally
    %   distributed random number generation, in which case the reset
    %   method not only resets the filters but also re-initializes the
    %   random number stream to the value of the Seed property. The default
    %   value of this property is 'Global stream'.
    RandomStream = 'Global stream';  
    %Seed Initial seed
    %   Specify the initial seed of a mt19937ar random number generator
    %   algorithm as a double precision, real, nonnegative integer scalar.
    %   This property applies when you set the RandomStream property to
    %   'mt19937ar with seed'. The Seed is to re-initialize the mt19937ar
    %   random number stream in the reset method. The default value of this
    %   property is 73.
    Seed = 73;
end

properties (Nontunable, Logical)
    %NormalizePathGains Normalize average path gains to 0 dB
    %   Set this property to true to normalize the fading processes such
    %   that the total power of the path gains, averaged over time, is 0dB.
    %   The default is true.
    NormalizePathGains = true;
    %FluorescentEffect Enable fluorescent effect
    %   Set this property to add fluorescent effect. This property is only
    %   applicable for Delayprofile, Model-D and Model-E. The default is
    %   true.
    FluorescentEffect = true;
    %NormalizeChannelOutputs Normalize output by number of receive antennas
    %   Set this property to true to normalize the channel outputs by the
    %   number of receive antennas. The default is true.
    NormalizeChannelOutputs = true;
end

properties (Access = private, Nontunable)
    % Number of transmit antennas
    pNt;
    % Number of receive antennas
    pNr;
    % Number of links, NL = pNt * pNr
    pNumLinks;
    % Channel sampling frequency
    pFc;
    % Normalized channel sampling rate
    pDoppler; 
    % Doppler filter weights
    pNumeratorB;
    pDenominatorB;
    pNumeratorS;
    pDenominatorS;
end

properties (Access = private)
    % Number of multipaths
    pNumPaths;
    % Rician K factor in decibels
    pKfactor;
    % Path power
    pPathPower;
    % Antenna correlation
    pAntennaCorrelation;
    % Rician LOS component
    pRicianLOS;
    % Rician NLOS component
    pRicianNLOS;
    % Channel filter tap gain sinc interpolation matrix
    pSincInterpMatrix;
    % Number of channel taps
    pNumChannelTaps;
    % Running Time Instance
    pRunningTimeInstant;
    % Index for oversampled channel samples
    pOversampledFadingTime;
    % Matrix to store the fadings samples before interpolation.
    pOversampledFadingMatrix;
    % Vector of channel samples at channel sampling rate
    pFadingTime;
end

properties (Access = private)
    % Seeding state
    pWGNState;
    % Filter state
    pFilterState;
    % Random phase
    pRandomInterfererToCarrierRatio;
    % Filter state
    pChannelFilterState;
    % State retention
    %pLastTwoColumn
    pLastTwoColumn;
    % Fading offset
    pFadingOffset;
    % Looping variables
    pRunningTime;
    % Fading sample reserve index
    pFadingBufferIndex;
    % Fading Buffer
    pFadingBuffer;
    % Dummy offset
    pOffset;
    % Fluorescent effect random phase
    pRandomPhase;
    % Large scale losses
    pLargeScaleLosses;
    % Stream
    pStream;
    % Power line frequency
    pPowerLineFrequency;
    % Default shadowing value
    pDefaultShadowFading;
end

% Child classes TGnChannel and TGacChannel can access these properties
properties (Access = protected)
    % Channel filter delay, measured in samples
    pChannelFilterDelay = 0;
    % Path power
    pPathPowerdBs;
    % Path delays
    pPathDelays;
    % Legacy generator
    pLegacyGenerator;
    % ShadowFading in decibels
    pShadowFading = 0;
    % Path loss in decibels
    pPathloss = 0;
end

properties(Constant, Hidden)
    RandomStreamSet = matlab.system.StringSet({'Global stream', 'mt19937ar with seed'});
    DelayProfileSet = matlab.system.StringSet({'Model-A','Model-B','Model-C','Model-D','Model-E','Model-F'});
    LargeScaleFadingEffectSet= matlab.system.StringSet({'None','Pathloss','Shadowing','Pathloss and shadowing'});
    PowerLineFrequencySet = matlab.system.StringSet({'50Hz','60Hz'});
end

methods
  function obj = ChannelBase(varargin) % Constructor
    setProperties(obj, nargin, varargin{:});
    obj.pPathDelays = 0;
    obj.pPathPowerdBs = 0;
  end 
    
   function set.CarrierFrequency(obj,val)
     propName = 'CarrierFrequency';
        validateattributes(val, {'numeric'}, ...
            {'real','scalar','>',0,'finite'}, ...
            [class(obj) '.' propName], propName); 
      obj.CarrierFrequency= val;
   end
   
  function set.TransmitReceiveDistance(obj, val)
    propName = 'TransmitReceiveDistance';
    validateattributes(val, {'numeric'}, ...
        {'real','scalar','>',0,'finite'}, ...
        [class(obj) '.' propName], propName);    
    obj.TransmitReceiveDistance = val;
  end
    
  function set.Seed(obj, seed)
    propName = 'Seed';
    validateattributes(seed, {'double'}, ...
        {'real','scalar','integer','nonnegative','finite'}, ...
        [class(obj) '.' propName], propName);  %#ok<*EMCA
    obj.Seed = seed;
  end 
end

methods(Access = protected)
  function num = getNumInputsImpl(~)
    num = 1;
  end
  
  function num = getNumOutputsImpl(~)
    num = 2;
  end  
  
  function validateInputsImpl(obj, x)    
      validateattributes(x, {'double'}, ... 
          {'2d', 'finite', 'ncols', obj.NumTransmitAntennas}, ...
          [class(obj) '.' 'Signal input'], 'Signal input');     
   end
     
  function setupImpl(obj, varargin)
     
    % Initialization of TGn and TGac channel model parameters
    getInfoParameters(obj);
    
    % Set power line frequency
    if strcmp(obj.PowerLineFrequency,'50Hz')
        obj.pPowerLineFrequency = 50;
    else
        obj.pPowerLineFrequency = 60;
    end
    
    % Display the minimum carrier frequency value in the error message
    coder.extrinsic('sprintf');
    coder.internal.errorIf((10*obj.pPowerLineFrequency)>(5*obj.pFc), ...
        'wlan:wlanChannel:AliasingfluorescentFrequency', ...
        sprintf('%f', ...
        3e8/(obj.ScattererSpeed/((2*obj.pPowerLineFrequency)*1/300))));
    
    
    % Computation of PDP for LOS and NLOS scenario
    [obj.pRicianLOS, obj.pRicianNLOS, obj.pPathPower] ...
                                    = ricianComponents(obj);
    
    % Setup filter weights (Doppler filter coefficients)
    obj.pNumeratorB = [ 2.785150513156437e-04
                  -1.289546865642764e-03
                   2.616769929393532e-03
                  -3.041340177530218e-03
                   2.204942394725852e-03
                  -9.996063557790929e-04
                   2.558709319878001e-04
                  -2.518824257145505e-05];
    obj.pDenominatorB =[1.000000000000000
                  -5.945307133332568
                   1.481117656568614e+01
                  -1.985278212976179e+01
                   1.520727030904915e+01
                  -6.437156952794267
                   1.279595585941577
                  -6.279622049460144e-02];

    obj.pNumeratorS= [7.346653645411014e-02
    -2.692961866120396e-01-3.573876752780644e-02i
     5.135568284321728e-01+1.080031147197969e-01i
    -5.941696436704196e-01-1.808579163219880e-01i
     4.551285303843579e-01+1.740226068499579e-01i
    -2.280789945309740e-01-1.111510216362428e-01i
     7.305274345216785e-02+4.063385976397657e-02i
    -1.281829045132903e-02-9.874529878635624e-03i];

    obj.pDenominatorS=[1.0
    -4.803186161814090e+00-6.564741337993197e-01i
     1.083699602445439e+01+2.655291948209460e+00i
    -1.461669273797422e+01-5.099798708358494e+00i
     1.254720870662511e+01+5.723905805435745e+00i
    -6.793962089799931e+00-3.887940726966912e+00i
     2.107762007599925e+00+1.503178356895452e+00i
    -2.777250532557400e-01-2.392692168502482e-01i];
   
  end
  
  function resetImpl(obj)
   
    if coder.target('MATLAB') 
       if strcmp(obj.RandomStream, 'Global stream')
           obj.pStream = RandStream.getGlobalStream;
       else
           obj.pStream = RandStream('mt19937ar', 'seed', obj.Seed);
           obj.pWGNState = obj.pStream.State;
       end
    elseif strcmp(obj.RandomStream, 'mt19937ar with seed')
          obj.pStream = eml_rand_mt19937ar('preallocate_state');
          obj.pWGNState= eml_rand_mt19937ar('seed_to_state', ...
                           obj.pStream, obj.Seed);
    end
       
  
   wgnoise = generateWGNoise(obj);
   obj.pShadowFading = double(wgnoise(1,1).*obj.pDefaultShadowFading);
      
   % Initialize Doppler filter
   filterOrder = 7;
   obj.pFilterState = complex(zeros(filterOrder, ...
                                    obj.pNt*obj.pNr*obj.pNumPaths));
                                
   % Initialize the filter in order to avoid transient state
   temp = generateNoiseSamples(obj, 1000); %#ok<NASGU>
     
   % Initialization of fluorescent effects random variables
   GaussianStandardDeviation = 0.0107;
   GaussianMean              = 0.0203;

   % Gaussian noise generation
   wgnoise = generateWGNoise(obj);

   obj.pRandomInterfererToCarrierRatio = ...,
        (double(wgnoise(1,1)*GaussianStandardDeviation + GaussianMean)).^2;

   % Set random phase
   if coder.target('MATLAB')   
     if strcmp(obj.RandomStream, 'Global stream') 
        stream = RandStream.getGlobalStream;
        wgnoise = rand(stream,1,1);
     else 
        stream = RandStream('mt19937ar', 'seed', obj.Seed);
        wgnoise = rand(stream,1,1);
     end
   else
     if strcmp(obj.RandomStream, 'Global stream') 
         wgnoise = rand(1,1);
     else
        stream = eml_rand_mt19937ar('preallocate_state');
        state = eml_rand_mt19937ar('seed_to_state', stream, obj.Seed);
        for idx = 1:1
           [state, wgnoise] = eml_rand_mt19937ar('generate_uniform',state);
        end
     end 
   end
   
   obj.pRandomPhase = double(wgnoise(1,1))*2*pi;
   
   if obj.pNumChannelTaps > 1
      obj.pChannelFilterState = complex(zeros(obj.pNumChannelTaps-1, ...
                                obj.pNt*obj.pNumPaths));
   else
      obj.pChannelFilterState = complex(0);
   end
   
   % Setup large scale fading effect for the simulation
    if ~strcmp(obj.LargeScaleFadingEffect,'None')
       switch obj.LargeScaleFadingEffect
         case 'Shadowing'
            obj.pLargeScaleLosses = 1/sqrt(10.^(0.1.*(obj.pShadowFading)));
         case 'Pathloss'
            obj.pLargeScaleLosses = 1/sqrt(10.^(0.1.*(obj.pPathloss)));
         otherwise
            obj.pLargeScaleLosses = 1/sqrt(10.^(0.1.*(obj.pPathloss ...
                                                + obj.pShadowFading)));
       end
    end
    
   % Initialization 
   obj.pOffset            = 0;
   obj.pLastTwoColumn     = complex(zeros( ...
                                   [obj.pNumPaths*obj.pNumLinks, 2]));
   obj.pRunningTimeInstant = 0;
   obj.pFadingOffset = 0;
   obj.pOversampledFadingTime = zeros(1,1);
   obj.pOversampledFadingMatrix = complex(zeros(1,1));
   obj.pFadingTime = zeros(1,1);

  end
  
  function varargout = stepImpl(obj, input)
   
   Ns = size(input,1);
   nTx = obj.pNt;
   nRx = obj.pNr;
   numPaths = obj.pNumPaths;

   % Output empty signals and path gains for an empty input
   if Ns == 0
        varargout{1} = zeros(Ns, nRx);
        varargout{2} = NaN(Ns, numPaths, nTx, nRx);
        return;
   end
   
   % Number of samples in time
   chSampleTime = 1/obj.pFc;
   inpSampleTime = 1/obj.SampleRate;
   Nt = Ns* inpSampleTime;
              
   runningTime = obj.pRunningTimeInstant:inpSampleTime: ...
                    (Ns-1)*inpSampleTime + obj.pRunningTimeInstant;
   
   if runningTime(1)==0
       numChSamples = ceil(Nt/chSampleTime) + 1;                 
       pathGains = generateFadingSamples(obj,runningTime,numChSamples);
       obj.pOffset = 1;
   else
       if runningTime(end) < obj.pOversampledFadingTime(end)
           % No additional channel samples are required to process the input samples.
           pathGains = (interp1(obj.pOversampledFadingTime.', ...
             obj.pOversampledFadingMatrix.',runningTime.','linear'));
       
       else
           numInterpolatedSamples = size(runningTime,2);
           % Use the remaining samples before generating more.
           previousIdx = find(runningTime<obj.pFadingTime(end));

           % Generate output samples before generating new channel samples
           H1 = (interp1(obj.pOversampledFadingTime.', ...
                obj.pOversampledFadingMatrix.', ...
                runningTime(previousIdx).','linear'));
           
           % Additional samples needed to process the input.
           newInterpolatedSamples = numInterpolatedSamples - size(previousIdx,2);
        
           % Time required to process the remaining interpolated samples.
           timeInterpolatedSamples = newInterpolatedSamples * inpSampleTime;
           
           % Number of channel samples required to process this input
           numChannelSamples = ceil(timeInterpolatedSamples/chSampleTime) + 1;

           % The isempty check is to avoid the special case when number of
           % interpolated channel samples are exact match to the length of
           % samples between two channel samples
           runningTimeInstant = runningTime(1,size(runningTime,2) ...
                                + isempty(previousIdx) ...
                                -newInterpolatedSamples) + ...
                                inpSampleTime*(1-isempty(previousIdx));
                   
           runningTime = runningTimeInstant:inpSampleTime: ...
               (newInterpolatedSamples-1)*inpSampleTime + runningTimeInstant;
          
           H2 = generateFadingSamples(obj,runningTime,numChannelSamples);
           pathGains = [H1;H2];
       end
   end
       
   % Update states
   obj.pFadingOffset = obj.pFadingTime(size(obj.pFadingTime,2))+ ...
                           chSampleTime;
   obj.pRunningTimeInstant  = runningTime(1,size(runningTime,2)) + inpSampleTime;
       
   varargout{1} = channelFilter(obj, input, pathGains);
 
   if obj.NormalizeChannelOutputs
         %Normalize by the number of selected receive antennas so that the
         %total output power is equal to the total input power
         varargout{1} = varargout{1}/sqrt(nRx);
   end

   varargout{2} = permute(reshape(pathGains, Ns, nRx, nTx, ...
                                              numPaths), [1, 4, 3, 2]);
    
  end
  
  function flag = isInactivePropertyImpl(obj, prop)
    if strcmp(prop, 'FluorescentEffect') ||  strcmp(prop, 'PowerLineFrequency') 
        flag = ~(strcmpi(obj.DelayProfile, 'Model-D') || strcmpi(obj.DelayProfile, 'Model-E'));
    elseif strcmp(prop, 'Seed')
        flag = strcmp(obj.RandomStream, 'Global stream');
    else 
        flag = false;
    end
  end
  
  function releaseImpl(~)

  end
  
  function s = saveObjectImpl(obj)
    s = saveObjectImpl@matlab.System(obj);
    if isLocked(obj)
        s.pNt = obj.pNt;
        s.pNr = obj.pNr;
        s.pNumPaths = obj.pNumPaths; 
        s.pPathPower = obj.pPathPower;
        s.pPathPowerdBs = obj.pPathPowerdBs;
        s.pNumLinks = obj.pNumLinks;
        s.pNumChannelTaps = obj.pNumChannelTaps; 
        s.pSincInterpMatrix = obj.pSincInterpMatrix;
        s.pWGNState = obj.pWGNState;
        s.pChannelFilterState = obj.pChannelFilterState; 
        s.pRunningTime = obj.pRunningTime; 
        s.pOffset = obj.pOffset;
        s.pFc = obj.pFc;
        s.pRandomPhase = obj.pRandomPhase;
        s.pRicianLOS = obj.pRicianLOS;
        s.pRicianNLOS = obj.pRicianNLOS;
        s.pPathPower = obj.pPathPower;
        s.pAntennaCorrelation = obj.pAntennaCorrelation;
        s.pPathloss = obj.pPathloss;
        s.pDoppler = obj.pDoppler;
        s.pShadowFading = obj.pShadowFading;
        s.pFilterState = obj.pFilterState;
        s.pLastTwoColumn = obj.pLastTwoColumn;
        s.pRunningTime = obj.pRunningTime;
        s.pRandomPhase = obj.pRandomPhase;
        s.pRandomInterfererToCarrierRatio = obj.pRandomInterfererToCarrierRatio;
        s.pLargeScaleLosses = obj.pLargeScaleLosses;
        s.pPowerLineFrequency = obj.pPowerLineFrequency;
        s.pNumeratorB = obj.pNumeratorB;
        s.pDenominatorB = obj.pDenominatorB;
        s.pNumeratorS = obj.pNumeratorS;
        s.pDenominatorS = obj.pDenominatorS;
        s.pLegacyGenerator = obj.pLegacyGenerator;
        s.pRunningTimeInstant = obj.pRunningTimeInstant;
        s.pOversampledFadingTime = obj.pOversampledFadingTime;
        s.pOversampledFadingMatrix = obj.pOversampledFadingMatrix;
        s.pFadingTime = obj.pFadingTime;
        s.pFadingOffset = obj.pFadingOffset;
        s.pChannelFilterDelay = obj.pChannelFilterDelay;
        s.pPathDelays = obj.pPathDelays;
        s.pDefaultShadowFading = obj.pDefaultShadowFading;
    end
  end
  
  function loadObjectImpl(obj, s, wasLocked)
    if wasLocked
        obj.pNt = s.pNt;
        obj.pNr = s.pNr;
        obj.pNumPaths = s.pNumPaths;
        obj.pPathPower = s.pPathPower;
        obj.pPathPowerdBs = s.pPathPowerdBs;
        obj.pNumLinks = s.pNumLinks;
        obj.pNumChannelTaps = s.pNumChannelTaps; 
        obj.pSincInterpMatrix = s.pSincInterpMatrix;
        obj.pWGNState = s.pWGNState;
        obj.pChannelFilterState = s.pChannelFilterState;
        obj.pRunningTime = s.pRunningTime;
        obj.pOffset = s.pOffset;
        obj.pFc = s.pFc;
        obj.pRandomPhase = s.pRandomPhase;
        obj.pRicianLOS = s.pRicianLOS;
        obj.pRicianNLOS = s.pRicianNLOS;
        obj.pPathPower = s.pPathPower;
        obj.pDoppler = s.pDoppler;
        obj.pAntennaCorrelation = s.pAntennaCorrelation;
        obj.pPathloss = s.pPathloss;
        obj.pShadowFading = s.pShadowFading;
        obj.pFilterState = s.pFilterState;
        obj.pLastTwoColumn = s.pLastTwoColumn;
        obj.pRunningTime = s.pRunningTime;
        obj.pRandomPhase = obj.pRandomPhase;
        obj.pRandomInterfererToCarrierRatio = s.pRandomInterfererToCarrierRatio;
        obj.pLargeScaleLosses = s.pLargeScaleLosses;
        obj.pPowerLineFrequency = s.pPowerLineFrequency;
        obj.pNumeratorB = s.pNumeratorB;
        obj.pDenominatorB = s.pDenominatorB;
        obj.pNumeratorS = s.pNumeratorS;
        obj.pDenominatorS = s.pDenominatorS;
        obj.pLegacyGenerator = s.pLegacyGenerator;
        obj.pRunningTimeInstant = s.pRunningTimeInstant;
        obj.pOversampledFadingTime = s.pOversampledFadingTime;
        obj.pOversampledFadingMatrix = s.pOversampledFadingMatrix;
        obj.pFadingTime = s.pFadingTime;
        obj.pFadingOffset = s.pFadingOffset;
        obj.pChannelFilterDelay = s.pChannelFilterDelay;
        obj.pPathDelays = s.pPathDelays;
        obj.pDefaultShadowFading = s.pDefaultShadowFading;
    end
    % Do not call the loadObjectImpl method of the matlab.System object
    % because it does not support private properties of the base class.
    % For example, pNumPaths is not a property of wlanTGnChannel and will
    % not be excluded from s before calling set(obj, s).
    field = fieldnames(s);
    for i = 1 : length(field)
        curField = field{i};
        if strcmp(curField(1), 'p')
            s = rmfield(s, curField);
        end
    end
    set(obj, s);
  end
  
  function flag = isInputSizeLockedImpl(~,~)
     flag = false;
  end
  
  function varargout = isOutputComplexImpl(~)
    varargout = {true};
  end 
  
  function getInfoParameters(obj)
   
    % Setup parameters
    obj.pNt = obj.NumTransmitAntennas; 
    obj.pNr = obj.NumReceiveAntennas; 
    obj.pNumLinks = obj.pNt * obj.pNr;
    
    % Doppler components
    wavelength   = 3e8/obj.CarrierFrequency;                
    ScatterSpeed = obj.ScattererSpeed; % Scatterer speed in m/s;
    
    % Cut-off frequency f_D, in Hz
    obj.pDoppler = ScatterSpeed/wavelength;

    % Normalized Doppler spread f_D
    normalizationFactor = 1/300;

    % Channel sampling frequency
    obj.pFc = obj.pDoppler/normalizationFactor;
    
    targetOverSampleFactor = 10;
   
    % Limitation between sample rate and cut-off frequency factors
    coder.extrinsic('sprintf');
    coder.internal.errorIf(any(obj.SampleRate < ...
         targetOverSampleFactor * obj.pFc), ...
         'wlan:wlanChannel:MaxDopplerAndInputSamplingRate', ...
         sprintf('%f',targetOverSampleFactor*obj.pFc));

    coder.extrinsic('wlan.internal.spatialCorrelation'); 
    modelConfig = struct( ...
                  'NumTransmitAntennas',    obj.NumTransmitAntennas, ...
                  'NumReceiveAntennas',     obj.NumReceiveAntennas, ...
                  'TransmitAntennaSpacing', obj.TransmitAntennaSpacing, ...
                  'ReceiveAntennaSpacing',  obj.ReceiveAntennaSpacing, ...
                  'DelayProfile',           obj.DelayProfile, ...
                  'UserIndex',              obj.UserIndex, ...
                  'ChannelBandwidth',       obj.ChannelBandwidth, ...
                  'TransmitReceiveDistance',obj.TransmitReceiveDistance, ...
                  'CarrierFrequency',       obj.CarrierFrequency, ...
                  'TransmissionDirection',  obj.TransmissionDirection);
             
    if coder.target('MATLAB')
        out = wlan.internal.spatialCorrelation(modelConfig);                                 
    else
        out = coder.const((wlan.internal.spatialCorrelation(modelConfig)));
    end
    
    obj.pAntennaCorrelation  = out.AntennaCorrelation;
    obj.pPathPower           = out.PathPower;
    obj.pPathDelays          = out.PathDelays;
    obj.pPathloss            = out.Pathloss;
    obj.pDefaultShadowFading = out.ShadowFading;
    obj.pKfactor             = out.Kfactor;
    
    obj.pNumPaths = size(obj.pPathPower,2);
    
    % This is to display the initial shadow fading value through an info
    % function.
    obj.pShadowFading = out.ShadowFading;
    
    % Path power in dBs returned by the info function
    obj.pPathPowerdBs = 10*log10(obj.pPathPower);
    
    % Setup channel filter
    setupChannelFilter(obj);
      
  end
end

methods(Access = private)    
  
  function setupChannelFilter(obj)
  
    % Initial estimate of tapidx range. Minimum value of range is 0.
    err1 = 0.1;         % Small value
    c = 1/(pi*err1);    % Based on bound sinc(x) < 1/(pi*x)

    tRatio = (obj.pPathDelays * obj.SampleRate).';
    tapidx = min(floor(min(tRatio) - c), 0) : ceil(max(tRatio) + c);
    
    % Pre-compute channel filter tap gain sinc interpolation matrix
    if isempty(coder.target)   
        A1 = bsxfun(@minus, tRatio, tapidx);
        A = sinc(A1);
    else % Written in this way to avoid constant folding timeout error
        A1 = (repmat(tRatio, size(tapidx)));
        A  = (double(sinc(A1 - repmat(tapidx, size(tRatio)))));
    end
    
    % The following steps ensure that the tap index vector is shortened
    % when tRatio values are close to integer values.
    err2 = 0.01;
    if isempty(coder.target)   
        maxA = max(abs(A), [], 1); 
        significantIdx = find(maxA > (err2 * max(maxA)));
    else 
        maxA = (max(abs(A), [], 1)); 
        significantIdx = (double(find(maxA > (err2 * max(maxA)))));
    end
    
    t1 = min(tapidx(significantIdx(1)), 0);
    t2 = tapidx(significantIdx(end));
    
    if (t2 - t1) > 200
        coder.internal.warning('wlan:wlanChannel:PathDelayTooLarge');
    end
    
    % If the first tap index is negative, then the channel filter delay is
    % positive. This is the usual case. But if the first tap index is
    % positive, the channel filter delay is *negative*. This is an unusual
    % case for which the smallest path delay is much greater than the
    % input signal's sample period.
    obj.pChannelFilterDelay = round(tRatio(1)) - t1; 

    % Set up channel filter tap gain sinc interpolation matrix, [NP, nTaps]
    tapidx2 = t1:t2;
    if isempty(coder.target)
        A2 = bsxfun(@minus, tRatio, tapidx2);
        obj.pSincInterpMatrix = sinc(A2); 
    else % Written in this way to avoid constant folding timeout error
        A2 = (repmat(tRatio, size(tapidx2)));
        obj.pSincInterpMatrix = (double(sinc(A2 - repmat(tapidx2, size(tRatio)))));
    end
    
    obj.pNumChannelTaps = size(obj.pSincInterpMatrix, 2);  
  end
 
  function y = channelFilter(obj, x, fadingSamples)
    Ns = size(x, 1);    % Number of samples
    nTx = obj.pNt;      % Number of Tx
    nRx = obj.pNr;      % Number of Rx
    NP = obj.pNumPaths; % Number of paths
    
    % Initialize number of active links 
    activeTxIdx = 1:nTx;
    activeRxIdx = 1:nRx;
    activeLIdx  = 1:nTx*nRx;
    activeMIdx  = 1:nTx*nRx*NP;    
    
    numActiveTx = length(activeTxIdx);
    numActiveRx = length(activeRxIdx);
     
    if obj.pNumChannelTaps == 1 % Frequency-flat fading
        numActiveL  = length(activeLIdx);
        z = reshape(fadingSamples(:, activeMIdx), [Ns*numActiveL, NP]); 
        g = reshape(z * obj.pSincInterpMatrix, Ns, numActiveRx, []); 
        y = sum(bsxfun(@times, reshape(x, Ns, 1, []), g), 3);
        
    else % Frequency-selective fading
        filterState = obj.pChannelFilterState;
        %Calculate tap gain from path gain input
        % Note that conv((A*B), C) = A*conv(B, C). When B is a constant
        % matrix, right hand equation can have much faster
        % implementation than left-hand one by using 'filter' function.
         filterOut = coder.nullcopy(complex(zeros(Ns, numActiveTx*NP)));
         for i = 1:NP
            colIdx = (i-1)*numActiveTx + (1:numActiveTx);
            stateIdx = (i-1)*nTx + activeTxIdx;
            [filterOut(:,colIdx), filterState(:,stateIdx)] = ...
               filter(obj.pSincInterpMatrix(i, :), 1, ...
                          x(:,1:numActiveTx), filterState(:,stateIdx), 1);
         end
         y = sum(bsxfun(@times, reshape(fadingSamples(:,activeMIdx), ...
             Ns, numActiveRx, numActiveTx*NP), reshape(filterOut, ...
             Ns, 1, numActiveTx*NP)), 3);
         
         % Save filter state
         obj.pChannelFilterState = filterState;
    end 
    
  end
  
  function y = initializeRice(cfg)
                   
    nTx = cfg.NumTransmitAntennas;
    txSpacingNormalized = cfg.TransmitAntennaSpacing;
    txAoDLOSrad = pi/4;
    nRx = cfg.NumReceiveAntennas;
    rxSpacingNormalized = cfg.ReceiveAntennaSpacing;
    rxAoDLOSrad = pi/4;

    stepTx   = exp(1i*2*pi*txSpacingNormalized*sin(txAoDLOSrad));
    vectorTx = stepTx.^(0:nTx-1);
    stepRx   = exp(1i*2*pi*rxSpacingNormalized*sin(rxAoDLOSrad));
    vectorRx = stepRx.^((0:nRx-1).');
    y = vectorRx * vectorTx;
  end
  
  function [ricianLOS, ricianNLOS, pathPower] = ricianComponents(obj)
    
    % Computation of Rician steering matrix
    ricianMatrix = initializeRice(obj);
    
    % Initialization of the LOS component
    riceFactor = 10.^(.1.*obj.pKfactor);
    ricianLOS  = complex(zeros(obj.pNumPaths*obj.pNumLinks ,1));
    ricianNLOS = complex(zeros(obj.pNumPaths*obj.pNumLinks ,1));

    % Computation of the power delay profile of the (LOS+NLOS) power

    % The PDP is defined as the time dispersion of the NLOS power. The
    % addition of the LOS component modifies the time dispersion of the
    % total power.

    pathPower =obj.pPathPower.*(1+riceFactor);
        
    % Normalization of the power delay profile of the (LOS+NLOS) power
    if obj.NormalizePathGains
        pathPower = pathPower./sum(pathPower);
    end

    out = reshape(ricianMatrix, obj.pNumLinks, 1);

    for i = 1:obj.pNumPaths
        ricianLOS(1+(i-1)*obj.pNumLinks:i*obj.pNumLinks,1) = ...
                    sqrt(complex(pathPower(1,i))).* ...
                    sqrt(riceFactor(i)/(riceFactor(i)+1)).*out;
        ricianNLOS(1+(i-1)*obj.pNumLinks:i*obj.pNumLinks,1)= ...
                    sqrt(1/(riceFactor(i)+1)).*ones(obj.pNumLinks, 1);
    end;
  end
 
  function out = generateNoiseSamples(obj, N)
        
    NP = obj.pNumPaths;
    NL = obj.pNt * obj.pNr;
    M  = NP * NL;
    out = complex(zeros(NL*NP,N));
    const = sqrt(.5);
    
    % Gaussian noise generation
    if coder.target('MATLAB') 
        if strcmp(obj.RandomStream, 'Global stream')
            if obj.pLegacyGenerator
               stream = RandStream.getGlobalStream;
               stream.State = obj.pWGNState;
               wgnoise = const*complex(randn(stream, M, N), ...
                       randn(stream, M, N));
               obj.pWGNState = stream.State;
            else 
                % Separating legacy global syntax from this implementation
                w = (randn(2*M, N)).';
                wgnoise = const*(w(:,1:M) + 1i*w(:,M+1:end));
            end
        else 
            obj.pStream.State = obj.pWGNState; % Retrieve previous state
            if obj.pLegacyGenerator 
                wgnoise =  const*complex(randn(obj.pStream, M, N), ...
                           randn(obj.pStream, M, N));
            else
                w = (randn(obj.pStream, 2*M, N)).';
                wgnoise = const*(w(:,1:M) + 1i*w(:,M+1:end));
            end
            obj.pWGNState = obj.pStream.State; % Log randstream state
        end
    else
        if strcmp(obj.RandomStream, 'Global stream')
            if obj.pLegacyGenerator
               wgnoise = const*complex(randn(M, N), randn(M, N));
            else
               w =  (randn(2*M, N)).';
               wgnoise = const*(w(:,1:M) + 1i*w(:,M+1:end));
            end
        else
            wgnoise = coder.nullcopy(complex(zeros(M,N))); %#ok<NASGU>
            if obj.pLegacyGenerator 
		        w = coder.nullcopy(zeros(M,2*N));
                state = obj.pWGNState;
                for colIdx = 1:2*N 
                    for rowIdx= 1:M
                        [state, w(rowIdx,colIdx)] =  ...
                            eml_rand_mt19937ar('generate_normal', state);
                    end
                end
                wgnoise =  const*complex(w(:,1:N), w(:,N+1:end));
            else
                w = coder.nullcopy(zeros(N, 2*M));
                state = obj.pWGNState;
                for rowIdx = 1:N % Noise is generated column-wise
                    for colIdx = 1:2*M
                        [state, w(rowIdx, colIdx)] = eml_rand_mt19937ar('generate_normal', state);
                    end
                end
                 wgnoise = const*(w(:,1:M) + 1i*w(:,M+1:end)); 
            end
            obj.pWGNState = state;
        end
    end
    
    % Filter definition
    filterOrder = 7;

    switch obj.DelayProfile

         case 'Model-F'
            % Indoor, bell shape Doppler spectrum with spike
            filterStateIn = obj.pFilterState;

            obj.pFilterState = complex(zeros(filterOrder, ...
                                    obj.pNt*obj.pNr*obj.pNumPaths));
            SpikePos = 3; %tap with Bell+Spike shape
            %index of Bell shaped fading coefficients
            BellTapsPositions = [1:(SpikePos-1)*NL ((SpikePos)*NL+1):M]; 
            %index of Bell+Spike shaped fading coefficients
            SpikeTapsPositions = ((SpikePos-1)*NL+1):(SpikePos)*NL;
            
            if obj.pLegacyGenerator
                %Bell shaped fading
                [FadingMatrixTimeBellTap,  ...
                    obj.pFilterState(:,BellTapsPositions)] =...
                    filter(obj.pNumeratorB, obj.pDenominatorB,  ...
                    wgnoise(BellTapsPositions,:), ...
                    filterStateIn(:,BellTapsPositions), 2);

                %Bell+Spike shaped fading
                [FadingMatrixTimeSpikeTap, ...
                    obj.pFilterState(:,SpikeTapsPositions)] = ...
                    filter(obj.pNumeratorS, obj.pDenominatorS, ...
                    wgnoise(SpikeTapsPositions,:), ...
                    filterStateIn(:, SpikeTapsPositions), 2);
                            
                % Fading Matrix Time with bell+spike on the 3-rd tap
                out(BellTapsPositions,:) = FadingMatrixTimeBellTap;
                out(SpikeTapsPositions,:) = FadingMatrixTimeSpikeTap;               
            else
                % Bell shaped fading
                [FadingMatrixTimeBellTap,  ...
                    obj.pFilterState(:,BellTapsPositions)] =...
                    filter(obj.pNumeratorB, obj.pDenominatorB,  ...
                    wgnoise(:,BellTapsPositions), ...
                    filterStateIn(:,BellTapsPositions), 1);

                %Bell+Spike shaped fading
                [FadingMatrixTimeSpikeTap, ...
                    obj.pFilterState(:,SpikeTapsPositions)] = ...
                    filter(obj.pNumeratorS, obj.pDenominatorS, ...
                    wgnoise(:,SpikeTapsPositions), ...
                    filterStateIn(:,SpikeTapsPositions), 1);
                
                % Fading Matrix Time with bell+spike on the 3-rd tap
                out(BellTapsPositions,:) = FadingMatrixTimeBellTap.';
                out(SpikeTapsPositions,:) = FadingMatrixTimeSpikeTap.';    
            end
        otherwise   
            % Indoor, bell shape Doppler spectrum
            if obj.pLegacyGenerator
                [out,obj.pFilterState] = filter(obj.pNumeratorB,obj.pDenominatorB, ...
                                  wgnoise, obj.pFilterState, 2);

            else
                [filterOut,obj.pFilterState] = filter(obj.pNumeratorB, obj.pDenominatorB, ...
                                            wgnoise, obj.pFilterState, 1);
                out =  filterOut.';  
                  
            end
    end

  end

 % Add fluorescent effects
 function out =  fluorescentEffects(obj, FadingMatrix, fadingSamplingTime)
        
    % Amplitudes of the modulating signal
    amplitudes = [0 -15 -20];
    % Taps to be used in model D
    tapsModelD = [12 14 16];
    % Taps to be used in model E
    tapsModelE = [3 5 7];

    % Initialization of the modulation matrix
    ModulationMatrix = complex(zeros(size(FadingMatrix)));

    % Computation of the modulation function g(t)
    g = complex(zeros(3,size(fadingSamplingTime,2)));

    for k = 1:3
        g(k,:) = (10^(amplitudes(k)/20)).* ...
            exp(1i.*(4.*pi.*(2*(k-1)+1).* ...
            obj.pPowerLineFrequency.*fadingSamplingTime ...
            + obj.pRandomPhase));
    end;

    modulationFunction = sum(g);

    % Modulation matrix
    if strcmpi(obj.DelayProfile, 'Model-D')
        
        for ii=1:obj.pNt
            for jj=1:obj.pNr
                for k=1:3
                    ModulationMatrix((((tapsModelD(k)-1)*obj.pNt*obj.pNr) ...
                        +((ii-1)*obj.pNr)+jj),:) = modulationFunction;
                end;
            end;   
        end;

    else       
        for ii=1:obj.pNt
            for jj=1:obj.pNr
                for k=1:3
                    ModulationMatrix((((tapsModelE(k)-1)*obj.pNt*obj.pNr) ...
                        +((ii-1)*obj.pNr)+jj),:) = modulationFunction;
                end;
            end;   
        end;
    end;

    % Multiplication of the modulation matrix and the fading matrix
    ModulationMatrix = ModulationMatrix.*FadingMatrix;
    
    if obj.pLegacyGenerator
        % Calculation of the energy of both matrices
        ModulationMatrixEnergy = sum(sum(abs(ModulationMatrix).^2));
        FadingMatrixEnergy     = sum(sum(abs(FadingMatrix).^2));

        % Comparison and calculation of the normalization constant alpha
        RealInterfererToCarrierRatio = ModulationMatrixEnergy/FadingMatrixEnergy;
        NormalizationConstant = sqrt(double( ...
            obj.pRandomInterfererToCarrierRatio/RealInterfererToCarrierRatio));

        out = bsxfun(@plus, FadingMatrix, NormalizationConstant(1,1).* ModulationMatrix);
    else
        % Calculation of the energy of both matrices
        ModulationMatrixEnergy = (sum(abs(ModulationMatrix).^2));
        FadingMatrixEnergy     = (sum(abs(FadingMatrix).^2));

        % Comparison and calculation of the normalization constant alpha
        RealInterfererToCarrierRatio = ModulationMatrixEnergy./FadingMatrixEnergy;
        NormalizationConstant = sqrt(double( ...
            obj.pRandomInterfererToCarrierRatio./RealInterfererToCarrierRatio));

        NC = repmat(NormalizationConstant, size(ModulationMatrix,1),1);

        out = bsxfun(@plus, FadingMatrix, NC.* ModulationMatrix);
    end

 end
 
 function out = generateWGNoise(obj)
   if coder.target('MATLAB')   
      if strcmp(obj.RandomStream, 'Global stream')
           if obj.pLegacyGenerator 
               obj.pWGNState = obj.pStream.State;
               out = randn(obj.pStream,1,1); 
           else
               out = randn(1,1);
           end
      else
        % Continuous generation of samples unlike TGn
        obj.pStream.State = obj.pWGNState;
        out =  randn(obj.pStream,1,1);
        obj.pWGNState = obj.pStream.State;
      end
    else
      if strcmp(obj.RandomStream, 'Global stream')
         out = randn(1,1);
      else 
         [obj.pWGNState, out] = eml_rand_mt19937ar('generate_normal', obj.pWGNState);
     end
   end
 end
 
 function H = generateFadingSamples(obj,runningTime,numChSamples)
     
       fadingSamplingTime = 1/obj.pFc;
       nTx = obj.pNt;
       nRx = obj.pNr;
     
       % Time references
       obj.pFadingTime  = obj.pFadingOffset-(obj.pFadingOffset~= 0)*2*fadingSamplingTime: ...
           fadingSamplingTime:...
           obj.pFadingOffset+((numChSamples-1)*fadingSamplingTime); 

       obj.pOversampledFadingTime = obj.pFadingTime(1):.1*fadingSamplingTime:...
                                  obj.pFadingTime(size(obj.pFadingTime,2));
        
                              
       % Computation of the matrix of fading coefficients 
        newFadingMatrixTime = generateNoiseSamples(obj, numChSamples);
        
       % State retention
       if obj.pOffset==0;
           fadingMatrixTime = newFadingMatrixTime;
       else
           fadingMatrixTime = [obj.pLastTwoColumn, newFadingMatrixTime]; 
       end
        
       obj.pLastTwoColumn = newFadingMatrixTime(:, ...
                                        numChSamples-1:numChSamples);

       % Spatial correlation of the fading matrix
       fadingMatrixTime = obj.pAntennaCorrelation * fadingMatrixTime;

       pdpCoef =kron(sqrt(complex(obj.pPathPower)), ones(1, nTx*nRx));
 
       % Normalization of the correlated fading processes
       fadingMatrixTime = diag(pdpCoef)*fadingMatrixTime;

       % Calculation of the Rice phasor AoA/AoD hard-coded to 45 degrees
       ricePhasor = exp(1i.*2.*pi.*obj.pDoppler.*cos(pi/4).*obj.pFadingTime);

       % Addition of the Rice component
       fadingMatrix = (obj.pRicianLOS*ricePhasor)+(obj.pRicianNLOS ...
                      *ones(1,size(fadingMatrixTime,2))).*fadingMatrixTime;
 
       % First (partial) interpolation, at 10*FadingSamplingFrequency_Hz
       % to avoid aliasing of the fluorescent effect
       obj.pOversampledFadingMatrix = (interp1(obj.pFadingTime.',fadingMatrix.', ...
                                obj.pOversampledFadingTime.','linear')).';
 
       % Call to generate fluorescent light effects in models D and E
       if ( strcmpi(obj.DelayProfile, 'Model-D') || ...
             strcmpi(obj.DelayProfile, 'Model-E')) && obj.FluorescentEffect
            obj.pOversampledFadingMatrix = fluorescentEffects(obj,  ...
                obj.pOversampledFadingMatrix, obj.pOversampledFadingTime);
       end;

       % Large-scale fading
       if ~strcmp(obj.LargeScaleFadingEffect,'None')
            obj.pOversampledFadingMatrix =  ...
                obj.pOversampledFadingMatrix.*obj.pLargeScaleLosses;
       end

       % Second interpolation, at SamplingRate_Hz
       H = interp1(obj.pOversampledFadingTime.',obj.pOversampledFadingMatrix.', ...
                  runningTime.','linear');
     
 end
 
end

end
 
% [EOF]