gusucode.com > 信号处理工具箱 - signal源码程序 > signal\signal\siggui\fdellip.m
function varargout = fdellip(varargin) %fdellip Elliptic Module for filtdes. % Author: T. Krauss % Copyright (c) 1988-98 by The MathWorks, Inc. % $Revision: 1.1 $ % 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 = []; filt.type = 'design'; 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 % fail (return false) even tough the two variables are equal. So, % remove the NaNs before comparing. nonNaNindx_L2 = ~isnan(L2.xdata); nonNaNindx_xd2 = ~isnan(xd2); if ~isequal(xd2(nonNaNindx_xd2),L2.xdata(nonNaNindx_L2)) % only set if changed L2.xdata = xd2; dirty = 1; end if dirty % Specs changed; update passband limits; show dotted lines ax.xlimPassband = fdutil('xlimpassband',type,... Fs,f1.value,f2.value,f3.value,f4.value); fdellip('dirty') end %--------------------------------------------------------------------- % fdellip('Rpchange') % Callback when Rp has changed % Need to update line L1 case 'Rpchange' type = bandpop.value; Rpass = Rp.value; above = 0; below = -Rpass; if type ~= 4 % 'ydata':[maxpass maxpass NaN minpass minpass] yd = [above above NaN below below]; else % 'ydata': [ maxpass maxpass NaN minpass minpass NaN ... % maxpass maxpass NaN minpass minpass]) yd = [above above NaN below below ... above above NaN below below ]; end L1.ydata = yd; ylim = [below above]; dyl = (ylim(2)-ylim(1))*.15; ax.ylimPassband = ylim + [-dyl/2 dyl/2]; fdellip('dirty') %--------------------------------------------------------------------- % fdellip('Rschange') % Callback when Rs has changed % Need to update line L2 case 'Rschange' type = bandpop.value; Rstop = Rs.value; if type ~= 3 yd = [-Rstop -Rstop]; else yd = [-Rstop -Rstop NaN -Rstop -Rstop]; end L2.ydata = yd; fdellip('dirty') %--------------------------------------------------------------------- % fdellip('checkbox') % Callback of minimum order checkbox case 'checkbox' filt = filtdes('filt'); newSetOrderFlag = ~get(minOrdCheckbox,'value'); type = bandpop.value; oldtype = filt.specs.fdellip.type; if ~newSetOrderFlag % from set to estimate order if filt.specs.fdellip.setOrderFlag % obtain frequencies from measurements c = {pbspecs(1) pbspecs(2) sbmeasures(1) sbmeasures(2)}; if (type==2) | (type==3) ind = [3 1 2 4]; else ind = [1 3 4 2]; end f = getFrequencyValues(oldtype,c{ind},Fs); else % obtain frequencies from filter specs field f = filt.specs.fdellip.f; end f = filt.specs.fdellip.f; f = [0; fdutil('changeFilterType',type,oldtype,sort(f(2:end-1))); 1]; Fpass = [0 0]; % place holder - ignored by 'newfilt' else % from estimate to set order Fpass = Fp1.value * 2/Fs; if type > 2 if oldtype > 2 Fpass(2) = Fp2.value * 2/Fs; else Fpass(2) = (Fpass(1)+1)/2; end end f = []; % place holder - ignored by 'newfilt' end fdellip('newfilt',newSetOrderFlag,... type,f,Rp.value,... Rs.value,Fpass,order.value) fdellip('dirty') %--------------------------------------------------------------------- % fdellip('newfilt',setOrderFlag,type,f,Rp,Rs,Fpass,order) % set values of SPECIFICATIONS objects ... DOES NOT DESIGN FILTER case 'newfilt' setOrderFlag = varargin{2}; type = varargin{3}; f = varargin{4}; % in range (0,1) Rpass = varargin{5}; Rstop = varargin{6}; Fpass = varargin{7}; % in range (0,1) N = varargin{8}; bandpop.value = type; % save last value of bandpop in passframe userdata: passframe.userdata = type; minOrdCheckbox.value = ~setOrderFlag; if ~setOrderFlag % estimate order % initialize specs: order = order1; set(order0,'visible','off') [f1,f2,f3,f4] = setupFrequencyObjects(type,'fdellip',... pbspecs,sbspecs,f,Fs,ax); pbspecs(1).visible = 'on'; pbspecs(3).visible = 'on'; sbspecs(1).visible = 'on'; sbspecs(3).visible = 'on'; Rp = pbspecs(3); Rs = sbspecs(3); set(Rp,'value',Rpass) set(Rs,'value',Rstop) set(L3_1,'visible','off') set(L3_2,'visible','off') else % set order order = order0; set(order0,'visible','on') set(sbspecs(1),'visible','off') set(sbspecs(2),'visible','off') set(L3_1,'visible','on','xdata',Fpass([1 1])*Fs/2) if type < 3 % low/high set(Fp1,'value',Fpass(1)*Fs/2,'range',[0 1]*Fs/2,... 'label','Fp','callback','fdellip(''fchange'')',... 'visible','on') Fp2.visible = 'off'; set(L3_2,'visible','off') else % pass/stop set(Fp1,'value',Fpass(1)*Fs/2,'range',[0 Fpass(2)]*Fs/2,... 'label','Fp1','callback','fdellip(''fchange'')',... 'visible','on') set(Fp2,'value',Fpass(2)*Fs/2,'range',[Fpass(1) 1]*Fs/2,... 'label','Fp2','callback','fdellip(''fchange'')',... 'visible','on') set(L3_2,'visible','on','xdata',Fpass([2 2])*Fs/2) end order.value = N; end if ax.xlimbound(2) ~= Fs/2 set(ax,'xlimbound',[0 Fs/2],'xlim',[0 Fs/2]) end if ~setOrderFlag % estimate order minpass = -Rpass; maxpass = 0; minstop = -Rstop; fdutil('setLines','fdellip',L1,L2,setOrderFlag,... type,f(:)',Fs,minpass,maxpass,minstop) else % set order set(L1,'segmentdragmode',{'none'},... 'segmentpointer',{'forbidden'},... 'vertexdragmode',{'none'},... 'vertexpointer',{'forbidden'}) end %--------------------------------------------------------------------- % fdellip('newtype') % callback of band configuration popup case 'newtype' filt = filtdes('filt'); newtype = bandpop.value; oldtype = get(passframe,'userdata'); if isempty(oldtype) oldtype = filt.specs.fdellip.type; end passframe.userdata = newtype; if (newtype ~= oldtype) | strcmp(filtdes('getenable'),'on') if oldtype < 3 % low or high pass edges = [f1.value f2.value]'*2/Fs; else edges = [f1.value f2.value f3.value f4.value]'*2/Fs; end edges = fdutil('changeFilterType',newtype,oldtype,edges); f = [0; edges(:); 1]; if ~minOrdCheckbox.value Fpass = Fp1.value * 2/Fs; if newtype > 2 Fpass(2) = Fp2.value * 2/Fs; if Fpass(2) <= Fpass(1) | Fpass(2)>1 Fpass(2) = (Fpass(1) + 1)/2; Fp2.value = Fpass(2)*Fs/2; end end else Fpass = [0 0]; % place holder - ignored by newfilt end fdellip('newfilt',~minOrdCheckbox.value,newtype,f,Rp.value,... Rs.value,Fpass,order.value) fdellip('dirty') else % disp('no change of type') end %--------------------------------------------------------------------- % fdellip('Lrespdown') % Button down fcn of Lresp (response line) - pan case 'LrespDown' bounds.xlim = [0 Fs/2]; bounds.ylim = [-500 30]; h = ax.h; panfcn('Ax',h,... 'Bounds',bounds,... 'UserHand',get(h,'zlabel'),... 'Invisible',[L3_1.h L3_2.h]) %--------------------------------------------------------------------- % fdellip('L1down') % Button down fcn of L1 % fdellip('L2down') % Button down fcn of L2 % fdellip('L3_down',i) % buttondown fcn of stopband edge line 1 or 2 (i==1 or 2) case {'L1down', 'L2down', 'L3_down'} L1.erasemode = 'xor'; L2.erasemode = 'xor'; %--------------------------------------------------------------------- % fdellip('L1up') % Button up fcn of L1 % fdellip('L2up') % Button up fcn of L2 case {'L1up', 'L2up'} L1.erasemode = 'normal'; L2.erasemode = 'normal'; Lresp.erasemode = 'normal'; %--------------------------------------------------------------------- % fdellip('L3_drag',ind) % segment drag callback of L3_1 and L3_2 - stopband edge frequency lines % Inputs: % ind - index of line being dragged, 1 or 2 case 'L3_drag' ind = varargin{2}; minspacing = Fs/500; if ind == 1 xd = L3_1.xdata; newFpass1 = inbounds(xd(1),[minspacing Fp1.range(2)-minspacing]); if newFpass1 ~= Fp1.value Fp1.value = newFpass1; Fp2.range = [newFpass1 Fs/2]; if newFpass1 ~= xd(1) L3_1.xdata = newFpass1([1 1]); end end else xd = L3_2.xdata; newFpass2 = inbounds(xd(1),[Fp2.range(1)+minspacing Fs/2-minspacing]); if newFpass2 ~= Fp2.value Fp2.value = newFpass2; Fp1.range = [0 newFpass2]; if newFpass2 ~= xd(1) L3_2.xdata = newFpass2([1 1]); end end end %--------------------------------------------------------------------- % fdellip('L1drag',type,ind) % vertex drag callback of L1 - passband line % Inputs: % type - band configuration 1==low, 2=high, 3=pass, 4=stop % ind - index of vertex being dragged case 'L1drag' type = varargin{2}; ind = varargin{3}; xd = L1.xdata; minspacing = Fs/500; switch type case 1 % lowpass newf1 = inbounds(xd(ind),[minspacing f2.value-minspacing]); xd([2 5]) = newf1; L1.xdata = xd; f1.value = newf1; i = 1; case 2 % highpass newf2 = inbounds(xd(ind),[f1.value+minspacing Fs/2-minspacing]); xd([1 4]) = newf2; L1.xdata = xd; f2.value = newf2; i = 2; case 3 % bandpass % L1 xdata = [f2 f3 NaN f2 f3] if any(ind == [1 4]) % dragging f2 newf2 = inbounds(xd(ind),[f1.value+minspacing f3.value-minspacing]); xd([1 4]) = newf2; L1.xdata = xd; f2.value = newf2; i = 2; else % dragging f3 newf3 = inbounds(xd(ind),[f2.value+minspacing f4.value-minspacing]); xd([2 5]) = newf3; L1.xdata = xd; f3.value = newf3; i = 3; end case 4 % bandstop % L1 xdata = [0 f1 NaN 0 f1 NaN f4 Fs/2 NaN f4 Fs/2] if any(ind == [2 5]) % dragging f1 newf1 = inbounds(xd(ind),[minspacing f2.value-minspacing]); xd([2 5]) = newf1; L1.xdata = xd; f1.value = newf1; i = 1; else % dragging f4 newf4 = inbounds(xd(ind),[f3.value+minspacing Fs/2-minspacing]); xd([7 10]) = newf4; L1.xdata = xd; f4.value = newf4; i = 4; end end ax.xlimPassband = fdutil('xlimpassband',type,... Fs,f1.value,f2.value,f3.value,f4.value); %--------------------------------------------------------------------- % fdellip('L2drag',type,ind) % drag callback of L2 - stopband line % Inputs: % type - band configuration 1==low, 2=high, 3=pass, 4=stop % ind - index of vertex being dragged case 'L2drag' type = varargin{2}; ind = varargin{3}; xd = L2.xdata; minspacing = Fs/500; switch type case 1 % lowpass newf2 = inbounds(xd(ind),[f1.value+minspacing Fs/2-minspacing]); xd(1) = newf2; L2.xdata = xd; f2.value = newf2; i = 2; case 2 % highpass newf1 = inbounds(xd(ind),[minspacing f2.value-minspacing]); xd(2) = newf1; L2.xdata = xd; f1.value = newf1; i = 1; case 3 % bandpass % L2 xdata = [0 f1 NaN f4 Fs/2] if ind == 2 % dragging f1 newf1 = inbounds(xd(ind),[minspacing f2.value-minspacing]); xd(2) = newf1; L2.xdata = xd; f1.value = newf1; i = 1; else % dragging f4 newf4 = inbounds(xd(ind),[f3.value+minspacing Fs/2-minspacing]); xd(4) = newf4; L2.xdata = xd; f4.value = newf4; i = 4; end case 4 % bandstop % L2 xdata = [f2 f3] if ind == 1 % dragging f2 newf2 = inbounds(xd(ind),[f1.value+minspacing f3.value-minspacing]); xd(1) = newf2; L2.xdata = xd; f2.value = newf2; i = 2; else % dragging f3 newf3 = inbounds(xd(ind),[f2.value+minspacing f4.value-minspacing]); xd(2) = newf3; L2.xdata = xd; f3.value = newf3; i = 3; end end %--------------------------------------------------------------------- % fdellip('Rpdrag',type,ind) % drag callback of L1 - passband line % Inputs: % type - band configuration 1==low, 2=high, 3=pass, 4=stop % ind - index of segment being dragged case 'Rpdrag' type = varargin{2}; ind = varargin{3}; yd = L1.ydata; below = yd(ind); if below >= 0 below = -.00001; elseif below < -10 below = -10; end above = 0; newRp = above-below; if type ~= 4 % 'ydata':[maxpass maxpass NaN minpass minpass] yd = [above above NaN below below]; else % 'ydata': [ maxpass maxpass NaN minpass minpass NaN ... % maxpass maxpass NaN minpass minpass]) yd = [above above NaN below below ... NaN above above NaN below below ]; end L1.ydata = yd; Rp.value = newRp; ylim = [below above]; dyl = (ylim(2)-ylim(1))*.15; ax.ylimPassband = ylim + [-dyl/2 dyl/2]; %--------------------------------------------------------------------- % fdellip('Rsdrag',type,ind) % drag callback of L2 - stopband line % Inputs: % type - band configuration 1==low, 2=high, 3=pass, 4=stop % ind - index of segment being dragged case 'Rsdrag' type = varargin{2}; ind = varargin{3}; yd = L2.ydata; newRs = -yd(ind); if newRs < 0 newRs = 0; end switch type case {1,2,4} L2.ydata = [-newRs -newRs]; case 3 L2.ydata = [-newRs -newRs NaN -newRs -newRs]; end set(Rs,'value', newRs) end % of function switch-yard %--------------------------------------------------------------------- % -------- LOCAL FUNCTIONS START HERE --------- %--------------------------------------------------------------------- function sethelp global minOrdCheckbox bandpop global passframe stopframe passframe1 stopframe1 global f1 f2 f3 f4 Fp1 Fp2 order Rp Rm pbspecs sbspecs global Fs1m Fs2m global ax L1 L2 Lresp global Fs % disp('setting help ... stub') function [n,Fpass] = estimateOrder(type,Rp,Rs,Fs,f1,f2,f3,f4) % [n,Fpass] = estimateOrder(type,Rp,Rs,Fs,f1,f2,f3,f4) % estimate filter order % takes the specifications as given by the input % parameters and estimates the order and stopband edge frequencies % needed to meet those specifications. % Inputs: % type - 1,2,3,4 specifies band configuration % Rp, Rs passband, stopband ripple % Fs - sampling frequency % f1,f2 first two frequencies in ascending order % f3,f4 only needed if type == 3 or 4, remaining frequencies % f1,f2,f3,f4 are assumed between 0 and Fs/2 on input % Outputs: % n - filter order % Fpass - filter pass band edges for ellip, normalized to range [0...1] if type == 1 % low pass Wp = f1; Ws = f2; elseif type == 2 % high pass Wp = f2; Ws = f1; elseif type == 3 % band pass Wp = [f2 f3]; Ws = [f1 f4]; elseif type == 4 % band stop Wp = [f1 f4]; Ws = [f2 f3]; end [n,Fpass] = ellipord(Wp*2/Fs,Ws*2/Fs,Rp,Rs); Fpass = Fpass(:)'; % make it a row function yd = passbandlimits(Rp) % return ydata = [minpass maxpass] of passband % given Rp decibels of ripple in passband (with maximum 1 in linear scale) above = 0; below = -Rp; yd = [below above]; function [maxpass,minpass,minstop] = getMagMeasurements(ff,Hlog,type,... f1,f2,f3,f4); %getMagMeasurements % Finds passband and stopband ripple for given band edges % given a filter's magnitude response % Inputs: % ff - xdata of response % Hlog - magnitude of response at frequencies ff, in dB % type - band configuration (lp = 1, hp = 2, bp = 3, bs = 4) % f1, f2, f3, f4 - band edges (f3 and f4 ignored if type < 3) % in same units as ff % Output: % fm - 2 or 4 element frequency vector in ascending order switch type case 1 % lowpass passInd = find(ff<=f1); stopInd = find(ff>=f2); case 2 % highpass stopInd = find(ff<=f1); passInd = find(ff>=f2); case 3 % bandpass stopInd = find((ff<=f1)|(ff>=f4)); passInd = find((ff>=f2)&(ff<=f3)); case 4 % bandstop passInd = find((ff<=f1)|(ff>=f4)); stopInd = find((ff>=f2)&(ff<=f3)); end maxpass = max(Hlog(passInd)); minpass = min(Hlog(passInd)); minstop = max(Hlog(stopInd)); function Fstop = getFreqMeasurements(ff,Hlog,type,Rp,Rs,Fpass) %getFreqMeasurements % Finds stop band edges for elliptic filter given passband and % stopband ripple and given a filter's magnitude response % Inputs: % ff - xdata of response (assumed a column vector) % Hlog - magnitude of response at frequencies ff, in dB % (assumed a column vector) % type - band configuration (lp = 1, hp = 2, bp = 3, bs = 4) % Rp - passband ripple, in dB % Rs - stopband attenuation in dB % Fpass - passband edges, normalized to [0 Fs/2] % Output: % Fstop - 1 or 2 element frequency (column) vector in ascending order ff = ff(:); switch type case 1 % lowpass stopInd = find(Hlog(:)<=-Rs); Fstop = ff(stopInd(1)); case 2 % highpass stopInd = find(Hlog(:)<=-Rs); Fstop = ff(stopInd(end)); %passInd = find(Hlog(:)>-Rs); %Fstop = ff(passInd(1)-1); case 3 % bandpass passInd = find(Hlog(:)>=-Rp); stopInd1 = find(Hlog(passInd(1):-1:1)<=-Rs); stopInd2 = find(Hlog(passInd(end):end)<=-Rs); Fstop = ff([passInd(1)-stopInd1(1) passInd(end)+stopInd2(1)]); case 4 % bandstop stopInd = find(Hlog(:)<=-Rs); Fstop = ff(stopInd([1 end])); end function updateLines(passbandChange,type,fchange_ind,f1,f2,f3,f4,Rp,Rs,Fs) % assume values of f1,f2,f3,f4,Rp and Rs are correct now % fchange_ind - vector of indices indicating which frequencies have % changed global L1 L2 ax f = getFrequencyValues(type,f1,f2,f3,f4,Fs)*Fs/2; if any(passbandChange==1) maxpass = 0; minpass = -Rp.value; % update L1 xdata and ydata switch type case 1 % lowpass set(L1,'xdata',[f(1:2) NaN f(1:2)],... 'ydata',[maxpass maxpass NaN minpass minpass]) case 2 % highpass set(L1,'xdata',[f(3:4) NaN f(3:4)],... 'ydata',[maxpass maxpass NaN minpass minpass ]) case 3 % bandpass set(L1,'xdata',[f(3:4) NaN f(3:4)],... 'ydata',[maxpass maxpass NaN minpass minpass]) case 4 % bandstop set(L1,'xdata',[f(1:2) NaN f(1:2) NaN f(5:6) NaN f(5:6)],... 'ydata',[ maxpass maxpass NaN minpass minpass NaN ... maxpass maxpass NaN minpass minpass]) end ylim = [minpass maxpass]; dyl = (ylim(2)-ylim(1))*.15; ax.ylimPassband = ylim + [-dyl/2 dyl/2]; if length(f)==4 f(6)=0; % zeropad for call to xlimpassband end ax.xlimPassband = fdutil('xlimpassband',type,... Fs,f(2),f(3),f(4),f(5)); end if any(passbandChange==0) minstop = -Rs.value; % update L2 xdata and ydata switch type case 1 % lowpass set(L2,'xdata',[f(3:4)],'ydata',[minstop minstop]) case 2 % highpass set(L2,'xdata',[f(1:2)],'ydata',[ minstop minstop]) case 3 % bandpass set(L2,'xdata',[f(1:2) NaN f(5:6)],... 'ydata',[ minstop minstop NaN minstop minstop]) case 4 % bandstop set(L2,'xdata',[f(3:4)],'ydata',[minstop minstop]) end end %fdutil('updateRanges',fchange_ind,f1,f2,f3,f4) set(f1,'range',[0 Fs/2]) set(f2,'range',[0 Fs/2]) set(f3,'range',[0 Fs/2]) set(f4,'range',[0 Fs/2]) function [f1,f2,f3,f4] = setupFrequencyObjects(type,module,pbobjects,... sbobjects,f,Fs,ax,setValueFlag) if nargin<8 setValueFlag = 1; end switch type case 1 % lowpass f1 = pbobjects(1); f2 = sbobjects(1); f3 = sbobjects(2); f4 = pbobjects(2); pbobjects(2).visible = 'off'; sbobjects(2).visible = 'off'; set(f1,'label','Fp') set(f2,'label','Fs') case 2 % highpass f1 = sbobjects(1); f2 = pbobjects(1); f3 = pbobjects(2); f4 = sbobjects(2); pbobjects(2).visible = 'off'; sbobjects(2).visible = 'off'; set(f1,'label','Fs') set(f2,'label','Fp') case 3 % bandpass f1 = sbobjects(1); f2 = pbobjects(1); f3 = pbobjects(2); f4 = sbobjects(2); pbobjects(2).visible = 'on'; sbobjects(2).visible = 'on'; set(f1,'label','Fs1') set(f2,'label','Fp1') set(f3,'label','Fp2') set(f4,'label','Fs2') case 4 f1 = pbobjects(1); f2 = sbobjects(1); f3 = sbobjects(2); f4 = pbobjects(2); pbobjects(2).visible = 'on'; sbobjects(2).visible = 'on'; set(f1,'label','Fp1') set(f2,'label','Fs1') set(f3,'label','Fs2') set(f4,'label','Fp2') end if setValueFlag if type < 3 set(f1,'value',f(2)*Fs/2,'range',[0 f(3)]*Fs/2) set(f2,'value',f(3)*Fs/2,'range',[f(2) 1]*Fs/2) else set(f1,'value',f(2)*Fs/2,'range',[0 f(3)*Fs/2]) set(f2,'value',f(3)*Fs/2,'range',[f(2) f(4)]*Fs/2) set(f3,'value',f(4)*Fs/2,'range',[f(3) f(5)]*Fs/2) set(f4,'value',f(5)*Fs/2,'range',[f(4) 1]*Fs/2) end ax.xlimPassband = fdutil('xlimpassband',type,... Fs,f1.value,f2.value,f3.value,f4.value); end set(f1,'range',[0 Fs/2]) set(f2,'range',[0 Fs/2]) set(f3,'range',[0 Fs/2]) set(f4,'range',[0 Fs/2]) f1.callback = [module '(''fchange'',1)']; f2.callback = [module '(''fchange'',2)']; f3.callback = [module '(''fchange'',3)']; f4.callback = [module '(''fchange'',4)']; function setupMeasurementObjects(specStruc,Fstop,Fs,... order1,sbmeasures,Fs1m,Fs2m) % set values of MEASUREMENTS objects ... assumes specStruct is current setOrderFlag = specStruc.setOrderFlag; type = specStruc.type; N = specStruc.order; set(Fs1m,'value',Fstop(1),'format','%1.4g') if type > 2 set(Fs1m,'label','Actual Fs1') set(Fs2m,'visible','on','value',Fstop(2),... 'format','%1.4g','label','Actual Fs2') else set(Fs1m,'label','Actual Fs') set(Fs2m,'visible','off') end if ~setOrderFlag % estimate order set(order1,'visible','on') order1.value = N; else set(order1,'visible','off') end for i=1:2 set(sbmeasures(i),'enable','on') end set(order1,'enable','on') function specStruc = measureFilt(objSetupFlag,specStruc,Fs,order1,... sbmeasures,Fs1m,Fs2m,ff,Hlog,L1,L2,ax) n = specStruc.order; setOrderFlag = specStruc.setOrderFlag; Fpass = specStruc.Fpass*Fs/2; Fstop = getFreqMeasurements(ff,Hlog,specStruc.type,... specStruc.Rp,specStruc.Rs,Fpass); if objSetupFlag setupMeasurementObjects(specStruc,Fstop,Fs,... order1,sbmeasures,Fs1m,Fs2m) else set(Fs1m,'value',Fstop(1)) if specStruc.type > 2 set(Fs2m,'value',Fstop(2)) end if ~setOrderFlag order1.value = n; end end if setOrderFlag % Update stopband edges in specStruc frequency vector: switch specStruc.type case 1 f = [0 Fpass Fstop Fs/2]; case 2 f = [0 Fstop Fpass Fs/2]; case 3 f = [0 Fstop(1) Fpass(:)' Fstop(2) Fs/2]; case 4 f = [0 Fpass(1) Fstop(:)' Fpass(2) Fs/2]; end specStruc.f = f*2/Fs; else f = specStruc.f*Fs/2; end maxpass = 0; minpass = -specStruc.Rp; minstop = -specStruc.Rs; % update L1 and L2 xdata and ydata, pointers, dragmodes fdutil('setLines','fdellip',L1,L2,specStruc.setOrderFlag,... specStruc.type,specStruc.f(:)',... Fs,minpass,maxpass,minstop) % update [ylim/xlim] passband limits ylim = [minpass maxpass]; dyl = (ylim(2)-ylim(1))*.15; set(ax,'ylimPassband',ylim + [-dyl/2 dyl/2]); ax.xlimPassband = fdutil('xlimpassband',specStruc.type,... Fs,f(2),f(3),f(end-2),f(end-1)); function f = getFrequencyValues(type,f1,f2,f3,f4,Fs); if type < 3 % low or high pass f = [0 f1.value f2.value Fs/2]*2/Fs; else f = [0 f1.value f2.value f3.value f4.value Fs/2]*2/Fs; end function [setOrderFlag_init, type_init, f_init, Rp_init, Rs_init, ... order_init, Fpass_init] = initSpecs(filt) %initSpecs Initial specifications for ellip filter, from % filt input %Switches off of filt.currentModule and if it finds any of % fdcheby1, fdbutter, fdcheby2, fdremez, fdfirls, or fdkaiser % retains the type, order, band edge, and any other relevant % parameters % first define default values setOrderFlag_init = 0; % by default, estimate order type_init = 1; % 1=lowpass, 2=highpass, 3=bandpass, 4=bandstop f_init = [0 .1 .15 1]; Rp_init = 3; Rs_init = 20; order_init = 30; Fpass_init = .22; if strcmp(filt.specs.currentModule,'fdpzedit') if isfield(filt.specs.fdpzedit,'oldModule') filt.specs.currentModule = filt.specs.fdpzedit.oldModule; end end switch filt.specs.currentModule case {'fdcheby1','fdbutter','fdcheby2','fdremez','fdkaiser','fdfirls'} s = eval(['filt.specs.' filt.specs.currentModule]); setOrderFlag_init = s.setOrderFlag; type_init = s.type; f_init = s.f; Rp_init = s.Rp; Rs_init = s.Rs; order_init = s.order; switch filt.specs.currentModule case 'fdcheby1' Fpass_init = s.Fpass; case 'fdbutter' Fpass_init = s.w3db; case 'fdcheby2' Fpass_init = s.Fstop; case {'fdremez','fdfirls'} switch s.type case {1,2} Fpass_init = s.f(3); case 3 Fpass_init = s.f([2 5]); case 4 Fpass_init = s.f(3:4); end case 'fdkaiser' Fpass_init = s.Wn; end if any(strcmp(filt.specs.currentModule,... {'fdremez','fdkaiser','fdfirls'})) order_init = ceil(order_init/10); % FIR filters are much higher order than IIR end case 'fdellip' if isfield(filt.specs,'fdellip') setOrderFlag_init = filt.specs.fdellip.setOrderFlag; type_init = filt.specs.fdellip.type; f_init = filt.specs.fdellip.f; Rp_init = filt.specs.fdellip.Rp; Rs_init = filt.specs.fdellip.Rs; order_init = filt.specs.fdellip.order; Fpass_init = filt.specs.fdellip.Fpass; end end