function [f_opt,b_opt,delay,mmse]=trdfe_opt_taps(channel,Lf,Lb,lambda); 

% [f_opt,b_opt,delay,mmse]=trdfe_opt_taps(channel,Lf,Lb,lambda)
%
% This function optimizes the MMSE-BiDFE(unbiased) tap settings, that 
% minimizes MSE at the output of the LC-BiDFE. Channel and DFE are assumed 
% to be symmetric and baud-spaced. It is assumed that f1=f2, b1=b2, 
% and equal-gain combining 
%
% channel - Channel impulse response (should be a row vector)
% Lf - Number of FFF taps
% Lb - Number of FBF taps
% lambda - (Noise variance)/(Signal Variance)
% f_opt - optimal FFF filter taps
% b_opt optimal FBF filter taps
% delay - optimal delay 
% mmse - minimum mean-squared error

[c]=channel;  % Initialize channel parameters;
Lc=length(c); % length of channel
Lh=Lc+Lf-1;

cm = transpose(convmtx(c,Lf)); % Find convolution matrix

% Baud spaced equalizer

[delta1,junk]=size(cm);
I_delta1=eye(delta1);
f1=zeros(Lf,delta1);
b1=zeros(Lb,delta1);

for delay1=1:delta1, % Delay optimization

% Generate the shifting matrices

S1=zeros(2*Lh-1,Lh);S2=S1;
M1=zeros(Lh+Lf-1,Lf);M2=M1;
S1(Lh-delay1+1:2*Lh-delay1,:)=eye(Lh);
S2(delay1:Lh+delay1-1,:)=fliplr(eye(Lh));
if ((2*delay1-1-Lh) >= 0)
     M1(1:Lf,:)=eye(Lf);
     M2(2*delay1-Lh:2*delay1-Lc,:)=fliplr(eye(Lf));
else
     M1(Lh-2*delay1+2:Lh-2*delay1+1+Lf,:)=eye(Lf);
     M2(1:Lf,:)=fliplr(eye(Lf));
end;

I_delta=I_delta1;
I_delta(delay1+1:min(delta1,delay1+Lb),delay1+1:min(delta1,delay1+Lb))=zeros(min(Lb,delta1-delay1));

% Generate solution

Temp=pinv(transpose((S1+S2)*I_delta*cm)*(S1+S2)*I_delta*cm+lambda*transpose(M1+M2)*(M1+M2))*transpose((S1+S2)*I_delta*cm)*(S1+S2);
f=zeros(Lf,1);b=zeros(Lb,1); % Initialize temporary variable
f=Temp(:,delay1);
h=cm*f;
b(1:min(Lb,delta1-delay1))=h(delay1+1:min(delta1,delay1+Lb));
f1(:,delay1)=f/h(delay1);
b1(:,delay1)=b/h(delay1);
mse(delay1)=trdfe_mse(c,f1(:,delay1),b1(:,delay1),delay1,lambda);
end;

[mmse,index]=min(mse);  % Delay optimization of mse
f_opt=f1(:,(index)); % FFF taps
b_opt=b1(:,(index)); % FBF taps
delay=index;









