%   Example matlab file for the paper: Balázs Bank, "Converting IIR
%   filters to parallel form," IEEE Signal Processing Magazine, Tips and
%   tricks, 2018.
%   Creating Fig. 3
%
%   http://www.mit.bme.hu/~bank/parconv/
%
%   C. Balázs Bank, 2018.

load roomresp; % loudspeaker-room response
Fs=44100;
N=6000;
impresp=impresp(225+1:N+225);


NB=200; % the order of the numerator
NA=200; % the order of the denominator

[B,A]=stmcb(impresp,NB,NA);  % designing direct-form filter by the Steighlitz-McBride method
imp=zeros(1,N);
imp(1)=1;
filtresp=filter(B,A,imp); % computing the filter response


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% delayed filter - partial fraction expansion

[Bmd,Amd,FIRd]=tf2delparf(B,A); % converting to the delayed parallel filter by partial fraction expansion
parfrespd=delparfilt(Bmd,Amd,FIRd,imp); % computing the parallel filter impulse reponse

% plotting the results
figure(1);
subplot(2,1,1);
[fr,h]=tfplot(filtresp); % plot the original filter response
semilogx(fr,db(h),'b','LineWidth',2);
hold on;
[fr,hp1]=tfplot(parfrespd); % plot the parallel filter response
semilogx(fr,db(hp1),'r--','LineWidth',2);
w=2*pi*fr/Fs;
Z=exp(-j*w(:)); %creating z^-1
Z2=Z.^2; %creating z^-2
Hsectv=zeros(length(w),size(Amd,2));
for k=1:size(Amd,2), % compute the transfer function of the second-order sections
    Hsectv(:,k) = (Bmd(1,k)+Bmd(2,k)*Z)./(Amd(1,k)+Amd(2,k)*Z+Amd(3,k)*Z2);
end;
semilogx(fr,db(Hsectv),'Linewidth',0.5);  % plot the transfer functions of the second-order sections
HFIR=freqz(FIRd,1,w); % plot the FIR part
semilogx(fr,db(HFIR),'k','Linewidth',1.5); 
axis([20 20000 -60 0]);
hold off;
SIZE=14;
set(gca,'FontName','Times','Fontsize',SIZE);
xlabel('Frequency [Hz]');
ylabel('Magnitude [dB]');
puttext('(a)');

start=434; % compute the mean dB error from 20 Hz to Fs/2
e1=mean(abs(db(h(start:end))-db(hp1(start:end))));
fprintf('\nMean abs. dB error for the PFE based conversion, 20Hz to 22kHz: %g dB\n',e1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% delayed filter - least squares procedure

NLS=NB*2; % the length of the impulse response used in the LS fit - must be larger than the number of free parameters NB
[Bmd2,Amd2,FIRd2]=tf2delparf_ls(B,A,NLS); % converting to the delayed parallel form by the LS fit
parfrespd2=delparfilt(Bmd2,Amd2,FIRd2,imp); % computing the parallel filter impulse reponse

% plotting the results
subplot(2,1,2);
[fr,h]=tfplot(filtresp); % plot the original filter response
semilogx(fr,db(h),'b','LineWidth',2);
hold on;
[fr,hp2]=tfplot(parfrespd2); % plot the parallel filter response
semilogx(fr,db(hp2),'r--','LineWidth',2);
w=2*pi*fr/Fs;
Z=exp(-j*w(:)); %creating z^-1
Z2=Z.^2; %creating z^-2
Hsectv=zeros(length(w),size(Amd2,2));
for k=1:size(Amd2,2), % compute the transfer function of the second-order sections
    Hsectv(:,k) = (Bmd2(1,k)+Bmd2(2,k)*Z)./(Amd2(1,k)+Amd2(2,k)*Z+Amd2(3,k)*Z2);
end;
semilogx(fr,db(Hsectv),'Linewidth',0.5); % plot the transfer function of the second-order sections
HFIR=freqz(FIRd2,1,w);
semilogx(fr,db(HFIR),'k','Linewidth',1.5); % plot the transfer function of the FIR part
axis([20 20000 -60 0]);
hold off;
SIZE=14;
set(gca,'FontName','Times','Fontsize',SIZE);
xlabel('Frequency [Hz]');
ylabel('Magnitude [dB]');
puttext('(b)');

start=434; % compute the mean dB error from 20 Hz to Fs/2
e2=mean(abs(db(h(start:end))-db(hp2(start:end))));
fprintf('Mean abs. dB error for the LS based conversion, 20Hz to 22kHz: %g dB\n \n',e2);



