📄 fdellip.m
字号:
function varargout = fdellip(varargin)
%fdellip Elliptic Module for filtdes.
% Author: T. Krauss
% Copyright (c) 1988-98 by The MathWorks, Inc.
% $Revision: 1.7 $
% Change this global to static when available:
% following are common to several modules
global minOrdCheckbox bandpop order pbspecs sbspecs pbmeasures sbmeasures
global passframe stopframe passframe1 stopframe1
% following static to fdellip
global f1 f2 f3 f4 Fp1 Fp2 Rp Rs
global Fs1m Fs2m
global order0 order1
global ax L1 L2 Lresp L3_1 L3_2
global Fs
switch varargin{1}
case 'init'
filt = varargin{2};
Fs = filt.Fs;
[setOrderFlag_init, type_init, f_init, Rp_init, Rs_init, ...
order_init, Fpass_init] = initSpecs(filt);
[minOrdCheckbox bandpop order pbspecs sbspecs ...
pbmeasures sbmeasures passframe stopframe ...
passframe1 stopframe1 ax Lresp L1 L2 order1 ...
L3_1 L3_2] = fdutil('commonObjects');
order0 = order;
co = get(0,'defaultaxescolororder');
lo = get(0,'defaultaxeslinestyleorder');
if ~strcmp(bandpop.userdata,'fdellip')
% this module is not current
bandpop.userdata = 'fdellip';
minOrdCheckbox.callback = 'fdellip(''checkbox'')';
bandpop.callback = 'fdellip(''newtype'')';
order0.callback = 'fdellip(''dirty'')';
set(ax,'title','Frequency Response',...
'xlabel','Frequency',...
'ylabel','Magnitude (dB)',...
'ylim',[-150 10],'xlim',[0 Fs/2],...
'xlimbound',[0 Fs/2]);
sethelp
set(Lresp,'buttondownfcn','fdellip(''LrespDown'')')
set(L1,'buttondownfcn','fdellip(''L1down'')',...
'buttonupfcn','fdellip(''L1up'')',...
'color',co(min(2,size(co,1)),:))
set(L2,'buttondownfcn','fdellip(''L2down'')',...
'buttonupfcn','fdellip(''L2up'')',...
'color',co(min(2,size(co,1)),:))
set(L3_1,'xdata',Fpass_init([1 1]),...
'segmentdragcallback',{'fdellip(''L3_drag'',1)'},...
'buttondownfcn','fdellip(''L3_down'',1)',...
'buttonupfcn','fdellip(''L1up'')');
set(L3_2,'xdata',Fpass_init([end end]),...
'segmentdragcallback',{'fdellip(''L3_drag'',2)'},...
'buttondownfcn','fdellip(''L3_down'',2)',...
'buttonupfcn','fdellip(''L1up'')');
Rp = pbspecs(3);
set(Rp,'value',Rp_init,'label','Rp')
Rs = sbspecs(3);
set(Rs,'value',Rs_init,'label','Rs')
set(Rp,'callback','fdellip(''Rpchange'')')
set(Rs,'callback','fdellip(''Rschange'')')
Fp1 = pbspecs(1);
Fp2 = pbspecs(2);
Fs1m = sbmeasures(1);
Fs2m = sbmeasures(2);
% fdutil('changeToEdit',pbmeasures(1:3))
fdutil('changeToText',[Fs1m Fs2m])
end
set(minOrdCheckbox,'visible','on')
set(Rp,'visible','on')
set(Rs,'visible','on')
set(sbspecs(1),'visible','on')
set(Fs1m,'visible','on')
set(pbmeasures(1),'visible','off')
set(pbmeasures(2),'visible','off')
set(pbmeasures(3),'visible','off')
set(sbmeasures(3),'visible','off')
fdellip('newfilt',setOrderFlag_init,type_init,f_init,Rp_init,...
Rs_init,Fpass_init,order_init)
[filt, errstr] = fdutil('callModuleApply',...
'fdellip',filt,'');
varargout{1} = filt;
varargout{2} = errstr;
case 'apply'
filt = varargin{2};
msg = varargin{3};
if strcmp(msg,'motion') & ~strcmp(get(Lresp,'erasemode'),'xor')
Lresp.erasemode = 'xor';
drawnow
end
% DESIGN FILTER!!!!
type = bandpop.value;
setOrderFlag = ~minOrdCheckbox.value;
if ~setOrderFlag % estimate order
[n,Fpass] = estimateOrder(type,Rp.value,Rs.value,Fs,...
f1.value,f2.value,f3.value,f4.value);
else
n = order.value;
Fpass = Fp1.value * 2/Fs;
if type > 2 % pass/stop
Fpass(2) = Fp2.value * 2/Fs;
end
end
% save specifications in specifications structure:
specstruc.setOrderFlag = setOrderFlag;
specstruc.type = type;
if ~setOrderFlag
f = getFrequencyValues(type,f1,f2,f3,f4,Fs);
specstruc.f = f;
else
specstruc.f = []; % place holder, will be defined by measureFilt
end
specstruc.Rp = Rp.value;
specstruc.Rs = Rs.value;
specstruc.Fpass = Fpass;
specstruc.order = n;
% if ~setOrderFlag & isfield(filt.specs,'fdellip') & ...
% isequal(specstruc.Fpass,filt.specs.fdellip.Fpass) ...
% & isequal(specstruc.order,filt.specs.fdellip.order)
% filt.specs.fdellip = specstruc;
% varargout{1} = filt;
% varargout{2} = '';
% return
% end
if n>50
[continueFlag,errstr] = fdutil('largeWarning',n,msg);
if ~continueFlag
varargout{1} = filt;
varargout{2} = errstr;
return
end
end
% design filter:
if type == 2
[b,a] = ellip(n,specstruc.Rp,specstruc.Rs,Fpass,'high');
elseif type == 4
[b,a] = ellip(n,specstruc.Rp,specstruc.Rs,Fpass,'stop');
else
[b,a] = ellip(n,specstruc.Rp,specstruc.Rs,Fpass);
end
% compute frequency response:
nfft = filtdes('nfft');
[H,ff] = freqz(b,a,nfft,Fs);
% avoid log of 0 at 0 and Fs/2:
if H(1) == 0, H(1) = H(2); end
if H(end) == 0, H(end) = H(end-1); end
Hlog = 20*log10(abs(H(:)));
set(Lresp,'xdata',ff,'ydata',Hlog);
% make measurements:
if ~ ((strcmp(msg,'motion') | strcmp(msg,'up')) & ~setOrderFlag ...
& strcmp(get(order1,'visible'),'on') ) | ...
(~setOrderFlag & (filt.specs.fdellip.type ~= type))
objSetupFlag = 1;
else
objSetupFlag = 0;
end
specstruc = measureFilt(objSetupFlag,specstruc,Fs,order1,...
sbmeasures,Fs1m,Fs2m,ff,Hlog,L1,L2,ax);
if ~strcmp(msg,'motion')
% if design is due to a drag operation, lines are already solid
% so we can skip this step
Lresp.linestyle = '-';
L1.linestyle = '-';
L2.linestyle = '-';
set(L3_1,'linestyle','-')
set(L3_2,'linestyle','-')
if strcmp(L3_1.erasemode,'normal')
warning('L3_1 erasemode is normal... why?')
L3_1.erasemode = 'xor';
L3_2.erasemode = 'xor';
end
end
% alter filt fields:
filt.tf.num = b;
filt.tf.den = a;
filt.specs.fdellip = specstruc;
filt.zpk = []; % clear out in case filtview has written these
filt.ss = [];
filt.sos = [];
varargout{1} = filt;
varargout{2} = '';
case 'revert'
filt = filtdes('filt');
oldtype = filt.specs.fdellip.type;
% need to restore filter type
setOrderFlag = filt.specs.fdellip.setOrderFlag;
oldSetOrderFlag = ~minOrdCheckbox.value;
f = filt.specs.fdellip.f;
Rpass = filt.specs.fdellip.Rp;
Rstop = filt.specs.fdellip.Rs;
Fpass = filt.specs.fdellip.Fpass;
N = filt.specs.fdellip.order;
fdellip('newfilt',setOrderFlag,oldtype,f,Rpass,Rstop,Fpass,N)
specStruc = measureFilt(1,filt.specs.fdellip,Fs,order1,...
sbmeasures,Fs1m,Fs2m,Lresp.xdata,Lresp.ydata,L1,L2,ax);
Lresp.linestyle = '-';
L1.linestyle = '-';
L2.linestyle = '-';
set(L3_1,'linestyle','-')
set(L3_2,'linestyle','-')
for i=1:2
set(sbmeasures(i),'enable','on')
end
set(order1,'enable','on')
case 'help'
str = fdhelpstr('fdellip');
varargout{1} = str{2};
case 'description'
varargout{1} = 'Elliptic IIR';
case 'Fs'
% Sampling frequency has changed
% The filter spec does not depend on the sampling frequency
filt = varargin{2};
varargout{1} = filt;
% update various lines and specifications:
oldFs = varargin{3};
Fs = filt.Fs; % new Fs
if minOrdCheckbox.value
f1.value = f1.value*Fs/oldFs;
f2.value = f2.value*Fs/oldFs;
f3.value = f3.value*Fs/oldFs;
f4.value = f4.value*Fs/oldFs;
f1.range = f1.range*Fs/oldFs;
f2.range = f2.range*Fs/oldFs;
f3.range = f3.range*Fs/oldFs;
f4.range = f4.range*Fs/oldFs;
else
Fp1.value = Fp1.value*Fs/oldFs;
Fp2.value = Fp2.value*Fs/oldFs;
Fp1.range = Fp1.range*Fs/oldFs;
Fp2.range = Fp2.range*Fs/oldFs;
end
ax.xlimbound = [0 Fs/2];
ax.xlim = ax.xlim*Fs/oldFs;
ax.xlimpassband = ax.xlimpassband*Fs/oldFs;
L1.xdata = L1.xdata*Fs/oldFs;
L2.xdata = L2.xdata*Fs/oldFs;
Lresp.xdata = Lresp.xdata*Fs/oldFs;
L3_1.xdata = L3_1.xdata*Fs/oldFs;
L3_2.xdata = L3_2.xdata*Fs/oldFs;
Fs1m.value = Fs1m.value*Fs/oldFs;
Fs2m.value = Fs2m.value*Fs/oldFs;
%---------------------------------------------------------------------
% -------- following cases are module specific ---------
%---------------------------------------------------------------------
case 'dirty'
% fdellip('dirty')
% Callback of a spec ... to change appearance so user can
% see that the specs and the currently designed filter
% don't match
if Lresp.linestyle ~= ':'
Lresp.linestyle = ':';
L1.linestyle = ':';
L2.linestyle = ':';
L3_1.linestyle = ':';
L3_2.linestyle = ':';
end
for i=1:2
set(sbmeasures(i),'enable','off')
end
set(order1,'enable','off')
%---------------------------------------------------------------------
% fdellip('clean')
% opposite of 'dirty'
case 'clean'
if Lresp.linestyle ~= '-'
Lresp.linestyle = '-';
L1.linestyle = '-';
L2.linestyle = '-';
L3_1.linestyle = '-';
L3_2.linestyle = '-';
end
for i=1:2
set(sbmeasures(i),'enable','on')
end
set(order1,'enable','on')
filtdes('setenable','off')
%---------------------------------------------------------------------
% fdellip('fchange',i)
% Callback when frequency i has changed
% Need to update ranges and lines L1, L2
case 'fchange'
type = bandpop.value;
if nargin == 1
% a passband freq spec has changed (we are in set mode)
if type >= 3
Fpass = [Fp1.value Fp2.value];
if Fpass(1) >= Fpass(2)
FpassOld = [L3_1.xdata(1) L3_2.xdata(1)];
i = find(Fpass~=FpassOld); % index of changed band edge
if i == 1
Fpass(2) = (Fpass(1)+Fs/2)/2;
set(Fp2,'value',Fpass(2))
else
Fpass(1) = Fpass(2)/2;
set(Fp1,'value',Fpass(1))
end
end
set(L3_1,'xdata',Fpass([1 1]))
set(L3_2,'xdata',Fpass([2 2]))
else
Fpass = Fp1.value;
set(L3_1,'xdata',Fpass([1 1]))
end
fdellip('dirty')
return
end
i = varargin{2};
xd1 = L1.xdata;
xd2 = L2.xdata;
f = [f1.value,f2.value,f3.value,f4.value];
% update lines
switch type
case 1
% L1 xdata = [0 f1 NaN 0 f1]
% L2 xdata = [f2 Fs/2]
if i==1
xd1([2 5]) = f(1);
else
xd2(1) = f(2);
end
case 2
% L1 xdata = [f2 Fs/2 NaN f2 Fs/2]
% L2 xdata = [0 f1]
if i == 1
xd2(2) = f(1);
else
xd1([1 4]) = f(2);
end
case 3 % bandpass
% L1 xdata = [f2 f3 NaN f2 f3]
% L2 xdata = [0 f1 NaN f4 Fs/2]
if xd2(2) ~= f(1)
xd2(2) = f(1);
elseif xd1(1) ~= f(2)
xd1([1 4]) = f(2);
elseif xd1(2) ~= f(3)
xd1([2 5]) = f(3);
elseif xd2(4) ~= f(4)
xd2(4) = f(4);
end
case 4
% L1 xdata = [0 f1 NaN 0 f1 NaN f4 Fs/2 NaN f4 Fs/2]
% L2 xdata = [f2 f3]
if xd1(2) ~= f(1)
xd1([2 5]) = f(1);
elseif xd2(1) ~= f(2)
xd2(1) = f(2);
elseif xd2(2) ~= f(3)
xd2(2) = f(3);
elseif xd1(7) ~= f(4)
xd1([7 10]) = f(4);
end
end
if ~minOrdCheckbox.value % set order
%passbandChange = ...
% (type==(1:4))*[1 0 0 0; 0 1 0 0;...
% 0 1 1 0; 1 0 0 1 ]*(i==(1:4))';
%if passbandChange
% fChangeMeas(i,type,Fs,Lresp,L1,L2,f1,f2,f3,f4,Rp,Rs,Fp1,Fp2)
% return
%end
L3_1.xdata = Fp1.value([1 1]);
if type>2
L3_2.xdata = Fp2.value([1 1]);
end
else
[xd1,xd2] = fdutil('validateBands',xd1,xd2,...
type,i,f,f1,f2,f3,f4,Fs);
end
dirty = 0; % Flag used to indicate that specs have changed.
% If there's a NaN in the data being compared the if-statement will
% fail (return false) even tough the two variables are equal. So,
% remove the NaNs before comparing.
nonNaNindx_L1 = ~isnan(L1.xdata);
nonNaNindx_xd1 = ~isnan(xd1);
if ~isequal(xd1(nonNaNindx_xd1),L1.xdata(nonNaNindx_L1))
% only set if changed
L1.xdata = xd1;
dirty = 1;
end
% If there's a NaN in the data being compared the if-statement will
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -