%%%%%%%%%%%%%%%%%%% Equation39.m  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% A Matlab script file which expresses the symmetric cone programme in
% Equation (39) of Wilbur, Davidson and Reilly, ``Efficient Design of 
% Oversampled NPR GDFT Filter Banks'' (accepted for publication, 
% subject to minor revisions, in the IEEE Transactions on Signal 
% Processing, July 2003) in the input format required by
% the Matlab-based general purpose symmetric cone programme solver, SeDuMi.
%
% Update: Equation (39) of the technical report appears as equation (38)
% of the paper in the IEEE Transactions on Signal Processing, 
% 52(7):1947-1963, July 2004.

%%%%%%%%%%%%%%%%%%% Instructions for use %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% The design specifications for the filter are made at the beginning of
% the file.  These can be changed, as desired.

% Following the specifications, is some code which translates these
% specifications into the input format required by SeDuMi. You should
% not need to change this section.

% To solve the optimization problem, you will need to have the
% SeDuMi solver installed on your system. To obtain a copy, and
% for more details on SeDuMi please visit 
% http://fewcal.kub.nl/sturm/software/sedumi.html
% UPDATE, August 2006:
% The home page for SeDuMi has moved to: http://sedumi.mcmaster.ca 

% At the end of the file, there are a few simple commands for
% extracting the optimal autocorrelation and the optimized
% objective value from the output provided by SeDuMi.

%%%%%%%%%%%%%%%%% Legal Statements %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Copyright (C) July 2003.
% Timothy N. Davidson,
% Dept. Elec. & Comp. Engineering,
% McMaster University,
% Hamilton, Ontario, Canada.
% davidson@mcmaster.ca

% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.

% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.

% A copy of the GNU General Public License is available on the web at:
% http://www.gnu.org/copyleft/gpl.html; or by writing to the Free Software
% Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%% The m-file begins... %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%


L=48;    % Filter length
M=8;     % Number of subbands 
Kds=6;   % Downsampling factor

% Now set up the contraints. The default constraints generate
% the point denoted by the triangle in Figure 3.

passband_ripple_dB=1;       % Allowable pass-band ripple
                            % See the discussion in Example 1.

rel_stopband_levels_dB=-30; % The relative stop-band level constraint
                            % This can be a vector if desired

dist_bound_factors=1e-06;   % The normalized distortion coefficient
                            % This can be a vector if desired

normalized_TBEs=1;          % The normalized transition band energy 
                            % constraint. 
                            % This can be a vector if desired

                            % If this constraint is set to 1 then it
                            % will be inactive. 

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% You should not need to change anything below this line. %%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Calculate the maximum spectral component constraint

passband_level_up_dB=10*log10(Kds) + passband_ripple_dB;

% Calculate the stop-band edge

f_s=1/(2*Kds);
f_s_for_mask=f_s;
f_s_for_energy=f_s;

% Calculate the number of elements of r_p which contribute to the
% distortion coefficient

N_dist=floor((L-1)/M);

% Set up some indicies which simplify the expressions for the matrix A

no_diagsX=L;
no_diagsZ=L-1;

no_elemsX=no_diagsX^2;
no_elemsZ=no_diagsZ^2;

startRcone=1+3+1 +1; 
start_sumoffdiagsXup_pb=startRcone+L;
start_sumoffdiagsXup_sb=start_sumoffdiagsXup_pb+L;
start_sumoffdiagsZup_sb=start_sumoffdiagsXup_sb+L;
start_dist_cone=start_sumoffdiagsZup_sb+L-1;

start_Xpr= start_dist_cone+N_dist+1;
start_Xup_pb=start_Xpr+no_elemsX;
start_Xup_sb=start_Xup_pb+no_elemsX;
start_Zup_sb=start_Xup_sb+no_elemsX;
no_vars=start_Zup_sb+no_elemsZ-1;

%Set up some convenient matrices

trace_L = vectransT(0,L-1);
trace_Lmin1 = vectransT(0,L-2);

all_sumoffdiags_L =[];
for ii=1:L-1
  all_sumoffdiags_L=[all_sumoffdiags_L;vectransT(ii,L-1)];
end;

all_sumoffdiags_Lmin1 =[];
for ii=1:L-2
  all_sumoffdiags_Lmin1=[all_sumoffdiags_Lmin1;vectransT(ii,L-2)];
end;

eye_Lmin1=eye(L-1);
dist_selector=eye_Lmin1(M*(1:N_dist),:);

% Now loop over the number of relative stop-band level constraints,
% the number of transition band energy constraints, and the
% number of normalized distortion constraints 

for count_SBLs=1:length(rel_stopband_levels_dB);

rel_stopband_level_dB=rel_stopband_levels_dB(count_SBLs);
stopband_level_dB=passband_level_up_dB +rel_stopband_level_dB; 

for count_TBEs=1:length(normalized_TBEs),

for count_dist_factors=1:length(dist_bound_factors);

dist_bound= sqrt(dist_bound_factors(count_dist_factors)*Kds/M/2);

% Now construct the matrix A, the vectors b and c, and the
% cone descriptor K required by SeDuMi

% Here's the cone descriptor.  The second to fifth quadratic
% cones are actually redundant. However, using them has the
% benefit that it reduces the iteration of the semidefine 
% matrix variables with the rest of the problem. This helps
% to keep the problem sparse. SeDuMi is quite good at exploiting
% sparsity in order to reduce the computational cost of solving
% the problem. 

  K.f=0;
  K.l=1+3+1;
  K.q=[L,L,L,L-1,N_dist+1];
  K.s=[L,L,L,L-1];

%Now we set up A and b to enforce equality constraints.

% Set r_p[0]=K/M;
A = sparse([1,zeros(1,no_vars-1)]);
b=Kds/M;

% Enforce the equality constraints between r_p and the X
% which enforces positive definiteness

A=[A;sparse([1,zeros(1,start_Xpr-2),-trace_L,zeros(1,no_vars-start_Xup_pb+1)])];
b=[b;0];

A=[A;sparse([zeros(L-1,startRcone),eye(L-1),zeros(L-1,start_Xpr -start_sumoffdiagsXup_pb),-all_sumoffdiags_L,zeros(L-1,no_vars-start_Xup_pb+1)])];
b=[b;zeros(L-1,1)];

% Do the same for the X which enforces the maximum spectral component
% constraint and the corresponding cone

temp_offset=1;

A=[A;sparse([zeros(1,temp_offset),1,zeros(1,start_Xup_pb-temp_offset-2),-trace_L,zeros(1,no_vars-start_Xup_sb+1)])];
b=[b;0];


A=[A;sparse([zeros(L-1,start_sumoffdiagsXup_pb),eye(L-1),zeros(L-1,start_Xup_pb-start_sumoffdiagsXup_sb),-all_sumoffdiags_L,zeros(L-1,no_vars-start_Xup_sb+1)])];
b=[b;zeros(L-1,1)];


% Do the same for the X and Z which enforce the maximum stop-band level 
% constraint 

% For the X part
temp_offset=2;
A=[A;sparse([zeros(1,temp_offset),1,zeros(1,start_Xup_sb-temp_offset-2),-trace_L,zeros(1,no_vars-start_Zup_sb+1)])];
b=[b;0];

A=[A;sparse([zeros(L-1,start_sumoffdiagsXup_sb),eye(L-1),zeros(L-1,start_Xup_sb-start_sumoffdiagsZup_sb),-all_sumoffdiags_L,zeros(L-1,(L-1)^2)])];
b=[b;zeros(L-1,1)];

% For the Z part
temp_offset=3;
A=[A;sparse([zeros(1,temp_offset),1,zeros(1,start_Zup_sb-temp_offset-2),-trace_Lmin1])];
b=[b;0];

A=[A;sparse([zeros(L-2,start_sumoffdiagsZup_sb),eye(L-2),zeros(L-2,start_Zup_sb-start_dist_cone),-all_sumoffdiags_Lmin1])];
b=[b;zeros(L-2,1)];


% Now enforce the relationships between the redundant quadratic cones
% and the cone which holds r_p

% For the maximum spectral component 
temp_offset=0;

A=[A;sparse([-1,zeros(1,temp_offset),-1,zeros(1,no_vars-temp_offset-2)])];
b=[b;-10^(passband_level_up_dB/10)];

A=[A;sparse([zeros(L-1,startRcone),-eye(L-1),zeros(L-1,start_sumoffdiagsXup_pb-start_sumoffdiagsXup_pb+1),-eye(L-1),zeros(L-1,no_vars-start_sumoffdiagsXup_sb+1)])];
b=[b;zeros(L-1,1)];

% For the stop-band level constraint

alpha=2*pi*f_s_for_mask;
beta=2*pi*(1-f_s_for_mask);

aa=sin(alpha)/(1-cos(alpha));
bb=sin(beta)/(1-cos(beta));
c0 = -(1+aa*bb);
c1= aa*bb -1 -(aa+bb)*sqrt(-1);
c1=real(c1);


part_matrix_of_Cs=zeros(L-1,L-2);
for ii=1:L-1
  if ii <=L-2
    part_matrix_of_Cs(ii,ii)=2*c0;
  end;
  if ii<= L-3
   part_matrix_of_Cs(ii,ii+1)=c1;
  end;
  if ii>=2,
    part_matrix_of_Cs(ii,ii-1)=conj(c1);
  end;
end;

temp_offset=1;

A=[A;sparse([-1,zeros(1,temp_offset),-1,-c0,zeros(1,start_sumoffdiagsZup_sb-temp_offset-3),-c1,zeros(1,L-3),zeros(1,no_vars-start_dist_cone+1)])];
b=[b;-10^(stopband_level_dB/10)];

A=[A;sparse([zeros(L-1,temp_offset+2),[-conj(c1);zeros(L-2,1)],zeros(L-1,startRcone-temp_offset-3),-2*eye(L-1),zeros(L-1,start_sumoffdiagsXup_sb-start_sumoffdiagsXup_pb+1),-2*eye(L-1),zeros(L-1,1),-part_matrix_of_Cs,zeros(L-1,no_vars-start_dist_cone+1)])];
b=[b;zeros(L-1,1)];

% Now set the bound on the cone which contains copies of the elements of r_p
% which cause distortion

A=[A;sparse([zeros(1,start_dist_cone-1),1,zeros(1,no_vars-start_dist_cone)])];
b=[b;dist_bound];

% Now ensure that equality between the elements of that cone and
% the true elements of r_p

A=[A;sparse([zeros(N_dist,startRcone),-dist_selector,zeros(N_dist,start_dist_cone-start_sumoffdiagsXup_pb+1),eye(N_dist),zeros(N_dist,no_vars-start_Xpr+1)])];
b=[b;zeros(N_dist,1)];

% Now set up the constraint on the transition band energy
% In order to do this via equality constraints, we need a "slack" variable

m_vec=1:L-1;
m_vec=m_vec(:);
one_on_m_vec=1./m_vec;

A=[A;sparse([1/Kds-1/M-normalized_TBEs(count_TBEs),zeros(1,startRcone-3),1,0,2/pi*(one_on_m_vec.').*(sin(pi*(m_vec.')/Kds)-sin(pi*(m_vec.')/M)),zeros(1,no_vars-start_sumoffdiagsXup_pb+1)])];
b=[b;0];


% Construct c so that c'*x is (half) the stop-band energy

c=[1/2-f_s_for_energy;zeros(startRcone-1,1);-1/pi*sin(2*pi*m_vec*f_s_for_energy).*one_on_m_vec;zeros(no_vars-start_sumoffdiagsXup_pb+1,1)];

% The "pars" parameter can be used to control the way in which
% SeDuMi operates. See the SeDuMi Users' Guide

pars=[];

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%% Call to SeDuMi %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Now that the matrix A, the vectors b and c, and the record K have
% been set, the problem can be solved using:
%

[x,y,info]=sedumi(A,b,c,K,pars);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%% Extracting the optimal solution %%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% If the filter specifications are feasible, as recorded in
% the info record above (see the SeDuMi Users' Guide for the
% details), then extract the solution

if info.pinf==0 & info.dinf==0 & info.numerr<2,

% The achieved normalized SBE is stored in a matrix so that trade-offs can be
% easily plotted   

  SBEvDist_tradeoff(count_SBLs,count_dist_factors,count_TBEs)= 2*c'*x/(Kds/M);

% You may also wish to store the optimal autocorrelation for each
% set of constraints.
% The following command stores the optimal r_p[0], ..., r_p[L-1] 

  optimal_autocorrelations(count_SBLs,count_dist_factors,count_TBEs).non_neg_part=[x(1);x(startRcone+1:startRcone+L-1)];


else

% SeDuMi could not (reliably) find a feasible solution

  SBEvDist_tradeoff(count_SBLs,count_dist_factors,count_TBEs)= inf;
  optimal_autocorrelations(count_SBLs,count_dist_factors,count_TBEs).non_neg_part=NaN;
end;

end; %count_Dist_factors
end; %count_TBEs
end; %count_SBLs
