function fdatool
%FDATOOL Filter Design & Analysis Tool.
%        FDATOOL launches the Filter Design and Analysis Tool (FDATool).  
%        FDATool is a Graphical User Interface (GUI) that allows you to 
%        design or import, and analyze digital FIR and IIR filters.
%
%        If the Filter Design Toolbox is installed, FDATool seamlessly 
%        integrates advanced filter design methods and the ability to
%        quantize filters.
%
% See also SPTOOL.
 
%   Author(s): P. Pacheco, R. Losada, P. Costa
%   Copyright 1988-2000 The MathWorks, Inc.
%   $Revision: 1.42 $  $Date: 2000/08/30 18:53:48 $ 

%  The following steps are taken when fdatool is launched:
%
%        1. Create a structure ud containing the state of GUI
%        2. Render the GUI (add handles to ud)
%        3. Save ud in the figure's userdata property
%        4. Load a session file if it exists (updates ud)
%        5. Save part of ud needed for reverting
%        6. Update the GUI based on ud values
%        7. Install Context Sensitive Help (CSH)

fprintf('Initializing Filter Design & Analysis Tool .');

% Build the data structure, ud, which defines the state and default
% settings of the GUI.
ud = factorySettings;
fprintf('.')

% Render (paint) the GUI.  Return a structure with all the UI handles. 
ud = render_gui(ud);
hFig = ud.h.Fig;
fprintf('.')
% Store the GUI's data structure in the figure's userdata.
set(hFig,'Userdata',ud);  

if exist('fdatool.fda'),  
    load_session(hFig);    % Modifies ud.
end

fprintf('.')

% Save info we need for reverting.
saverevertinfo(hFig);

% Populate the GUI with the current (default/loaded) settings.
update_gui(hFig); % ud is modified
fprintf('.')

% Install the context-sensitive help system:
help_cbs = fdatool_help;
feval(help_cbs.install_CSH,hFig);
fprintf(' done. \n')

%-------------------------------------------------------------------
function load_session(hFig)
% LOAD_SESSION Loads a session if the file exists and overwrites 
%              parts of ud with newly loaded data.

% Cache figure's userdata.
ud = get(hFig,'Userdata');

% Load default session file and overwrite ud with newly loaded data.
sessionud = load_exec(ud,'fdatool.fda');
ud = updateud(ud,sessionud);   

% Overwrite the filename
ud.filename.session = 'untitled.fda';

% Check if QFILT exists.
ud.flags.fdqexists = qfiltexists;

% Store the GUI's data structure in the figure's userdata.
set(hFig,'Userdata',ud);  

%-------------------------------------------------------------------
function ud = factorySettings(ud)
%FACTORYSETTINGS Sets up the default state of the GUI.
%
% Output:
%    ud - updated with all the factory settings (state) of the GUI.
% 

% Default session file name that will display in the toolbar when
% the tool first launchs.
ud.filename.session = 'untitled.fda';

% Create a strcture containing tags for the analysis buttons and menus.
ud.tags = analysisTags;

% Boolean flags used in the GUI.
ud.flags = setupFlags;

% Mode (tabs) sate.
ud.mode = setupMode;

% Filter design default specification values and GUI state.
ud.specs.design = setupDesignspecs;

% Create a default filter - uses default settings as defined in
% setupDesignspecs above.
% Note: The filter coeffs. are hard coded, if the default specs.
% above a re changed, we must recapture the hard-coded coeffs.
[ud.reffilter, filtOrder] = defaultFilter(ud.specs.design);
ud.filter = ud.reffilter;
ud.measurements.order = num2str(filtOrder); % ud stores everything as strings.

% Specify (import) filter coeffs default values and GUI state.
ud.specs.import = setupSpecifycoeffsVals;

% Define the Export dialog defaults.
ud.specs.export = setupExport;

% Define the Convert dialog defaults.
ud.specs.convert = setupConvert;

% Default reference quantized filter.
if ud.flags.fdqexists
    ud.specs.quantize.refqfilt = qfilt;
end

% Set up the state of the toolbar buttons.
ud.toolbar = setupToolbarstate;

%-------------------------------------------------------------------
function tags = analysisTags
%ANALYSISTAGS Creates a structure with tags for the analysis toolbar
%             buttons and menus.

% Generate tags for the analysis menu items, and corresponding 
% toolbar items
tags.analysis = {...
        'filterresponsespecs',...
        'magresp',...
        'phaseresp',...
        'magnphaseresp',...
        'groupdelay',...
        'impresp',...
        'stepresp',...
        'pzplot',...
        'filtercoeffs',...
        'whatsthis'};

%        'mcode',...

%----------------------------------------------------------------------
function flags = setupFlags
%SETUPFLAGS Sets up all the flags used in the GUI.
%
% Output:
%   flags - structure containing several fields with boolean flags.

% Session file flags.
flags.file_dirty = 0;
flags.overwrite = 0;

% Flags indicating when the filter has been updated: designed,
% imported, or quantized.  By default thy're all true.
flags.filter_designed = 1;
flags.filter_imported = 1;
flags.filter_quantized = 1;

% Flag indicating if quantization is on.  By default it's off.
flags.quantizationswitch = 0;

% Boolean flag indicating if the Filter Design Toolbox is installed.
flags.fdqexists = qfiltexists;

%----------------------------------------------------------------------
function mode = setupMode
%SETUPMODE Sets the mode (tabs) currently and previously selected mode.
%
% Output:
%   mode - structure containing fields indicating the mode (tab) was
%          selected. 

% fdatool can be in one of the following three modes:
%    1 - Filter Design Mode [default]
%    2 - Specify Coefficients Mode 
%    3 - Quantize Coefficients Mode
mode.old     = 1; % Keep track of the last mode.
mode.current = 1;

% Indicates which mode created the filter; the choices are
% 1-Design or 2-Specify (import).  For the default case it should match 
% the current mode.
mode.filtermadeby = 1; 

%-------------------------------------------------------------------
function design = setupDesignspecs
%SETUPDESIGNSPECS  Sets up all the filter design spec defaults.
%
% Output:
%   design - a structure containing several fieds that store the 
%            filter design specifications.

design.type = 'lp';
design.method = 'remez';
design.window = 'kaiser';
design.winparam = '1';
design.order.calc = 'minimum order';
design.order.value = {'10','8'};


% Specs. defaults
%------------------------ lowpass -------------------------------------
design.freq.lp.units = 'hz'; % Frequency units

design.freq.lp.fs    = '48000'; % Sampling frequency

design.freq.lp.passStop = {...
        '9600',... % fpass
        '12000'}; % fstop

design.freq.lp.cutoff = {'10800'}; % fc

design.freq.lp.pass = {'9600'}; % fpass

design.freq.lp.stop = {'12000'}; % fstop

design.mag.lp.units = 'db'; % Magnitude units

design.mag.lp.passStop = {...
        '1',... % Apass
        '60'}; % Astop

design.mag.lp.ellip = {...
        '1',... % Apass
        '60'}; % Astop

design.mag.lp.cheby1 = {'1'}; % Apass

design.mag.lp.cheby2 = {'60'}; % Astop

design.mag.lp.fircutoff = {'6'}; % Attenuation at fc, FIR case.

design.mag.lp.butter = {'3'}; % Attenuation at fc, IIR case.

%------------------------ highpass ------------------------------------
design.freq.hp.units = 'hz'; % Frequency units

design.freq.hp.fs    = '48000'; % Sampling frequency

design.freq.hp.passStop = {...
        '9600',... % fstop
        '12000'}; % fpass

design.freq.hp.cutoff = {'10800'}; % fc

design.freq.hp.pass = {'9600'}; % fstop

design.freq.hp.stop = {'12000'}; % fpass

design.mag.hp.units = 'db'; % Magnitude units

design.mag.hp.passStop = {...
        '60',... % Astop
        '1'}; % Apass

design.mag.hp.ellip = {...
        '60',... % Astop
        '1'}; % Apass

design.mag.hp.cheby1 = {'1'}; % Apass

design.mag.hp.cheby2 = {'60'}; % Astop

design.mag.hp.fircutoff = {'6'}; % Attenuation at fc, FIR case.

design.mag.hp.butter = {'3'}; % Attenuation at fc, IIR case.

%------------------------ bandpass -------------------------------------
design.freq.bp.units = 'hz'; % Frequency units

design.freq.bp.fs    = '48000'; % Sampling frequency

design.freq.bp.passStop = {...
        '7200',... % fstop1
        '9600',... % fpass1
        '12000',... % fpass2
        '14400'};   % fstop2

design.freq.bp.cutoff = {...
        '8400',... % fc1
        '13200'};  % fc2

design.freq.bp.pass = {...
        '9600',... % fpass1
        '12000'};  % fpass2
        
design.freq.bp.stop = {...
        '7200',... % fstop1
        '14400'};  % fstop2

design.mag.bp.units = 'db'; % Magnitude units

design.mag.bp.passStop = {...
        '60',... % Astop1
        '1',... % Apass
        '80'};  % Astop2

design.mag.bp.ellip = {...
        '60',... % Astop
        '1'}; % Apass

design.mag.bp.cheby1 = {'1'}; % Apass

design.mag.bp.cheby2 = {'60'}; % Astop

design.mag.bp.fircutoff = {'6'}; % Attenuation at fc, FIR case.

design.mag.bp.butter = {'3'}; % Attenuation at fc, IIR case.


%----------------------- bandstop --------------------------------------
design.freq.bs.units = 'hz'; % Frequency units

design.freq.bs.fs    = '48000'; % Sampling frequency

design.freq.bs.passStop = {...
        '7200',... % fpass1
        '9600',... % fstop1
        '12000',... % fstop2
        '14400'};   % fpass2

design.freq.bs.cutoff = {...
        '8400',... % fc1
        '13200'};  % fc2

design.freq.bs.pass = {...
        '9600',... % fstop1
        '12000'};  % fstop2
        
design.freq.bs.stop = {...
        '7200',... % fpass1
        '14400'};  % fpass2

design.mag.bs.units = 'db'; % Magnitude units

design.mag.bs.passStop = {...
        '0.5',... % Apass1
        '60',... % Astop
        '1'};  % Apass2

design.mag.bs.ellip = {...
        '0.5',... % Apass
        '60'}; % Astop

design.mag.bs.cheby1 = {'1'}; % Apass

design.mag.bs.cheby2 = {'60'}; % Astop

design.mag.bs.fircutoff = {'6'}; % Attenuation at fc, FIR case.

design.mag.bs.butter = {'3'}; % Attenuation at fc, IIR case.

%---------------------Differentiator-------------------------------------

design.freqmag.diff.remez = {'[0 .5 .55 1]','[0 1 0 0]','[1 1]'};
design.freqmag.diff.firls = {'[0 .5 .55 1]','[0 1 0 0]','[1 1]'};
design.freqmag.diff.units = 'normalized (0 to 1)'; % Frequency units
design.freqmag.diff.fs    = '1'; % Sampling frequency

%---------------------Hilbert Transformer-------------------------------------
design.freqmag.hilb.remez = {'[0.05 0.95]','[1 1]','[1]'};
design.freqmag.hilb.firls = {'[0.05 0.95]','[1 1]','[1]'};
design.freqmag.hilb.units = 'normalized (0 to 1)'; % Frequency units
design.freqmag.hilb.fs    = '1'; % Sampling frequency

%---------------------Multiband-------------------------------------
design.freqmag.multiband.remez = {'[0 .28 .3 .48 .5 .69 .7 .8 .81 1]',...
        '[0 0 1 1 0 0 1 1 0 0]','[1 1 10 0.3 1]'};
design.freqmag.multiband.firls = {'[0 .28 .3 .48 .5 .69 .7 .8 .81 1]',...
        '[0 0 1 1 0 0 1 1 0 0]','[1 1 10 0.3 1]'};
design.freqmag.multiband.units = 'normalized (0 to 1)'; % Frequency units
design.freqmag.multiband.fs    = '1'; % Sampling frequency

%---------------------Arbitrary Mag-------------------------------------
design.freqmag.arbitrarymag.remez = {'[0:.05:.55 .6 1]',...
        '[1./sinc(0:.05:.55) 0 0]',...
        '[100*ones(1,6) 10]'};
design.freqmag.arbitrarymag.firls =  {'[0:.05:.55 .6 1]',...
        '[1./sinc(0:.05:.55) 0 0]',...
        '[100*ones(1,6) 10]'};
design.freqmag.arbitrarymag.iirlpnorm = {'[0:.0005:.0175 .02 .0215 .025 1]',...
        '[0 .0175 .02 .0215 .025 1]',...
        '[.4845 ./ (1 - ((0:.0005:.0175)./0.0179).^2).^0.25 0 0 0 0]',...
        '[ones(1,39) 300]'};
design.freqmag.arbitrarymag.iirlpnormc = {'[0 0.4 0.42 1]',...
        '[0 0.4 0.42 1]',...
        '[0 0 1 1]',...
        '[100 100 1 1]',...
        '.97'};
design.freqmag.arbitrarymag.units = 'normalized (0 to 1)'; % Frequency units
design.freqmag.arbitrarymag.fs    = '1'; % Sampling frequency

%---------------------Arbitrary Grpdelay---------------------------------
design.freqmag.arbitrarygrp.iirlpnormc = {'[0 0.1 1]',...
        '[0 1]',...
        '[2 3 1]',...
        '[1 1 1]',...
        '.95'};
design.freqmag.arbitrarygrp.units = 'normalized (0 to 1)'; % Frequency units
design.freqmag.arbitrarygrp.fs    = '1'; % Sampling frequency

% -- Filter Structure frame (Design) --
design.filtstruct.struct  = 'Direct form II transposed';

% -- Export Coefficients frame (default variables) --
design.filtstruct.tfVarStrs       = {'Num','Den'};
design.filtstruct.sosVarStrs      = {'G','SOS'};
design.filtstruct.ssVarStrs       = {'A','B','C','D'};
design.filtstruct.lattarmaVarStrs = {'K','V'};

% Default for the "Scale" popupmenu (for the SOS case)
design.filtstruct.sosScale = 'none';

% Filter Coefficient viewer prompt labels (Design mode)
design.filtstruct.tflbl       = {'Numerator','Denominator'};
design.filtstruct.soslbl      = {'Gain','SOS'};
design.filtstruct.sslbl       = {'A','B','C','D'};
% Used by Lattice (MA), Lattice(AR), and Lattice(ARMA) 
design.filtstruct.lattlbl = {'K','V'};

%-------------------------------------------------------------------
function import = setupSpecifycoeffsVals
%SETUPSPECIFYCOEFFSVALS Sets up the Specify (Import) Filter 
%                       Coefficients default values.
% Output:
%    import - structure containing the state and values of specify 
%             (import) filter coefficients frame.

% -- Filter Structure --
import.impfiltstruct.struct = 'Direct form II transposed';

% -- Specify Coefficients tab (default variables) --
import.impfiltstruct.tfVarStrs          = {'[0.028  0.053 0.071  0.053 0.028]',...
                                           '[1.000 -2.026 2.148 -1.159 0.279]'};
import.impfiltstruct.sosVarStrs         = {'SOS','1'};
import.impfiltstruct.ssVarStrs          = {'A','B','C','D'};
import.impfiltstruct.lattarmaVarStrs    = {'K','V'};
import.impfiltstruct.lattapsVarStrs     = {'K','V'};
import.impfiltstruct.lattmaminVarStrs   = {'K','V'};
import.impfiltstruct.lattmamaxVarStrs   = {'K','V'};
import.impfiltstruct.qfiltVarStrs       = {'Hq'};

% Sampling Frequency units
import.fs.freqUnits = 'Normalized (0 to 1)'; 

% Sampling Frequency default variable
import.fs.Fs = '1';


%-------------------------------------------------------------------
function export = setupExport
%SETUPEXPORT Set up the Export dialog defaults.
%
% Output:
%  export - Structure containing the default Export dialog options 

% Export To popupmenu
export.exportto = 'Workspace';

% Coefficient Edit box default strings
export.tfVarStrs        = {'Num','Den'};
export.sosVarStrs       = {'SOS','G'};
export.ssVarStrs        = {'A','B','C','D'};
export.latcapsVarStrs   = {'K'}; % Lattice allpass
export.latcmaminVarStrs = {'K'}; 
export.latcmamaxVarStrs = {'K'};
export.latcarmaVarStrs  = {'K','V'};
export.quantizedVarStrs = {'Hq'};

% Variable collision checkbox value
export.overwritechk = 0;


%-------------------------------------------------------------------
function convert = setupConvert
%SETUPCONVERT Set up the Convert dialog defaults.
%
% Output:
%  convert - Structure containing the default Convert dialog options. 

% Target "quantized" filter structure (filter structure to be converted to)
convert.qconvertto = 'Direct form II transposed';

% Target "double" filter structure 
convert.dconvertto = 'Direct form II transposed';

% "Use second-order sections" checkbox value.
convert.soschkbox = 0;

% Default for the "Scale" popupmenu (for the SOS case)
convert.sosScale = 'None';


%-------------------------------------------------------------------
function toolbar = setupToolbarstate
%SETUPTOOLBARSTATE Sets up default values for the state of the toolbar.
%
% Output:
%    toolbar - structure storing the state of the toolbar buttons.

% Default Filter Analysis 
toolbar.analysis = 'filterresponsespecs';

% Default Zoom status
toolbar.zoom = 'none';

%-------------------------------------------------------------------
function [filter,n] = defaultFilter(design)
%DEFAULTFILTER  Designs a default filter and then converts to a
%               filter object.

% % Extract specs from the input data structure.
% Wp = evaluatevars(design.freq.lp.passStop{1});
% Ws = evaluatevars(design.freq.lp.passStop{2});
% Fs = evaluatevars(design.freq.lp.fs);
% Rp = evaluatevars(design.mag.lp.passStop{1});
% Rs = evaluatevars(design.mag.lp.passStop{2});
% 
% % Default designed filter coeffs.
% [n,fo,mo,w]=remezord([Wp Ws],[1 0],...
%     [(10^(0.05.*Rp)-1)/(10^(0.05.*Rp)+1) 10^(-0.05*Rs)],44100);
% b = remez(n,fo,mo,w);

b = [...
    -4.307020045684871e-003;
    -1.308561664228007e-002;
    -1.651509138704759e-002;
    -6.436813460236936e-003;
    9.812995804477174e-003;
    1.080509015770817e-002;
    -6.559090988025997e-003;
    -1.680168434011382e-002;
    6.469080997496893e-004;
    2.246173646835666e-002;
    1.013863182521490e-002;
    -2.566675360315268e-002;
    -2.656981085404965e-002;
    2.304448932000174e-002;
    5.039554410986893e-002;
    -9.271206111969254e-003;
    -8.790401571487327e-002;
    -3.376590386366615e-002;
    1.873340190414154e-001;
    4.015071566405832e-001;
    4.015071566405832e-001;
    1.873340190414154e-001;
    -3.376590386366615e-002;
    -8.790401571487327e-002;
    -9.271206111969254e-003;
    5.039554410986893e-002;
    2.304448932000174e-002;
    -2.656981085404965e-002;
    -2.566675360315268e-002;
    1.013863182521490e-002;
    2.246173646835666e-002;
    6.469080997496893e-004;
    -1.680168434011382e-002;
    -6.559090988025997e-003;
    1.080509015770817e-002;
    9.812995804477174e-003;
    -6.436813460236936e-003;
    -1.651509138704759e-002;
    -1.308561664228007e-002;
    -4.307020045684871e-003];

filter = df2t(b);
n = order(filter);

%--------------------------------------------------------------------------
function ud = updateud(ud,sessionud)
%UPDATEUD  Update user data with fields from default session.
%   We don't save all of ud in a session, copy only the fields
%   we save in the session

ud.flags     = sessionud.flags;
ud.filename  = sessionud.filename;
ud.specs     = sessionud.specs;
ud.toolbar   = sessionud.toolbar;
ud.filter    = sessionud.filter;
ud.reffilter = sessionud.reffilter;
ud.mode      = sessionud.mode;

%--------------------------------------------------------------------------
function fdqexists = qfiltexists
%QFILTEXISTS  Test to see if the QFILT constructor exists.

fdqexists = (exist('qfilt','file')==2);


% [EOF] fdatool.m
