function [NumErrors, ResultsStruct] = MCNarrowBand( ParametersStruct )
% MCNarrowBand - Monte Carlo Simulation of a NarrowBand System with
% Multi-path
%
% Simulate a simple communication system in a time-varying multi-path
% environment and measure the symbol error rate.
%
% Inputs:
%   ParametersStruct - a structure containing system parameters ( see
%   MCNarrowBandDriver for details) 
%
% Output:
%   NumErrors     - number of errors
%   ResultsStruct - return complete results in a structure; look at
%                   fieldnames for details.
%
% Example:
%   NumErrors = MCNarrowBand( ParametersStruct )

%% Parameters
% unpack parameters structure - convert to local variables
Fields = fieldnames( ParametersStruct );
for kk = 1:length(Fields)
    if ( isstruct(ParametersStruct.(Fields{kk})) )
        eval([Fields{kk} '= ParametersStruct.' Fields{kk} ';' ]);
    else
    eval([ Fields{kk} ...
        '= [' num2str( ParametersStruct.( Fields{kk} ) ) '];' ]);
    end
end

%% derived parameters
% transmitted signal should be scaled to energy Es. Since Es=L*A^2*||h||*Ts,
% where h is the sampled transmit pulse shape:
A        = sqrt(1/L)*sqrt(Es/T*fsT)/norm(hh);
N0       = Es/EsOverN0;   % noise PSD (complex noise)
NoiseVar = N0/T*fsT;      % corresponding noise variance N0/Ts
fs       = fsT/T;         % sampling rate
ChannelParams.fd = fd;    % add Doppler to Channel model

%% simulate discrete-time equivalent system
% transmitter and channel via toolbox functions
InfoSymbols = RandomSymbols( NSymbols, Alphabet, Priors );
% insert training sequence
Symbols = [ InfoSymbols(1:TrainLoc) TrainingSeq ...
    InfoSymbols(TrainLoc+1:end)];
% linear modulation
Signal = A * LinearModulation( Symbols, hh, fsT );

% loop over diversity channels
for kk = 1:L
    % time-varying multi-path channels and additive noise
    Received(kk,:) = SimulateCOSTChannel( Signal, ChannelParams, fs);
    Received(kk,:) = addNoise( Received(kk,:), NoiseVar );

    % digital matched filter, gain estimation
    MFOut(kk,:)     = DMF( Received(kk,:), hh, fsT );
    GainEst(kk)     = 1/TrainLength * ...
        MFOut( kk, TrainLoc+1 : TrainLoc+TrainLength) * TrainingSeq';
end

% delete traning, MRC, and slicer
MFOut(:, TrainLoc+1 : TrainLoc+TrainLength) = [ ]; 
MRC = conj(GainEst)*MFOut;                       
Decisions = SimpleSlicer( MRC(1:NSymbols), Alphabet,  ...
    norm(GainEst)^2 );

%% Count errors
NumErrors = sum( Decisions ~= InfoSymbols );

%% Return results in a structure, if needed
if (nargout > 1)
    ResultsStruct.NumErrors  = NumErrors;
    ResultsStruct.NumSymbols = length( Symbols );
    ResultsStruct.Received   = Received;
    ResultsStruct.MFOut      = MFOut;
    ResultsStruct.Symbols    = Symbols;
    ResultsStruct.Decisions  = Decisions;
end