function SymbolEst = OFDMDemod( Signal, NCarriers, LPrefix, NSymbols )
% OFDMDemod - Orthogonal frequency divison multiplexing demodulator
%
% Inputs:
%   Signal     - vector of OFDM samples
%   NCarriers  - number of carriers; block size
%   LPrefix    - length of cyclic prefix
%   NSymbols   - number of information symbols
%
% Output:
%   SymbolEst  - Symbol Estimates for input to slicer
%
% Example:
%   SymbolEst = OFDMDemod( Signal, NCarriers, LPrefix, NSymbols )

%% convert symbols to row vector
% the processing below assumes signals passed as row vector. We enforce
% this convention here and restore matters at the end.
OrigSize     = size(Signal);
DoReverseDim = false;

if ( min( OrigSize ) > 1 )
    error('First input must be a row or column vector');
end

if( OrigSize(1) > 1 ) % it's a column vector
    Signal = Signal.';
    DoReverseDim = true;
end

%% Serial-to-parallel conversion
NBlocks = ceil( length(Signal) / (NCarriers+LPrefix) );
if ( (NCarriers+LPrefix)*NBlocks ~= length(Signal) )
    error('Length of Signal must be a multiple of (NCarriers+LPrefix)');
end
% serial-to-parallel
Blocks = reshape( Signal/sqrt(NCarriers), NCarriers+LPrefix, NBlocks );

%% remove cyclic prefix
% remove first LPrefix samples of each column
Blocks( 1:LPrefix, : ) = [ ];

%% FFT
% fft works column-wise by default
Blocks = fft( Blocks );

%% Parallel-to-serial conversion
SymbolEst = reshape( Blocks, 1, NBlocks*NCarriers );
% remove zero-padding
SymbolEst = SymbolEst(1:NSymbols);

%% restore original dimensions
if ( DoReverseDim )
    SymbolEst = SymbolEst.';
end