% Bidirectional DFE

% Initialization
rand('seed',0);
block_num=[100*ones(1,8) 1000*ones(1,12)];   
% Number of blocks
N=1000;           % block length
Lf=4;            % Number of feedfroward taps
Lb=3;             % Number of feedback taps
P=1;              % Fractional sampling factor
snr=[2:1:14];            % in dB

% Generate Channel & equalizer

C1=[0.3162 1 0.3162];
C2=[0.2 1 0.3162 -0.2 0.1 -0.05 0.02];
C3=[-0.3920  0.0152  0.8320  0.0152  -0.3920]
C=C2;
C=C./sqrt(C*C');%'

tic
for snr_index=1:length(snr)
snr(snr_index)
sig=10^(-snr(snr_index)/20);

[f_opt,b_opt,delay,mmse]=dfe_tap_estimator(C,Lf,Lb,10^(-snr(snr_index)/10),P,0);
[f_opt_tr,b_opt_tr,delay_tr,mmse_tr]=dfe_tap_estimator(fliplr(C),Lf,Lb,10^(-snr(snr_index)/10),P,0);
[mmse_div,rho,alpha]=trdfe_mse(C,f_opt,b_opt,delay,f_opt_tr,b_opt_tr,delay_tr,10^(-snr(snr_index)/10));
Lc=length(C);

for iter=1:block_num(snr_index)
iter
% Generate Source Sequence
symb=pam(N,2,1);
symb_up=zeros(1,P*N-P+1);
symb_up(1:P:P*N-P+1)=symb;

% Transmit through channel
rec_seq=conv(symb_up,C);
rec_seq=rec_seq+noise(length(rec_seq),snr(snr_index),1);

% Feedforward filtering
rec_seq1=conv(rec_seq,transpose(f_opt));
r=rec_seq1(delay:P:end); % downsampled signal

% Feedback filtering

% Ideal feedback
symb_hat_ideal(1:Lb)=symb(1:Lb);
for k=Lb+1:N
y(k)=r(k)-symb(k-1:-1:k-Lb)*b_opt;
symb_hat_ideal(k)=pamdet(y(k),2,1);
end;

% Hard Decision feedback
symb_hat(1:Lb)=symb(1:Lb);
for k=Lb+1:N
y(k)=r(k)-symb_hat(k-1:-1:k-Lb)*b_opt;
symb_hat(k)=pamdet(y(k),2,1);
end;

% Soft Decision feedback
symb_hat_soft(1:Lb)=symb(1:Lb);
for k=Lb+1:N
y_soft(k)=r(k)-symb_hat_soft(k-1:-1:k-Lb)*b_opt;
symb_hat_soft(k)=tanh(y_soft(k)/sig);
end;

% Time reversed decision feedback

% Feedforward filtering
rec_seq_tr=fliplr(rec_seq);
rec_seq1_tr=conv(rec_seq_tr,transpose(f_opt_tr));
r_tr=rec_seq1_tr(delay_tr:P:end); % downsampled signal

% Feedback filtering

% Ideal feedback
symb_tr=fliplr(symb);
symb_hat_ideal_tr(1:Lb)=symb_tr(1:Lb);
for k=Lb+1:N
y_tr(k)=r_tr(k)-symb_tr(k-1:-1:k-Lb)*b_opt_tr;
symb_hat_ideal_tr(k)=pamdet(y_tr(k),2,1);
end;

% Hard Decision feedback
symb_hat_tr(1:Lb)=symb_tr(1:Lb);
for k=Lb+1:N
y_tr(k)=r_tr(k)-symb_hat_tr(k-1:-1:k-Lb)*b_opt_tr;
symb_hat_tr(k)=pamdet(y_tr(k),2,1);
end;

% Soft Decision feedback
symb_hat_soft_tr(1:Lb)=symb_tr(1:Lb);
for k=Lb+1:N
y_soft_tr(k)=r_tr(k)-symb_hat_soft_tr(k-1:-1:k-Lb)*b_opt_tr;
symb_hat_soft_tr(k)=tanh(y_soft_tr(k)/sig);
end;


% Diversity combining for hard decision feedback
err_seq=abs(sign(symb-symb_hat));
err_seq_tr=abs(sign(symb_tr-symb_hat_tr));

% Diversity combining for soft decision feedback (BPSK)
err_seq_soft=abs(sign(symb-sign(symb_hat_soft)));
err_seq_soft_tr=abs(sign(symb_tr-sign(symb_hat_soft_tr)));

% Optimal (demon-aided !) Combining
err_opt=min(err_seq,fliplr(err_seq_tr));


% Suboptimal combining for hard DFE(Add & detect)
symb_hat_subopt1(1:Lb)=symb(1:Lb);
symb_hat_subopt1(N-Lb+1:N)=symb(N-Lb+1:N);
symb_hat_subopt1(Lb+1:N-Lb)=pamdet(alpha*y(Lb+1:N-Lb)+(1-alpha)*fliplr(y_tr(Lb+1:N-Lb)),2,1);

% Suboptimal combining for soft DFE(Add & detect)
symb_hat_soft_subopt1(1:Lb)=symb(1:Lb);
symb_hat_soft_subopt1(N-Lb+1:N)=symb(N-Lb+1:N);
symb_hat_soft_subopt1(Lb+1:N-Lb)=pamdet(alpha*y_soft(Lb+1:N-Lb)+(1-alpha)*fliplr(y_soft_tr(Lb+1:N-Lb)),2,1);

% Plots & Performance measures

ser_ideal(iter)=symberror(symb,symb_hat_ideal);
ser(iter)=symberror(symb,symb_hat);
ser_soft(iter)=symberror(symb,sign(symb_hat_soft));
ser_ideal_tr(iter)=symberror(symb_tr,symb_hat_ideal_tr);
ser_tr(iter)=symberror(symb_tr,symb_hat_tr);
ser_soft_tr(iter)=symberror(symb_tr,sign(symb_hat_soft_tr));
ser_opt(iter)=mean(err_opt);
ser_subopt1(iter)=symberror(symb,symb_hat_subopt1);
ser_soft_subopt1(iter)=symberror(symb,symb_hat_soft_subopt1);


end;

SER_ideal(snr_index)=mean(ser_ideal)
SER(snr_index)=mean(ser)
SER_soft(snr_index)=mean(ser_soft)
SER_ideal_tr(snr_index)=mean(ser_ideal_tr)
SER_tr(snr_index)=mean(ser_tr)
SER_soft_tr(snr_index)=mean(ser_soft_tr)
SER_opt(snr_index)=mean(ser_opt)
SER_subopt1(snr_index)=mean(ser_subopt1)
SER_soft_subopt1(snr_index)=mean(ser_soft_subopt1)
%SER_subopt2(snr_index)=mean(ser_subopt2)

end;

figure;
pl1=semilogy(snr,SER_ideal,'r');
hold on;
pl2=semilogy(snr,SER,'b-.');
pl3=semilogy(snr,SER_tr,'m-*');
pl4=semilogy(snr,SER_subopt1,'k-^');
pl5=semilogy(snr,SER_soft_subopt1,'g--');
xlabel('SNR  in  dB','FontSize',18);
ylabel('Symbol  Error  Rate','FontSize',18);
legend([pl1,pl2,pl3,pl4,pl5],'Ideal feedback','Normal Mode DFE','Time-Reversal Mode DFE','LC-BiDFE: Hard,'LC-BiDFE: Soft');
grid;

save result_trdfe_asym1 block_num snr SER_ideal SER SER_soft SER_tr SER_soft_tr SER_opt SER_subopt1 SER_soft_subopt1 SER_ideal_tr C Lf Lb P N;

toc







