%% FUNCIÓN BER GFDM
%<BER_GFDM>

%PARÁMETROS DE RETORNO:
%berEst: vector valores BER estimado
%EbNoVec: vector EbNo en dB

%PARÁMETROS DE INGRESO:
%parametros: Estructura con parámetros de simulación

function  [berEst,EbNoVec]= BER_GFDM(parametros);

% Inicialización de parámetros
numTotBits =32*2*(parametros.numSub-1);%Número total de bits. Equivale a (32 bloques*2 bitsPorSubportadora*(numSubportadoras-1))
numSubSimb=parametros.numSubSimb;%Número de subsímbolos
numSubP=(parametros.numSub-1)/numSubSimb; %Número de subportadoras
pc=parametros.pc(2);%Longitud prefijo cíclico
totSubEq=floor((numSubP*parametros.tamFFT/parametros.numSub));%Total subportadoras equivalente
longSigMap=numTotBits/2;%numTotBits/bitPorSubportadora
nBloq = longSigMap/(numSubP*numSubSimb);%número de bloques
longBloq = numSubSimb * numSubP;%longitud del bloque
totNumSubSimb= numSubSimb;%número total de subsímbolos
longTotBloq = totSubEq * totNumSubSimb;%longitud total del bloque
sGFDM = zeros((nBloq*longTotBloq)+pc,1);%Inicialización señal GFDM
bGlat=(totSubEq-numSubP)/2;%Banda de guarda lateral

EbNoVec = 0:10;
numErrs   = zeros(length(EbNoVec), 1);
sf = zeros(numSubP,numSubSimb,nBloq);%hipermatriz[numSubPortadoras,numSubSimbolos,numBloques]
s2 = zeros(numSubP*numSubSimb,nBloq);%matriz[vector fila a partir de submatriz KxM,columnas equivale a número de bloques]
s3 = zeros(1,numSubP*numSubSimb*nBloq);%vector fila con señal recibida previa demodulación QPSK

% Filtro coseno alzado
g=fca(totNumSubSimb,totSubEq,0.3);%equivale a fca(M,K,alpha)

%*****************************TX*****************************
% Generación datos
datosIn = generacionDatos(numTotBits)';

% Modulación QPSK
 datosQPSK=modQPSK(datosIn);

for i = 0:nBloq-1 %Iteración por cada bloque
   
    %Mapeo estructuctura KxM 
    mapSig=mapKxM(datosQPSK,longBloq,i,nBloq, numSubP, numSubSimb);%señal mapeada KxM

    %Cálculo IFFT
    sig_rep = calcIFFT_GFDM(totSubEq,totNumSubSimb,bGlat,numSubP,mapSig);%Cálculo y arreglo con repetición de matriz

    sig_sum = zeros(longTotBloq, 1);%Inicialización acumulador suma de señales
    
    for j = 1:totNumSubSimb %Iteración en subsímbolos de cada bloque
        % Conformación pulso digital 
        sCPD = sig_rep(:,j).*g;
        sCPD = circshift(sCPD, totSubEq*(j-1));
        sig_sum = sig_sum + sCPD;
    end
    
     % Inserción prefijo cíclico
        sig_pc = [sig_sum(end-pc+1:end); sig_sum];
        sGFDM(i*(longTotBloq+pc) + (1:longTotBloq + pc)) = sig_pc; 
end

vTxGFDM = sGFDM.';%señal transmitida

%*****************************RX*****************************

for si = 1:length(EbNoVec)% Iteración por cada elemento del vector EbNo
    
    D = zeros(totSubEq,numSubSimb,nBloq);%hipermatriz [subportadoras_equivalente,subsímbolos,num_bloques]

    % Paso de la señal a través de un canal AWGN
    snrdB = EbNoVec(si);
    rxSig = awgn(vTxGFDM,snrdB,'measured');%señal recibida tras paso por canal con ruido AWGN

    % Remoción prefijo cíclico
    x=rxSig;
    y = reshape(x,[],nBloq);
    y = y(pc+1:end,:); 
 
    for b = 1:nBloq %Iteración por cada bloque
        % Cálculo FFT
        yhat = y(:,b);
        xhat = fft(yhat);

        for k = 1:totSubEq %Iteración por cada subportadora equivalente
           % Filtro adaptado
           dhat = FA_GFDM(g,numSubSimb,xhat,k);
           D(k,:,b) = dhat;
        end

         % Remoción bandas de guarda
         sf(:,:,b) = D(bGlat+1:numSubP+bGlat,:,b); 
         s2(:,b) = reshape(sf(:,:,b),[],1);
         
    end
        s3 = reshape(s2,1,[]);
        
        %Demodulación QPSK
        datosOut=demQPSK(s3);
        
        % Cálculo error
        numErrs(si) = biterr(datosOut,datosIn');

end

% Cálculo BER
berEst = numErrs/length(datosOut);

end


