Code covered by the BSD License  

Highlights from
Analog Filter Design Toolbox

image thumbnail

Analog Filter Design Toolbox

by

 

27 Dec 2005 (Updated )

GUI to design and simulate active (opamp) LP and HP Bessel, Butter, Cheby, and Elliptic filters.

strFilterObject=Utility_zpk(strFilterObject,p2,p3,p4)
function strFilterObject=Utility_zpk(strFilterObject,p2,p3,p4)
% Utility_zpk is a subfile of the AnalogFilter GUI collection
%
% James C. Squire, 2002
% Assistant Professor, Virginia Military Institute
% ver 1.0

% Utility_zpk returns finds the zeros, poles, and gain of an analog filter
% The filter, strFilterObject, is a global variable

%global strFilterObject

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%      Fminsearch  Callbacks        %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

if nargin==4 % called as part of fminsearch for the elliptic filters
    switch p4
        case 'krat'
            m=strFilterObject;
            krat=p2;
            m = min(1,max(m,0));
            if abs(m) > eps & abs(m)+eps < 1
                k = ellipke([m,1-m]);
                r = k(1)./k(2) - krat;
            elseif abs(m) <= eps	% m==0
                r = -krat;
            else	% m==1 => r == inf, but can't for non-ieee machines
                r = 1e20;
            end
            strFilterObject = abs(r);
        case 'vrat'
            u=strFilterObject;
            ineps=p2;
            mp=p3;
            [s,c] = ellipj(u,mp);
            strFilterObject = abs(ineps - s/c);
        otherwise
            error(['Unknown fminsearch callback in ' mfilename])
    end
    return
end   

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%           Main Program            %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Create local variables
n = strFilterObject.nOrder;
Wc = strFilterObject.fFc * 2* pi;
Gp = strFilterObject.fGp;
Gs = strFilterObject.fGs;
Gain = strFilterObject.fGain;

% Get N-th order normalized  prototype
switch lower(strFilterObject.sType)
    case 'bessel'
        [z,p,k] = NormalBessel(n);
    case 'butterworth'
        [z,p,k] = NormalButterworth(n);
    case 'chebychev i'
        [z,p,k] = NormalChebychevI(n,Gp);
    case 'chebychev ii'
        [z,p,k] = NormalChebychevII(n,Gs);
    case 'elliptic'
        [z,p,k] = NormalElliptic(n,Gp,Gs);
    otherwise
        error(['Unknown Type in ' mfilename])
end

% Scale frequency and change to highpass if necessary
switch lower(strFilterObject.sPurpose)
    case 'lowpass'
        [z,p,k] = denormalizeLP(z,p,k,Wc);
    case 'highpass'
        [z,p,k] = denormalizeHP(z,p,k,Wc);
    otherwise
        error(['Unknown Purpose in ' mfilename])
end

% sort, pair, and fix roundoff errors
strFilterObject.vZeros = cplxpair(z);
strFilterObject.vPoles = cplxpair(p);
strFilterObject.fK = k*Gain;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%              Bessel               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [z,p,k] = NormalBessel(n)
z = [];
switch n
    case 1
        p = -1;
        k = 1;
    case 2
        p = [-1.10160133059216 + 0.63600982475703*i; -1.10160133059216 - 0.63600982475703*i];
        k =  1.61803398874989;
    case 3
        p = [-1.04740916100894 + 0.99926443628064*i; -1.04740916100894 - 0.99926443628064*i; -1.32267579991044];
        k = 2.77179327460633;
    case 4
        p = [ -1.37006783055144 + 0.41024971749375*i;-1.37006783055144 - 0.41024971749375*i;-0.99520876435027 + 1.25710573945467*i; -0.99520876435027 - 1.25710573945467*i];
        k = 5.25819901024417;
    case 5
        p = [ -0.95767654856268 + 1.47112432073039*i;-0.95767654856268 - 1.47112432073039*i;-1.38087732586044 + 0.71790958762677*i;-1.38087732586044 - 0.71790958762677*i;-1.50231627144748];
        k = 11.21283668537052;
    case 6
        p = [-1.57149040361604 + 0.32089637422262*i; -1.57149040361604 - 0.32089637422262*i;-1.38185809759657 + 0.97147189071158*i;-1.38185809759657 - 0.97147189071158*i; -0.93065652294686 + 1.66186326894259*i;-0.93065652294686 - 1.66186326894259*i];
        k = 26.62976888914601;
    case 7
        p = [-0.90986778062347 + 1.83645135303639*i;-0.90986778062347 - 1.83645135303639*i; -1.37890321679547 + 1.19156677780065*i; -1.37890321679547 - 1.19156677780065*i; -1.61203876622612 + 0.58924450693146*i; -1.61203876622612 - 0.58924450693146*i; -1.68436817927317];
        k = 69.22126457866750;
    case 8
        p = [-1.75740840040164 + 0.27286757510224*i;-1.75740840040164 - 0.27286757510224*i;-1.63693941812687 + 0.82279562513969*i;-1.63693941812687 - 0.82279562513969*i;-1.37384121763736 + 1.38835657587755*i;-1.37384121763736 - 1.38835657587755*i;-0.89286971884713 + 1.99832584364129*i;-0.89286971884713 - 1.99832584364129*i];
        k = 1.940261933033208e+002;
    case 9
        p = [-0.87839927616096 + 2.14980052431333*i;-0.87839927616096 - 2.14980052431333*i; -1.36758830979291 + 1.56773371223728*i;-1.36758830979291 - 1.56773371223728*i;-1.65239648457884 + 1.03138956698440*i;-1.65239648457884 - 1.03138956698440*i;-1.80717053496210 + 0.51238373057492*i;-1.80717053496210 - 0.51238373057492*i;-1.85660050122801];
        k = 5.801750529768317e+002;
    case 10
        p = [-1.92761969137237 + 0.24162347097177*i;-1.92761969137237 - 0.24162347097177*i;-1.84219624452473 + 0.72725759775741*i;-1.84219624452473 - 0.72725759775741*i;-1.66181024136221 + 1.22110021857916*i;-1.66181024136221 - 1.22110021857916*i;-1.36069227838455 + 1.73350574266150*i;-1.36069227838455 - 1.73350574266150*i;-0.86575690170838 + 2.29260483098249*i;-0.86575690170838 - 2.29260483098249*i];
        k = 1.836246770717193e+003;
    case 11
        p = [-0.85451258135236 + 2.42805946691507*i;-0.85451258135236 - 2.42805946691507*i;-1.35348667738810 + 1.88829684475974*i;-1.35348667738810 - 1.88829684475974*i;-1.66719364224535 + 1.39596290364648*i;-1.66719364224535 - 1.39596290364648*i;-1.86736123888712 + 0.92311558295178*i;-1.86736123888712 - 0.92311558295178*i;-1.98016064530384 + 0.45959874382676*i;-1.98016064530384 - 0.45959874382676*i;-2.01670147345004];
        k = 6.114589477119062e+003;
    case 12
        p = [ -2.08464450693174 + 0.21916153519047*i;-2.08464450693174 - 0.21916153519047*i;-2.01994593307477 + 0.65899650071675*i;-2.01994593307477 - 0.65899650071675*i;-1.88564961973203 + 1.10381488121541*i;-1.88564961973203 - 1.10381488121541*i;-1.66980358885276 + 1.55880270084110*i;-1.66980358885276 - 1.55880270084110*i;-1.34617468029050 + 2.03399850827847*i;-1.34617468029050 - 2.03399850827847*i;-0.84437887285039 + 2.55718896920289*i;-0.84437887285039 - 2.55718896920289*i];
        k = 2.131985288096244e+004;
    case 13
        p = [-0.83515201045011 + 2.68080279689105*i;-0.83515201045011 - 2.68080279689105*i;-1.33888032408279 + 2.17202294710701*i;-1.33888032408279 - 2.17202294710701*i;-1.67045856262298 + 1.71167828638810*i;-1.67045856262298 - 1.71167828638810*i;-1.89898611748036 + 1.27211943651370*i;-1.89898611748036 - 1.27211943651370*i;-2.05058087608408 + 0.84338310857716*i;-2.05058087608408 - 0.84338310857716*i;-2.13764829462372 + 0.42041630675713*i;-2.13764829462372 - 0.42041630675713*i;-2.16608270567884];
        k = 7.752998977990125e+004;
    case 14
        p = [-2.23093074227585 + 0.20200027007892*i;-2.23093074227585 - 0.20200027007892*i;-2.17970952065207 + 0.60702982702828*i;-2.17970952065207 - 0.60702982702828*i;-2.07445158463977 + 1.01536708959161*i;-2.07445158463977 - 1.01536708959161*i;-1.90866457514154 + 1.43007973190289*i;-1.90866457514154 - 1.43007973190289*i;-1.66971016070877 + 1.85613874359928*i;-1.66971016070877 - 1.85613874359928*i;-1.33167919736814 + 2.30345534461641*i;-1.33167919736814 - 2.30345534461641*i;-0.82668133243230 + 2.79955221217277*i;-0.82668133243230 - 2.79955221217277*i];
        k = 2.930813527521330e+005;
    case 15
        p = [ -0.81885183033332 + 2.91396992652773*i;-0.81885183033332 - 2.91396992652773*i;-2.28342656234184 + 0.38982893598505*i;-2.28342656234184 - 0.38982893598505*i;-2.21352748734394 + 0.78142997785105*i;-2.21352748734394 - 0.78142997785105*i;-2.09319972155537 + 1.17691617609367*i;-2.09319972155537 - 1.17691617609367*i;-1.91558434659226 + 1.57926035556851*i;-1.91558434659226 - 1.57926035556851*i;-1.66794080077851 + 1.99338080832681*i;-1.66794080077851 - 1.99338080832681*i;-1.32461676006183 + 2.42914977398455*i;-1.32461676006183 - 2.42914977398455*i;-2.30637005662894];
        k = 1.148461735754945e+006;
    case 16
        p = [ -2.36834668175327 + 0.18833295674897*i;-2.36834668175327 - 0.18833295674897*i;-2.32647906263646 + 0.56573669095214*i;-2.32647906263646 - 0.56573669095214*i;-2.24099322267511 + 0.94547404667305*i;-2.24099322267511 - 0.94547404667305*i;-2.10799083457213 + 1.32955250584788*i;-2.10799083457213 - 1.32955250584788*i;-1.92038809489843 + 1.72088333292392*i;-1.92038809489843 - 1.72088333292392*i;-1.66542192928512 + 2.12434959299958*i;-1.66542192928512 - 2.12434959299958*i;-1.31771943728305 + 2.54979207329592*i;-1.31771943728305 - 2.54979207329592*i;-0.81157346724783 + 3.02449807602193*i;-0.81157346724783 - 3.02449807602193*i];
        k = 4.653711491998211e+006;
    otherwise
        error(['Order of bessel filter in ' mfilename ' cannot be greater than 16'])
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%           Butterworth             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [z,p,k] = NormalButterworth(n)
z = [];
p = exp(i*(pi*(1:2:n-1)/(2*n) + pi/2));
p = [p; conj(p)];
p = p(:);
if rem(n,2)==1   % n is odd
    p = [p; -1];
end
k = real(prod(-p));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%           Chebychev I             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [z,p,k] = NormalChebychevI(n,Gp)
epsilon = sqrt(10^(.1*Gp)-1);
mu = asinh(1/epsilon)/n;
p = exp(j*(pi*(1:2:2*n-1)/(2*n) + pi/2)).';
p = sinh(mu)*real(p) + j*cosh(mu)*imag(p);
z = [];
k = real(prod(-p));
if ~rem(n,2)	% n is even so patch k
	k = k/sqrt((1 + epsilon^2));
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%           Chebychev II            %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [z,p,k] = NormalChebychevII(n,Gs)
delta = 1/sqrt(10^(.1*Gs)-1);
mu = asinh(1/delta)/n;
if (rem(n,2))
	m = n - 1;
	z = j ./ cos([1:2:n-2 n+2:2:2*n-1]*pi/(2*n))';
else
	m = n;
	z = j ./ cos((1:2:2*n-1)*pi/(2*n))';
end
p = exp(j*(pi*(1:2:2*n-1)/(2*n) + pi/2)).';
p = sinh(mu)*real(p) + j*cosh(mu)*imag(p);
p = 1 ./ p;
k = real(prod(-p)/prod(-z));

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%            Elliptic               %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [z,p,k] = NormalElliptic(n,Gp,Gs)
if n == 1,    
    z = [];	p = -sqrt(1/(10^(Gp/10)-1)); k = -p;
    return
else
    % Zeros
    epsilon = sqrt(10^(0.1*Gp)-1);
    k1 = epsilon/sqrt(10^(0.1*Gs)-1);
    k1p = sqrt(1-k1^2);
    if k1p == 1
        error('Cannot design filter, Gp and Gs specifications are too strict.')
    end
    wp = 1;
    if abs(1-k1p^2) < eps
        krat = 0;
    else
        capk1 = ellipke([k1^2,k1p^2]);
        krat = n*capk1(1)/capk1(2);
    end
    fopt = optimset('maxfunevals',250,'maxiter',250,'display','none');
    m = fminsearch('Utility_zpk',.5,fopt,krat,[],'krat'); 
    if m<0 | m>1
        m = fminbnd('Utility_zpk',0,1,fopt,krat,[],'krat');
    end
    capk = ellipke(m);
    ws = wp/sqrt(m);
    m1 = 1 - m;
    j = (1-rem(n,2)):2:n-1;
    [ij,jj] = size(j);
    [s,c,d] = ellipj(j*capk/n,m*ones(ij,jj));
    is = find(abs(s) > eps);
    z = 1 ./(sqrt(m)*s(is));
    z = i*z(:);
    z = [z ; conj(z)];
    % Poles
    r = fminsearch('Utility_zpk', ellipke(1-m),fopt,1/epsilon,k1p^2,'vrat');
    v0 = capk*r/(n*capk1(1));
    [sv,cv,dv] = ellipj(v0,1-m);
    p = -(c.*d*sv*cv + i*s*dv)./(1-(d*sv).^2);
    p = p(:); 
    if rem(n,2)
        ip = find(abs(imag(p)) < eps*norm(p));
        [pm,pn] = size(p);
        pp = 1:pm;
        pp(ip) = [];
        p = [p ; conj(p(pp))];
    else
        p = [p; conj(p)];
    end
    % Gain
    k = real(prod(-p)/prod(-z));
    if (~rem(n,2))
        k = k/sqrt((1 + epsilon^2));
    end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%        Lowpass Denormalize        %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [z,p,k] = denormalizeLP(z,p,k,w)
Np = length(p);
Nz = length(z);
k = k*w^(Np-Nz);
p = p*w;
z = z*w;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%       Highpass Denormalize        %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function[z,p,k] = denormalizeHP(z,p,k,w)
Np = length(p);
Nz = length(z);
k = abs( k * prod(z) / prod(p) );
z = w./z;
p = w./p;
if Np > Nz % add extra zeros at zero
    z = [zeros(Np-Nz,1); z];
end

Contact us