📄 fdbutter.m
字号:
function varargout = fdbutter(varargin)
%fdbutter Butterworth 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 fdbutter
global f1 f2 f3 f4 w3db1 w3db2 Rp Rs
global Rpm w3db1m w3db2m
global order0 order1
global ax L1 L2 Lresp L3db1 L3db2
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, w3db_init] = initSpecs(filt);
[minOrdCheckbox bandpop order pbspecs sbspecs ...
pbmeasures sbmeasures passframe stopframe ...
passframe1 stopframe1 ax Lresp L1 L2 order1 ...
L3db1 L3db2] = fdutil('commonObjects');
order0 = order;
if ~strcmp(bandpop.userdata,'fdbutter')
% this module is not current
bandpop.userdata = 'fdbutter';
minOrdCheckbox.callback = 'fdbutter(''checkbox'')';
bandpop.callback = 'fdbutter(''newtype'')';
order0.callback = 'fdbutter(''dirty'')';
f3 = pbspecs(2);
f4 = sbspecs(2);
Rp = pbspecs(3);
Rs = sbspecs(3);
w3db1 = pbspecs(1);
w3db2 = sbspecs(2);
w3dbm1 = sbmeasures(1);
w3dbm2 = sbmeasures(2);
Rpm = pbmeasures(3);
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','fdbutter(''LrespDown'')')
set(L1,'buttondownfcn','fdbutter(''L1down'')',...
'buttonupfcn','fdbutter(''L1up'')');
set(L2,'buttondownfcn','fdbutter(''L2down'')',...
'buttonupfcn','fdbutter(''L2up'')');
set(L3db1,'xdata',w3db_init([1 1]),...
'segmentdragcallback',{'fdbutter(''3db_drag'',1)'},...
'buttondownfcn','fdbutter(''3db_down'',1)',...
'buttonupfcn','fdbutter(''L1up'')');
set(L3db2,'xdata',w3db_init([end end]),...
'segmentdragcallback',{'fdbutter(''3db_drag'',2)'},...
'buttondownfcn','fdbutter(''3db_down'',2)',...
'buttonupfcn','fdbutter(''L1up'')');
end
set(minOrdCheckbox,'visible','on')
set(pbspecs(1),'visible','on')
fdbutter('newfilt',setOrderFlag_init,type_init,f_init,Rp_init,...
Rs_init,w3db_init,order_init)
if setOrderFlag_init
% set these fields since 'Apply' gets them from the specifications struc
% to make the measurements
filt.specs.fdbutter.Rp = Rp_init;
filt.specs.fdbutter.Rs = Rs_init;
end
[filt, errstr] = fdutil('callModuleApply',...
'fdbutter',filt,'');
varargout{1} = filt;
varargout{2} = errstr;
case 'apply'
filt = varargin{2};
msg = varargin{3};
if strcmp(msg,'motion') | strcmp(msg,'up')
inputLine = varargin{4};
if ~minOrdCheckbox.value & (isequal(inputLine,L1) | isequal(inputLine,L2))
varargout{1} = filt;
varargout{2} = '';
return
end
end
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,w3db] = estimateOrder(type,Rp.value,Rs.value,Fs,...
f1.value,f2.value,f3.value,f4.value);
else
n = order.value;
w3db = w3db1.value * 2/Fs;
if type > 2 % pass/stop
w3db(2) = w3db2.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;
specstruc.Rp = Rp.value;
specstruc.Rs = Rs.value;
else
specstruc.f = []; % place holder, will be defined by measureFilt
specstruc.Rp = filt.specs.fdbutter.Rp;
specstruc.Rs = filt.specs.fdbutter.Rs;
end
specstruc.w3db = w3db;
specstruc.order = n;
% if ~setOrderFlag & isfield(filt.specs,'fdbutter') & ...
% isequal(specstruc.w3db,filt.specs.fdbutter.w3db) ...
% & isequal(specstruc.order,filt.specs.fdbutter.order)
% filt.specs.fdbutter = 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] = butter(n,w3db,'high');
elseif type == 4
[b,a] = butter(n,w3db,'stop');
else
[b,a] = butter(n,w3db);
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.fdbutter.type ~= type))
objSetupFlag = 1;
else
objSetupFlag = 0;
end
[Rp,Rs,w3db1m,w3db2m,Rpm,f1,f2,f3,f4,specstruc] = ...
measureFilt(objSetupFlag,specstruc,Fs,order,order1,stopframe1,ax,...
pbmeasures,sbmeasures,Rp,Rs,w3db1m,w3db2m,Rpm,f1,f2,f3,f4,...
ff,Hlog,L1,L2);
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(L3db1,'linestyle','-')
set(L3db2,'linestyle','-')
if strcmp(L3db1.erasemode,'normal')
warning('L3db1 erasemode is normal... why?')
L3db1.erasemode = 'xor';
L3db2.erasemode = 'xor';
end
end
% alter filt fields:
filt.tf.num = b;
filt.tf.den = a;
filt.specs.fdbutter = 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.fdbutter.type;
% need to restore filter type
setOrderFlag = filt.specs.fdbutter.setOrderFlag;
oldSetOrderFlag = ~minOrdCheckbox.value;
f = filt.specs.fdbutter.f;
Rpass = filt.specs.fdbutter.Rp;
Rstop = filt.specs.fdbutter.Rs;
w3db = filt.specs.fdbutter.w3db;
N = filt.specs.fdbutter.order;
fdbutter('newfilt',setOrderFlag,oldtype,f,Rpass,Rstop,w3db,N)
[Rp,Rs,w3db1m,w3db2m,Rpm,f1,f2,f3,f4] = ...
measureFilt(1,...
filt.specs.fdbutter,Fs,order,order1,stopframe1,ax,...
pbmeasures,sbmeasures,Rp,Rs,w3db1m,w3db2m,Rpm,f1,f2,f3,f4,...
Lresp.xdata,Lresp.ydata,L1,L2);
Lresp.linestyle = '-';
L1.linestyle = '-';
L2.linestyle = '-';
set(L3db1,'linestyle','-')
set(L3db2,'linestyle','-')
for i=1:3
set(pbmeasures(i),'enable','on')
set(sbmeasures(i),'enable','on')
end
set(order1,'enable','on')
case 'help'
str = fdhelpstr('fdbutter');
varargout{1} = str{2};
case 'description'
varargout{1} = 'Butterworth 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
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;
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;
L3db1.xdata = L3db1.xdata*Fs/oldFs;
L3db2.xdata = L3db2.xdata*Fs/oldFs;
if minOrdCheckbox.value
w3db1m.value = w3db1m.value*Fs/oldFs;
w3db2m.value = w3db2m.value*Fs/oldFs;
elseif ~any(w3db1==[f1 f2 f3 f4])
w3db1.value = w3db1.value*Fs/oldFs;
w3db2.value = w3db2.value*Fs/oldFs;
w3db1.range = w3db1.range*Fs/oldFs;
w3db2.range = w3db2.range*Fs/oldFs;
end
%---------------------------------------------------------------------
% -------- following cases are module specific ---------
%---------------------------------------------------------------------
case 'dirty'
% fdbutter('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 = ':';
L3db1.linestyle = ':';
L3db2.linestyle = ':';
end
for i=1:3
set(pbmeasures(i),'enable','off')
set(sbmeasures(i),'enable','off')
end
set(order1,'enable','off')
%---------------------------------------------------------------------
% fdbutter('clean')
% opposite of 'dirty'
case 'clean'
if Lresp.linestyle ~= '-'
Lresp.linestyle = '-';
L1.linestyle = '-';
L2.linestyle = '-';
L3db1.linestyle = '-';
L3db2.linestyle = '-';
end
for i=1:3
set(pbmeasures(i),'enable','on')
set(sbmeasures(i),'enable','on')
end
set(order1,'enable','on')
filtdes('setenable','off')
%---------------------------------------------------------------------
% fdbutter('fchange',i)
% Callback when frequency i has changed
% Need to update ranges and lines L1, L2
% fdbutter('fchange')
% called w/o input i when a 3db frequency spec has
% changed (in case ~minOrdCheckbox.val==1)
case 'fchange'
type = bandpop.value;
if nargin == 1
% a 3db freq spec has changed (we are in set mode)
if type >= 3
w3db = [w3db1.value w3db2.value];
set(L3db1,'xdata',w3db([1 1]))
set(L3db2,'xdata',w3db([2 2]))
w3db1.range = [0 w3db(2)];
w3db2.range = [w3db(1) Fs/2];
else
w3db = w3db1.value;
set(L3db1,'xdata',w3db([1 1]))
end
fdbutter('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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -