function [NumErrors, ResultsStruct] = MCOFDM( ParametersStruct )
% MCOFDM - Monte Carlo Simulation of a OFDM Communications System
%
% Simulate a OFDM communication system and measure the symbol error rate.
% The main limitation of this simulation is that the receiver it employs
% accounts only for additive, white Gaussian noise and is not equipped to
% handle intersymbol interference.
%
% Inputs:
%   ParametersStruct - a structure containing system parameters ( see
%   MCOFDMDriver for details) 
%
% Output:
%   NumErrors     - number of errors
%   ResultsStruct - return complete results in a structure; look at
%                   fieldnames for details.
%
% Example:
%   NumErrors = MCOFDM( ParametersStruct )

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

%% derived parameters
A        = sqrt(Es/T*Nc); % transmitter gain
N0       = Es/EsOverN0;   % noise PSD (complex noise)
NoiseVar = N0/T*fsT;      % corresponding noise variance N0/Ts
Scale    = A;             % gain through signal chain

%% simulate OFDM system
% transmitter and channel via toolbox functions
Symbols = RandomSymbols( NSymbols, Alphabet, Priors );
Signal = A * OFDMMod( Symbols, Nc, Lp );
Received = addNoise( Signal, NoiseVar );

% OFDM Receiver
MFOut     = OFDMDemod( Received, Nc, Lp, NSymbols );
Decisions = SimpleSlicer( MFOut, Alphabet,  Scale );

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

%% 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;
    ResultsStruct.Scale      = Scale;
end