%DFILDEMO Nonlinear filter design problem using discrete optimization.

%   Copyright (c) 1990-98 by The MathWorks, Inc.
%   $Revision: 1.17 $  $Date: 1998/07/21 22:50:23 $

clf
echo on
% Example script-file for the design of finite precision filters
nbits = 8;      % How many bits have we to realize filter
maxbin = 2^nbits-1;     % Maximum number
n=4;            % Number of coefficients (Order of filter plus 1)
Wn = 0.2;       % Cut-off frequency for filter
Rp = 1.5;       % Decibels of ripple in the passband
w = 128;        % Number of frequency points to take 

% Continuous filter design 
% (could use any of cheby, ellip, yulewalk or remez here.)
[b1,a1]=cheby1(n-1,Rp,Wn); 


pause % Strike any key to continue

[h,w]=freqz(b1,a1,w);   % Frequency response
h=abs(h);       % Magnitude response
plot(w, h), title('Frequency response using non-integer variables')
x = [b1,a1];        % The design variables

% Set bounds on the maximum and minimum values. 
if (any(x < 0))
% If there are negative coefficients - must use sign bit
    maxbin = floor(maxbin/2);
    vlb = -maxbin * ones(1, 2*n)-1;
    vub = maxbin * ones(1, 2*n); 
else
% otherwise, all positive
    vlb = zeros(1,2*n); 
    vub = maxbin * ones(1, 2*n); 
end

% Set the biggest value equal to maxbin. 
[m, mix] = max(abs(x)); 
factor =  maxbin/m; 
x =  factor * x;    % Rescale other filter coefficients
xorig = x;

xmask = 1:2*n;
% Remove the biggest value and the element that controls D.C. Gain
% from the list of values that can be changed. 
xmask([mix]) = [];
nx = 2*n; 

pause % Strike any key to continue

% Set termination criteria to reasonably high values 
% to promote fast convergence.

options = optimset('Display','iter','TolX',0.1,'TolFun',1e-4,'TolCon',1e-6);

% Need to minimize absolute maximum values so set options.MinAbsMax to the 
% number of frequency points. 

if length(w) == 1
   options = optimset(options,'MinAbsMax',w);
else
   options = optimset(options,'MinAbsMax',length(w));
end

pause % Strike any key to continue

% Discretize and eliminate first value
[x, xmask] = elimone(x, xmask, h, w, n, maxbin)

pause % Strike any key to continue

niters = length(xmask); 

pause % Strike any key to continue

disp(sprintf('Performing %g stages of optimization.\n\n', niters));

% This may take a long time ! (Ctrl-C to abort)

for m = 1:niters
    disp(sprintf('Stage: %g \n', m));
    x(xmask) = fminimax('filtobj',x(xmask),[],[],[],[],vlb(xmask),vub(xmask),'filtcon',options,x, xmask, n, h, maxbin);
    [x, xmask] = elimone(x, xmask, h, w, n, maxbin);
end

% Check nearest integer values for better filter
pause % Strike any key to continue

xold = x;
xmask = 1:2*n;
xmask([n+1, mix]) = [];
x = x + 0.5; 
for i = xmask
    [x, xmask] = elimone(x, xmask, h, w, n, maxbin);
end
xmask = 1:2*n;
xmask([n+1, mix]) = [];
x= x - 0.5;
for i = xmask
    [x, xmask] = elimone(x, xmask, h, w, n, maxbin);
end
if any(abs(x) > maxbin), x = xold; end

% Frequency response of filter
pause % Strike any key to continue
subplot(211)
bo = x(1:n); 
ao = x(n+1:2*n); 
h2 = abs(freqz(bo,ao,128));
plot(w,h,w,h2,'o')
title('Optimized filter versus original')

% Compare it to a filter where the coefficients are just rounded 
% up or down.
xround =round(xorig)
b = xround(1:n); 
a = xround(n+1:2*n); 
h3 = abs(freqz(b,a,128));
subplot(212)
plot(w,h,w,h3,'+')
title('Rounded filter versus original')
set(gcf,'NextPlot','replace')
