function ConceptSimulator
 
    close all ;
%    ho    All parameters for the home window

%>>>>>>>>>>>>>>>>>>>>>Beginning of Signal Function Window<<<<<<<<<<<<<<<<<<<

%    sfn    All parameters for the signal function window
%           fns  Structure containing parameters of current functions. Stored in 
%                   the figure window's data with guidata.
%               .cL The parameters of the current continuous-time function on 
%                   the left side.  
%               .cR The parameters of the current continuous-time function on 
%                   the right side.  
%               .dL The parameters of the current discrete-time function on 
%                   the left side.  
%               .dR The parameters of the current discrete-time function on 
%                   the right side.  
%           sdL  An array of structures, one for each signal type, containing all 
%                information for graphing the associated prototype and signal on
%                the left side. Stored as user data in the left menu.
%               .pe   A flag indicating whether the signal is an energy signal
%                        or a power signal, 'p' for power and 'e' for energy
%               .pa   A flag indicating whether the signal is periodic, 'p'
%                        for periodic, 'a' for aperiodic
%               .tg   A short tag name used for identifying the function type
%               .pc   A structure for continuous-time prototypes
%                   .t    Time vector
%                   .x    Continuous signal values
%                   .ti   Impulse time vector
%                   .xi   Impulse strengths
%                   .an   A 4 by N cell array of annotation data
%                   .ttl  A title for the prototype
%               .sc    A structure for continuous-time signals
%                   .v    An array of 4 parameter slider values
%                   .mx   An array of 4 slider maxima
%                   .mn   An array of 4 slider minima
%                   .ss   An array of 4 by 2 slider step values
%                   .pn   A 1 by 4 cell array of parameter names
%                   .t    Time vector for continuous signals
%                   .x    Continuous signal values
%                   .ti   Impulse time vector
%                   .xi   Signal impulse strengths
%                   .f    Frequency vector for continuous CTFT's
%                   .X    Continuous CTFT values
%                   .fi   Impulse frequency vector
%                   .Xi   CTFT impulse strengths
%                   .ttl  A title for the graph
%               .pd    A structure for discrete-time prototypes
%                   .t    Time vector
%                   .x    Continuous signal values
%                   .ti   Impulse time vector
%                   .xi   Impulse strengths
%                   .an   A 4 by N cell array of annotation data
%                   .ttl  A title for the prototype
%               .sd   A structure for discrete-time signals
%                   .v    An array of 4 parameter slider values
%                   .mx   An array of 4 slider maxima
%                   .mn   An array of 4 slider minima
%                   .ss   An array of 4 by 2 slider step values
%                   .pn   A 1 by 4 cell array of parameter names
%                   .n    Time vector
%                   .x    Signal values
%                   .W    Frequency vector for continuous CTFT's (Omega in radians)
%                   .X    Continuous DTFT values
%                   .Wi   Impulse frequency vector
%                   .Xi   DTFT impulse strengths
%                   .ttl  A title for the graph
%           sdR  An array of structures, one for each signal type, containing all 
%                information for graphing the associated prototype and signal on
%                the right side. Stored as user data in the right menu.  Identical
%                to sdL structure.

%>>>>>>>>>>>>>>>>>>>>>End of Signal Function Window<<<<<<<<<<<<<<<<<<<<<<<<<

%   >>>>>>>>>>>>>>>>>>>>>>>Beginning of Program<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
%   Create the home window and all its buttons
    f = initHomeWindow ;
    %   Create the signal function window and all its user interface elements
    h = guihandles(f) ; 
    disableControls(h) ;
    initSigFuncWind(f) ;
    %   Create the feedback system window and all its user interface elements
    fbs = initFBSysWind(f) ;
    %   Create the feedback system window and all its user interface elements
    sam = initSampWind(f) ;
    enableControls(h) ;
    
%   Create the home window with a message "Choose the Type of Simulation"
%   and a button for each type of simulation
    function f = initHomeWindow
        %   Names of the types of simulations
        names = {'Signal Functions','Feedback Systems','Sampling'} ;
        %   Three-letter tags for the types of simulations
        tgs = {'sfn','fbs','sam'} ;
        %   Create the home window
        f = figure('Units','Normalized','Position',[0.05,0.05,0.9,0.9],...
            'NumberTitle','off','Resize','off','Name','Home','Color',...
            'k','MenuBar','none','Color',[242,217,156]/256) ;
        %   Display message "Choose the Type of Simulation"
        axes('Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
        set(gca,'Visible','off') ;
        axes('Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
        ptr = text(0.5,0.85,'Choose the Type of Simulation','HorizontalAlignment',...
            'center','VerticalAlignment','bottom','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.08,'Color','b','FontWeight','Bold') ;
        ptr = text(0.5,0.14,'Notice:  Incomplete Draft Version - Still Has Bugs','HorizontalAlignment',...
            'center','VerticalAlignment','bottom','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.03,'Color','b','FontWeight','Bold') ;
        ptr = text(0.5,0.1,'\copyright M. J. Roberts - February 2011','HorizontalAlignment',...
            'center','VerticalAlignment','bottom','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.03,'Color','b','FontWeight','Bold') ;
        ptr = text(0.5,0.06,'www.eecs.utk.edu/~roberts','HorizontalAlignment',...
            'center','VerticalAlignment','bottom','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.03,'Color','b','FontWeight','Bold') ;
        ptr = text(0.5,0.02,'mjr@utk.edu','HorizontalAlignment',...
            'center','VerticalAlignment','bottom','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.03,'Color','b','FontWeight','Bold') ;
        %   Hide the graphic axes on the home window
        set(gca,'Visible','off') ;
        %   Put buttons on the home window for choosing the type of simulation
        cnt = 0 ; wd = 0.4 ; ht = 0.15 ;
        fnum = 1 ; fss = [] ;
        row = 0.6 ; col = 0.5 - wd/2 ;
        while cnt < length(names),
            %   Create next simulation-choice button 
            cnt = cnt + 1 ;
            uicontrol('Style','Pushbutton','Units',...
                'Normalized','Position',[col,row,wd,ht],'String',...
                names{cnt},'FontUnits','Normalized','FontName','Utopia',...
                'FontSize',0.45,'Callback',@selSim,'BackgroundColor',...
                'w','ForeGroundColor','b','Tag',tgs{cnt},'Interruptible','off',...
                'BusyAction','cancel') ;
            row = row - 0.2 ;
        end
    
    %   Select the simulation to be performed
    %
    %   hObject and eventdata are automatically sent to each user interface
    %   object and must be the first two parameters passed to its handler
    function selSim(hObject,eventdata)
        %   Get from the userdata in the callback object the figure number 
        %   of the simulation window, hide the current figure window and 
        %   show the simulation window
        obj = gcbo ; f = get(obj,'UserData') ;
        set(gcf,'Visible','off') ; figure(f) ;
        if f == 4,
            h = guihandles(f) ; sam = guidata(f) ;
            sam.par.name = 'Exponential' ;
            axes(h.samSysPanelAx) ; set(sam.par.ptr,'String',sam.par.name) ;
            updateSliderAndEdit(sam,h) ;
            sam = NewSamplingGraphs('ai',sam,h) ;
            guidata(f,sam) ;
        end
        
    %   Create the signal function window and all its user interface elements
    %   f is a pointer to the home window
    function initSigFuncWind(f)
        %   Create the window
        figure('Units','Normalized','Resize','off','Position',...
            [0.05,0.05,0.9,0.9],'NumberTitle','off','Name',...
            'Signal Functions','Color',[1,0.9,0.8],'Visible','off',...
            'Menubar','none','Tag','sfn') ;
        axes('Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
%         I = find(double(lo)>30) ; lo(I) = 0 ; 
%         contrastFactor = 0.4 ;
%         pattern = granite(lo,[0.9,0.85,0.6;1,1,1],contrastFactor) ;
%         image(pattern) ;
        set(gca,'Visible','off') ;
        h = guihandles(f) ;
        %   Store in the associated button on the home window a pointer
        %   to this window
        set(h.sfn,'UserData',gcf) ;
        %   Create all the user-interface elements in the window
        %   Store last-selected signal numbers in figure window
        %   Init to empty indicating no selection yet
        fns.cL = [] ; fns.cR = [] ; fns.dL = [] ; fns.dR = [] ;
        guidata(gcf,fns) ;
        %   Create signal function window user-interface elements
        sfnUI(f) ; 
        
    %   Create all the user-interface elements for the signal function window
    %   including buttons for signal selection, a home button,
    %   a button to toggle between continuous and discrete time, sliders
    %   to adjust parameters and axes for the graphs
    function sfnUI(f)
        sfnSliders ;   %   Create a 4 by 2 array of sliders
        sfnAxes ;    %   Create all axes objects for graphs
        %   Create a 4 by 2 array of axes objects for display of slider values
        sfnValAxes ;
        fss = [] ;
        %   Add a button to transfer control back to the home window
        uicontrol('Style','Pushbutton',...
            'Units','Normalized','Position',[0.91,0.01,0.08,0.03],'String',...
            'Home','FontName','Utopia','FontUnits','Normalized','FontSize',...
            0.6,'Callback',@goHome,'ForeGroundColor','k','Tag','sfnho',...
            'UserData',f,'Interruptible','off','BusyAction','cancel') ;
        %   Add a button to toggle between continuous and discrete time
        uicontrol('Style','Pushbutton',...
            'Units','Normalized','Position',[0.02,0.01,0.15,0.04],'String',...
            'To Continuous Time Mode','FontName','Utopia','FontUnits',...
            'Normalized','FontSize',0.4,'Callback',@toggleCD,'ForeGroundColor',...
            'k','Tag','sfncd','UserData','c','Interruptible','off','BusyAction',...
            'cancel') ;
        %   Add a button to do a convolution
        uicontrol('Style','Pushbutton',...
            'Units','Normalized','Position',[0.34,0.01,0.15,0.04],'String',...
            'Convolve','FontName','Utopia','FontUnits','Normalized',...
            'FontSize',0.4,'Callback',@convolve,'ForeGroundColor','k','Tag',...
            'sfncv','Enable','off','Interruptible','off','BusyAction','cancel') ;
        %   Add a button to toggle between display of sum and product and
        %   display of convolution
        spcvData.spcv = 'sp' ;
        uicontrol('Style','Pushbutton',...
            'Units','Normalized','Position',[0.18,0.01,0.15,0.04],'String',...
            'To Convolution Mode','FontName','Utopia','FontUnits','Normalized',...
            'FontSize',0.4,'Callback',@toggleSPCV,'ForeGroundColor','k','Tag',...
            'sfnspcv','UserData',spcvData,'Interruptible','off','BusyAction','cancel') ;
        %   Create two popupmenus for signal selection
        sfnMenu('L') ; sfnMenu('R') ;
        h = guihandles(gcf) ;
        set(h.sfncd,'String','To Discrete Time Mode') ;
    
    %   Return to the home window to select another simulation
    %   hObject and eventdata are automatically sent to each user interface
    %   object and must be the first two parameters passed to its handler
    function goHome(hObject,eventdata)
        %   Get a pointer to the home button, get from its user data a 
        %   pointer to the home window, hide the current window and
        %   show the home window
        set(gcf,'Visible','off') ; figure(get(gcbo,'UserData')) ;
        
    %   Create a button to toggle between continuous-time and discrete-
    %   time signal function displays
    %   hObject and eventdata are automatically sent to each user interface
    %   object and must be the first two parameters passed to its handler
    function toggleCD(hObject,eventdata)
        %   Get a pointer to the toggle button, get a structure of handles
        %   of all user-interface objects on the signal function window
        %   and get pointers to the last functions selected, two continuous-
        %   time and two discrete-time
        [obj,f] = gcbo ; h = guihandles(f) ; fns = guidata(f) ;
        %   Clear all graphic axes
        axes(h.sfnS) ; cla ; axes(h.sfnP) ; cla ; 
        axes(h.sfnPL) ; cla ; axes(h.sfnPR) ; cla ; 
        axes(h.sfnLt) ; cla ; axes(h.sfnRt) ; cla ;
        axes(h.sfnLm) ; cla ; axes(h.sfnRm) ; cla ;
        axes(h.sfnLp) ; cla ; axes(h.sfnRp) ; cla ;
        namesC = {'Impulse','Signum','Unit Step','Exponential','Rectangle',...
                    'Triangle','Sinc','Sine','Cosine','Periodic Impulse',...
                    'Dirichlet','Rectangular Wave','Triangular Wave'} ;
        namesD = {'Impulse','Signum','Unit Sequence','Exponential','Rectangle',...
                    'Triangle','Sinc','Sine','Cosine','Periodic Impulse',...
                    'Dirichlet','Rectangular Wave','Triangular Wave'} ;
        %   Get a character indicating the current function type, continuous
        %   (c) or discrete (d), being displayed from the toggle button's
        %   userdata
        cd = get(h.sfncd,'UserData') ;
        %   Determine the mode, sum/product or convolution
        spcvData = get(h.sfnspcv,'UserData') ;
        if cd == 'c',
            %   Change to discrete-time mode and change toggle button's
            %   label to "To Continuous Time"
            set(obj,'String','To Continuous Time Mode') ;
            %   Change two signal labels from "Unit Step" to "Unit Sequence"
            set(h.sfnmL3,'Label','Unit  Sequence') ;
            sdL = get(h.sfnmL3,'UserData') ; 
            sdL.sd.ttl = 'Unit Sequence' ; set(h.sfnmL3,'UserData',sdL) ;
            set(h.sfnmR3,'Label','Unit  Sequence') ;
            sdR = get(h.sfnmR3,'UserData') ; 
            sdR.sd.ttl = 'Unit Sequence' ; set(h.sfnmR3,'UserData',sdR) ;
            %   Change character indicating mode from "c" to "d"
            set(obj,'UserData','d') ;
            %   Re-draw the last used discrete-time signal functions
            %   If none has ever been selected, draw nothing
            sL = ~isempty(fns.dL) ;
            if sL, drawSignal(sdL(fns.dL),'d','L',h) ; end
            sR = ~isempty(fns.dR) ;
            if sR, drawSignal(sdR(fns.dR),'d','R',h) ; end
            if sL & sR & strcmp(spcvData.spcv,'sp') ;
                disableControls(h) ; 
                    drawSumD(sdL(fns.dL),sdR(fns.dR),h) ; 
                    drawProdD(sdL(fns.dL),sdR(fns.dR),h) ; 
                enableControls(h) ; 
            end
        else
            %   Change to continuous-time mode and change toggle button's
            %   label to "To Discrete Time"
            set(obj,'String','To Discrete Time Mode') ;
            %   Change two signal buttons' labels from "Unit Sequence" to 
            %   "Unit Step"
            %   Change two signal labels from "Unit Sequence" to "Unit Step"
            set(h.sfnmL3,'Label','Unit Step') ;
            sdL = get(h.sfnmL3,'UserData') ; sdL.sd.ttl = 'Unit Step' ;
            set(h.sfnmL3,'UserData',sdL) ;
            set(h.sfnmR3,'Label','Unit Step') ;
            sdR = get(h.sfnmR3,'UserData') ; sdR.sd.ttl = 'Unit Step' ;
            set(h.sfnmR3,'UserData',sdR) ;
            %   Change character indicating mode from "d" to "c"
            set(obj,'UserData','c') ;
            %   Re-draw the last used continuous-time signal functions
            %   If none has ever been selected, draw nothing
            sL = ~isempty(fns.cL) ;
            if sL, drawSignal(sdL(fns.cL),'c','L',h) ; end
            sR = ~isempty(fns.cR) ;
            if sR, drawSignal(sdR(fns.cR),'c','R',h) ; end
            if sL & sR & strcmp(spcvData.spcv,'sp') ;
                disableControls(h) ; 
                    drawSumC(sdL(fns.cL),sdR(fns.cR),h) ; 
                    drawProdC(sdL(fns.cL),sdR(fns.cR),h) ; 
                enableControls(h) ; 
            end
        end
        
    function toggleSPCV(hObject,eventdata)
        %   Get a pointer to the button, get a structure of handles
        %   of all user-interface objects on the signal function window
        %   and get numbers of the last functions selected, two continuous-
        %   time and two discrete-time
        [obj,f] = gcbo ; h = guihandles(f) ; fns = guidata(f) ;
        %   Clear sum and product graphic axes
        axes(h.sfnS) ; cla ; axes(h.sfnP) ; cla ;
        %   Get a character indicating the current function type, continuous
        %   (c) or discrete (d), being displayed from the toggle button's
        %   userdata
        cd = get(h.sfncd,'UserData') ;
        %   Get current state of sum/product or convolution
        spcvData = get(obj,'UserData') ; 
        %   Get the signal parameters from the menu userdata
        if cd == 'c',
            st = ['sdL = get(h.sfnmL',num2str(fns.cL),',''UserData'') ;'] ; eval(st) ;
            st = ['sdR = get(h.sfnmR',num2str(fns.cR),',''UserData'') ;'] ; eval(st) ;
        else
            st = ['sdL = get(h.sfnmL',num2str(fns.dL),',''UserData'') ;'] ; eval(st) ;
            st = ['sdR = get(h.sfnmR',num2str(fns.dR),',''UserData'') ;'] ; eval(st) ;
        end
%         sdL = get(h.sfnmL,'UserData') ; sdR = get(h.sfnmR,'UserData') ;
        if strfind(spcvData.spcv,'sp'), 
            %   Set spcv flag to 'cv', change button text to "To Sum/Product Mode"
            %   and enable the convolve button
            spcvData.spcv = 'cv' ; set(obj,'UserData',spcvData) ;
            set(obj,'String','To Sum/Product Mode') ;
            set(h.sfncv,'Enable','on') ;
        else
            %   Set spcv flag to 'sp', change button text to "To Convolution Mode",
            %   draw the sum and product and disable the convolve button
            spcvData.spcv = 'sp' ; set(obj,'UserData',spcvData) ; 
            set(obj,'String','To Convolution Mode') ;
            if cd == 'c',
                if ~isempty(fns.cL) & ~isempty(fns.cR),
                    disableControls(h) ; 
                        drawSumC(sdL,sdR,h) ;                    
                        drawProdC(sdL,sdR,h) ; 
                    enableControls(h) ; 
                end
            else
                if ~isempty(fns.dL) & ~isempty(fns.dR),
                    disableControls(h) ; 
                        drawSumD(sdL,sdR,h) ;                    
                        drawProdD(sdL,sdR,h) ; 
                    enableControls(h) ; 
                end
            end
            set(h.sfncv,'Enable','off') ;
        end
        
        %   Convolve the two current signals
    function convolve(hObject,eventdata)
        %   Get a pointer to the button, get a structure of handles
        %   of all user-interface objects on the signal function window
        %   and get pointers to the last functions selected, two continuous-
        %   time and two discrete-time
        [obj,f] = gcbo ; h = guihandles(f) ; fns = guidata(f) ;
        %   Clear sum and product graphic axes
        axes(h.sfnS) ; cla ; axes(h.sfnP) ; 
        %   Get a character indicating the current function type, continuous
        %   (c) or discrete (d), being displayed from the toggle button's
        %   userdata
        cd = get(h.sfncd,'UserData') ;
        disableControls(h) ; 
        if cd == 'c',
            %   Get the signal data for the continuous-time signal
            st = ['sdL = get(h.sfnmL',num2str(fns.cL),',''UserData'') ;'] ; eval(st) ;
            st = ['sdR = get(h.sfnmR',num2str(fns.cR),',''UserData'') ;'] ; eval(st) ;
            %   Re-draw the last used continuous-time signal functions
            %   If none has ever been selected, draw nothing
            drawConvC(sdL,sdR,h) ;
        else
            %   Get the signal data for the discrete-time signal
            st = ['sdL = get(h.sfnmL',num2str(fns.dL),',''UserData'') ;'] ; eval(st) ;
            st = ['sdR = get(h.sfnmR',num2str(fns.dR),',''UserData'') ;'] ; eval(st) ;
            %   Re-draw the last used discrete-time signal functions
            %   If none has ever been selected, draw nothing
            drawConvD(sdL,sdR,h) ;
        end
        enableControls(h) ;
        
    %   Create all the axes objects for display of pALIprototypes, signal
    %   graphs, sum graphs and product graphs
    function sfn = sfnAxes(sfn) 
        sfn.PLax   = axes('Position',[0.13,0.78,0.25,0.2],'Tag','sfnPL','Visible','off') ;
        sfn.PRax   = axes('Position',[0.63,0.78,0.25,0.2],'Tag','sfnPR','Visible','off') ;
        sfn.SLax.t = axes('Position',[0.02,0.46,0.22,0.2],'Tag','sfnLt','Visible','off') ;
        sfn.SRax.t = axes('Position',[0.52,0.46,0.22,0.2],'Tag','sfnRt','Visible','off') ;
        sfn.SLax.m = axes('Position',[0.25,0.54,0.24,0.22],'Tag','sfnLm','Visible','off') ;
        sfn.SRax.m = axes('Position',[0.75,0.54,0.24,0.22],'Tag','sfnRm','Visible','off') ;
        sfn.SLax.p = axes('Position',[0.25,0.35,0.24,0.18],'Tag','sfnLp','Visible','off') ;
        sfn.SRax.p = axes('Position',[0.75,0.35,0.24,0.18],'Tag','sfnRp','Visible','off') ;
        sfn.Sax    = axes('Position',[0.1,0.08,0.35,0.22],'Tag','sfnS','Visible','off') ;
        sfn.Pax    = axes('Position',[0.6,0.08,0.35,0.22],'Tag','sfnP','Visible','off') ;
        
    %   Create two sets of four sliders used to enter parameter values
    %   Amplitude, time shift, width parameter, period, etc...
    %   All sliders are initially invisible and disabled
    %   Their values, maxima, minima and slider step sizes are set when a 
    %   signal is selected so they need not be selected now
    function sfnSliders
        for col = 1:2,
            x1 = 0.38 + 0.5*(col-1) ;
            %   Create an amplitude slider
            uicontrol('Style','Slider',...
                'Units','Normalized','Position',[x1,0.92,0.115,0.05],...
                'Callback',@setParam,'Tag',['sfnsl1',num2str(col)],'UserData',...
                [1,col],'Enable','off','Visible','off','Interruptible','off',...
                'BusyAction','cancel') ;
            %   Create a time-shift slider
            uicontrol('Style','Slider',...
                'Units','Normalized','Position',[x1,0.86,0.115,0.05],...
                'Callback',@setParam,'Tag',['sfnsl2',num2str(col)],'UserData',...
                [2,col],'Enable','off','Visible','off','Interruptible','off',...
                'BusyAction','cancel') ;
            %   Create a width slider
            uicontrol('Style','Slider',...
                'Units','Normalized','Position',[x1,0.8,0.115,0.05],...
                'Callback',@setParam,'Tag',['sfnsl3',num2str(col)],'UserData',...
                [3,col],'Enable','off','Visible','off','Interruptible','off',...
                'BusyAction','cancel') ;
            %   Create a period slider
            uicontrol('Style','Slider',...
                'Units','Normalized','Position',[x1,0.74,0.115,0.05],...
                'Callback',@setParam,'Tag',['sfnsl4',num2str(col)],'UserData',...
                [4,col],'Enable','off','Visible','off','Interruptible','off',...
                'BusyAction','cancel') ;
        end
        
    %   Create all the axes for displaying slider values as text
    %   A 4 by 2 array corresponding one-to-one to the slider array
    function vax = sfnValAxes      
        for col = 1:2,
            x1 = 0.41 + 0.5*(col-1) ;
            %   Create graphics axes to contain slider annotation
            vax(1,col) = axes('Units','Normalized','Position',...
                [x1,0.97,0.08,0.02],'Color','c','Visible','off',...
                'Tag',['sfnvax1',num2str(col)],'UserData',[1,col]) ;
            vax(2,col) = axes('Units','Normalized','Position',...
                [x1,0.91,0.08,0.02],'Color',[1,0.6,0.4],'Visible','off',...
                'Tag',['sfnvax2',num2str(col)],'UserData',[2,col]) ;
            vax(3,col) = axes('Units','Normalized','Position',...
                [x1,0.85,0.08,0.02],'Color',[1,0.6,0.4],'Visible','off',...
                'Tag',['sfnvax3',num2str(col)],'UserData',[3,col]) ;
            vax(4,col) = axes('Units','Normalized','Position',...
                [x1,0.79,0.08,0.02],'Color',[1,0.6,0.4],'Visible','off',...
                'Tag',['sfnvax4',num2str(col)],'UserData',[4,col]) ;
        end                
        
    %   Create a signal function menu for the signal function
    %   window.  Include in each menu's user data all information for graphing 
    %   the signal prototype and current graph
    function sfnMenu(LR)
        %   Names of all signal forms
        namesC = {'Impulse','Signum','Unit Step','Exponential','Rectangle',...
                    'Triangle','Sinc','Sine','Cosine','Periodic Impulse',...
                    'Dirichlet','Rectangular Wave','Triangular Wave'} ;
        tgs = {'Imp','Sgn','Us','Exp','Rect','Tri','Sinc','Sin','Cos','Pimp',...
                'Drcl','Rwav','Twav'} ;
        peFlags = {'e','p','p','e','e','e','e','p','p','p','p','p','p'} ;
        paFlags = {'a','a','a','a','a','a','a','p','p','p','p','p','p'} ;
        if LR == 'L', x = 0.01 ; col = 1 ; else x = 0.52 ; col = 2 ; end
        wd = 0.12 ;
        %   Create the menu
        if LR == 'L', posn = 1 ; lbl = 'Left Signal' ; else posn = 2 ;lbl = 'Right Signal' ; end
        me = uimenu('Position',posn,'Label',lbl,...
            'Tag',['sfnm',LR],'Interruptible','off','BusyAction','cancel') ;
        for snum = 1:length(namesC)
            %   Initialize the parameters that control continuous-time
            %   prototype drawing 
            sd.pc = proDataC(tgs{snum}) ;
            %   Initialize the signal parameters that control its graph
            sd.sc = sfnDataC(tgs{snum}) ;
            %   Initialize the parameters that control discrete-time
            %   prototype drawing 
            sd.pd = proDataD(tgs{snum}) ;
            %   Initialize the signal parameters that control its graph
            sd.sd = sfnDataD(tgs{snum}) ;
            %   Set the power/energy and periodic/aperiodic flags
            sd.pe = peFlags{snum} ; sd.pa = paFlags{snum} ;
            %   Store the signal's tag
            sd.tg = tgs{snum} ;
            uimenu(me,'Label',namesC{snum},'Callback',@sfnSigResp,'Tag',...
                    ['sfnm',LR,num2str(snum)],'UserData',sd) ;
        end

    %   Select which continuous-time prototype data to initialize based on the 
    %   tag passed to this function.  Use an "eval" statement to reduce the 
    %   code length.  Each function is named according to the corresponding
    %   tag.
    function pc = proDataC(tg)
        pc.ti = [] ; pc.xi = [] ;
        s = ['pc = pro',tg,'C(pc) ;'] ; eval(s) ;
        
    %   Display Impulse Prototype
    function pc = proImpC(pc)
        pc.t = [-0.3,1.3]' ; pc.x = [0,0]' ; pc.ti = 0.6 ; pc.xi = 1.5 ;
        pc.an = {[-0.1,0.6],1.5,'b','{\itA}';0.6,[0,-0.1],'e',' {\itt}_0'} ;
        
    %   Display Signum prototype
    function pc = proSgnC(pc)
        pc.t = [-0.3,0.6,0.6,1.3]' ; pc.x = [-1.5,-1.5,1.5,1.5]' ;
        pc.an = {[-0.1,0.6],1.5,'b','{\itA}';[0.6,0.7],-1.5,'e','-{\itA}';...
                 0.6,[-1.5,-1.7],'e','{\itt}_0'} ;

    %   Display Unit Step Prototype
    function pc = proUsC(pc)
        pc.t = [-0.3,0.6,0.6,1.3]' ; pc.x = [0,0,1.5,1.5]' ;
        pc.an = {[-0.1,0.6],1.5,'b','{\itA}';0.6,[0,-0.1],'e','{\itt}_0'} ;

    %   Display Exponential Prototype
    function pc = proExpC(pc)
        pc.t = [-0.3,0.599999,0.600001,[0.62:0.02:1.3]]' ;
        pc.x = 1.5*exp(-3*(pc.t-0.6)).*us(pc.t-0.6) ;
        pc.an = {[-0.1,0.6],1.5,'b','{\itA}';0.6,[0,-0.1],'e','{\itt}_0';...
                 [0.6,0.933],[1.5,0],'e','';0.933,[0.2,-0.2],'e','  {\itt}_0 + \tau'} ;

    %   Display Rectangle Prototype
    function pc = proRectC(pc)
        pc.t = [-0.3,0.399999,0.400001,0.799999,0.800001,1.3]' ;
        pc.x = 1.5*rect((pc.t-0.6)/0.4) ;
        pc.an = {[-0.1,0.4],1.5,'b','\itA';0.6,[1.4,-0.1],'e',' {\itt}_0';...
                 [0.2,0.4],0.75,'b',' >';[1,0.8],0.75,'b','{\itw}>'} ;
        
    %   Display Triangle Prototype
    function pc = proTriC(pc)
        pc.t = [-0.3,0.4,0.6,0.8,1.3]' ; pc.x = 1.5*tri((pc.t-0.6)/0.2) ;
        pc.an = {[-0.1,0.6],1.5,'b','\itA';0.6,[1.4,-0.4],'e','{\itt}_0';...
                 0.8,[0,-0.4],'e',''; [0.4,0.6],-0.2,'e',' >';...
                 [1,0.8],-0.2,'b','{\itw}>'} ;
             
    %   Display Sinc Prototype
    function pc = proSincC(pc)
        pc.t = [-0.3:0.02:1.3]' ; pc.x = 1.5*sinc((pc.t-0.6)/0.2) ;
        pc.an = {[-0.1,0.6],1.5,'b','{\itA}';0.6,[1.4,-0.2],'e','{\itt}_0';...
                 0.8,[0.6,-0.2],'e','';[0.2,0.6],0.5,'b',' >';...
                 [1.2,0.8],0.5,'b','{\itw}>'} ;

    %   Display Sine Prototype
    function pc = proSinC(pc)
        pc.t = [-0.3:0.02:1.3]' ; pc.x = 1.5*sin(2*pi*(pc.t-0.25)) ;
        pc.an = {[-0.1,0.5],1.5,'b','{\itA}';0.25,[1,-0.7],'e','{\itt}_0';...
                 1.25,[1,-0.7],'e',''; [-0.2,0.25],0.8,'b',' >';...
                 [1.6,1.25],0.8,'b','{\itT }>'} ;

    %   Display Cosine Prototype
    function pc = proCosC(pc)
        pc.t = [-0.3:0.02:1.3]' ; pc.x = 1.5*cos(2*pi*(pc.t-0.25)) ;
        pc.an = {[-0.1,0.25],1.5,'b','{\itA}'; 0.25,[1.5,-0.7],'e','{\itt}_0';   
                 1.25,[1.5,-0.7],'b',''; [-0.2,0.25],0.8,'b',' >';...
                 [1.6,1.25],0.8,'b','{\itT }>'} ;

    %   Display Periodic Impulse Prototype
    function pc = proPimpC(pc)
        pc.t = [-0.35,1.35]' ; pc.x = [0,0]' ; 
        pc.ti = [-0.2,0.3,0.8,1.3] ; pc.xi = [1.5,1.5,1.5,1.5] ;
        pc.an = {[-0.05,0.3],1.5,'b','{\itA}';0.3,[1.8,-0.1],'e','{\itt}_0';...
                 0.8,[1.8,0],'b',''; [0.2,0.3],1.7,'b',' >';[1,0.8],1.7,'b','{\itT }>'} ;

    %   Display Dirichlet Prototype
    function pc = proDrclC(pc)
        pc.t = [-0.3:0.02:1.3]' ; pc.x = 1.5*drcl((pc.t-0.6)/0.5,5) ;
        pc.an = {[-0.1,0.1],1.5,'b','{\itA}'; 0.6,[1.9,-1.2],'e','{\itt}_0';...
                 1.1,[1.9,-1],'b',''; [0.3,0.6],1.8,'b',' >';...
                 [1.4,1.1],1.8,'b','{\itT }>'; [0.5,0.6],-0.7,'b',' >';...
                 [0.8,0.7],-0.7,'b','{\itT/N }>'; 0.7,[0.4,-1],'b',''} ;

    %   Display Rectangular Wave Prototype
    function pc = proRwavC(pc)
        pc.t = [-0.3,0.099999,0.100001,0.299999,0.300001,0.99999,1.00001,...
                1.199999,1.2000001,1.3] ;
        pc.x = 1.5*(rect((pc.t-0.2)/0.2) + rect((pc.t-1.1)/0.2)) ;
        pc.an = {[-0.1,0.1],1.5,'b','{\itA}';0.2,[1.5,-0.4],'e',' {\itt}_0';   
                 1.1,[1.5,-0.4],'b','';[-0.1,0.2],0.6,'b',' >';...
                 [1.4,1.1],0.6,'b','{\itT }>';[0.8,1],-0.7,'b',' >';...
                 [1.4,1.2],-0.7,'b','{\itw}>';1,[0.4,-1],'b','';...
                 1.2,[0.4,-1],'b',''} ;
        
    %   Display Triangular Wave Prototype
    function pc = proTwavC(pc)
        pc.t = [-0.3,0.1,0.2,0.3,1,1.1,1.2,1.3] ;
        pc.x = 1.5*(tri((pc.t-0.2)/0.1) + tri((pc.t-1.1)/0.1)) ;
        pc.an = {[-0.1,0.2],1.5,'b','{\itA}';0.2,[1.5,-0.4],'e',' {\itt}_0';...
                  1.1,[1.5,-0.4],'b','';[-0.1,0.2],0.3,'b',' >';...
                  [1.4,1.1],0.3,'b','{\itT }>';[0.8,1.1],-0.4,'b',' >';...
                  [1.4,1.2],-0.4,'b','{\itw}>';1.1,[0,-0.6],'b','';...
                  1.2,[0,-0.6],'b',''} ;
          
    %   Initialize the parameters controlling the continuous-time signal display
    %   for all the signal types, Impulse through Triangular Wave 
    function sc = sfnDataC(tg)
        sc = [] ;
        switch tg,
            case 'Imp',  sc = sfnImpC([1,0,NaN,NaN],sc) ;
            case 'Sgn',  sc = sfnSgnC([1,0,NaN,NaN],sc) ;
            case 'Us',   sc = sfnUsC([1,0,NaN,NaN],sc) ;
            case 'Exp',  sc = sfnExpC([1,0,4,NaN],sc) ;
            case 'Rect', sc = sfnRectC([1,0,4,NaN],sc) ;
            case 'Tri',  sc = sfnTriC([1,0,2,NaN],sc) ;
            case 'Sinc', sc = sfnSincC([1,0,2,NaN],sc) ;
            case 'Sin',  sc = sfnSinC([1,0,NaN,4],sc) ;
            case 'Cos',  sc = sfnCosC([1,0,NaN,4],sc) ;
            case 'Pimp', sc = sfnPimpC([1,0,NaN,4],sc) ;
            case 'Drcl', sc = sfnDrclC([1,0,5,8],sc) ;
            case 'Rwav', sc = sfnRwavC([1,0,2,8],sc) ;
            case 'Twav', sc = sfnTwavC([1,0,1,8],sc) ;
        end
                
    %   Compute impulse values and its CTFT values
    function sc = sfnImpC(vals,sc)
        %   Set the strength and location
        A = vals(1) ; t0 = vals(2) ; w = NaN ; T = NaN ; 
        %   Decide whether to generate all new parameter values or to just
        %   compute the signal values based on the current parameters
        %   If "sc" is empty, all new values are generated.  Otherwise only
        %   new x values are computed.
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;   %   Initialize slider values
        %   Initialize slider maxima and minima
        sc.mx = [1,15,NaN,NaN] ; sc.mn = [-1,-15,NaN,NaN] ;
        %   Initialize slider step values
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [NaN,NaN]] ;
        %   Initialize signal parameter names
        sc.pn = {'{\itA}','{\itt}_0','',''} ;
        if newt,
            %   Generate times and values for the signal display
            sc.t = [-40,40]' ; sc.ti = t0 ;
        end
        %   Generate signal values
        sc.x = 0*sc.t ; sc.xi = A*(sc.ti == t0) ;
        %   Generate CTFT values.  Set frequency range based on the
        %   function shape and the amount of phase shift
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        df = fmax/200 ; sc.f = [-fmax:df:fmax]' ;
        %   Compute the CTFT values
        sc.X = A*exp(-j*2*pi*sc.f*t0) ; sc.fi = [] ; sc.Xi = [] ;
        sc.ttl = 'Impulse' ;

    %   Functions in the next group are all very similar to the previous one

    %   Compute signum values and its CTFT values
    function sc = sfnSgnC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = NaN ; T = NaN ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,NaN,NaN] ; sc.mn = [-1,-15,NaN,NaN] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [NaN,NaN]] ;
        sc.pn = {'{\itA}','{\itt}_0','',''} ;
        if newt,
            sc.t = [-40,t0-1e-6,t0+1e-6,40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*sign(sc.t-t0) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.X = A*exp(-j*2*pi*sc.f*t0)./(j*pi*sc.f) ;
        I = find(abs(sc.f) < fmax/10) ; sc.X(I) = NaN ;
        sc.fi = [] ; sc.Xi = [] ;
        sc.ttl = 'Signum' ;
        
    %   Compute unit step values and its CTFT values
    function sc = sfnUsC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = NaN ; T = NaN ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,NaN,NaN] ; sc.mn = [-1,-15,NaN,NaN] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [NaN,NaN]] ;
        sc.pn = {'{\itA}','{\itt}_0','',''} ;
        if newt,
            sc.t = [-40,t0-1e-6,t0+1e-6,40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*us(sc.t-t0) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.X = A*exp(-j*2*pi*sc.f*t0)./(j*2*pi*sc.f) ;
        I = find(abs(sc.f) < fmax/10) ; sc.X(I) = NaN ;
        sc.fi = 0 ; sc.Xi = A/2 ;
        sc.ttl = 'Unit Step' ;

    %   Compute exponential values and its CTFT values
    function sc = sfnExpC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; tau = vals(3) ; T = NaN ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,10,NaN] ; sc.mn = [-1,-15,1,NaN] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/9,1/3]; [NaN,NaN]] ;
        sc.pn = {'{\itA}','{\itt}_0','{\tau}',''} ;
        if newt,
            sc.t = [-40,t0-1e-6,t0+1e-6,t0+0.1:0.1:40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*exp(-(sc.t-t0)/tau).*us(sc.t-t0) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,4/(2*pi*tau)) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.X = A*exp(-j*2*pi*sc.f*t0)./(j*2*pi*sc.f+1/tau) ;
        sc.fi = [] ; sc.Xi = [] ;
        sc.ttl = 'Exponential' ;

    %   Compute rectangle values and its CTFT values
    function sc = sfnRectC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = vals(3) ; T = NaN ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,10,NaN] ; sc.mn = [-1,-15,1,NaN] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/9,1/3]; [NaN,NaN]] ;
        sc.pn = {'{\itA}','{\itt}_0','{\itw}',''} ;
        if newt,
            sc.t = [-40,t0-w/2-1e-6,t0-w/2+1e-6,...
                t0+w/2-1e-6,t0+w/2+1e-6,40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*rect((sc.t-t0)/w) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,4/w) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.X = (A*w)*exp(-j*2*pi*sc.f*t0).*sinc(w*sc.f) ;
        sc.fi = [] ; sc.Xi = [] ;
        sc.ttl = 'Rectangle' ;

    %   Compute triangle values and its CTFT values
    function sc = sfnTriC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = vals(3) ; T = NaN ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,9,NaN] ; sc.mn = [-1,-15,1,NaN] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [NaN,NaN]] ;
        sc.pn = {'{\itA}','{\itt}_0','{\itw}',''} ;
        if newt,
            sc.t = [-40:0.2:40]' ; sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*tri((sc.t-t0)/w) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,4/w) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.X = (A*w)*exp(-j*2*pi*sc.f*t0).*sinc(w*sc.f).^2 ;
        sc.fi = [] ; sc.Xi = [] ;
        sc.ttl = 'Triangle' ;

    %   Compute sinc values and its CTFT values
    function sc = sfnSincC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = vals(3) ; T = NaN ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,9,NaN] ; sc.mn = [-1,-15,1,NaN] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [NaN,NaN]] ;
        sc.pn = {'{\itA}','{\itt}_0','{\itw}',''} ;
        if newt,
            sc.t = [-40:0.1:40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*sinc((sc.t-t0)/w) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,1/w) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.X = (A*w)*exp(-j*2*pi*sc.f*t0).*rect(w*sc.f) ;
        sc.fi = [] ; sc.Xi = [] ;
        sc.ttl = 'Sinc' ;

    %   Compute sine values and its CTFT values
    function sc = sfnSinC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = NaN ; T = vals(4) ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,NaN,10] ; sc.mn = [-1,-15,NaN,1] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [1/9,1/3]] ;
        sc.pn = {'{\itA}','{\itt}_0','','{\itT }'} ;
        if newt,
            sc.t = [-40:0.1:40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*sin(2*pi*(sc.t-t0)/T) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,2/T) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.f = [-fmax,fmax]' ; sc.X = [0,0]' ;
        sc.fi = [-1,1]'/T ; 
        sc.Xi = A*(j/2)*[1,-1]'.*exp(-j*2*pi*sc.fi*t0) ;
        sc.ttl = 'Sine' ;

    %   Compute cosine values and its CTFT values
    function sc = sfnCosC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = NaN ; T = vals(4) ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,NaN,10] ; sc.mn = [-1,-15,NaN,1] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [1/9,1/3]] ;
        sc.pn = {'{\itA}','{\itt}_0','','{\itT }'} ;
        if newt,
            sc.t = [-40:0.1:40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*cos(2*pi*(sc.t-t0)/T) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,2/T) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.f = [-fmax,fmax]' ; sc.X = [0,0]' ;
        sc.fi = [-1,1]'/T ; 
        sc.Xi = A*(1/2)*[1,1]'.*exp(-j*2*pi*sc.fi*t0) ;
        sc.ttl = 'Cosine' ;

    %   Compute periodic impulse values and its CTFT values
    function sc = sfnPimpC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = NaN ; T = vals(4) ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,NaN,10] ; sc.mn = [-1,-15,NaN,1] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [1/9,1/3]] ;
        sc.pn = {'{\itA}','{\itt}_0','','{\itT }'} ;
        if newt,
            sc.t = [-40,40]' ; sc.x = [0,0]' ;
            sc.ti = [] ; kmax = ceil(40/T) ;
            for k = -kmax:kmax,
                if t0-k*T >= -40 & t0-k*T <= 40, 
                    sc.ti = [t0-k*T;sc.ti] ; 
                end
            end
        end
        sc.x = 0*sc.t ;
        sc.xi = A*impND(T,sc.ti-t0) ; I = find(isnan(sc.xi)) ; sc.xi(I) = 0 ;
        %   Generate CTFT values
        if t0 == 0, fmax = 1 ; else fmax = 1/abs(2*t0) ; end
        fmax = max(fmax,4/T) ;
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.f = [-fmax,fmax]' ; sc.X = [0,0]' ;
        f0 = 1/T ;
        sc.fi = [] ; sc.Xi = [] ; kmax = ceil(fmax/f0) ;
        for k = -kmax:kmax,
            if k*f0 >= -fmax & k*f0 <= fmax, 
                sc.fi = [sc.fi;k*f0] ; 
            end
        end
        sc.Xi = (A/T)*exp(-j*2*pi*sc.fi*t0) ;
        sc.ttl = 'Periodic Impulse' ;

    %   Compute dirichlet values and its CTFT values
    function sc = sfnDrclC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; M = vals(3) ; T = vals(4) ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,9,10] ; sc.mn = [-1,-15,1,1] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [1/9,1/3] ] ;
        sc.pn = {'{\itA}','{\itt}_0','{\itN} ','{\itT }'} ;
        if newt,
            sc.t = [-40:0.1:40]' ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = A*drcl((sc.t-t0)/T,M) ;
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        if mod(M,2) == 0, 
            f0 = 1/(2*T) ; fmax = 16*f0 ; kmax = M ; 
        else
            f0 = 1/T ; fmax = 8*f0 ; kmax = (M-1)/2 ; 
        end
        df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        sc.f = [-fmax,fmax]' ; sc.X = [0,0]' ;
        sc.fi = [] ;
        for k = -kmax:kmax,
            if k*f0 >= -fmax & k*f0 <= fmax, sc.fi = [sc.fi;k*f0] ; end
        end
        if mod(M,2) == 0,
            sc.Xi = A*exp(-j*2*pi*sc.fi*t0).*(1-exp(-j*pi*sc.fi/f0))/(2*M) ; 
        else
            sc.Xi = A*exp(-j*2*pi*sc.fi*t0)/M ; 
        end
        sc.ttl = 'Dirichlet' ;

    %   Compute rectangular wave values and its CTFT values
    function sc = sfnRwavC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = vals(3) ; T = vals(4) ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,9,10] ; sc.mn = [-1,-15,1,1] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [1/9,1/3]] ;
        sc.pn = {'{\itA}','{\itt}_0','{\itw}','{\itT }'} ;
        A = A ; t0 = t0 ; w = w ; T = T ;
        tmax = 40 ; kmax = ceil(tmax/T) ; 
        if newt,
            sc.t = [] ;
            for k = -kmax:kmax,
                if k*T+t0+w/2 >= -tmax & k*T+t0-w/2 <= tmax, 
                    sc.t = [sc.t;k*T+t0-w/2-1e-6;k*T+t0-w/2+1e-6;...
                        k*T+t0+w/2-1e-6;k*T+t0+w/2+1e-6] ;
                end
            end
            I = find(sc.t>=-tmax & sc.t<=tmax) ; 
            sc.t = sc.t(I) ; sc.t = sort(sc.t) ; sc.t = [-tmax;sc.t;tmax] ; 
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = 0*sc.t ;
        for k = -kmax:kmax, sc.x = sc.x + A*rect((sc.t+k*T-t0)/w) ; end
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        f0 = 1/T ; fmax = 4/w ; df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ;
        kmax = ceil(fmax/f0) ;
        sc.f = [-fmax,fmax]' ; sc.X = [0,0]' ;
        sc.fi = [] ; kmax = ceil(fmax/f0) ;
        for k = -kmax:kmax,
            if k*f0 >= -fmax & k*f0 <= fmax, sc.fi = [sc.fi;k*f0] ; end
        end
        sc.Xi = (A*w/T)*exp(-j*2*pi*sc.fi*t0).*sinc(w*sc.fi) ; 
        sc.ttl = 'Rectangular Wave' ;

    %   Compute triangular values and its CTFT values
    function sc = sfnTwavC(vals,sc)
        A = vals(1) ; t0 = vals(2) ; w = vals(3) ; T = vals(4) ; 
        if isempty(sc), newt = 1 ; else newt = 0 ; end
        sc.v = vals ;
        sc.mx = [1,15,5,10] ; sc.mn = [-1,-15,1,1] ;
        sc.ss = [[1/20,1/4]; [1/30,1/6]; [1/4,1/2]; [1/9,1/3]] ;
        sc.pn = {'{\itA}','{\itt}_0','{\itw}','{\itT }'} ;
        A = A ; t0 = t0 ; w = w ; T = T ;
        tmax = 40 ; kmax = ceil(tmax/T) ; 
        if newt,
            sc.t = [] ;
            for k = -kmax:kmax,
                if k*T+t0+w >= -tmax & k*T+t0-w <= tmax, 
                    sc.t = [sc.t;k*T+t0-w;k*T+t0;k*T+t0+w] ;
                end
            end
            I = find(sc.t>=-tmax & sc.t<=tmax) ; 
            sc.t = sc.t(I) ; sc.t = sort(sc.t) ; 
            sc.t = [sc.t;[-tmax:0.2:tmax]'] ; sc.t = sort(sc.t) ;
            sc.ti = [] ; sc.xi = [] ;
        end
        sc.x = 0*sc.t ;
        for k = -kmax:kmax, sc.x = sc.x + A*tri((sc.t+k*T-t0)/w) ; end
        sc.xi = 0*sc.ti ;
        %   Generate CTFT values
        f0 = 1/T ; fmax = 2/w ; df = fmax/1000 ; sc.f = [-fmax:df:fmax]' ; 
        kmax = ceil(fmax/f0) ;
        sc.f = [-fmax,fmax]' ; sc.X = [0,0]' ;
        sc.fi = [] ;
        for k = -kmax:kmax,
            if k*f0 >= -fmax & k*f0 <= fmax, sc.fi = [sc.fi;k*f0] ; end
        end
        sc.Xi = (A*w/T)*exp(-j*2*pi*sc.fi*t0).*sinc(w*sc.fi).^2 ; 
        sc.ttl = 'Triangular Wave' ;

    %   Select which discrete-time prototype data to initialize based on the 
    %   tag passed to this function.  Use an "eval" statement to reduce the 
    %   code length.  Each function is named according to the corresponding
    %   tag
    function pd = proDataD(tg)
        s = ['pd = pro',tg,'D ;'] ; eval(s) ;
        
    %   Display Impulse Prototype
    function pd = proImpD
        pd.n = [-3:13]' ; pd.x = 1.5*impD(pd.n-6) ;
        pd.an = {[-1,6],1.5,'b','\itA';6,[0,-0.1],'e',' {\itn}_0'} ;

    %   Display Signum prototype
    function pd = proSgnD
        pd.n = [-3:13]' ; pd.x = 1.5*sign(pd.n-6) ;
        pd.an = {[-1,6],1.5,'b','{\itA}';[5,7],-1.5,'e','-{\itA}' ;...
                 6,[-0.1,-1.6],'e','{\itn}_0'} ;

    %   Display Unit Sequence Prototype
    function pd = proUsD
        pd.n = [-3:13]' ; pd.x = 1.5*usD(pd.n-6) ;
        pd.an = {[-1,6],1.5,'b','\itA';6,[0,-0.1],'e','{\itn}_0'} ;

    %   Display Exponential Prototype
    function pd = proExpD
        pd.n = [-3:13]' ; pd.x = 1.5*(0.8).^(pd.n-6).*usD(pd.n-6) ;
        pd.an = {[-1,6],1.5,'b','{\itA}';[-3,7],1.5*0.8,'b','{\itA}\alpha ';...
                 6,[0,-0.1],'e','{\itn}_0'} ;
             
    %   Display Rectangle Prototype
    function pd = proRectD
        pd.n = [-3:13]' ; pd.x = 1.5*(usD(pd.n-4) - usD(pd.n-8)) ;
        pd.an = {[-1,4],1.5,'b','{\itA}';4,[0,-0.2],'e',' {\itn}_0';...
                 8,[0,-0.2],'e',' {\itn}_1'} ;

    %   Display Triangle Prototype
    function pd = proTriD
        pd.n = [-3:13]' ; pd.x = 1.5*tri((pd.n-6)/2) ;
        pd.an = {[-1,4],1.5,'b','{\itA}';6,[0,-0.4],'e','{\itn}_0';...
                 8,[0,-0.4],'b','';[2,6],-0.3,'b',' >';[12,8],-0.3,'b','{\itw}>'} ;

    %   Display Sinc Prototype
    function pd = proSincD
        pd.n = [-3:13]' ; pd.x = 1.5*sinc((pd.n-6)/2) ;
        pd.an = {[-1,6],1.5,'b','\itA';6,[1.4,-0.2],'e',' {\itn}_0';...
                 [2,6],0.5,'e',' >';[12,8],0.5,'b','{\itw}>';6,[0.6,-0.2],'b','';...
                 8,[0.6,-0.2],'b',''} ;
             
    %   Display Sine Prototype
    function pd = proSinD
        pd.n = [-3:13]' ; pd.x = 1.5*sin(2*pi*(pd.n-2)/8) ;
        pd.an = {[-1,4],1.5,'b','{\itA}'; 2,[0.4,-0.7],'e','  {\itn}_0';...
                 10,[0.4,-0.7],'e','       {\itn}_0+\itN'} ;
             
    %   Display Cosine Prototype
    function pd = proCosD
        pd.n = [-3:13]' ; pd.x = 1.5*cos(2*pi*(pd.n-2)/8) ;
        pd.an = {[-1,2],1.5,'b','{\itA}'; 2,[0.4,-0.7],'e',' {\itn}_0';...
                 10,[0.4,-0.7],'e','{\itn}_0+{\itN} '} ;
             
    %   Display Periodic Impulse Prototype
    function pd = proPimpD
        pd.n = [-3:13]' ; pd.x = 1.5*impND(5,pd.n-3) ;
        pd.an = {[-0.5,3],1.5,'b','{\itA}'; 3,[0,-0.1],'e','{\itn}_0';...
                 8,[0,-0.1],'e','{\itn}_0 + {\itN} '} ;
             
    %   Display Dirichlet Prototype
    function pd = proDrclD
        pd.n = [-3:13]' ; pd.x = 1.5*drcl((pd.n-2)/10,5) ;
        pd.an = {[-1,2],1.5,'b','{\itA}'; 2,[0.4,-0.7],'e','  {\itn}_0';...
                 12,[0.4,-0.7],'e','       {\itn}_0+\itN';...
                 7,-1.7,'b','{\itM} - 1 zero crossings per period {\itN} '} ;
             
    %   Display Rectangular Wave Prototype
    function pd = proRwavD
        pd.n = [-3:13]' ; 
        pd.x = 1.5*(usD(pd.n) - usD(pd.n-5) + usD(pd.n-9) -usD(pd.n-14)) ;
        pd.an = {[-1,0],1.5,'b','{\itA}'; 2,[0.4,-0.7],'e','  {\itn}_0';...
                 11,[0.4,-0.7],'e','       {\itn}_0+\itN';...
                 4,[0.4,-0.7],'e','         {\itn}_0+{\itN_w}'} ;
            
    %   Display Triangular Wave Prototype
    function pd = proTwavD
        pd.n = [-3:13]' ; pd.x = 1.5*(tri((pd.n-2)/2) + tri((pd.n-11)/2)) ;
        pd.an = {[-1,2],1.5,'b','{\itA}'; 2,[0.4,-0.7],'e','  {\itn}_0';...
                 11,[0,-0.7],'e','       {\itn}_0+{\itN} ';...
                 4,[0,-0.7],'e','         {\itn}_0+{\itw}'} ;
        
    %   Initialize the parameters controlling the discrete-time signal display
    function sd = sfnDataD(tg)
        sd = [] ;
        switch tg,
            case 'Imp', sd = sfnImpD([1,0,NaN,NaN],sd) ;
            case 'Sgn', sd = sfnSgnD([1,0,NaN,NaN],sd) ;
            case 'Us', sd = sfnUsD([1,0,NaN,NaN],sd) ;
            case 'Exp', sd = sfnExpD([1,0,0.8,NaN],sd) ;
            case 'Rect', sd = sfnRectD([1,-2,3,NaN],sd) ;
            case 'Tri', sd = sfnTriD([1,0,3,NaN],sd) ;
            case 'Sinc', sd = sfnSincD([1,0,4,NaN],sd) ;
            case 'Sin', sd = sfnSinD([1,0,NaN,8],sd) ;
            case 'Cos', sd = sfnCosD([1,0,NaN,8],sd) ;
            case 'Pimp', sd = sfnPimpD([1,0,NaN,6],sd) ;
            case 'Drcl', sd = sfnDrclD([1,0,5,8],sd) ;
            case 'Rwav', sd = sfnRwavD([1,0,2,8],sd) ;
            case 'Twav', sd = sfnTwavD([1,0,3,8],sd) ;
        end
                
    %   Compute impulse values and its DTFT values
    function sd = sfnImpD(vals,sd)
        %   Set the strength and location of the impulse
        A = vals(1) ; n0 = vals(2) ; w = NaN ; N = NaN ; 
        %   Decide whether to generate all new parameter values or to just
        %   compute the signal values based on the current parameters
        %   If "sd" is empty, all new values are generated.  Otherwise only
        %   new x values are computed.
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;   %   Initialize slider values
        %   Initialize slider maxima and minima
        sd.mx = [1,15,NaN,NaN] ; sd.mn = [-1,-15,NaN,NaN] ;
        %   Initialize slider step values
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [NaN,NaN]] ;
        %   Initialize signal parameter names
        sd.pn = {'{\itA}','{\itn}_0','',''} ;
        if newn,
            %   Generate a set of times for the signal display
            sd.n = [-40:40] ;
        end
        %   Use current time to generate signal values
        sd.x = A*impD(sd.n-n0) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ; 
        sd.X = A*exp(-j*sd.W*n0) ; sd.Wi = [] ; sd.Xi = [] ;
        sd.ttl = 'Impulse' ;

    %   Functions in the next group are all very similar to the previous one

    %   Compute signum values and its DTFT values
    function sd = sfnSgnD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = NaN ; N = NaN ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,NaN,NaN] ; sd.mn = [-1,-15,NaN,NaN] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [NaN,NaN]] ;
        sd.pn = {'{\itA}','{\itn}_0','',''} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*sign(sd.n-n0) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ;
        sd.X = A*exp(-j*sd.W*n0).*j.*sin(sd.W)./(cos(sd.W)-1) ; 
        I = find(abs(sd.W) < pi/20) ; sd.X(I) = NaN ;
        sd.Wi = [] ; sd.Xi = [] ;
        sd.ttl = 'Signum' ;

    %   Compute unit sequence values and its DTFT values
    function sd = sfnUsD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = NaN ; N = NaN ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,NaN,NaN] ; sd.mn = [-1,-15,NaN,NaN] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [NaN,NaN]] ;
        sd.pn = {'{\itA}','{\itn}_0','',''} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*usD(sd.n-n0) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ; 
        sd.X = A*exp(-j*sd.W*n0)./(1-exp(-j*sd.W)) ; 
        I = find(abs(sd.W) < pi/20) ; sd.X(I) = NaN ;
        sd.Wi = 0 ; sd.Xi = A*pi ;
        sd.ttl = 'Unit Sequence' ;

    %   Compute exponential values and its DTFT values
    function sd = sfnExpD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; alpha = vals(3) ; N = NaN ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,0.9,NaN] ; sd.mn = [-1,-15,0.1,NaN] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [NaN,NaN]] ;
        sd.pn = {'{\itA}','{\itn}_0','\alpha',''} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*alpha.^(sd.n-n0).*usD(sd.n-n0) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ; 
        sd.X = A*exp(-j*sd.W*n0)./(1-alpha*exp(-j*sd.W)) ; 
        sd.Wi = [] ; sd.Xi = [] ;
        sd.ttl = 'Exponential' ;

    %   Compute rectangle values and its DTFT values
    function sd = sfnRectD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; n1 = vals(3) ; N = NaN ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,15,NaN] ; sd.mn = [-1,-15,-15,NaN] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/30,1/6]; [NaN,NaN]] ;
        sd.pn = {'{\itA}','{\itn}_0','{\itn}_1',''} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*(usD(sd.n-n0) - usD(sd.n-n1)) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ;
        if n0 == n1, 
            sd.X = 0*sd.W ;
        else
            sd.X = A*exp(-j*(sd.W/2)*(n0+n1)).*(n1-n0)...
                .*drcl(sd.W/(2*pi),abs(n1-n0))./exp(-j*(sd.W/2));
        end
        sd.Wi = [] ; sd.Xi = [] ;
        sd.ttl = 'Rectangle' ;

    %   Compute triangle values and its DTFT values
    function sd = sfnTriD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = vals(3) ; N = NaN ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,9,NaN] ; sd.mn = [-1,-15,1,NaN] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [NaN,NaN]] ;
        sd.pn = {'{\itA}','{\itn}_0','{\itw}',''} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*tri((sd.n-n0)/w) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ; 
        sd.X = A*exp(-j*sd.W*n0).*w.*sinc(w*sd.W/(2*pi)).^2 ; 
        sd.Wi = [] ; sd.Xi = [] ;
        sd.ttl = 'Triangle' ;

    %   Compute sinc values and its DTFT values
    function sd = sfnSincD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = vals(3) ; N = NaN ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,9,NaN] ; sd.mn = [-1,-15,1,NaN] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [NaN,NaN]] ;
        sd.pn = {'{\itA}','{\itn}_0','{\itw}',''} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*sinc((sd.n-n0)/w) ;
        %   Generate DTFT values
        dW = 2*pi/1000 ; sd.W = [-pi:dW:pi]' ; 
        sd.X = A*exp(-j*sd.W*n0).*w.*rect(w*sd.W/(2*pi)) ; 
        sd.Wi = [] ; sd.Xi = [] ;
        sd.ttl = 'Sinc' ;

    %   Compute sine values and its DTFT values
    function sd = sfnSinD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = NaN ; N = vals(4) ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,NaN,10] ; sd.mn = [-1,-15,NaN,1] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [1/9,1/3]] ;
        sd.pn = {'{\itA}','{\itn}_0','','{\itN} '} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*sin(2*pi*(sd.n-n0)/N) ;
        %   Generate DTFT values
        sd.W = [-pi,pi]' ; sd.X = [0,0]' ;
        sd.Wi = 2*pi*[-1,1]'/N ; sd.Xi = -j*pi*A.*exp(-j*sd.Wi*n0) ;
        if N <= 2, sd.Xi = sd.Wi*0 ; end
        sd.ttl = 'Sine' ;

    %   Compute cosine values and its DTFT values
    function sd = sfnCosD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = NaN ; N = vals(4) ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,NaN,10] ; sd.mn = [-1,-15,NaN,1] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [1/9,1/3]] ;
        sd.pn = {'{\itA}','{\itn}_0','','{\itN} '} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*cos(2*pi*(sd.n-n0)/N) ;
        %   Generate DTFT values
        sd.W = [-pi,pi]' ; sd.X = [0,0]' ;
        sd.Wi = 2*pi*[-1,1]'/N ; sd.Xi = pi*A.*exp(-j*sd.Wi*n0) ;
        if N == 1, sd.Wi = 0 ; sd.Xi = 2*pi*A ; end
        if N == 2, sd.Xi = 2*sd.Xi ; end
        sd.ttl = 'Cosine' ;

    %   Compute periodic impulse values and its DTFT values
    function sd = sfnPimpD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = NaN ; N = vals(4) ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,NaN,10] ; sd.mn = [-1,-15,NaN,1] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [NaN,NaN]; [1/9,1/3]] ;
        sd.pn = {'{\itA}','{\itn}_0','','{\itN} '} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*impND(N,(sd.n-n0)) ;
        %   Generate DTFT values
        sd.W = [-pi,pi]' ; sd.X = [0,0]' ;
        F0 = 1/N ;
        sd.Wi = [] ; sd.Xi = [] ; kmax = ceil(0.5/F0) ;
        for k = -kmax:kmax,
            if k*F0 >= -0.5 & k*F0 <= 0.5, 
                sd.Wi = [sd.Wi;2*pi*k*F0] ; 
            end
        end
        sd.Xi = (2*pi*A/N)*exp(-j*sd.Wi*n0) ;
        sd.ttl = 'Periodic Impulse' ;

    %   Compute dirichlet values and its DTFT values
    function sd = sfnDrclD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; M = vals(3) ; N = vals(4) ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,9,10] ; sd.mn = [-1,-15,1,1] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [1/9,1/3]] ;
        sd.pn = {'{\itA}','{\itn}_0','{\itM}','{\itN} '} ;
        if newn, sd.n = [-40:40] ; end
        sd.x = A*drcl((sd.n-n0)/N,M) ;
        %   Generate DTFT values
        sd.W = [-pi,pi]' ; sd.X = [0,0]' ;
        sd.Wi = [] ; sd.Xi = [] ; 
        if mod(M,2) == 0,
            N0 = 2*N ;
            for k = -M/2:M/2-1,
                if (2*k+1)/N0 >= -0.5 & (2*k+1)/N0 <= 0.5, 
                    sd.Wi = [sd.Wi;2*pi*(2*k+1)/N0] ; 
                end
            end
            sd.Xi = (2*pi*A/M)*exp(-j*sd.Wi*n0) ;
        else
            N0 = N ;
            for k = -(M-1)/2:(M-1)/2,
                if k/N0 >= -0.5 & k/N0 <= 0.5, 
                    sd.Wi = [sd.Wi;2*pi*k/N0] ; 
                end
            end
            sd.Xi = (2*pi*A/M)*exp(-j*sd.Wi*n0) ;
        end
        sd.ttl = 'Dirichlet' ;

    %   Compute rectangular wave values and its DTFT values
    function sd = sfnRwavD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; Nw = vals(3) ; N = vals(4) ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,9,10] ; sd.mn = [-1,-15,1,1] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [1/9,1/3]] ;
        sd.pn = {'{\itA}','{\itn}_0','{\itN_w}','{\itN} '} ;
        kmax = ceil(40/N) ;
        if newn, sd.n = [-40:40] ; end
        n = sd.n ; x = 0*n ;
        for k = -kmax:kmax,
            x = x + A*(usD(n-k*N-n0+Nw) - usD(n-k*N-n0-Nw-1)) ;
        end
        sd.x = x ;
        %   Generate DTFT values
        sd.W = [-pi,pi]' ; sd.X = [0,0]' ;
        F0 = 1/N ;
        sd.Wi = [] ; sd.Xi = [] ; kmax = ceil(0.5/F0) ;
        for k = -kmax:kmax,
            if k*F0 >= -0.5 & k*F0 <= 0.5, 
                sd.Wi = [sd.Wi;2*pi*k*F0] ; 
            end
        end
        sd.Xi = (2*pi*A/N)*(2*Nw+1)*drcl(sd.Wi/(2*pi),2*Nw+1).*exp(-j*sd.Wi*n0) ;
        sd.ttl = 'Rectangular Wave' ;

    %   Compute triangular wave values and its DTFT values
    function sd = sfnTwavD(vals,sd)
        A = vals(1) ; n0 = vals(2) ; w = vals(3) ; N = vals(4) ; 
        if isempty(sd), newn = 1 ; else newn = 0 ; end
        sd.v = vals ;
        sd.mx = [1,15,9,10] ; sd.mn = [-1,-15,1,1] ;
        sd.ss = [[1/20,1/4]; [1/30,1/6]; [1/8,1/4]; [1/9,1/3]] ;
        sd.pn = {'{\itA}','{\itn}_0','{\itN_w}','{\itN} '} ;
        kmax = ceil(40/N) ;
        if newn, sd.n = [-40:40] ; end
        n = sd.n ; x = 0*n ;
        for k = -kmax:kmax,
            x = x + A*tri((n+k*N-n0)/w) ;
        end
        sd.x = x ;
        %   Generate DTFT values
        sd.W = [-pi,pi]' ; sd.X = [0,0]' ;
        F0 = 1/N ;
        sd.Wi = [] ; sd.Xi = [] ; kmax = ceil(0.5/F0) ;
        for k = -kmax:kmax,
            if k*F0 >= -0.5 & k*F0 <= 0.5, 
                sd.Wi = [sd.Wi;2*pi*k*F0] ; 
            end
        end
        sd.Xi = (2*pi*A/N)*w*drcl(sd.Wi/(2*pi),w).^2.*exp(-j*sd.Wi*n0) ;
        sd.ttl = 'Triangular Wave' ;

    %   Respond to signal menu selection. Draw all the graphs in the 
    %   signal function window and update latest selected signal numbers.
    function sfnSigResp(hObject,eventdata)
        %   Get pointer to signal button pressed and handles to all 
        %   use interface elements in the signal function window
        [obj,f] = gcbo ; h = guihandles ; 
        %   Get the menu tag
        LR = get(get(obj,'Parent'),'Tag') ; LR = LR(end) ;
        %   Get character indicator of mode (continuous or discrete) and
        %   get the parameters for the signal associated with the menu item just
        %   selected
        cd = get(h.sfncd,'UserData') ; sd = get(obj,'UserData') ;
        %   Get the menu position of the signal
        %   Menu positions are in reverse order of signal names
        sigNum = get(obj,'Position') ;
        %   Get two-character indication of sum/product or convolution mode
        spcvData = get(h.sfnspcv,'UserData') ;
        ttl = get(obj,'Label') ; 
        %   Set the title for the graph
        sd.sc.ttl = ttl ; sd.sd.ttl = ttl ;
        %   Draw the signal
        drawSignal(sd,cd,LR,h) ;
        %   Retrieve from the figure window pointers to the last two functions
        %   selected (in the current mode)
        fns = guidata(f) ; 
        if LR == 'L', col = 1 ; else col = 2 ; end
        %   Get the user data from both menus
        if cd == 'c',
            %   Set sliders needed for this continuous-time signal visible and 
            %   enabled.  Set other sliders invisible and disabled.  A parameter 
            %   value of NaN indicates a slider is not needed.
            for k = 1:4,
                sltag = ['sfnsl',num2str(k),num2str(col)] ;
                if ~isnan(sd.sc.v(k)),
                    s = ['set(h.',sltag,',''Visible'',''on'',''Enable'',''on'') ;'] ;
                else
                    s = ['set(h.',sltag,',''Visible'',''off'',''Enable'',''off'') ;'] ;
                end     
                eval(s) ;
            end
            if LR == 'L', 
                fns.cL = sigNum ; sdLc = sd ;
                if ~isempty(fns.cR), 
                    st = ['sdRc = get(h.sfnmR',num2str(fns.cR),',''UserData'') ;'] ; 
                    eval(st) ;
                else
                    sdRc = [] ; 
                end
            else
                fns.cR = sigNum ; sdRc = sd ;
                if ~isempty(fns.cL), 
                    st = ['sdLc = get(h.sfnmL',num2str(fns.cL),',''UserData'') ;'] ; 
                    eval(st) ;
                else
                    sdLc = [] ; 
                end
            end
            %   Store number of current signal in figure window with guidata
            if strfind(spcvData.spcv,'sp'),
                %   Draw the sum and product of the two current signals (if both
                %   are defined)
                if ~isempty(fns.cL) & ~isempty(fns.cR),
                    disableControls(h) ; 
                        drawSumC(sdLc,sdRc,h) ; drawProdC(sdLc,sdRc,h) ; 
                    enableControls(h) ;
                end
                set(h.sfncv,'Enable','off') ;
            else
                axes(h.sfnP) ; cla ; axes(h.sfnS) ; cla ;
            end
        else
            %   Set sliders needed for this discrete-time signal visible and 
            %   enabled.  Set other sliders invisible and disabled.  A parameter 
            %   value of NaN indicates a slider is not needed.
            for k = 1:4,
                sltag = ['sfnsl',num2str(k),num2str(col)] ;
                if ~isnan(sd.sd.v(k)),
                    s = ['set(h.',sltag,',''Visible'',''on'',''Enable'',''on'') ;'] ;
                else
                    s = ['set(h.',sltag,',''Visible'',''off'',''Enable'',''off'') ;'] ;
                end     
                eval(s) ;
            end
            if LR == 'L', 
                fns.dL = sigNum ; sdLd = sd ;
                if ~isempty(fns.dR), 
                    st = ['sdRd = get(h.sfnmR',num2str(fns.dR),',''UserData'') ;'] ; 
                    eval(st) ;
                else
                    sdRd = [] ; 
                end
            else
                fns.dR = sigNum ; sdRd = sd ;
                if ~isempty(fns.dL), 
                    st = ['sdLd = get(h.sfnmL',num2str(fns.dL),',''UserData'') ;'] ; 
                    eval(st) ;
                else
                    sdLd = [] ; 
                end
            end
            %   Store number of current signal in figure window with guidata
            if strfind(spcvData.spcv,'sp'),
                %   Draw the sum and product of the two current signals (if both
                %   are defined)
                if ~isempty(fns.dL) & ~isempty(fns.dR),
                    disableControls(h) ; 
                        drawSumD(sdLd,sdRd,h) ; drawProdD(sdLd,sdRd,h) ; 
                    enableControls(h) ;
                end
                set(h.sfncv,'Enable','off') ;
            else
                axes(h.sfnP) ; cla ; axes(h.sfnS) ; cla ;
            end
        end
        guidata(f,fns) ;
        
    %   Lock all user interface controls so the user cannot activate them before
    %   a graphics operation is completed
    function disableControls(h)
        names = fieldnames(h) ;
        for k = 1:length(names),
            s = ['obj = h.',names{k},' ;'] ; eval(s) ;
            st = get(obj,'Type') ;
            if strfind(st,'uicontrol'), set(obj,'Enable','off') ; end
            if strfind(st,'uimenu'), set(obj,'Enable','off') ; end
        end
        
    %   Unlock all user interface controls 
    function enableControls(h)
        names = fieldnames(h) ;
        for k = 1:length(names),
            s = ['obj = h.',names{k},' ;'] ; eval(s) ;
            st = get(obj,'Type') ;
            if strfind(st,'uicontrol'), set(obj,'Enable','on') ; end
            if strfind(st,'uimenu'), set(obj,'Enable','on') ; end
        end
        
    %   Draw the signal described by the parameter data in "sd"
    function drawSignal(sd,cd,LR,h)
        if LR == 'L', Pax = h.sfnPL ; else Pax = h.sfnPR ; end
        if cd == 'c', 
            %   Update the prototype and graph of the current continuous-time signal
            drawProtoC(sd.pc,Pax) ; updateSigC(sd.sc,LR,h) ; 
        else
            %   Update the prototype and graph of the current discrete-time signal
            drawProtoD(sd.pd,Pax) ; updateSigD(sd.sd,LR,h) ;
        end
        
    function drawProtoC(pc,ax)
        %   Select appropriate axes for display of continuous-time prototype
        axes(ax) ;
        if isempty(pc.ti),
            %   Draw prototype if it does not contain impulses
            ptr = xyplot(pc.t,pc.x,[-0.5,1.5,-1.5,1.5],'\itt','x({\itt})',...
                  'Times',0.1,'Times',0.08,'','Times',0.12,'n','c','k',...
                  {'ah','ah'}) ;
        else
            %   Draw prototype if it does contain impulses
            ptr = xyplot({pc.t,pc.ti},{pc.x,pc.xi},[-0.5,1.5,-1.5,1.5],...
                  '\itt','x({\itt})','Times',0.1,'Times',0.08,'','Times',0.12,...
                  'n',{'c','i'},'k',{'ah','ah'}) ;
        end
        %    Get the number of rows and columns in the annotation cell array
        rc = size(pc.an) ;
        %   Apply annotations to prototype
        for k = 1:rc(1),
            ptr = annotate(pc.an{k,1},pc.an{k,2},pc.an{k,3},pc.an{k,4}) ;
        end

    function drawProtoD(pd,ax)
        %   Select appropriate axes for display of discrete-time prototype
        axes(ax) ;
        %   Draw the signal in the time domain
        ptr = xyplot(pd.n,pd.x,[-5,15,-1.5,1.5],'\itn','x[{\itn}]',...
            'Times',0.1,'Times',0.08,'','Times',0.12,'n','d','k',{'ah','ah'}) ;
        %    Get the number of rows and columns in the annotation cell array
        rc = size(pd.an) ; 
        %   Apply annotations to prototype
       for k = 1:rc(1),
            ptr = annotate(pd.an{k,:}) ;
       end
        
    %   Update slider values, maxima, minima and slider steps based on current 
    %   continuous-time signal parameters and display updated slider values
    function sc = updateSigC(sc,LR,h)
        if LR == 'L', col = '1' ; else col = '2' ; end
        for k = 1:4,
            s = ['vax = h.sfnvax',num2str(k),col,' ;'] ; eval(s) ; axes(vax) ; cla ; 
            s = ['sli = h.sfnsl',num2str(k),col,' ;'] ; eval(s) ;
            if ~isnan(sc.v(k)),
                set(sli,'Max',sc.mx(k),'Min',sc.mn(k),'SliderStep',sc.ss(k,:)) ;
                set(sli,'Value',sc.v(k)) ;
                set(sli,'Visible','on','Enable','on') ;
                %   Display slide value just above slider
                s = [sc.pn{k},'  = ',num2str(sc.v(k))] ;
                text(0.5,0.5,s,'HorizontalAlignment','center',...
                    'VerticalAlignment','middle','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.9) ;
            else
                set(sli,'Visible','off','Enable','off') ;
            end
        end
        %   Draw the signal in both the time and frequency domains
        sc = drawSigC(sc,LR,h) ;
        
    %   Draw one continuous-time signal graph in the time domain and also
    %   draw its CTFT magnitude and phase if it is a signal and not a sum
    %   or product of signals
    function sc = drawSigC(sc,LRSP,h)
        ymx = 0 ; ymn = 0 ;
        if ~isempty(sc.x),
            ymx = max(ymx,max(sc.x)) ; ymn = min(ymn,min(sc.x)) ;
        end
        if LRSP == 'L' | LRSP == 'R',
            s = ['ax = h.sfn',LRSP,'t ;'] ; eval(s) ; axes(ax) ; cla ;
        else
            if LRSP == 'S', axes(h.sfnS) ; cla ; end
            if LRSP == 'P', axes(h.sfnP) ; cla ; end
        end
        %   Draw the signal in the time domain
        if isempty(sc.ti),
            %   Draw signal if it does not contain impulses
           ptr = xyplot(sc.t,sc.x,[-15,15,ymn,ymx],'\itt','x({\itt})',...
                  'Times',0.1,'Times',0.08,sc.ttl,'Utopia',0.12,'n','c','k',...
                  {'ahstc','ahstc'}) ;
        else
            if ~isempty(sc.xi)
                ymx = max(ymx,max(sc.xi)) ; ymn = min(ymn,min(sc.xi)) ;
            end
            %   Draw signal if it does contain impulses
            ptr = xyplot({sc.t,sc.ti},{sc.x,sc.xi},[-15,15,ymn,ymx],...
                  '\itt','x({\itt})','Times',0.1,'Times',0.08,sc.ttl,'Utopia',...
                  0.12,'n',{'c','i'},'k',{'ahstc','ahstc'}) ;
        end
        if LRSP == 'L' | LRSP == 'R',
            %   Draw the magnitude of the CTFT of the signal
            s = ['ax = h.sfn',LRSP,'m ;'] ; eval(s) ; axes(ax) ; cla ;
            ttl = ['CTFT of ',sc.ttl] ;
            if isempty(sc.fi),
                %   Draw CTFT magnitude if it does not contain impulses
               ptr = xyplot(sc.f,abs(sc.X),[min(sc.f),max(sc.f),0,max(abs(sc.X))],...
                      '\itf','|X( {\itf} )|','Times',0.1,'Times',0.08,ttl,'Utopia',...
                      0.12,'n','c','k',{'ahstc','ahstc'}) ;
            else
                Xmax = max(abs([sc.X;sc.Xi])) ;
                fmin = min([sc.f;sc.fi]) ; fmax = max([sc.f;sc.fi]) ;
                %   Draw signal if it does contain impulses
                ptr = xyplot({sc.f,sc.fi},{abs(sc.X),abs(sc.Xi)},...
                    [fmin,fmax,0,Xmax],...
                      '\itf','|X( {\itf} )|','Times',0.1,'Times',0.08,ttl,'Utopia',...
                      0.12,'n',{'c','i'},'k',{'ahstc','ahstc'}) ;
            end
            %   Draw the phase of the CTFT of the signal
            s = ['ax = h.sfn',LRSP,'p ;'] ; eval(s) ; axes(ax) ; cla ;
            ttl = '' ;
            ang = angle(sc.X) ; 
            I = find(abs(sc.X) < max(abs(sc.X))/10000) ; ang(I) = NaN ;
            I = find(abs(sc.X) == 0) ; ang(I) = NaN ;
            N = length(sc.f) ; I = find(sc.f > 0) ; ang(N-I+1) = -ang(I) ;
            angi = angle(sc.Xi) ; 
            I = find(abs(sc.Xi) < max(abs(sc.Xi))/1000) ; angi(I) = NaN ;
            I = find(abs(sc.Xi) == 0) ; angi(I) = NaN ;
            Ni = length(sc.fi) ; I = find(sc.fi > 0) ; angi(Ni-I+1) = -angi(I) ;
            if isempty(sc.fi),
                if sum(isnan(ang)) == length(ang),
                    ptr = text(0.5,0.5,'Phase is Undefined','FontUnits',...
                        'Normalized','FontSize',0.2,...
                        'FontName','Times','HorizontalAlignment','center',...
                        'VerticalAlignment','middle') ;
                    axis([0,1,0,1]) ;
                else
                    %   Draw CTFT phase if it does not contain impulses
                   ptr = xyplot(sc.f,ang,[],'\itf','\<X( {\itf} )',...
                          'Times',0.12,'Times',0.1,ttl,'Utopia',0.14,'n','c','k',...
                          {'ahstc','ahstc'}) ;
                end
            else
                if sum(isnan([ang;angi])) == length([ang;angi])
                     ptr = text(0.5,0.5,'Phase is Undefined','FontUnits',...
                        'Normalized','FontSize',0.2,...
                        'FontName','Times','HorizontalAlignment','center',...
                        'VerticalAlignment','middle') ;
                     axis([0,1,0,1]) ;
                else
                   %   Draw signal if it does contain impulses
                    ptr = xyplot({sc.f,sc.fi},{ang,angi},[],...
                          '\itf','\<X( {\itf} )','Times',0.12,'Times',0.1,ttl,'Utopia',...
                          0.14,'n',{'c','s'},'k',{'ahstc','ahstc'}) ;
                end
            end
        end
        
%     function drawAngleSign(ptr,fs)
%        ex = get(ptr,'Extent') ; 
%        xptr = text(ex(1),ex(2)+ex(4),'M','VerticalAlignment','top',...
%                     'HorizontalAlignment','right','FontUnits','Normalized',...
%                     'FontName','Times','FontSize',fs,'Visible','off') ; 
%        set(xptr,'Color','r') ;
%        xex = get(xptr,'Extent') ;
%        lt = xex(1) ; bt = xex(2) ; wd = xex(3) ; ht = xex(4) ;
%        p = line([lt+wd,lt,lt+wd],[bt,bt,bt+ht]) ;
%        set(p,'Color','k','LineWidth',1) ;
%        xrad = 0.7*wd ; yrad = 0.6*ht ; xc = lt ; yc = bt ; angs = [-pi/16:pi/64:7*pi/16]' ;
%        p = line(xc+xrad*cos(angs),yc+yrad*sin(angs)) ; 
%        set(p,'Color','k','LineWidth',1) ; 

    %   Update slider values, maxima, minima and slider steps based on current 
    %   discrete-time signal parameters and display update slider values
    function sd = updateSigD(sd,LR,h)
        if LR == 'L', col = '1' ; else col = '2' ; end
        for k = 1:4, 
            s = ['vax = h.sfnvax',num2str(k),col,' ;'] ; eval(s) ; axes(vax) ; cla ; 
            s = ['sli = h.sfnsl',num2str(k),col,' ;'] ; eval(s) ;
            if ~isnan(sd.v(k)), 
                set(sli,'Max',sd.mx(k),'Min',sd.mn(k),'SliderStep',sd.ss(k,:)) ;
                set(sli,'Value',sd.v(k)) ;
                set(sli,'Enable','on','Visible','on') ;
                s = [sd.pn{k},'  = ',num2str(sd.v(k))] ;
                %   Display slide value just above slider
                text(0.5,0.5,s,'HorizontalAlignment','center',...
                    'VerticalAlignment','middle','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.9) ;
            else
                set(sli,'Enable','off','Visible','off') ;
            end
        end
        sd = drawSigD(sd,LR,h) ;   %   Draw the signal

    %   Draw one discrete-time signal graph
    function sd = drawSigD(sd,LRSP,h)
        if LRSP == 'L' | LRSP == 'R',
            s = ['ax = h.sfn',LRSP,'t ;'] ; eval(s) ; axes(ax) ; cla ;
        else
            if LRSP == 'S', axes(h.sfnS) ; cla ; end
            if LRSP == 'P', axes(h.sfnP) ; cla ; end
        end
        %   Draw the signal in the time domain
        ptr = xyplot(sd.n,sd.x,[-15,15,min(0,min(sd.x)),max(0,max(sd.x))],...
            '\itn','x[{\itn}]','Times',0.1,'Times',0.08,sd.ttl,'Times',0.12,'n',...
            'd','k',{'ahstc','ahstc'}) ;
        if LRSP == 'L' | LRSP == 'R',
            %   Draw the magnitude of the DTFT of the signal
            s = ['ax = h.sfn',LRSP,'m ;'] ; eval(s) ; axes(ax) ; cla ;
            ttl = ['DTFT of ',sd.ttl] ;
            maxX = max(abs(sd.X)) ;
            if isempty(sd.Wi),
                %   Draw DTFT magnitude if it does not contain impulses
               ptr = xyplot(sd.W,abs(sd.X),[-pi,pi,0,maxX],'\Omega',...
                      '|X({\ite}^{ {\itj}\Omega})|','Times',0.1,'Times',0.08,ttl,...
                      'Utopia',0.12,'n','c','k',{'ahstc','ahstc'}) ;
            else
                maxX = max(maxX,max(abs(sd.Xi))) ;
                %   Draw DTFT magnitude if it does contain impulses
                ptr = xyplot({sd.W,sd.Wi},{abs(sd.X),abs(sd.Xi)},...
                      [-pi,pi,0,maxX],'\Omega','|X({\ite}^{ {\itj}\Omega})|',...
                      'Times',0.1,'Times',0.08,ttl,'Utopia',0.12,'n',{'c','i'},'k',...
                      {'ahstc','ahstc'}) ;
            end
            %   Draw the phase of the DTFT of the signal
            s = ['ax = h.sfn',LRSP,'p ;'] ; eval(s) ; axes(ax) ; cla ;
            ang = angle(sd.X) ; 
            I = find(abs(sd.X) < max(abs(sd.X))/10000) ; ang(I) = NaN ;
            I = find(abs(sd.X) == 0) ; ang(I) = NaN ;
            I = find(abs(abs(angle(sd.X))-pi) < pi/2000) ; ang(I) = pi ;
            N = length(sd.W) ; I = find(sd.W > 0) ; ang(N-I+1) = -ang(I) ;
            angi = angle(sd.Xi) ; 
            I = find(abs(sd.Xi) < max(abs(sd.Xi))/1000) ; angi(I) = NaN ;
            I = find(abs(sd.Xi) == 0) ; angi(I) = NaN ;
            I = find(abs(abs(angle(sd.Xi))-pi) < pi/2000) ; angi(I) = pi ;
            Ni = length(sd.Wi) ; I = find(sd.Wi > 0) ; angi(Ni-I+1) = -angi(I) ;
            if isempty(sd.Wi),
                if sum(isnan(ang)) == length(ang),
                    ptr = text(0.5,0.5,'Phase is Undefined','FontUnits',...
                        'Normalized','FontSize',0.2,...
                        'FontName','Times','HorizontalAlignment','center',...
                        'VerticalAlignment','middle') ;
                    axis([0,1,0,1]) ;
                else
                    %   Draw DTFT phase if it does not contain impulses
                   ptr = xyplot(sd.W,ang,[-pi,pi,-pi,pi],'\Omega','\<X({\ite}^{ {\itj}\Omega})',...
                          'Times',0.12,'Times',0.1,ttl,'Utopia',0.14,'n','c','k',...
                          {'ahstc','ahstc'}) ;
    %                    drawAngleSign(ptr.an.y.lab,0.12) ;
                end
            else
                if sum(isnan([ang;angi])) == length([ang;angi])
                     ptr = text(0.5,0.5,'Phase is Undefined','FontUnits',...
                        'Normalized','FontSize',0.2,...
                        'FontName','Times','HorizontalAlignment','center',...
                        'VerticalAlignment','middle') ;
                     axis([0,1,0,1]) ;
                else
                %   Draw DTFT phase if it does contain impulses
                ptr = xyplot({sd.W,sd.Wi},{ang,angi},[],...
                      '\Omega','\<X({\ite}^{ {\itj}\Omega})','Times',0.12,'Times',0.1,ttl,...
                      'Utopia',0.14,'n',{'c','s'},'k',{'ahstc','ahstc'}) ;
    %                    drawAngleSign(ptr.an.y.lab,0.12) ;
                end
            end
        end

    %   Function to place directed line segment with annotation on a graph
    %       x    A scalar or 2 vector for the x coordinates of the ends of 
    %           the indicator line which is drawn from x(1) to x(2)
    %       y    A scalar or 2 vector for the y coordinates of the ends of 
    %           the indicator line which is drawn from y(1) to y(2)
    %       p    A flag indicating where to put the annotation
    %           'b' - before the beginning of the line
    %           'e' - after the end of the line
    %       txt  The text to be written
    %   If the last character in the text is either ">" or "<" an
    %   arrowhead is placed on the line.  If the character is ">" the
    %   arrowhead is at the end of the line.  If the character is
    %   "<" the arrowhead is at the beginning of the line.  If the last two
    %   characters are "<>" arrowheads are placed on both ends.
    function ptr = annotate(x,y,p,txt)
        ang = [] ;
        if length(x) == 1, x = [x,x] ; end
        if length(y) == 1, y = [y,y] ; end
        ws = get(gcf,'Position') ; wx = ws(3) ; wy = ws(4) ;
        as = get(gca,'Position') ; ax = as(3) ; ay = as(4) ;
        dx = (x(2) - x(1))*(ax*wx) ; dy = (y(2) - y(1))*(ay*wy) ; 
        ang = atan2(dy,dx) ;
        ptr = line(x,y) ; set(ptr,'Color','k') ;
        [txt,arrow] = strtok(txt,'<>') ;
        switch p
            case 'b',
            ptr = text(x(1),y(1),txt,'FontName','Times',...
                'HorizontalAlignment','center','VerticalAlignment','middle',...
                'FontUnits','Normalized','FontSize',0.12) ;
            ex = get(ptr,'Extent') ;
            xa = x(1)-sign(dx)*ex(3)/2 ; ya = y(1)-sign(dy)*ex(4)/2 ; 
            case 'e', 
            ptr = text(x(2),y(2),txt,'FontName','Times',...
                'HorizontalAlignment','center','VerticalAlignment','middle',...
                'FontUnits','Normalized','FontSize',0.12) ;
               ex = get(ptr,'Extent') ;
            xa = x(2)+sign(dx)*ex(3)/2 ; ya = y(2)+sign(dy)*ex(4)/2 ; 
        end
        set(ptr,'Position',[xa,ya]) ;
        if ~isempty(strfind(arrow,'>')), 
            ptr = arrowHead(x(2),y(2),ang,8,'k') ; 
        end
        if ~isempty(strfind(arrow,'<')), 
            ptr = arrowHead(x(1),y(1),ang+pi,12,'k') ; 
        end
        
    function setParam(hObject,eventdata)
        %   Get pointer to slider just selected
        [obj,f] = gcbo ; h = guihandles(f) ;
        val = get(obj,'Value') ;    %   Get slider value
        cd = get(h.sfncd,'UserData') ; %   Get state of cd button
        %   Get state of spcv button and pointer to convolve button
        spcvData = get(h.sfnspcv,'UserData') ; 
        rc = get(obj,'UserData') ;  %   Get row and column of slider
        fns = guidata(f) ;
        if cd == 'c',
            st = ['sdL = get(h.sfnmL',num2str(fns.cL),',''UserData'') ;'] ; eval(st) ;
            st = ['sdR = get(h.sfnmR',num2str(fns.cR),',''UserData'') ;'] ; eval(st) ;
        else
            st = ['sdL = get(h.sfnmL',num2str(fns.dL),',''UserData'') ;'] ; eval(st) ;
            st = ['sdR = get(h.sfnmR',num2str(fns.dR),',''UserData'') ;'] ; eval(st) ;
        end
        %   Get number of current signal associated with this slider
        if cd == 'c',
            if rc(2) == 1, 
                sdL = updateSigDataC(sdL,val,rc(1),'L',h) ;
                st = ['set(h.sfnmL',num2str(fns.cL),',''UserData'',sdL) ;'] ; eval(st) ;
            else
                sdR = updateSigDataC(sdR,val,rc(1),'R',h) ;
                st = ['set(h.sfnmR',num2str(fns.cR),',''UserData'',sdR) ;'] ; eval(st) ;
            end
            %   Get data from both active functions in prep for sum and prod
            if strcmp(spcvData.spcv,'sp'),
                %   Draw sum and product of last-selected continuous-time signals
                if ~isempty(fns.cL) & ~isempty(fns.cR),
                    disableControls(h) ; 
                        drawSumC(sdL,sdR,h) ; drawProdC(sdL,sdR,h) ; 
                    enableControls(h) ;
                end
                set(h.sfncv,'Enable','off') ;
            end
        else
            if rc(2) == 1, 
                sdL = updateSigDataD(sdL,val,rc(1),'L',h) ;
                st = ['set(h.sfnmL',num2str(fns.dL),',''UserData'',sdL) ;'] ; eval(st) ;
            else
                sdR = updateSigDataD(sdR,val,rc(1),'R',h) ;
                st = ['set(h.sfnmR',num2str(fns.dR),',''UserData'',sdR) ;'] ; eval(st) ;
            end
            %   Get data from both active functions in prep for sum and prod
            if strcmp(spcvData.spcv,'sp'),
                %   Draw sum and product of last-selected discrete-time signals
                if ~isempty(fns.dL) & ~isempty(fns.dR),
                    disableControls(h) ; 
                        drawSumD(sdL,sdR,h) ; drawProdD(sdL,sdR,h) ; 
                    enableControls(h) ;
                end
            end
        end
        
    function sd = updateSigDataC(sd,val,rc,LR,h)
        %   Get previous parameter values from menu user data
        vals = sd.sc.v ;    
        %   Quantize the slider value
        dval = (sd.sc.mx(rc) - sd.sc.mn(rc)) *sd.sc.ss(rc,1) ;
        %   Put new parameter value in slider value structure in menu
        vals(rc) = round(val/dval)*dval ;
        sc = [] ;   %   Send empty structure to signal parameter generator
                    %   to update parameter values
        %   Compute new time and signal vectors from new parameters
        s = ['sd.sc = sfn',sd.tg,'C(vals,sc) ;'] ; eval(s) ;
        %   Update the signal based on the new structure of parameters
        updateSigC(sd.sc,LR,h) ; 

    function sd = updateSigDataD(sd,val,rc,LR,h)
        %   Get previous parameters values from menu user data
        vals = sd.sd.v ;    
        %   Quantize the slider value
        dval = (sd.sd.mx(rc) - sd.sd.mn(rc)) *sd.sd.ss(rc,1) ;
        %   Put new parameter value in slider value structure in menu
        vals(rc) = round(val/dval)*dval ;
        %   Form a temporary structure for pointers to axes, sliders and
        %   slider-value axes for graphing the current signal
        sd1 = [] ;   %   Send empty structure to signal parameter generator
                    %   to update parameter values
        %   Compute new time and signal vectors from new parameters
        s = ['sd.sd = sfn',sd.tg,'D(vals,sd1) ;'] ; eval(s) ;
        %   Update the signal based on the new structure of parameters
        updateSigD(sd.sd,LR,h) ; 

    %   Draw the sum of two continuous-time signals
    function drawSumC(sdL,sdR,h)
        %   Form a combined time vector which has all the points from both
        %   signals
        [t,sdL,sdR] = combineTimes(sdL,sdR) ;
        %   Generate new graphing values with same time scale for both signals
        [sdL,sdR] = newGraphVals(t,sdL,sdR,'c') ;
        %   Set up a temporary structure to contain all the information
        %   necessary for a sum graph
        sc.x = sdL.sc.x + sdR.sc.x ; sc.xi = sdL.sc.xi + sdR.sc.xi ;
        sc.ti = sdL.sc.ti ; sc.t = sdL.sc.t ; sc.ttl = 'Sum' ; sc.ax.t = h.sfnS ;
        %   Draw the sum and label it "Sum"
        sc = drawSigC(sc,'S',h) ;
        
    %   Draw the product of two continuous-time signals   
    function drawProdC(sdL,sdR,h)
        %   Select and clear the product axes
        axes(h.sfnP) ; cla ;
        %   Form a combined time vector which has all the points from both
        %   signals
        [t,sdL,sdR] = combineTimes(sdL,sdR) ;
        %   Generate new graphing values with same time scale for both signals
        [sdL,sdR] = newGraphVals(t,sdL,sdR,'c') ;
        %   Create two numbers each of which is 0 if the signal contains
        %   no impulses or 1 if it contains any impulses
        impSig1 = 0 ; impSig2 = 0 ;
        if ~isempty(strfind(upper(sdL.tg),'IMP')), impSig1 = 1 ; end
        if ~isempty(strfind(upper(sdR.tg),'IMP')), impSig2 = 1 ; end
        sc.ttl = 'Product' ; sc.ax.t = h.sfnP ;
        %   If both signals contain impulses, don't draw anything but rather
        %   print a message saying that multiplication of continuous time
        %   impulses is not defined.  If one signal has impulses and the other
        %   does not, the product is a set of impulses whose strengths have
        %   been multiplied by the other continuous-time function.  If neither
        %   signal has impulses, just graph the product.
        switch impSig1+impSig2,
            case 0,     %   Neither signal contains impulses
                sc.x = sdL.sc.x.*sdR.sc.x ; sc.t = sdL.sc.t ;
                sc.ti = [] ; 
                sc = drawSigC(sc,'P',h) ; %   Draw the product and label it "Product"
            case 1,     %   One signal contains impulses
                if impSig1 == 1,    %   Multiply the impulse signal by the
                                    %   continuous signal
                    sc.xi = sdL.sc.xi.*sdR.sc.x ; sc.ti = sdL.sc.ti ;
                    sc.t = sc.ti ; sc.x = 0*sc.t ; 
                else
                    sc.xi = sdR.sc.xi.*sdL.sc.x ; sc.ti = sdL.sc.ti ;
                    sc.t = sc.ti ; sc.x = 0*sc.t ; 
                end
                sc = drawSigC(sc,'P',h) ; %   Draw the product and label it "Product" 
                %   Both signals contain impulses
            case 2,     %   Notify user why no graph is drawn
                s = 'Multiplication of Continuous-Time' ;
                s = str2mat(s,'     Impulses Is Not Defined') ;
                ptr = text(0.5,0.5,s,'VerticalAlignment','middle',...
                            'HorizontalAlignment','center','FontName',...
                            'Times','FontUnits','Normalized','FontSize',0.18) ;
        end
        
    %   Combine the time vector(s) from the two signals into one time vector
    %   for graphing the sum and product or convolution
    function [t,sdL,sdR] = combineTimes(sdL,sdR)
        %   Concatenate the time vectors to form one column vector of times
        t = sort([sdL.sc.t(:);sdR.sc.t(:);sdL.sc.ti(:);sdR.sc.ti(:)]) ;
        %   Search for forward differences of zero and remove redundant time
        %   values
        d = diff(t) ; I = find(d ~= 0) ; t = [t(I);t(end)] ;
        
    function [sdL,sdR] = newGraphVals(nt,sdL,sdR,cd)
        if cd == 'c',
            %   Make the time vectors for both signals for both continuous and
            %   impulse signals the same
            sdL.sc.t = nt ; sdL.sc.ti = nt ; sdR.sc.ti = nt ; sdR.sc.t = nt ;
            vals = sdL.sc.v ;   %   Get stored slider values for left signal
            %   Put a new set of graphing values in one signal menu position
            s = ['sdL.sc = sfn',sdL.tg,'C(vals,sdL.sc) ;'] ; eval(s) ;
            vals = sdR.sc.v ;   %   Get stored slider values
            %   Put a new set of graphing values in the other signal menu position
            s = ['sdR.sc = sfn',sdR.tg,'C(vals,sdR.sc) ;'] ; eval(s) ;
        else
            %   Make the time vectors for both signals the same
            sdL.sd.n = nt ;  sdR.sd.n = nt ;
            vals = sdL.sd.v ;   %   Get stored slider values for left signal
            %   Put a new set of graphing values in one signal menu position
            s = ['sdL.sd = sfn',sdL.tg,'D(vals,sdL.sd) ;'] ; eval(s) ;
            vals = sdR.sd.v ;   %   Get stored slider values
            %   Put a new set of graphing values in the other signal menu position
            s = ['sdR.sd = sfn',sdR.tg,'D(vals,sdR.sd) ;'] ; eval(s) ;
        end

    %   Draw the sum of two discrete-time signals
    function drawSumD(sdL,sdR,h)
        %   Add the two signals
        sd.x = sdL.sd.x + sdR.sd.x ; sd.n = sdL.sd.n ;
        %   Graph the sum and put a title "Sum" on the graph
        sd.ttl = 'Sum' ; sd.ax.n = h.sfnS ; sd = drawSigD(sd,'S',h) ;

    %   Draw the product of two discrete-time signals
    function drawProdD(sdL,sdR,h)
        %   Multiply the two signals
        sd.x = (sdL.sd.x).*(sdR.sd.x) ; sd.n = sdL.sd.n ;
        %   Graph the product and put a title "Product" on the graph
        sd.ttl = 'Product' ; sd.ax.n = h.sfnP ; 
        sd = drawSigD(sd,'P',h) ;

    %   Animate the convolution of the two continuous-time signals currently 
    %   selected
    function drawConvC(sdL,sdR,h)
        %   Select and clear the sum axes for the convolution animation
        axes(h.sfnS) ; cla ;
        %   Select and clear the product axes for the convolution result
        axes(h.sfnP) ; cla ;
        iL = ~isempty(strfind(upper(sdL.tg),'IMP')) ; 
        iR = ~isempty(strfind(upper(sdR.tg),'IMP')) ; 
        if xor(iL,iR),
            drawConvCci(sdL,sdR,h) ;
        else
            if iL & iR, drawConvCi(sdL,sdR,h) ; else drawConvCc(sdL,sdR,h) ; end
        end
        
    %   Handle the convolution case of two continuous signals
    %   Convolution is the area under the product of x1(tau) and x2(t-tau)
    %   as a function of t
    function drawConvCc(sdL,sdR,h)
        tauL = sdL.sc.t ; xL = sdL.sc.x ; tauR = sdR.sc.t ; xR = sdR.sc.x ;
        %   Check to see whether the signals are energy or power signals and
        %   decide whether an aperiodic convolution is possible
        cv = areConvolvable(sdL,sdR) ;
        if cv == 'n' , 
            %   If convolution cannot be done, print a message indicating that
            printNonConvolvable(h.sfnS,h.sfnP) ;
        else
            %   Create a tau vector with uniformly-spaced points to be used in
            %   computing the convolution of the two signals.  The tau range should
            %   be well beyond the time range to be displayed to avoid end effects
            dtau = 0.05 ; N = ceil(60/dtau) ; tau = dtau*[-N:N-1]' ;  
            %   Compute new function values at the time points in the uniform time
            %   vector just created
            [sdLu,sdRu] = newGraphVals(tau,sdL,sdR,'c') ;
            tauLu = sdLu.sc.t ; xLu = sdLu.sc.x ; tauRu = sdRu.sc.t ; xRu = sdRu.sc.x ; 
            %   If a periodic convolution is indicated, find a common period and
            %   truncate the left-hand signal to the common period centered at tau = 0
            %   Also create a separate left-hand signal over just the common period
            if cv == 'p',
                T = lcm(sdL.sc.v(4),sdR.sc.v(4)) ;
                xLu = xLu.*(tauLu >= -T/2 & tauLu < T/2) ;
                I = find(tauLu >= -T/2 & tauLu < T/2) ; xLuT = xLu(I) ; tauLuT = tauLu(I) ;
            end
            %   Form a vector of discrete times corresponding to the real time
            %   vectors in preparation for doing a discrete-time convolution as an
            %   approximation to the continuous-time convolution
            nL = floor(tauLu/dtau) ; nL = nL' ; nR = nL ;
            %   Convolve the two signals corresponding to the uniform time vector
            [y,n] = convD(xLu,nL,xRu,nR) ;
            %   Scale the result by multiplying by the time between points
            %   and quantize the values to avoid an approximation error when convolving 
            %   rectangles
            y = dtau*y ; [ymx,I] = max(y) ; y(I) = ceil(y(I)/dtau)*dtau ;
            %   Form a time vector for the convolution
            t = n*dtau ;
            %   Graph the two signals and their convolution only for shifts less than
            %   15 in magnitude
            I = find(abs(t)<=15) ; t = t(I) ; y = y(I) ; 
            %   tau reverse the uniformly-sampled right-hand signal
            xRurev = xRu(end:-1:1) ;
            %   Display the convolution.  Jump 8 time units in each loop to speed
            %   up the animation display
            for k = 1:8:length(t),
                %   Find the maximum and minimum function values and the span
                %   and use them to set the location of the moving text that 
                %   indicates the shift "t" in each iteration of the animation
                xmn = min([xL(:);xR(:)]) ; xmx = max([xL(:);xR(:)]) ; 
                if xmx == xmn, xmn = xmn - 1 ; end
                xsp = xmx - xmn ; xtxt = xmn - xsp/20 ;
                if k == 1,
                    %   In the first loop, set up the graphic displays
                    %   Draw the axes for the animation
                    ttl = '\color{red}x_1({\tau}) ' ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color{blue}x_2({\itt} - \tau) '] ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color[rgb]{0 0.5 0}Area under x_1({\itt})x_2({\itt} - \tau)'] ;
                    axes(h.sfnS) ; drawAxes(-15,15,xmn,xmx,ttl,'') ;
                    %   Hold the axes for more graphs on the same axes
                    hold on ;
                    %   Graph the area under the product in green
                    xLxR = prodxLxR(xLu,xRurev,round(t(k)/dtau)) ;
                    I = find(abs(tau)<=18) ; 
                    cmap = colormap([0 0.5 0]) ;
                    pxprod = patch([-18;tau(I);18],[0;xLxR(I);0],cmap) ;
                    set(pxprod,'EdgeColor',[0 0.5 0]) ;
                    %   Graph the signal on the left in the window in red
                    pxL = plot(tauL,xL,'r') ;
                    if cv == 'a',
                        set(pxL,'LineWidth',2,'EraseMode','normal') ;
                    else
                        set(pxL,'LineWidth',1,'EraseMode','normal','LineStyle','--') ;
                        pxp = plot(tauLuT,xLuT,'r') ;
                        set(pxp,'LineWidth',2,'EraseMode','normal') ;
                    end
                    %   Graph the time reversed and shifted signal on the right
                    %   in the window in blue
                    pxR = plot(t(k)-tauR,xR,'b') ;
                    set(pxR,'LineWidth',2,'EraseMode','normal') ;
                    %   Display the current shift of the second function
                    ptxt = text(t(k),xtxt,['{\itt} = ',num2str(t(k),'%5.1f')],'HorizontalAlignment',...
                            'center','VerticalAlignment','top','FontName','Times',...
                            'FontUnits','Normalized','FontSize',0.1,'Color','b') ;
                    ptic = line([t(k),t(k)],[xmn,xtxt]) ; set(ptic,'Color','b') ;
                    %   Draw the axes for the convolution result
                    axes(h.sfnP) ;
                    %   Find the range of convolution values to set the graphing
                    %   axis values
                    ymn = -1 ; ymx = 1 ;
                    if ~isempty(y), 
                        ymn = min(min(y),ymn) ; ymx = max(max(y),ymx) ; 
                    end
                    if cv == 'a', 
                        ttl = '\color[rgb]{0 0.5 0}Aperiodic Convolution of x_1({\itt}) with x_2({\itt})' ;       
                    else
                        ttl = '\color[rgb]{0 0.5 0}Periodic Convolution of x_1({\itt}) with x_2({\itt})' ;
                        ttl = [ttl,', {\itT} = ',num2str(T)] ;
                    end
                    drawAxes(-15,15,ymn,ymx,ttl,'\itt') ;
                    %   Graph the convolution for the initial shift only (one point)
                    py = plot(t(1),y(1),'Color',[0 0.5 0]) ; set(py,'LineWidth',2) ;
                    hold on ;
                else
                    %   Replace the old data for the time-reversed and shifted
                    %   right-hand function with the new data for the new shift
                    set(pxR,'XData',t(k)-tauR) ; 
                    xLxR = prodxLxR(xLu,xRurev,round(t(k)/dtau)) ;
                    set(pxprod,'XData',[-18;tau(I);18],'YData',[0;xLxR(I);0]) ; 
                    %   Graph the convolution result up to the current shift value
                    set(py,'XData',t(1:k),'YData',y(1:k)) ;
                    %   Update the text indication of shift amount
                    set(ptxt,'Position',[t(k),xtxt],'String',['{\itt} = ',num2str(t(k),'%5.1f')]) ;
                    set(ptic,'XData',[t(k),t(k)]) ;
                end
                drawnow ;   %   Force a graph draw at each iteration
            end
        end
        
    function cv = areConvolvable(sdL,sdR)
        %   Return a convolution flag. 'a' means aperiodic convolution is
        %   appropriate, 'p' means periodic convolution is appropriate and
        %   'n' means no convolution is appropriate
        peL = sdL.pe ; peR = sdR.pe ; paL = sdL.pa ; paR = sdR.pa ;
        %   If either signal is an energy signal do an aperiodic convolution
        if peL == 'e' | peR == 'e',
            cv = 'a' ;    %   Convolution flag indicating aperiodic convolution
                          %   is allowed
        else
            %   The only other allowed aperiodic convolution is a step with itself
            if strcmp(upper(sdL.tg),'US') & strcmp(upper(sdR.tg),'US'),
                cv = 'a' ;
            else
                if paL == 'p' & paR == 'p' ; cv = 'p' ; else cv = 'n' ; end
            end
        end
        
    function printNonConvolvable(S,P)
        axes(S) ;
        ptr = text(0,0,'Convolution Not Defined for These Signals',...
                    'HorizontalAlignment','center','VerticalAlignment',...
                    'middle','FontName','Times','FontUnits','Normalized',...
                    'FontSize',0.15) ;
        axis([-1,1,-1,1]) ; axes(P) ;
        ptr = text(0,0,'Convolution Not Defined for These Signals',...
                    'HorizontalAlignment','center','VerticalAlignment',...
                    'middle','FontName','Times','FontUnits','Normalized',...
                    'FontSize',0.15) ;
        axis([-1,1,-1,1]) ; axes(P) ;
        
function xLxR = prodxLxR(xL,xR,n)
    xLxR = xL.*rot(xR,n) ;
    
function y = rot(x,n)
    y = x ;
    if n > 0,
        y = [x(end-n+1:end);x(1:end-n)] ;
    else
        y = [x(-n+1:end);x(1:-n)] ;
    end
        
%   Handle the convolution case of one impulse signal and one continuous signal
    function drawConvCci(sdL,sdR,h)
        iL = ~isempty(strfind(upper(sdL.tg),'IMP')) ;
        iR = ~isempty(strfind(upper(sdR.tg),'IMP')) ;
        if ~xor(iL,iR),
            error('drawConvCi: Signals are both impulse signals or both continuous') ;
            return ;
        end
        %   If either signal (or both) is an (are) energy signal(s) do an aperiodic 
        %   convolution, otherwise do a perioidic convolution, if possible
        cv = areConvolvable(sdL,sdR) ;
        if cv == 'n', 
            %   If convolution cannot be done, indicate that in a 
            %   message on both lower axes
            dispNonConvolvable(h.sfnS,h.sfnP)
        else
            %   Create a time vector with uniformly-spaced times for computing
            %   the convolution result.  Make the time increment small so as to 
            %   accurately reproduce the discontinuities in some functions
            dt = 0.002 ; ty = [-40:dt:40]' ; tau = ty ; y = 0*ty ;
            [sdLu,sdRu] = newGraphVals(ty,sdL,sdR,'c') ;
            if iL, 
                ti = sdL.sc.ti ; xi = sdL.sc.xi ; tc = sdRu.sc.t ; xc = sdRu.sc.x ;
            else
                ti = sdR.sc.ti ; xi = sdR.sc.xi ; tc = sdLu.sc.t ; xc = sdLu.sc.x ;
            end
            %   Find the maximum, minimum and span of the function values and
            %   use them to set the location of the time-shift indicator
            xmn = min([xi(:);xc(:)]) ; xmx = max([xi(:);xc(:)]) ; 
            if xmx == xmn, xmn = xmn - 1 ; end
            xsp = xmx - xmn ; xtxt = xmn - xsp/20 ;
            [tip,xip] = polyImp(ti,xi,xsp) ;
            %   If a periodic convolution is indicated, truncate the left-hand
            %   signal to one common period centered at t = 0
            if cv == 'p',
                T = lcm(sdL.sc.v(4),sdR.sc.v(4)) ; %   Find a common period
            end
            if iL,
                if cv == 'p',
                    xi = xi.*(ti >= -T/2 & ti < T/2) ;
                    I = find(ti >= -T/2 & ti < T/2) ;
                    xiT = xi(I) ; tiT = ti(I) ;
                    [tipT,xipT] = polyImp(tiT,xiT,xsp) ;
                    xcrev = xc(end:-1:1) ;
                end
            else
                if cv == 'p',
                    I = find(tc >= -T/2 & tc < T/2) ;
                    xcT = xc(I) ; tcT = tc(I) ;
                    xc0 = xc.*(tc >= -T/2 & tc < T/2) ;
                    xcrev = xc0(end:-1:1) ;
                else
                    xcrev = xc(end:-1:1) ;
                end
            end
            %   Find subscripts of elements of continuous signal occurring at
            %   the impulse time(s) (at zero convolution shift)
            ni = round((ti-ty(1))/dt) + 1 ;
            %   Compute the convolution
            if cv == 'a',
                for k = 1:length(ti),
                    [sdLk,sdRk] = newGraphVals(ty-ti(k),sdL,sdR,'c') ;
                    if iL,
                        yk = xi(k)*sdRk.sc.x ;
                    else
                        yk = xi(k)*sdLk.sc.x ;
                    end
                    y = y + yk ;
                end
            else
                if iL,
                    for k = 1:length(tiT),
                        [sdLk,sdRk] = newGraphVals(ty-tiT(k),sdL,sdR,'c') ;
                        yk = xiT(k)*sdRk.sc.x ;
                        y = y + yk ;
                    end
                else
                    for k = 1:length(ti),
                        [sdLk,sdRk] = newGraphVals(ty-tcT(k),sdL,sdR,'c') ;
                        yk = xi(k)*sdLk.sc.x ;
                        y = y + yk ;
                    end
                end
            end
            %   Graph the convolution result and the animation for time values
            %   between -15 and 15
            I = find(abs(ty)<=15) ; ty = ty(I) ; y = y(I) ;
            %   Animate and graph convolution only at every 100th step to speed
            %   up the animation
            for k = 1:200:length(ty),
                %   Set the current time shift value
                if k == 1,
                    %   On the first pass set up the graphic elements 
                    %   Draw the axes for the animation
                    %   Draw the axes for the animation
                    ttl = '\color{red}x_1({\tau}) ' ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color{blue}x_2({\itt} - \tau) '] ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color[rgb]{0 0.5 0}x_1({\itt})x_2({\itt} - \tau)'] ;
                    axes(h.sfnS) ; drawAxes(-15,15,xmn,xmx,ttl,'') ;
                    hold on ;   %   Hold the axes for more graphs
                    %    If the impulse signal is on the left in the window
                    %    draw it and shift the other function
                    if iL,
                        %   Draw the impulse signal
                        pxi = patch(tip,xip,'r') ;
                        if cv == 'a',
                            set(pxi,'LineWidth',2,'EraseMode','normal','EdgeColor','r') ;
                        else
                            set(pxi,'LineWidth',1,'EraseMode','normal',...
                                'FaceColor','m','Edgecolor','m') ;
                            pxiT = patch(tipT,xipT,'r') ;
                            set(pxiT,'LineWidth',2,'EraseMode','normal','EdgeColor','r') ;
                        end
                        %    Draw the other signal as the one to be shifted
                        pxc = plot(ty(k)-tc,xc,'b') ; set(pxc,'LineWidth',2) ;
                        %   Draw the product
                        n = round(ty(k)/dt) ; xcrevsh = rot(xcrev,n) ;
                        xixc = xi.*xcrevsh(ni) ;
                        [tp,xp] = polyImp(ti,xixc,xsp) ;
                        cmap = [0 0.5 0] ;
                        pxixc = patch(tp,xp,cmap) ; 
                        set(pxixc,'EdgeColor',[0 0.5 0],'LineWidth',2) ;
                    else
                        %   Draw the non-impulse signal
                        pxc = plot(tc,xc,'r') ;
                        if cv == 'a',
                            set(pxc,'LineWidth',2,'EraseMode','normal') ;
                        else
                            set(pxc,'LineWidth',1,'EraseMode','normal','LineStyle','--') ;
                            pxcT = plot(tcT,xcT,'r') ; set(pxcT,'LineWidth',2) ;
                        end
                        pxi = patch(ty(k)-tip,xip,'b') ;
                        set(pxi,'LineWidth',2,'EraseMode','normal','EdgeColor','b') ;
                        %   Draw the product
                        n = round(ty(k)/dt) ; xcrevsh = rot(xcrev,n) ;
                        xixc = xi.*xcrevsh(n) ;
                        [tp,xp] = polyImp(ty(k)-ti,xixc,xsp) ;
                        pxixc = patch(tp,xp,cmap) ; 
                        set(pxixc,'EdgeColor',[0 0.5 0],'LineWidth',2) ;
                    end
                    %   Create the text indication of shift amount
                    ptxt = text(ty(k),xtxt,['{\itt} = ',num2str(ty(k),'%5.1f')],'HorizontalAlignment',...
                            'center','VerticalAlignment','top','FontName','Times',...
                            'FontUnits','Normalized','FontSize',0.1,'Color','b') ;
                    ptic = line([ty(k),ty(k)],[xmn,xtxt]) ; set(ptic,'Color','b') ;
                    %   Draw the convolution result on the right side of the 
                    %   window
                    axes(h.sfnP) ;
                    %   Find the range of convolution result values
                    ymn = -1 ; ymx = 1 ;
                    if ~isempty(y), 
                        ymn = min(min(y),ymn) ; ymx = max(max(y),ymx) ; 
                    end
                    %   Draw the axes for the convolution result
                    if cv == 'a', 
                        ttl = '\color[rgb]{0 0.5 0}Aperiodic Convolution of x_1({\itt}) with x_2({\itt})' ;       
                    else
                        ttl = '\color[rgb]{0 0.5 0}Periodic Convolution of x_1({\itt}) with x_2({\itt})' ;
                        ttl = [ttl,', {\itT} = ',num2str(T)] ;
                    end
                    drawAxes(-15,15,ymn,ymx,ttl,'\itt') ;
                    %   Draw the convolution result for the first shift (one point)
                    py = plot(ty(1),y(1),'Color',[0 0.5 0]) ; set(py,'LineWidth',2) ;
                    hold on ;
                else
                    %   Draw the shifted signal at its new shift
                    if iL, 
                        set(pxc,'XData',ty(k)-tc) ; 
                        %   Draw the product
                        n = round(ty(k)/dt) ; xcrevsh = rot(xcrev,n) ;
                        if cv == 'a',
                            xixc = xi.*xcrevsh(ni) ;
                            [tp,xp] = polyImp(ti,xixc,xsp) ;
                        else
                            xixc = xi.*xcrevsh(ni) ;
                            [tp,xp] = polyImp(ti,xixc,xsp) ;
                        end
                        set(pxixc,'XData',tp,'YData',xp) ;
                    else
                        set(pxi,'XData',ty(k)-tip) ; 
                        %   Draw the product
                        n = round(ty(k)/dt) ; xcrevsh = rot(xcrev,n) ;
                        xixc = xi.*xcrevsh(ni) ;
                        [tp,xp] = polyImp(ty(k)-ti,xixc,xsp) ;
                        set(pxixc,'Xdata',tp,'YData',xp) ;
                    end
                    %   Draw the convolution result up to the current shift value
                    set(py,'Xdata',ty(1:k),'Ydata',y(1:k)) ;
                    %   Update and move the text indication of shift amount
                    set(ptxt,'Position',[ty(k),xtxt],'String',['{\itt} = ',num2str(ty(k),'%5.1f')]) ;
                    set(ptic,'Xdata',[ty(k),ty(k)]) ;
                end
                drawnow ;   %   Force a graph draw after every iteration
            end
        end
    
    %   Handle the convolution case of two impulse signals
    function drawConvCi(sdL,sdR,h)
        %   Select and clear the sum axes for the convolution animation
        axes(h.sfnS) ; cla ;
        %   Select and clear the product axes for the convolution result
        axes(h.sfnP) ; cla ;
        cv = areConvolvable(sdL,sdR)
        %   Use short names for the two time vectors and the two impulse-strength
        %   vectors
        tiL = sdL.sc.ti ; xiL = sdL.sc.xi ; tiR = sdR.sc.ti ; xiR = sdR.sc.xi ;
        %   Find the maximum, minimum and span of the impulse strengths and use
        %   them to set the location of the text indicator of shift amount
        xmn = min([xiL(:);xiR(:);0]) ; xmx = max([xiL(:);xiR(:);0]) ; 
        if xmx == xmn, xmn = xmn - 1 ; end
        xsp = xmx - xmn ; xtxt = xmn - xsp/20 ;
        %   If a periodic convolution is indicated, find a common period and
        %   truncate the left-hand signal to the common period centered at n = 0
        %   Also create a separate left-hand signal over just the common period
        if cv == 'p',
            T = lcm(sdL.sc.v(4),sdR.sc.v(4)) ;
            xiL0 = xiL.*(tiL >= -T/2 & tiL < T/2) ;
            I = find(tiL >= -T/2 & tiL < T/2) ; xiLT = xiL(I) ; tiLT = tiL(I) ;
        end
        %   Initialize the convolution to an empty time vector and an empty
        %   impulse-strength vector
        ti = [] ; xi = [] ;
        %   Find the locations and strengths of the impulses in the convolution
        %   of the two vectors
        for kL = 1:length(tiL),
            for kR = 1:length(tiR),
                ti = [ti;tiL(kL)+tiR(kR)] ; xi = [xi;xiL(kL)*xiR(kR)] ;
            end
        end
        %   Create patch objects for drawing the two impulse signals
        [tpiL,xpiL] = polyImp(tiL,xiL,xsp) ; 
        [tpiR,xpiR] = polyImp(tiR,xiR,xsp) ; 
        if cv == 'p', [tpiLT,xpiLT] = polyImp(tiLT,xiLT,xsp) ; end
        if cv == 'n', 
            %   If no convolution can be done, indicate that fact with
            %   a text message on the graphic axes
            dispNonConvolvable(h.sfnS,h.sfnP)
        else
            %   Time reverse the right-hand signal and use the result in the
            %   graphical convolution animation
            xiRrev = xiR(end:-1:1) ;
            %   Create a time vector of uniformly-spaced points for use in 
            %   graphing the convolution and the animation
            tyu = [-15:0.25:15]' ;
            %   Draw the two signals only every 4th increment value in the time
            %   vector to speed  up the animation
            for k = 1:length(tyu),
                %   Set the current time-shift amount
                ty = tyu(k) ; 
                if k == 1,
                    %   On the first pass in the for loop set up the graphic
                    %   displays for the animation and the convolution result
                    ttl = '\color{red}x_1({\tau}) ' ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color{blue}x_2({\itt} - {\tau}) '] ;
%                     ttl = [ttl,'\color{black}and '] ;
%                     ttl = [ttl,'\color[rgb]{0 0.5 0} x_1({\tau})x_2({\itt} - {\tau})'] ;
                    axes(h.sfnS) ; drawAxes(-15,15,xmn,xmx,ttl,'') ;
                    hold on ;
                    %   Draw left signal
                    pxL = patch(tpiL,xpiL,'r') ;
                    set(pxL,'EdgeColor','r','LineWidth',2) ;
                    if cv == 'p',
                        set(pxL,'FaceColor',[1,0.5,0.5],'EdgeColor',[1,0.5,0.5],...
                                'LineWidth',1) ;
                        pxp = patch(tpiLT,xpiLT,'r') ;
                        set(pxp,'EdgeColor','r','LineWidth',2) ;
                    end
                    %   Draw signal 2 time-reversed and shifted
                    pxR = patch(ty-tpiR,xpiR,'b') ;
                    set(pxR,'EdgeColor','b','LineWidth',2) ;
%                     %   Graph the product in green
%                     if cv == 'a', 
%                         tiLt = tiL ; xiLt = xiL ; 
%                     else
%                         tiLt = tiLT ; xiLt = xiLT ;
%                     end
%                     xiLxiR = 0*tiLt ;
%                     for kL = 1:length(tiLt),
%                         for kR = 1:length(tiR),
%                             if abs(ty-tiR(kR) - tiLt(kL)) < 100*eps, 
%                                 xiLxiR(kL) = xiLt(kL)*xiR(kR) ;
%                             end
%                         end
%                     end
%                     [tpxiLxiR,xpiLxiR] = polyImp(tiLt,xiLxiR,xsp) ;
%                     pxprod = patch(tpxiLxiR,xpiLxiR,'g') ;
%                     set(pxprod,'LineWidth',2,'EdgeColor','g') ;
                    %   Indicate the time shift with a text message
                    ptxt = text(ty,xtxt,['{\itt} = ',num2str(ty,'%5.2f')],'HorizontalAlignment',...
                            'center','VerticalAlignment','top','FontName','Times',...
                            'FontUnits','Normalized','FontSize',0.1,'Color','b') ;
                    ptic = line([ty,ty],[xmn,xtxt]) ; set(ptic,'Color','b') ;
                    %   Draw the convolution result
                    axes(h.sfnP) ;
                    %   Find the maximum, minimum and span of the convolution result
                    ymn = min([xi(:);0]) ; ymx = max([xi(:);0]) ;
                    if ymn == ymx, ymn = ymn - 1 ; end
                    %   Draw the axes
                    if cv == 'a',
                        drawAxes(-15,15,ymn,ymx,...
                        '\color[rgb]{0 0.5 0}Aperiodic Convolution of x_1({\itt}) with x_2({\itt})',...
                        '\itt') ;
                    else
                        drawAxes(-15,15,ymn,ymx,...
                        '\color[rgb]{0 0.5 0}Periodic Convolution of x_1({\itt}) with x_2({\itt})',...
                        '\itt') ;
                    end
                    %   Create a patch object to represent the convolution result
                    %   for shifts up to the current value.  Then draw the result.
                    I = find(ti <= ty) ; 
                    [tpi,xpi] = polyImp(ti(I),xi(I),ymx-ymn) ;
                    py = patch(tpi,xpi,'k') ; set(py,'LineWidth',2) ;
                    set(py,'EdgeColor','k','LineWidth',2) ;
                    hold on ;
                else
                    %   Shift the second time-reversed signal to the new shift amount
                    set(pxR,'Xdata',ty-tpiR) ;
%                     %   Graph the product in green
%                     if cv == 'a', 
%                         tiLt = tiL ; xiLt = xiL ; 
%                     else
%                         tiLt = tiLT ; xiLt = xiLT ;
%                     end
%                     xiLxiR = 0*tiLt ;
%                     for kL = 1:length(tiLt),
%                         for kR = 1:length(tiR),
%                             if abs(ty-tiR(kR) - tiLt(kL)) < 100*eps, 
%                                 xiLxiR(kL) = xiLt(kL)*xiR(kR) ;
%                             end
%                         end
%                     end
%                     [tpxiLxiR,xpiLxiR] = polyImp(tiLt,xiLxiR,xsp) ;
%                     set(pxprod,'XData',tpxiLxiR,'YData',xpiLxiR) ;
                    %   Update and draw the latest convolution result for shifts 
                    %   up to the current amount
                    I = find(ti <= ty) ; 
                    [tpi,xpi] = polyImp(ti(I),xi(I),ymx-ymn) ; set(py,'Xdata',tpi,'Ydata',xpi) ;
                    %   Update the text indication of shift amount
                    set(ptxt,'Position',[ty,xtxt],'String',['{\itt} = ',num2str(ty,'%5.1f')]) ;
                    set(ptic,'Xdata',[ty,ty]) ;
                end
                drawnow ;   %   Force a graph draw at each iteration to animate
            end
        end
   
    %   Function to create a patch object to represent an impulse signal
    %   consisting of either a single impulse or a periodic impulse
    function [tpi,xpi] = polyImp(ti,xi,xsp)
        %   Represent the impulse signal between -40 and 40 so that, when it
        %   is shifted between -15 and +15 the ends are never seen and a
        %   periodic impulse looks periodic
        tpi = -40 ; xpi = 0 ; 
        %   Add the arrows representing impulses one at at time in this loop
        for k = 1:length(ti),
            if abs(xi(k)) > 100*eps, 
                [tpik,xpik] = oneImp(ti(k),xi(k),xsp) ;
                tpi = [tpi;tpik] ; xpi = [xpi;xpik] ;
            end
        end
        %   Make the last point be at time t = +40
        tpi = [tpi;40] ; xpi = [xpi;0] ;
        
    function [tpi,xpi] = oneImp(ti,xi,xsp)
        %   Set the size of the arrow head based on the span data from the 
        %   ordinate of the graph
        dx = 0.15*xsp/2 ;
        tpi = [ti;ti;ti-0.2;ti;ti+0.2;ti;ti] ;
        xpi = [0;xi-sign(xi)*dx;xi-sign(xi)*dx;xi;xi-sign(xi)*dx;xi-sign(xi)*dx;0] ;
        
    %   Handle discrete-time convolution 
    function  drawConvD(sdL,sdR,h)
        %   Select and clear the sum axes for the convolution animation
        axes(h.sfnS) ; cla ;
        %   Select and clear the product axes for the convolution result
        axes(h.sfnP) ; cla ;
        cv = areConvolvable(sdL,sdR)
        %   Form a discrete time vector 
        nL = [-40:40]' ; nR = nL ;
        %   Generate new signal values for this time range
        [sdL,sdR] = newGraphVals(nL,sdL,sdR,'d') ;
        %   Use short names for the function values
        xL = sdL.sd.x ; xR = sdR.sd.x ;
        %   If a periodic convolution is indicated, find a common period and
        %   truncate the left-hand signal to the common period centered at n = 0
        %   Also create a separate left-hand signal over just the common period
        if cv == 'p',
            N = lcm(sdL.sd.v(4),sdR.sd.v(4)) ;
            xL0 = xL.*(nL >= -N/2 & nL < N/2) ;
            I = find(nL >= -N/2 & nL < N/2) ; xLN = xL(I) ; nLN = nL(I) ;
        end
        %   Do the discrete-time convolution
        if cv == 'a',
            [y,ny] = convD(xL,nL,xR,nR) ;
        else
            [y,ny] = convD(xL0,nL,xR,nR) ;
        end
        %   Display the convolution only over the range -15<=n<=15
        I = find(abs(ny)<=15) ; ny = ny(I) ; y = y(I) ; m = nL ;
        if ~cv,
            %   If aperiodic convolution cannot be done, display a message 
            %   indicating that
            dispNonConvolvable(h.sfnS,h.sfnP)
        else
            xRrev = xR(end:-1:1) ;
            %   Do the convolution animation in this loop
            for k = 1:length(ny),
                %   Set the current time-shift value
                n = ny(k) ; 
                %   Find the maximum, minimum and span of the function values
                xmn = min([xL;xR]) ; xmx = max([xL;xR]) ; 
                if xmx == xmn, xmx = xmx + 1 ; xmn = xmn - 1 ; end
                xsp = xmx-xmn ; xtxt = xmn - xsp/20 ;
                if k == 1,
                    %   In the first pass through the loop set up the graphics
                    %   elements for the animation and convolution results
                    ttl = '\color{red}x_1[{\itm}] ' ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color{blue}x_2[{\itn} - {\itm}] '] ;
                    ttl = [ttl,'\color{black}and '] ;
                    ttl = [ttl,'\color[rgb]{0 0.5 0} x_1[{\itm}]x_2[{\itn} - {\itm}]'] ;
                    axes(h.sfnS) ; drawAxes(-15,15,xmn,xmx,ttl,'') ;
                    hold on ; 
                    %   Graph the product in green
                    if cv == 'a',
                        xLxR = prodxLxR(xL,xRrev,n) ;
                    else
                        xLxR = prodxLxR(xL0,xRrev,n) ;
                    end
                    I = find(abs(m)<=18) ;
                    pxprod = stem(m(I),xLxR(I),'filled') ;
                    set(pxprod,'LineWidth',4,'MarkerSize',12,'Color',[0 0.5 0]) ;
                    %   Graph the left function in the display window in red
                    pxL = stem(m,xL,'r','filled') ;
                    set(pxL,'LineWidth',2,'MarkerSize',4) ;
                    if cv == 'p',
                        set(pxL,'Color',[1,0.5,0.5]) ;
                        pxp = stem(nLN,xLN,'r') ;
                        set(pxp,'LineWidth',2,'MarkerSize',4) ;
                    end
                    %   Graph the time-reversed and shifted right function in blue
                    pxR = stem(n-m,xR,'b','filled') ;
                    set(pxR,'LineWidth',2,'MarkerSize',4,'EraseMode','normal') ;
                    %   Create a text indicator for the shift amount
                    ptxt = text(n,xtxt,['{\itn} = ',num2str(n,'%4.0f')],'HorizontalAlignment',...
                            'center','VerticalAlignment','top','FontName','Times',...
                            'FontUnits','Normalized','FontSize',0.1,'Color','b') ;
                    ptic = line([n,n],[xmn,xtxt]) ; set(ptic,'Color','b') ;
                    %   Display the convolution result
                    axes(h.sfnP) ;
                    %   Set the maximum and minimum range for the convolution graph
                    ymn = -1 ; ymx = 1 ;
                    ymn = min([y(:);ymn]) ; ymx = max([y(:);ymx]) ; 
                    if ymn == ymx, ymn = ymn - 1 ; end
                    %   Create the axes for the convolution result
                    if cv == 'a',
                        drawAxes(-15,15,ymn,ymx,...
                        '\color[rgb]{0 0.5 0}Aperiodic Convolution of x_1[{\itn}] with x_2[{\itn}]',...
                        '\itn') ;
                    else
                        drawAxes(-15,15,ymn,ymx,...
                        '\color[rgb]{0 0.5 0}Periodic Convolution of x_1[{\itn}] with x_2[{\itn}]',...
                        '\itn') ;
                    end
                    %   Draw the convolution result only for the first shift (one point)
                    py = stem(ny(1),y(1),'filled') ; 
                    set(py,'LineWidth',2,'MarkerSize',4,'Color',[0 0.5 0]) ;
                    hold on ;
                else
                    %   Graph the product in green
                    if cv == 'a',
                        xLxR = prodxLxR(xL,xRrev,n) ;
                    else
                        xLxR = prodxLxR(xL0,xRrev,n) ;
                    end
                    I = find(abs(m)<=18) ; 
                    set(pxprod,'XData',m(I),'YData',xLxR(I)) ;
                    %   Shift the time-reversed signal one more step
                    set(pxR,'Xdata',n-m) ;
                    %   Draw the convolution result up to the present shift
                    set(py,'Xdata',ny(1:k),'Ydata',y(1:k)) ;
                    %   Update the text indicator of shift amount
                    set(ptxt,'Position',[n,xtxt],'String',['{\itn} = ',num2str(n,'%4.0f')]) ;
                    set(ptic,'Xdata',[n,n]) ;
                end
                drawnow ;   %   Force a graph draw on each iteration of the loop
                pause(0.3) ;
            end
        end
             
    %   Function to draw a set of axes on which will be graphed a convolution
    %   animation or a convolution result
    function drawAxes(xmn,xmx,ymn,ymx,ttl,xl)
        %   Get the span of the ordinate values and set any very small limits 
        %   to zero
        ysp = ymx - ymn ; 
        if abs(ymn) < 0.1*ysp, ymn = 0 ; end
        if abs(ymx) < 0.1*ysp, ymx = 0 ; end
        %   Set a margin around the graph based on the spans of the two variables
        %   to be graphed
        xsp = xmx - xmn ; ysp = ymx - ymn ;
        xmxax = xmx + xsp/10 ; xmnax = xmn - xsp/10 ;
        ymxax = ymx + ysp/10 ; ymnax = ymn - ysp/10 ;
        axis([xmnax,xmxax,ymnax,ymxax]) ;
        %   Draw the "x" axis
        ptr = line([xmnax,xmxax],[0,0]) ; set(ptr,'Color','k') ;
        set(gca,'Clipping','on') ;
        hold on ;
            %   Draw the "y" axis
            ptr = line([0,0],[ymnax,ymxax]) ; set(ptr,'Color','k') ;
            set(gca,'Visible','off') ;
            %   Add the "x" axis label
            text(xmxax,0,xl,'HorizontalAlignment','left','VerticalAlignment',...
                    'middle','FontName','Times','FontUnits','Normalized',...
                    'FontSize',0.1) ;
            %   Add the title of the graph
            text(0,ymxax,ttl,'HorizontalAlignment','center',...
                    'VerticalAlignment','bottom','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.12,'FontWeight','bold') ;
            ptr = line([xmx,xmx],[ysp/20,-ysp/20]) ; set(ptr,'Color','k') ;
            %   Annotate the axes with scale values
            %   "x" maximum
            ptr = text(xmx,ysp/20,num2str(xmx),'HorizontalAlignment','center',...
                    'VerticalAlignment','bottom','FontUnits','Normalized',...
                    'FontName','Times','FontSize',0.1) ;
            ptr = line([xmn,xmn],[ysp/20,-ysp/20]) ; set(ptr,'Color','k') ;
            %   "x" minimum
            ptr = text(xmn,ysp/20,num2str(xmn),'HorizontalAlignment','center',...
                    'VerticalAlignment','bottom','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.1) ;
            %   "y" maximum
            if ymx ~= 0,
                ptr = line([-xsp/40,xsp/40],[ymx,ymx]) ; set(ptr,'Color','k') ;
                ptr = text(-xsp/40,ymx,num2str(ymx),'HorizontalAlignment','right',...
                        'VerticalAlignment','middle','FontUnits','Normalized',...
                        'FontName','Times','FontSize',0.1) ;
            end
            %   "y" minimum
            if ymn ~= 0,
                ptr = line([-xsp/40,xsp/40],[ymn,ymn]) ; set(ptr,'Color','k') ;
                ptr = text(-xsp/40,ymn,num2str(ymn),'HorizontalAlignment','right',...
                        'VerticalAlignment','middle','FontUnits','Normalized',...
                        'FontName','Times','FontSize',0.1) ;
            end
   
%	Function to define a single arrow head at a specified location and angle
%	with a specified length in pixels on the current axes in the current 
%	window.  A "standard" arrow has a length of 8 pixels.
%
%	x		x location in current axes units
%	y		y location in current axes units
%	theta	orientation angle in ccw radians (zero is pointing to the right)
%	pixlen	length of the arrow in pixels
%   xa      The x coordinates of the arrowhead in current axis coordinates
%   ya      The y coordinates of the arrowhead in current axis coordinates
%
%	function [x,y] = aHd(x,y,theta,pixlen)

function [xa,ya] = aHd(x,y,theta,pixlen)
	wunits = get(gcf,'Units') ; set(gcf,'Units','pixels') ;
    aunits = get(gca,'Units') ; set(gca,'Units','normalized') ;
	ws = get(gcf,'Position') ; wx = ws(3) ; wy = ws(4) ;
	as = get(gca,'Position') ; ax = as(3) ; ay = as(4) ;
	lims = axis ; dx = lims(2) -lims(1) ; dy = lims(4) - lims(3) ;
    xpixvs = [-8,0,-8] ; ypixvs = [2,0,-2] ;
	xpixvs = xpixvs*pixlen/8 ; ypixvs = ypixvs*pixlen/8 ;
	pixvs = [xpixvs ; ypixvs ; ones(1,3)] ;
	scale = [dx/(ax*wx),0,0 ; 0,dy/(ay*wy),0 ; 0,0,1] ;
	rot = [cos(theta),-sin(theta),0 ; sin(theta),cos(theta),0 ; 0,0,1] ;
	trans = [1,0,x ; 0,1,y ; 0,0,1] ;
	datvs = trans*scale*rot*pixvs ;
    xa = datvs(1,:) ; ya = datvs(2,:) ;
% 	p = patch(datvs(1,:),datvs(2,:),clr) ;
	set(gcf,'Units',wunits) ; set(gca,'Units',aunits) ;

%>>>>>>>>>>>>>>>>>>>>>Beginning of Feedback Systems Window<<<<<<<<<<<<<<<<<<<
%   Each system is described by a transfer function of the form
%   H1(s) or H2(s) = A(1-s/z1)(1-s/z2)...(1-s/zM)/((1-s/p1)(1-s/p2)...(1-s/pN))
%   for continuous-time systems or
%   H1(z) or H2(z) = A(1-z/z1)(1-z/z2)...(1-z/zM)/((1-z/p1)(1-z/p2)...(1-z/pN))
%   for discrete-time systems
%   fbs    All the parameters for the feedback systems window
%       .sz    Flag indicating whether the system is conintuous or discrete time
%       .H1c   All the parameters for the forward-path continuous-time system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .H2c   All the parameters for the feedback-path continuous-time system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .Hc   All the parameters for the continuous-time feedback system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .Tc   All the parameters for the loop transfer function of the continuous-
%               time feedback system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .H1d   All the parameters for the forward-path discrete-time system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .H2d   All the parameters for the feedback-path discrete-time system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .Hd   All the parameters for the discrete-time feedback system
%           .A    Frequency independent gain (in system object)
%           .zs   The locations of the zeros (in system object)
%           .ps   The locations of the poles (in system object)
%       .Td   All the parameters for the loop transfer function of the discrete-
%               time feedback system
%       .os1   The graphic objects representing the zeros on the pole-zero 
%               diagram for H1c or H1d 
%       .xs1   The graphic objects representing the poles on the pole-zero
%               diagram for H1c or H1d 
%       .os2   The graphic objects representing the zeros on the pole-zero 
%               diagram for H2c or H2d 
%       .xs2   The graphic objects representing the poles on the pole-zero
%               diagram for H2c or H2d 
%       .os   The graphic objects representing the zeros on the pole-zero 
%               diagram for Hc or Hd 
%       .xs   The graphic objects representing the poles on the pole-zero
%               diagram for Hc or Hd 
%       .osrl  The graphic objects representing the zeros on the pole-zero 
%               diagram for the root locus 
%       .xsrl  The graphic objects representing the poles on the pole-zero
%               diagram for the root locus 
%       .f     Vector of frequencies for the continuous-time system frequency response
%       .frc   Vector of frequency responses for the continuous-time system
%       .W     Vector of frequencies for the continuous-time system frequency response
%       .frd   Vector of frequency responses for the continuous-time system
%
%       Tags of user interface elements
%
%       fbsA1sl     Slider used to set A for the forward path
%       fbsA1ax     Axes object for display of H1 gain
%       fbsAddz1    Button used to add a zero to the forward path
%       fbsAddp1    Button used to add a pole to the forward path
%       fbsA2sl     Slider used to set A for the feedback path
%       fbsA1ax     Axes object for display of H2 gain
%       fbsAddz2    Button used to add a zero to the feedback path
%       fbsAddp2    Button used to add a pole to the feedback path
%       fbsAni      Button used to animate the display of frequency response
%       fbsClr      Button used to clear both H1 and H2 to an initial state
%       fbsSZ       Button used to toggle between continuous and discrete-time modes
%       fbsHo       Button to transfer control back to the home window
%       fbsH1ax     Axes object for displaying the poles and zeros of H1c or H1d
%       fbsH2ax     Axes object for displaying the poles and zeros of H2c or H2d
%       fbsHax      Axes object for displaying the poles and zeros of Hc or Hd
%       fbsRLax     Axes object for displaying the poles and zeros of Tc or Td
%       fbsProax    Axes object for displaying the prototype transfer function form
%       fbsSRax     Axes object for displaying the step response
%       fbsMagax    Axes object for displaying the magnitude frequency response
%       fbsPhaax    Axes object for displaying the phase frequency response
%>>>>>>>>>>>>>>>>>>>>>End of Feedback Systems Window<<<<<<<<<<<<<<<<<<<<<<<<<<

%   Create the feedback systems window and all its user interface elements
%   "bu" is the button on the home window that selects the feedback systems function
%   simulator.  "f" is a pointer to the home window
function fbs = initFBSysWind(f)
    %   Create the window
    figure('Units','Normalized','Position',...
        [0.05,0.05,0.9,0.9],'NumberTitle','off','Name',...
        'Feedback Systems','Color',[1,0.9,0.8],'Visible','off',...
        'Menubar','none','Tag','fbs') ;
    axes('Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
%     I = find(double(lo)>30) ; lo(I) = 0 ; 
%     contrastFactor = 0.4 ;
%     pattern = granite(lo,[0.9,0.85,0.6;1,1,1],contrastFactor) ;
%     image(pattern) ;
    set(gca,'Visible','off') ;
    h = guihandles(f) ;
    %   Store in the associated button on the home window a pointer
    %   to this window
    set(h.fbs,'UserData',gcf) ;
    %   Create all the user-interface elements in the window
    %   Init to empty indicating no selection yet
    %   Create feedback system window user-interface elements
    fbs = fbsUI(f) ;
    %   Store the system description in this window's gui data
    guidata(gcf,fbs) ;
    
function fbs = fbsUI(f)
%   Create a gain slider for system H1
    uicontrol('Style','Slider', 'Units','Normalized','Position',...
            [0.26,0.61,0.01,0.35], 'Callback',@setA1,'Tag','fbsA1sl','Enable',...
            'on','Visible','on','Max',10,'Min',0,'SliderStep',[1/10,1/5],...
            'Value',1,'Interruptible','off','BusyAction','cancel') ;
%   Create an axes object for display of H1 gain slider value
    axes('Position',[0.272,0.61,0.01,0.35],'Visible','off','Tag','fbsA1ax') ;
    axis([0 1 0 1]) ; 
    ptr = text(0,0.5,'1','HorizontalAlignment','left','VerticalAlignment',...
            'middle','FontName','Times','FontUnits','Normalized','FontSize',...
                0.08) ;
%   Create a button to add a zero to system H1
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
            [0.0625,0.565,0.06,0.03],'String','Add Zero(s)','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.45,'Callback',@addZero,...
            'BackgroundColor',[1,0.6,0.4],'ForeGroundColor','k','Tag','fbsAddz1',...
            'Interruptible','off','BusyAction','cancel') ;
%   Create a button to add a pole to system H1
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
            [0.1275,0.565,0.06,0.03],'String','Add Pole(s)','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.45,'Callback',@addPole,...
            'BackgroundColor',[1,0.6,0.4],'ForeGroundColor','k','Tag','fbsAddp1',...
            'Interruptible','off','BusyAction','cancel') ;
%   Create a gain slider for system H2
    uicontrol('Style','Slider','Units','Normalized','Position',[0.26,0.04,0.01,0.35],...
            'Callback',@setA2,'Tag','fbsA2sl','Enable','on','Visible','on','Max',10,...
            'Min',0,'SliderStep',[1/10,1/5],'Value',0,'Interruptible','off',...
            'BusyAction','cancel') ;
%   Create an axes object for display of H2 slider value
    axes('Position',[0.272,0.04,0.01,0.35],'Visible','off','Tag','fbsA2ax') ;
    ptr = text(0,0.5,'0','HorizontalAlignment','left','VerticalAlignment',...
            'middle','FontName','Times','FontUnits','Normalized','FontSize',...
                0.08) ;
%   Create a button to add a zero to system H2
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
            [0.0625,0.002,0.06,0.03],'String','Add Zero(s)','FontName','Utopia',...
            'FontUnits','Normalized','FontSize',0.45,'Callback',@addZero,...
            'BackgroundColor',[1,0.6,0.4],'ForeGroundColor','k','Tag','fbsAddz2',...
            'Enable','off','Interruptible','off','BusyAction','cancel') ;
%   Create a button to add a pole to system H2
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
        [0.1275,0.002,0.06,0.03],'String','Add Pole(s)','FontName','Utopia',...
        'FontUnits','Normalized','FontSize',0.45,'Callback',@addPole,...
        'BackgroundColor',[1,0.6,0.4],'ForeGroundColor','k','Tag','fbsAddp2',...
        'Enable','off','Interruptible','off','BusyAction','cancel') ;
%   Create a button to animate the overall frequency response
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
        [0.38,0.35,0.19,0.03],'String','Animate Frequency Response','FontName',...
        'Utopia','FontUnits','Normalized','FontSize',0.45,'Callback',@animateFR,...
        'BackgroundColor',[1,0.6,0.4],'ForeGroundColor','k','Tag','fbsAni',...
        'Interruptible','off','BusyAction','cancel') ;
%   Create a button to reset the simulation to an initial state
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
            [0.38,0.95,0.19,0.03],'String','Reset to Initial State','FontName',...
            'Utopia','FontUnits','Normalized','FontSize',0.45,'Callback',@resetH,...
            'BackgroundColor',[1,0.6,0.4],'ForeGroundColor','k','Tag','fbsClr',...
            'Interruptible','off','BusyAction','cancel') ;
%   Set up the window initially for continuous-time systems
    sz = 's' ; mx = 10 ;
%   Create a button to switch between continuous-time and discrete-time modes
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
            [0.38,0.90,0.19,0.03],'String','To Discrete-Time Mode','FontName',...
            'Utopia','FontUnits','Normalized','FontSize',0.45,'Callback',...
            @togglesz,'BackgroundColor',[1,0.6,0.4],'ForeGroundColor',...
            'k','Tag','fbsSZ','UserData',sz,'Interruptible','off','BusyAction',...
            'cancel') ;
%   Create a button to transfer control back to the home window
    uicontrol('Style','Pushbutton','Units','Normalized','Position',...
            [0.91,0.01,0.08,0.03],'String','Home','FontName','Utopia','FontUnits',...
            'Normalized','FontSize',0.45,'Callback',@goHome,'ForeGroundColor',...
            'k','Tag','fbsHo','UserData',f,'Interruptible','off','BusyAction',...
            'cancel') ;
%   Initialize the system objects
    fbs.H1c = tf(1,1) ; fbs.H2c = tf(0,1) ; fbs.Hc = tf(0,1) ;
    fbs.H1d = tf(1,1,1) ; fbs.H2d = tf(0,1,1) ; fbs.Hd = tf(0,1,1) ;
%   Initialize the pole-zero graphic elements to empty
    fbs.xs1 = [] ; fbs.os1 = [] ; fbs.xs2 = [] ; fbs.os2 = [] ;
    fbs.xs = [] ; fbs.os = [] ; fbs.xsrl = [] ; fbs.osrl = [] ;
%   Draw the prototype feedback system
    rec = [0.01,0.42,0.27,0.14] ;
    axes('Position',rec,'Tag','fbsSysax','Visible','off') ;
    ptr = drawSystem(rec,sz) ;
%   Draw the pole-zero diagram area for H1
    recH1 = [0.02,0.62,0.21,0.33] ;
    axes('Position',recH1,'Tag','fbsH1ax','Visible','off') ;
    ptr = drawPZ(['H_1({\it',sz,'})'],sz,mx,[]) ;
%   Draw the pole-zero diagram area for H2
    recH2 = [0.02,0.05,0.21,0.33] ;
    fbs.H2ax = axes('Position',recH2,'Tag','fbsH2ax','Visible','off') ;
    ptr = drawPZ(['H_2({\it',sz,'})'],sz,mx,[]) ;
%   Assign the pole-zero diagram area for H
    recH = [0.37,0.4,0.21,0.34] ;
    axes('Position',recH,'Tag','fbsHax','Visible','off') ;
%   Assign the pole-zero diagram area for the root locus
    recRL = [0.66,0.53,0.26,0.418] ;
    axes('Position',recRL,'Tag','fbsRLax','Visible','off') ;
%   Display the prototype transfer function form
    recPro = [0.27,0.8,0.37,0.1] ;
    axes('Position',recPro,'Tag','fbsProax','Visible','off') ;
    ptr = dispH(recPro,sz) ;
%   Create axes for step response
    recSR = [0.33,0.03,0.25,0.24] ;
    axes('Position',recSR,'Tag','fbsSRax','Visible','off') ;
%   Create axes for magnitude frequency response
    recMag = [0.63,0.28,0.35,0.2] ;
    axes('Position',recMag,'Tag','fbsMagax','Visible','off') ;
%   Create axes for phase frequency response
    recPha = [0.63,0.03,0.35,0.2] ;
    axes('Position',recPha,'Tag','fbsPhaax','Visible','off') ;

%   Function to draw the prototype feedback system block diagram
%   "rec" is the rectangular area inside which the block diagram is drawn
%   "sz" is a flag indicating whether to draw a continuous-time or discrete-
%   time block diagram
function ptr = drawSystem(rec,sz)
    %   Set the left, bottom, width and height of the diagram area and
    %   set the graphic area scale to 0 to 1 in both directions
    lt = rec(1) ; bt = rec(2) ; wd = rec(3) ; ht = rec(4) ; axis([0 1 0 1]) ;
    %   Draw a block for H1
    x = [0.4444,0.6296,0.6296,0.4444,0.4444] ; 
    y = [0.6429,0.6429,0.9286,0.9286,0.6429] ; 
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    %   Draw a block for H2
    y = [0.0714,0.0714,0.3571,0.3571,0.0714] ;
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    %   Draw input arrow
    x = [0.1481,0.2519] ; y = [0.7857,0.7857] ; ptr = line(x,y) ; set(ptr,'Color','k') ;
    x = 0.2519 ; y = 0.7857 ; [xa,ya] = aHd(x,y,0,10) ; patch(xa,ya,'k') ;
    %   Draw summing junction, circle first
    x0 = 0.2963 ; y0 = 0.7857 ; xr = 0.0444 ; yr = 0.1429 ;
    angs = [0:pi/32:2*pi] ; x = x0 + xr*cos(angs) ; y = y0 + yr*sin(angs) ;
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    %   Then the "plus sign" in the middle
    x = [0.2963,0.2963] ; y = [0.7143,0.8571] ;
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    x = [0.2741,0.3185] ; y = [0.7857,0.7857] ;
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    %   Draw error signal arrow
    x = [0.3407,0.4444] ; y = [0.7857,0.7857] ; ptr = line(x,y) ; set(ptr,'Color','k') ;
    x = 0.4444 ; y = 0.7857 ; [xa,ya] = aHd(x,y,0,10) ; patch(xa,ya,'k') ;
    %   Draw output signal arrow
    x = [0.6296,0.8148] ; y = [0.7857,0.7857] ; ptr = line(x,y) ; set(ptr,'Color','k') ;
    x = 0.8148 ; y = 0.7857 ; [xa,ya] = aHd(x,y,0,10) ; patch(xa,ya,'k') ;
    %   Draw input signal arrow for H2
    x = [0.7037,0.7037,0.6296] ; y = [0.7857,0.2143,0.2143] ; 
    ptr = line(x,y) ; set(ptr,'Color','k') ;
    x = 0.6296 ; y = 0.2143 ; [xa,ya] = aHd(x,y,pi,10) ; patch(xa,ya,'k') ;
    %   Draw output signal arrow for H2
    x = [0.4444,0.2963,0.2963] ; y = [0.2143,0.2143,0.6429] ;
    ptr = line(x,y) ; set(ptr,'Color','k') ;
    x = 0.2963 ; y = 0.6429 ; [xa,ya] = aHd(x,y,pi/2,10) ; patch(xa,ya,'k') ;
    %   Annotate the forward and feedback systems
    x = 0.5370 ; y = 0.75 ; 
    ptr = text(x,y,['H_1({\it',sz,'})'],'HorizontalAlignment','center',...
            'VerticalAlignment','middle','FontName','Times','FontUnits',...
            'Normalized','FontSize',0.15) ;
    x = 0.5370 ; y = 0.1786 ; 
    ptr = text(x,y,['H_2({\it',sz,'})'],'HorizontalAlignment','center',...
            'VerticalAlignment','middle','FontName','Times','FontUnits',...
            'Normalized','FontSize',0.15) ;
    %   Annotate input and output signals
    x = 0.1296 ; y = 0.7857 ;
    ptr = text(x,y,['X({\it',sz,'})'],'HorizontalAlignment','right',...
            'VerticalAlignment','middle','FontName','Times','FontUnits',...
            'Normalized','FontSize',0.15) ;
    x = 0.8333 ; y = 0.7857 ; 
    ptr = text(x,y,['Y({\it',sz,'})'],'HorizontalAlignment','left',...
            'VerticalAlignment','middle','FontName','Times','FontUnits',...
            'Normalized','FontSize',0.15) ;
            
% Draw a graphical grid for a pole-zero diagram
function ptr = drawPZ(H,sz,mx,ax)
    if ~isempty(ax), axes(ax) ; end
    cla ;   %   Clear the axes
    st = ['[{\it',sz,'}]'] ;    %   Create designation [s] or [z]
    axis([-mx mx -mx mx]) ;     %   Set axes scale
    if sz == 's',   %   Continuous-time case
        %   Draw a rectangular grid
        %   Draw vertical grid lines
        Nl = 10 ; dx = mx/Nl ;  %   dx is the line spacing
        x = -mx + [0:dx:2*mx] ; y = -mx + zeros(1,length(x)) ; 
        x = [x;x] ; y = [y;y+2*mx] ;
        ptr = line(x,y) ; set(ptr,'Color','k') ;
        %   Draw horizontal grid lines
        %   dx is the line spacing
        y = -mx + [0:dx:2*mx] ; x = -mx + zeros(1,length(y)) ; 
        y = [y;y] ; x = [x;x+2*mx] ;
        ptr = line(x,y) ; set(ptr,'Color','k') ;
    end
    if sz == 'z',   %   Discrete-time case
        angs = [0:pi/32:2*pi] ; %   Draw a polar grid
        %   Draw the circles of constant radius
        for n = 1:30,
            rx = mx*n/20 ; ry = mx*n/20 ; 
            x = rx*cos(angs) ; y = ry*sin(angs) ;
            ptr = line(x,y) ; set(ptr,'Color','k') ;
            if abs(rx-1) < 0.01, set(ptr,'LineWidth',2) ; end
        end
        %   Draw the lines of constant angle
        %   Increase angular resolution as radius increases
        %   Three angular resolution ranges
        rx = sqrt(2)*mx ; ry = sqrt(2)*mx ; N = 16 ;
        for n = 1:N,
            ang = n*2*pi/N ;
            x = [0,rx*cos(ang)] ; y = [0,ry*sin(ang)] ;
            ptr = line(x,y) ; set(ptr,'Color','k') ;
        end
        rx = sqrt(2)*mx ; ry = sqrt(2)*mx ; N = 32 ;
        rx0 = mx/5 ; ry0 = mx/5 ;
        for n = 1:2:N,
            ang = n*2*pi/N ;
            x = [rx0,rx]*cos(ang) ; y = [ry0,ry]*sin(ang) ;
            ptr = line(x,y) ; set(ptr,'Color','k') ;
        end
        rx = sqrt(2)*mx ; ry = sqrt(2)*mx ; N = 64 ;
        rx0 = mx/2 ; ry0 = mx/2 ;
        for n = 1:2:N,
            ang = n*2*pi/N ;
            x = [rx0,rx]*cos(ang) ; y = [ry0,ry]*sin(ang) ;
            ptr = line(x,y) ; set(ptr,'Color','k') ;
        end
    end
%   Draw real axis
    x = [-mx,mx] ; y = [0,0] ;
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    %   Draw imaginary axis
    x = [0,0] ; y = [-mx,mx] ;
    ptr = line(x,y) ; set(ptr,'Color','k','LineWidth',2) ;
    %   Annotate scale
    x = mx ; y = 0 ; 
    ptr = text(x,y,num2str(mx),'HorizontalAlignment','center','VerticalAlignment',...
            'top','FontName','Times','FontUnits','Normalized','FontSize',0.08) ;
    x = -mx ; y = 0 ;
    ptr = text(x,y,num2str(-mx),'HorizontalAlignment','center','VerticalAlignment',...
            'top','FontName','Times','FontUnits','Normalized','FontSize',0.08) ;
    x = 0 ; y = mx ; 
    ptr = text(x,y,num2str(mx),'HorizontalAlignment','right','VerticalAlignment',...
            'middle','FontName','Times','FontUnits','Normalized','FontSize',0.08) ;
    x = 0 ; y = -mx ;
    ptr = text(x,y,num2str(-mx),'HorizontalAlignment','right','VerticalAlignment',...
            'middle','FontName','Times','FontUnits','Normalized','FontSize',0.08) ;
    x = 0 ; y = 1.05*mx ;
    ptr = text(x,y,H,'HorizontalAlignment','center','VerticalAlignment',...
            'bottom','FontName','Times','FontUnits','Normalized','FontSize',0.08) ;
    %   If this is H1 or H2, put an "A" above the gain slider
    if strfind(H,'_')
        x = 1.3*mx ; y = 1.05*mx ; 
        ptr = text(x,y,'\itA','HorizontalAlignment','left','VerticalAlignment',...
                'bottom','FontName','Times','FontUnits','Normalized','FontSize',...
                0.08) ;
    end
    %   Put designation [s] or [z] just above and to the right side
    x = 0.99*mx ; y = 1.02*mx ;
    ptr = text(x,y,st,'HorizontalAlignment','right','VerticalAlignment',...
                'bottom','FontName','Times','FontUnits','Normalized','FontSize',...
                0.08) ;

%   Display the prototype form of the transfer function
function ptr = dispH(rec,sz)
    axis([0 1 0 1]) ;
    %   Left side of the equation
    x = 0.2162 ; y = 0.5 ; st = ['H({\it',sz,'}) = '] ;
    ptr = text(x,y,st,'HorizontalAlignment','left','VerticalAlignment',...
                'middle','FontName','Times','FontUnits','Normalized','FontSize',...
                0.25) ;
    %   Ratio of Y to X
    x = 0.3378 ; y = 0.5 ; st = ['Y({\it',sz,'})'] ;
    ptr = text(x,y,st,'HorizontalAlignment','left','VerticalAlignment',...
                'bottom','FontName','Times','FontUnits','Normalized','FontSize',...
                0.25) ;
    st = ['X({\it',sz,'})'] ;
    ptr = text(x,y,st,'HorizontalAlignment','left','VerticalAlignment',...
                'top','FontName','Times','FontUnits','Normalized','FontSize',...
                0.25) ;
    %   Fraction line
    x = [0.3378,0.4054] ; y = [0.46,0.46] ; ptr = line(x,y) ; set(ptr,'Color','k') ;
    %   Frequency-independent gain factor
    x = 0.4189 ; y = 0.5 ;
    ptr = text(x,y,'= {\itA}','HorizontalAlignment','left','VerticalAlignment',...
                'middle','FontName','Times','FontUnits','Normalized','FontSize',...
                0.25) ;
    %   Fraction line
    x = [0.4861,0.925] ; y = [0.46,0.46] ; ptr = line(x,y) ; set(ptr,'Color','k') ;
    %   Numerator as a polynomial in either "s" or "z"
    x = 0.4825 ; y = 0.47 ;
    st = ['(1-{\it',sz,'}/{\itz}_1)(1-{\it',sz,'}/{\itz}_2)...(1-{\it',sz,'}/{\itz}_{\itM})'] ;
    ptr = text(x,y,st,'HorizontalAlignment','left','VerticalAlignment',...
                'bottom','FontName','Times','FontUnits','Normalized','FontSize',...
                0.25) ;
    %   Denominator as a polynomial in either "s" or "z"
    x = 0.4811 ; y = 0.45 ;
    st = ['(1-{\it',sz,'}/{\itp}_1)(1-{\it',sz,'}/{\itp}_2)...(1-{\it',sz,'}/{\itp}_{\itN})'] ;
    ptr = text(x,y,st,'HorizontalAlignment','left','VerticalAlignment',...
                'top','FontName','Times','FontUnits','Normalized','FontSize',...
                0.25) ;

%   Set the frequency-independent gain for system H1
function setA1(hObject,eventdata)
    %   Get pointer to slider just selected
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
    val = get(obj,'Value') ;    %   Get slider value
    val = round(10*val)/10 ;    %   Quantize slider value to nearest 0.1
    %   Designate axes for display of slider value and set scale
    axes(h.fbsA1ax) ; axis([0 1 0 1]) ; cla ;
    %   Indicate slider value
    ptr = text(0,0.5,num2str(val),'HorizontalAlignment','left','VerticalAlignment',...
            'middle','FontName','Times','FontUnits','Normalized','FontSize',...
                0.08) ;
    sz = get(h.fbsSZ,'UserData') ;     %   Get flag indicating "s" or "z" system
    if sz == 's',   %   Continuous-time case
        %   Get the zeros, poles and gain of system 1
        [zs,ps,A] = zpkdata(fbs.H1c,'v') ; fbs.H1c = zpk(zs,ps,val) ;
    else    %   Discrete-time case
        %   Get the zeros, poles and gain of system 1
        [zs,ps,A] = zpkdata(fbs.H1d,'v') ; fbs.H1d = zpk(zs,ps,val,1) ;
    end
    %   Before refreshing graphs lock controls so user cannot interrupt
%     disableControls(h) ;
        fbs = refreshGraphs(fbs,h) ;  %   Update all graphs
%     enableControls(h) ; %   Unlock controls
    %   If the H2 gain is zero, relock the buttons for adding zeros and poles
    if sz == 's',
        [zs,ps,A] = zpkdata(fbs.H2c,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    else
        [zs,ps,A] = zpkdata(fbs.H2d,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    end
    guidata(f,fbs) ;
    
%   Update all graphs
function fbs = refreshGraphs(fbs,h)
    sz = get(h.fbsSZ,'UserData') ;   %   Get indicator of cont. or disc. time
    if sz == 's',   %   Continuous-time case
        %   Select axes for H1 poles and zeros, then draw them
        axes(h.fbsH1ax) ; fbs.xs1 = drawPoles(sz,fbs.H1c,fbs.xs1) ;
        fbs.os1 = drawZeros(sz,fbs.H1c,fbs.os1) ;
        %   Select axes for H2 poles and zeros, then draw them
        axes(h.fbsH2ax) ; fbs.xs2 = drawPoles(sz,fbs.H2c,fbs.xs2) ;
        fbs.os2 = drawZeros(sz,fbs.H2c,fbs.os2) ;
        %   Form the overall continuous-time system object
        fbs.Hc = minreal(fbsys(fbs.H1c,fbs.H2c)) ;
        %   Set scale for pole-zero graph
        mx = setmx(fbs.Hc,10) ;
        %   Select axes for H poles and zeros, then draw them
        axes(h.fbsHax) ; drawPZ('H',sz,mx,gca) ; 
        fbs.xs = [] ; fbs.xs = drawPoles(sz,fbs.Hc,fbs.xs) ;
        fbs.os = [] ; fbs.os = drawZeros(sz,fbs.Hc,fbs.os) ;
        %   Form the loop transfer function
        fbs.Tc = minreal(fbs.H1c*fbs.H2c) ; 
        %   Select axes for root locus, then draw it if loop transfer function
        %   is not zero
        axes(h.fbsRLax) ; cla ;
        [zs,ps,A] = zpkdata(fbs.Tc,'v') ; 
        if A ~= 0,
            [R,K] = rlocus(fbs.Tc) ;    %   Generate root locus data
            %   If the root locus data exist, draw the root locus
            if ~isempty(R),
                %   Set scale for root locus graph
                mx = setrlmx(R) ; mx = min(20,mx) ;
                %   Draw the grid for the root locus
                drawPZ('Root Locus',sz,mx,gca) ; 
                %   Draw the poles and zeros of the loop transfer function
                fbs.xsrl = [] ; fbs.xsrl = drawPoles(sz,fbs.Tc,fbs.xsrl) ;
                fbs.osrl = [] ; fbs.osrl = drawZeros(sz,fbs.Tc,fbs.osrl) ;
                rc = size(R) ; hold on ;
                %   Draw the root locus, one branch at a time
                for row = 1:rc(1),
                    ptr = plot(real(R(row,:)),imag(R(row,:)),'k') ;
                    set(ptr,'Color',[0 0.5 0],'LineWidth',2) ;
                end
                hold off ;
            end
        end
        %   If the system, H, is proper and stable draw its step and frequency
        %   responses
        if isproper(fbs.Hc) & isstable(fbs.Hc),
            %   Generate step response data and draw it
            [sr,t] = step(fbs.Hc) ; mn = min(0,min(sr)) ; mx = max(0,max(sr)) ;
            %   Select step response axes object
            axes(h.fbsSRax) ; 
            %   Draw the step response
            ptr = xyplot(t,sr,[0,max(t),mn,mx],'\itt','h_{-1}({\itt})','Times',...
                    0.1,'Times',0.08,'','Times',0.12,'n','c','k') ;
            %   Based on pole and zero locations, set frequency range
            [b,a] = tfdata(fbs.Hc,'v') ; [zs,ps,k] = zpkdata(fbs.Hc,'v') ;
            %   Set maximum frequency for frequency response graph
            wmx = 5*max(abs([zs;ps])) ; 
            %   Create radian frequency vector for frequency response
            if ~isempty(wmx),
                Nw = 200 ; dw = wmx/Nw ; w = [-wmx:dw:wmx]' ;
            else
                wmx = 100 ; w = [-100:2:100] ;
            end
            %   Create cyclic frequency vector also and then compute freq. resp.
            fbs.f = w/(2*pi) ; fbs.frc = freqs(b,a,w) ; 
            %   Select the frequency response magnitude axes object
            axes(h.fbsMagax) ; 
            %   Draw the frequency response magnitude
            ptr = xyplot(fbs.f,abs(fbs.frc),[-wmx/(2*pi),wmx/(2*pi),0,max(abs(fbs.frc))],...
                        '\itf','|H( {\itf} )|','Times',0.1,'Times',0.08,'','Times',0.12,...
                        'n','c','k') ;
            %   Select the frequency response phase axes object
            axes(h.fbsPhaax) ; 
            %   Draw the frequency response phase
            ptr = xyplot(fbs.f,angle(fbs.frc),[-wmx/(2*pi),wmx/(2*pi),-pi,pi],'\itf',...
                        '\<H( {\itf} )','Times',0.1,'Times',0.08,'','Times',0.12,...
                        'n','c','k') ;
            %   Draw the angle sign in the ordinate label
%             drawAngleSign(ptr.an.y.lab,0.1) ;
        else
            %   If H is improper or unstable, indicate that instead of graphing
            %   step and frequency response
            mess = '' ; if ~isproper(fbs.Hc), mess = [mess,' Improper '] ; end
            if ~isstable(fbs.Hc), mess = [mess,'Unstable '] ; end
            mess = [mess,'System'] ;
            axes(h.fbsSRax) ; cla ; axis([0 1 0 1]) ; 
            ptr = text(0.5,0.5,mess,'HorizontalAlignment','center',...
                        'VerticalAlignment','middle','FontName','Times',...
                        'FontUnits','Normalized','FontSize',0.15) ;
            axes(h.fbsMagax) ; cla ; axis([0 1 0 1]) ; 
            ptr = text(0.5,0.5,mess,'HorizontalAlignment','center',...
                        'VerticalAlignment','middle','FontName','Times',...
                        'FontUnits','Normalized','FontSize',0.18) ;
            axes(h.fbsPhaax) ; cla ; axis([0 1 0 1]) ; 
            ptr = text(0.5,0.5,mess,'HorizontalAlignment','center',...
                        'VerticalAlignment','middle','FontName','Times',...
                        'FontUnits','Normalized','FontSize',0.18) ;
            fbs.f = [] ; fbs.frc = [] ; 
        end
    else
        %   Select axes for H1 poles and zeros, then draw them
        axes(h.fbsH1ax) ; fbs.xs1 = drawPoles(sz,fbs.H1d,fbs.xs1) ;
        fbs.os1 = drawZeros(sz,fbs.H1d,fbs.os1) ;
        %   Select axes for H2 poles and zeros, then draw them
        axes(h.fbsH2ax) ; fbs.xs2 = drawPoles(sz,fbs.H2d,fbs.xs2) ;
        fbs.os2 = drawZeros(sz,fbs.H2d,fbs.os2) ;
        %   Form the overall discrete-time system object
        fbs.Hd = minreal(fbsys(fbs.H1d,fbs.H2d)) ; 
        %   Set scale for pole-zero graph
        mx = setmx(fbs.Hd,2) ;
        %   Select axes for H poles and zeros, then draw them
        axes(h.fbsHax) ; drawPZ('H',sz,mx,gca) ;
        fbs.xs = [] ; fbs.xs = drawPoles(sz,fbs.Hd,fbs.xs) ;
        fbs.os = [] ; fbs.os = drawZeros(sz,fbs.Hd,fbs.os) ;
        %   Form the loop transfer function
        fbs.Td = minreal(fbs.H1d*fbs.H2d) ; 
        %   Select axes for root locus, then draw it if loop transfer function
        %   is not zero
        axes(h.fbsRLax) ;  cla ; 
        [zs,ps,k] = zpkdata(fbs.Td,'v') ; 
        if k ~= 0,
            [R,K] = rlocus(fbs.Td) ;    %   Generate root locus data
            %   If the root locus data exist, draw the root locus
            if ~isempty(R),
                %   Set scale for root locus graph
                mx = setrlmx(R) ; mx = min(5,mx) ;
                %   Draw the grid for the root locus
                drawPZ('Root Locus',sz,mx,gca) ; 
                %   Draw the poles and zeros of the loop transfer function
                fbs.xsrl = [] ; fbs.xsrl = drawPoles(sz,fbs.Td,fbs.xsrl) ;
                fbs.osrl = [] ; fbs.osrl = drawZeros(sz,fbs.Td,fbs.osrl) ;
                rc = size(R) ; hold on ;
                %   Draw the root locus, one branch at a time
                for row = 1:rc(1),
                    ptr = plot(real(R(row,:)),imag(R(row,:)),'k') ;
                    set(ptr,'Color',[0 0.5 0],'LineWidth',2) ;
                end
                hold off ;
            end
        end
        %   If the system, H, is proper and stable draw its step and frequency
        %   responses
        if isproper(fbs.Hd) & isstable(fbs.Hd),
            %   Generate step response data and draw it
            [sr,n] = step(fbs.Hd) ; mn = min(0,min(sr)) ; mx = max(0,max(sr)) ;
            %   Select step response axes object
            axes(h.fbsSRax) ; 
            %   Draw the step response
            ptr = xyplot(n,sr,[0,max(n),mn,mx],'\itn','h_{-1}[{\itn}]','Times',...
                    0.1,'Times',0.08,'','Times',0.12,'n','d','k') ;
            %   Set frequency range
            [b,a] = tfdata(fbs.Hd,'v') ; fbs.W = [-pi:pi/200:pi]' ; 
            %   Compute frequency response
            fbs.frd = freqz(b,a,fbs.W) ;
            %   Select the frequency response magnitude axes object
            axes(h.fbsMagax) ; 
            %   Draw the frequency response magnitude
            ptr = xyplot(fbs.W,abs(fbs.frd),[-pi,pi,0,max(abs(fbs.frd))],'\Omega',...
                    '|H({\ite}^{ {\itj}\Omega})|','Times',0.1,'Times',0.08,'',...
                    'Times',0.12,'n','c','k') ;
            %   Select the frequency response phase axes object
            axes(h.fbsPhaax) ; 
            %   Draw the frequency response phase
            ptr = xyplot(fbs.W,angle(fbs.frd),[-pi,pi,-pi,pi],'\Omega',...
                    '\<H({\ite}^{ {\itj}\Omega})','Times',0.1,'Times',0.08,...
                    '','Times',0.12,'n','c','k') ;
            %   Draw the angle sign in the ordinate label
%             drawAngleSign(ptr.an.y.lab,0.1) ;
        else
            %   If H is improper or unstable, indicate that instead of graphing
            %   step and frequency response
            mess = '' ; if ~isproper(fbs.Hd), mess = [mess,' Improper '] ; end
            if ~isstable(fbs.Hd), mess = [mess,'Unstable '] ; end
            mess = [mess,'System'] ;
            axes(h.fbsSRax) ; cla ; axis([0 1 0 1]) ; 
            ptr = text(0.5,0.5,mess,'HorizontalAlignment','center',...
                        'VerticalAlignment','middle','FontName','Times',...
                        'FontUnits','Normalized','FontSize',0.15) ;
            axes(h.fbsMagax) ; cla ; axis([0 1 0 1]) ; 
            ptr = text(0.5,0.5,mess,'HorizontalAlignment','center',...
                        'VerticalAlignment','middle','FontName','Times',...
                        'FontUnits','Normalized','FontSize',0.18) ;
            axes(h.fbsPhaax) ; cla ; axis([0 1 0 1]) ; 
            ptr = text(0.5,0.5,mess,'HorizontalAlignment','center',...
                        'VerticalAlignment','middle','FontName','Times',...
                        'FontUnits','Normalized','FontSize',0.18) ;
        end
    end
    
%   Set nice graphic limits based on maximum data excursion
function mx = setmx(H,mx)
    [zs,ps,k] = zpkdata(H,'v') ; mxzp = max([abs(zs);abs(ps);mx]) ;
    mx = 10^floor(log10(mxzp)) ;
    if mx < mxzp, mx = mx*2 ; end
    if mx < mxzp, mx = mx*2.5 ; end
    if mx < mxzp, mx = mx*2 ; end

%   Set nice limits for the root locus graph
function mx = setrlmx(R)
    mxR = max([abs(real(R(:)));abs(imag(R(:)))]) ;
    mxR = max(mxR,2) ;
    mx = 10^floor(log10(mxR)) ;
    if mx < mxR, mx = mx*2 ; end
    if mx < mxR, mx = mx*2.5 ; end
    if mx < mxR, mx = mx*2 ; end

function setA2(hObject,eventdata)
    %   Get pointer to slider just selected
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
    sz = get(h.fbsSZ,'UserData') ;     %   Get flag indicating "s" or "z" system
    val = get(obj,'Value') ;    %   Get slider value
    val = round(10*val)/10 ;    %   Quantize slider value to nearest 0.1
    %   If the slider value is zero, disable buttons for adding poles and zeros
    if val > 0, 
        set(h.fbsAddp2,'Enable','on') ; set(h.fbsAddz2,'Enable','on') ;
    else
        set(h.fbsAddp2,'Enable','off') ; set(h.fbsAddz2,'Enable','off') ;
        if sz == 's', fbs.H2c = zpk([],[],0) ; else fbs.H2d = zpk([],[],0,1) ; end
    end
    %   Designate axes for display of slider value and set scale
    axes(h.fbsA2ax) ; axis([0 1 0 1]) ; cla ;
    %   Indicate slider value
    ptr = text(0,0.5,num2str(val),'HorizontalAlignment','left','VerticalAlignment',...
            'middle','FontName','Times','FontUnits','Normalized','FontSize',...
                0.08) ;
    if sz == 's',   %   Continuous-time case
        %   Get the zeros, poles and gain of system 2
        [zs,ps,A] = zpkdata(fbs.H2c,'v') ; fbs.H2c = zpk(zs,ps,val) ;
    else    %   Discrete-time case
        %   Get the zeros, poles and gain of system 1
        [zs,ps,A] = zpkdata(fbs.H2d,'v') ; fbs.H2d = zpk(zs,ps,val,1) ;
    end
    %   Before refreshing graphs lock controls so user cannot interrupt
%     disableControls(h) ;
        fbs = refreshGraphs(fbs,h) ;  %   Update all graphs
%     enableControls(h) ; %   Unlock controls
    %   If the H2 gain is zero, relock the buttons for adding zeros and poles
    if sz == 's',
        [zs,ps,A] = zpkdata(fbs.H2c,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    else
        [zs,ps,A] = zpkdata(fbs.H2d,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    end
    guidata(f,fbs) ;
    
%   Add a pole to the pole-zero graph
function addPole(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
    %   Determine which system is being graphed based on the tag of the calling
    %   button
    tg = get(obj,'Tag') ; fbs.Hnum = str2num(tg(8)) ;
    %   Select the appropriate axes object based on the system number, 1 or 2
    if fbs.Hnum == 1, axes(h.fbsH1ax) ; else axes(h.fbsH2ax) ; end
    sz = get(h.fbsSZ,'UserData') ;   %   Get flag indicating "s" or "z" system
    %   Get the pole location from the user interactively and quantize it
    [x,y] = ginput(1) ; [x,y] = quant(sz,x,y) ;
    if sz == 's',   %   Continuous-time case
        s = tf('s') ;   %   Define "s" variable
        if fbs.Hnum == 1,   %   System 1 case
            if abs(y) < 0.01,   %   Real pole case
                fbs.H1c = minreal(fbs.H1c/(s-x)) ;
            else    %   Complex-conjugate-pole-pair case
                fbs.H1c = minreal(fbs.H1c/(s^2-2*x*s+x^2+y^2)) ; 
            end
        else    %   System 2 case
            if abs(y) < 0.01,   %   Real pole case
                fbs.H2c = minreal(fbs.H2c/(s-x)) ;
            else    %   Complex-conjugate-pole-pair case
                fbs.H2c = minreal(fbs.H2c/(s^2-2*x*s+x^2+y^2)) ; 
            end
        end
    else    %   Discrete-time case
        z = tf('z',1) ; %   Define "z" variable
        if fbs.Hnum == 1,    %   System 1 case
            if abs(y) < 0.01,   %   Real pole case
                fbs.H1d = minreal(fbs.H1d/(z-x)) ;
            else   %   Complex-conjugate-pole-pair case
                fbs.H1d = minreal(fbs.H1d/(z^2-2*x*z+x^2+y^2)) ; 
            end
        else     %   System 2 case
            if abs(y) < 0.01,   %   Real pole case
                fbs.H2d = minreal(fbs.H2d/(z-x)) ;
            else   %   Complex-conjugate-pole-pair case
                fbs.H2d = minreal(fbs.H2d/(z^2-2*x*z+x^2+y^2)) ; 
            end
        end
    end
    %   Before refreshing graphs lock controls so user cannot interrupt
    disableControls(h) ;
        fbs = refreshGraphs(fbs,h) ;  %   Update all graphs
    enableControls(h) ; %   Unlock controls
    %   If the H2 gain is zero, relock the buttons for adding zeros and poles
    if sz == 's',
        [zs,ps,A] = zpkdata(fbs.H2c,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    else
        [zs,ps,A] = zpkdata(fbs.H2d,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    end
    guidata(f,fbs) ;
    
%   Quantize pole or zero location to nearest grid intersection 
function [x,y] = quant(sz,x,y)
    if sz == 's',   %   Continuous-time case
        %   Find nearest grid intersection by rounding to nearest integer
        x = round(x) ; y = round(y) ;   
    else   %   Continuous-time case
        %   Compute radius and azimuth from rectangular data
        r = sqrt(x^2+y^2) ; th = angle(x+j*y) ;
        %   Quantize to nearest 0.1 in radius
        r = round(r/0.1)*0.1 ;
        %   Based on radius, quantize angle to nearest pi/32, pi/16 or pi/8
        if r >= 1, 
            da = pi/32 ;
        else
            if r >= 0.2, da = pi/16 ; else da = pi/8 ; end 
        end
        th = round(th/da)*da ; 
        x = r*cos(th) ; y = r*sin(th) ;
    end
    
%   Draw all the poles for a system transfer function
function xs = drawPoles(sz,H,xs)
    %   Set invisible, then set to empty former pole graphic symbols
    if ~isempty(xs), set(xs,'Visible','off') ; end
    xs = [] ; 
    %   Get zeros, poles and gain factor for this system
    [zs,ps,A] = zpkdata(H,'v') ;
    %   If there are no finite poles, abort by returning
    if length(ps) == 0, return ; end
    %   Get axis scale to set the size of the pole graphic symbol
    lims = axis ; xsize = (lims(2) - lims(1))/60 ;
    %   Define lines for one pole symbol
    x = [-xsize,-xsize;xsize,xsize] ; y = [xsize,-xsize;-xsize,xsize] ;
    %   Draw all poles, one at a time indicating multiplicity if greater than one
    while length(ps) > 0,
        %   Draw one pole symbol and add pointer to that symbol to "xs"
        ptr = drawOnePole(ps(1),x,y) ; xs = [xs;ptr] ; 
        %   Detect repeated poles and indicate multiplicity if repeated
        ds = abs(ps(1)-ps) ; I = find(abs(ds)<0.01) ; 
        m = length(I) ;
        if m > 1,
            ptr = text(real(ps(1))+xsize,imag(ps(1))+xsize,num2str(m),...
                'HorizontalAlignment','left','VerticalAlignment','bottom',...
                'FontName','Utopia','FontUnits','Normalized','FontSize',...
                0.05,'FontWeight','bold','Color','r') ;
            xs = [xs;ptr] ;
        end
        %   Reduce pole vector by deleting poles already graphed
        I = find(abs(ds)>0.01) ; ps = ps(I) ;
    end
    
%   Draw one pole at coordinates (real(p),imag(p))
%   x and y define the pole graphic symbol
%   Draw the pole in red
function ptr = drawOnePole(p,x,y)
    ptr = line([real(p)+x],[imag(p)+y]) ; 
    set(ptr,'Color','r','LineWidth',2) ;

%   Add a zero to the pole-zero graph
function addZero(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
    %   Determine which system is being graphed based on the tag of the calling
    %   button
    tg = get(obj,'Tag') ; fbs.Hnum = str2num(tg(8)) ;
    %   Select the appropriate axes object based on the system number, 1 or 2
    if fbs.Hnum == 1, axes(h.fbsH1ax) ; else axes(h.fbsH2ax) ; end
    sz = get(h.fbsSZ,'UserData') ;   %   Get flag indicating "s" or "z" system
    %   Get the zero location from the user interactively and quantize it
    [x,y] = ginput(1) ; [x,y] = quant(sz,x,y) ;
    if sz == 's',   %   Continuous-time case
        s = tf('s') ;   %   Define "s" variable
        if fbs.Hnum == 1,   %   System 1 case
            if abs(y) < 0.01,    %   Real zero case
                fbs.H1c = minreal(fbs.H1c*(s-x)) ;
            else    %   Complex-conjugate-zero-pair case
                fbs.H1c = minreal(fbs.H1c*(s^2-2*x*s+x^2+y^2)) ; 
            end
        else     %   System 2 case
            if abs(y) < 0.01,    %   Real zero case
                fbs.H2c = minreal(fbs.H2c*(s-x)) ;
            else   %   Complex-conjugate-zero-pair case
                fbs.H2c = minreal(fbs.H2c*(s^2-2*x*s+x^2+y^2)) ; 
            end
        end
    else    %   Discrete-time case
        z = tf('z',1) ; %   Define "z" variable
        if fbs.Hnum == 1,     %   System 1 case
            if abs(y) < 0.01,    %   Real pole case
                fbs.H1d = minreal(fbs.H1d*(z-x)) ;
            else   %   Complex-conjugate-pole-pair case
                fbs.H1d = minreal(fbs.H1d*(z^2-2*x*z+x^2+y^2)) ; 
            end
            fbs.os1 = drawZeros(sz,fbs.H1d,fbs.os1) ;
        else      %   System 2 case
            if abs(y) < 0.01,    %   Real pole case
                fbs.H2d = minreal(fbs.H2d*(z-x)) ;
            else  %   Complex-conjugate-pole-pair case
                fbs.H2d = minreal(fbs.H2d*(z^2-2*x*z+x^2+y^2)) ; 
            end
            fbs.os2 = drawZeros(sz,fbs.H2d,fbs.os2) ;
        end
    end
    %   Before refreshing graphs lock controls so user cannot interrupt
    disableControls(h) ;
        fbs = refreshGraphs(fbs,h) ;  %   Update all graphs
    enableControls(h) ; %   Unlock controls
    %   If the H2 gain is zero, relock the buttons for adding zeros and poles
    if sz == 's',
        [zs,ps,A] = zpkdata(fbs.H2c,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    else
        [zs,ps,A] = zpkdata(fbs.H2d,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    end
    guidata(f,fbs) ;
    
%   Draw all the zeros for a system transfer function
function os = drawZeros(sz,H,os)
    %   Set invisible, then set to empty former zero graphic symbols
    if ~isempty(os), set(os,'Visible','off') ; end
    os = [] ; 
    %   Get zeros, poles and gain factor for this system
    [zs,ps,A] = zpkdata(H,'v') ;
    %   If there are no finite poles, abort by returning
    if length(zs) == 0, return ; end
    %   Get axis scale to set the size of the pole graphic symbol
    lims = axis ; osize = (lims(2) - lims(1))/60 ;
    %   Define lines for one zero symbol
    angs = 0:pi/16:2*pi ; x = osize*cos(angs) ; y = osize*sin(angs) ;
    %   Draw all zero, one at a time indicating multiplicity if greater than one
    while length(zs) > 0,
        %   Draw one zero symbol and add pointer to that symbol to "os"
        ptr = drawOneZero(zs(1),x,y) ; os = [os;ptr] ; 
        %   Detect repeated zeros and indicate multiplicity if repeated
        ds = abs(zs(1)-zs) ; I = find(abs(ds)<0.01) ; 
        m = length(I) ;
        if m > 1,
            ptr = text(real(zs(1))+osize,imag(zs(1))+osize,num2str(m),...
                'HorizontalAlignment','left','VerticalAlignment','bottom',...
                'FontName','Utopia','FontUnits','Normalized','FontSize',0.05,...
                'FontWeight','bold','Color','b') ;
            os = [os;ptr] ;
        end
        %   Reduce zero vector by deleting zeros already graphed
        I = find(abs(ds)>0.01) ; zs = zs(I) ;
    end
    
%   Draw one zero at coordinates (real(z),imag(z))
%   x and y define the zero graphic symbol
%   Draw the zero in blue
function ptr = drawOneZero(z,x,y)
    ptr = line([real(z)+x],[imag(z)+y]) ; 
    set(ptr,'Color','b','LineWidth',2) ;

%   Reset all systems back to their original states
function resetH(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
%   Initialize the system objects
    fbs.H1c = tf(1,1) ; fbs.H2c = tf(0,1) ; fbs.Hc = tf(0,1) ;
    fbs.H1d = tf(1,1,1) ; fbs.H2d = tf(0,1,1) ; fbs.Hd = tf(0,1,1) ;
%   Hide the graphic elements
    set(fbs.xs1,'Visible','off') ; set(fbs.os1,'Visible','off') ; 
    set(fbs.xs2,'Visible','off') ; set(fbs.os2,'Visible','off') ;
    set(fbs.xs,'Visible','off') ; set(fbs.os,'Visible','off') ; 
    set(fbs.xsrl,'Visible','off') ; set(fbs.osrl,'Visible','off') ;
%   Initialize the pole-zero graphic elements to empty
    fbs.xs1 = [] ; fbs.os1 = [] ; fbs.xs2 = [] ; fbs.os2 = [] ;
    fbs.xs = [] ; fbs.os = [] ; fbs.xsrl = [] ; fbs.osrl = [] ;
%   Set the slider values to 1 for H1 and 0 for H2
    set(h.fbsA1sl,'Value',1) ; set(h.fbsA2sl,'Value',0) ;
%   Set the slider values indicators to 1 for H1 and 0 for H2
    axes(h.fbsA1ax) ; cla ; axis([0 1 0 1]) ;
    ptr = text(0.5,0.5,'1','HorizontalAlignment','center',...
                'VerticalAlignment','middle','FontName','Times',...
                'FontUnits','Normalized','FontSize',0.08) ; 
    axes(h.fbsA2ax) ; cla ; axis([0 1 0 1]) ;
    ptr = text(0.5,0.5,'0','HorizontalAlignment','center',...
                'VerticalAlignment','middle','FontName','Times',...
                'FontUnits','Normalized','FontSize',0.08) ; 
%   Disable the add zeros and add poles functions for H1 and H2
    set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
%   Erase the step response and frequency response graphs
    axes(h.fbsSRax) ; cla ; axes(h.fbsMagax) ; cla ; axes(h.fbsPhaax) ; cla ;
%   Erase the H and root locus pole-zero graphs
    axes(h.fbsHax) ; cla ; axes(h.fbsRLax) ; cla ;
    guidata(f,fbs) ;

%   Toggle between continuous and discrete time each time this button is pressed
function togglesz(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
    sz = get(h.fbsSZ,'UserData') ;   %   Get the "s" or "z" indicator
    recSys = [0.01,0.42,0.27,0.14] ; recPro = [0.27,0.8,0.37,0.1] ;
    if sz == 's',   %   Continuous-time to discrete-time case
        axes(h.fbsSysax) ; cla ; ptr = drawSystem(recSys,'z') ;
        axes(h.fbsProax) ; cla ; ptr = dispH(recPro,'z') ;
        %   Change button message to reflect going to discrete-time status
        set(h.fbsSZ,'UserData','z','String','To Continuous Time Mode') ; 
        %   Draw discrete-time polar grid for H1 and H2 poles and zeros
        axes(h.fbsH1ax) ; ptr = drawPZ(['H_1({\itz})'],'z',2,gca) ;
        axes(h.fbsH2ax) ; ptr = drawPZ(['H_2({\itz})'],'z',2,gca) ;
        %   Set the slider values and their indications back to the last values 
        %   for H1
        [zs,ps,A] = zpkdata(fbs.H1d,'v') ; set(h.fbsA1sl,'Value',A) ;
        %   Select slider-value axis, clear graphics and set scale
        axes(h.fbsA1ax) ; cla ; axis([0 1 0 1]) ;
        %   Update slider value indication
        ptr = text(0.5,0.5,num2str(A),'HorizontalAlignment','center',...
                    'VerticalAlignment','middle','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.08) ; 
        %   Set the slider values and their indications back to the last values 
        %   for H2
        [zs,ps,A] = zpkdata(fbs.H2d,'v') ; set(h.fbsA2sl,'Value',A) ;
        %   Select slider-value axis, clear graphics and set scale
        axes(h.fbsA2ax) ; cla ; axis([0 1 0 1]) ;
        %   Update slider value indication
        ptr = text(0.5,0.5,num2str(A),'HorizontalAlignment','center',...
                    'VerticalAlignment','middle','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.08) ; 
    else   %   Discrete-time to continuous-time case
        axes(h.fbsSysax) ; cla ; ptr = drawSystem(recSys,'s') ;
        axes(h.fbsProax) ; cla ; ptr = dispH(recPro,'s') ;
        %   Change button message to reflect going to continuous-time status
        set(h.fbsSZ,'UserData','s','String','To Discrete Time Mode') ;
        %   Draw continuous-time rectangular grid for H1 and H2 poles and zeros
        axes(h.fbsH1ax) ; ptr = drawPZ(['H_1({\its})'],'s',10,gca) ;
        axes(h.fbsH2ax) ; ptr = drawPZ(['H_2({\its})'],'s',10,gca) ;
        %   Set the slider values and their indications back to the last values 
        %   for H1
        [zs,ps,A] = zpkdata(fbs.H1c,'v') ; set(h.fbsA1sl,'Value',A) ;
        %   Select slider-value axis, clear graphics and set scale
        axes(h.fbsA1ax) ; cla ; axis([0 1 0 1]) ;
        %   Update slider value indication
        ptr = text(0.5,0.5,num2str(A),'HorizontalAlignment','center',...
                    'VerticalAlignment','middle','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.08) ; 
        %   Set the slider values and their indications back to the last values 
        %   for H2
        [zs,ps,A] = zpkdata(fbs.H2c,'v') ; set(h.fbsA2sl,'Value',A) ;
        %   Select slider-value axis, clear graphics and set scale
        axes(h.fbsA2ax) ; cla ; axis([0 1 0 1]) ;
        %   Update slider value indication
        ptr = text(0.5,0.5,num2str(A),'HorizontalAlignment','center',...
                    'VerticalAlignment','middle','FontName','Times',...
                    'FontUnits','Normalized','FontSize',0.08) ;
    end
    %   Initialize all pole and zero symbols to empty
    fbs.xs1 = [] ; fbs.xs2 = [] ; fbs.os1 = [] ; fbs.os2 = [] ;
    fbs.xs = [] ; fbs.os = [] ; fbs.xsrl = [] ; fbs.osrl = [] ;
    %   Before refreshing graphs lock controls so user cannot interrupt
    disableControls(h) ;
        fbs = refreshGraphs(fbs,h) ;  %   Update all graphs
    enableControls(h) ; %   Unlock controls
    %   If the H2 gain is zero, relock the buttons for adding zeros and poles
    if sz == 's',
        [zs,ps,A] = zpkdata(fbs.H2c,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    else
        [zs,ps,A] = zpkdata(fbs.H2d,'v')  ;
        if A == 0, 
            set(h.fbsAddz2,'Enable','off') ; set(h.fbsAddp2,'Enable','off') ;
        end
    end
    guidata(f,fbs) ;

%   Animate the pole-zero diagram and the frequency response graphs to show the
%   graphical relationship between them
function animateFR(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; fbs = guidata(f) ;
    sz = get(h.fbsSZ,'UserData') ;   %   Get flag indicating "s" or "z" system
    if sz == 's',   %   Continuous-time case
        if ~isempty(fbs.f), %   If the freq. resp. vector is not empty
            %   Get poles, zeros and gain of overall system and select axes
            [zs,ps,A] = zpkdata(fbs.Hc,'v') ; axes(h.fbsHax) ;
            %   Initialize vector of zero symbol and vector of pole symbol pointers
            %   Restrict animation frequency range to minimum of 20 and maximum
            %   of largest frequency in freq. resp. vector
            zvs = [] ; pvs = [] ; mx = min(20,max(abs(fbs.f))*(2*pi)) ;
            I = find(abs(fbs.f)*(2*pi) <= mx) ; frc = fbs.frc(I) ; f = fbs.f(I) ;
            fmn = min(f) ;
            %   Set up initial graphic vectors from poles and zeros to omega axis
            for m = 1:length(zs),
                ptr = line([real(zs(m)),0],[imag(zs(m)),2*pi*fmn]) ;
                set(ptr,'Color','b','LineWidth',2) ; zvs = [zvs,ptr] ;
            end
            for m = 1:length(ps),
                ptr = line([real(ps(m)),0],[imag(ps(m)),2*pi*fmn]) ;
                set(ptr,'Color','r','LineWidth',2) ; pvs = [pvs,ptr] ;
            end
            %   Initialize a green dot on pole-zero diagram and on frequency
            %   response graphs to indicate progress of frequency during 
            %   animation
            hold on ; wmark = plot(0,2*pi*fmn,'g.') ; set(wmark,'MarkerSize',18) ; 
            axes(h.fbsMagax) ; hold on ;
            mag = plot(fmn,abs(frc(1)),'g.') ; set(mag,'MarkerSize',18) ;
            axes(h.fbsPhaax) ; hold on ;
            pha = plot(fmn,angle(frc(1)),'g.') ; set(pha,'MarkerSize',18) ;
        end
        %   Go through the full frequency response range moving the vectors and
        %   the frequency green dot synchronously
        dk = floor(length(f)/50) ; dk = max(dk,1) ;
        for k = 2:dk:length(f),
            for m = 1:length(zvs),
                set(zvs(m),'Ydata',[imag(zs(m)),2*pi*f(k)]) ;
            end
            for m = 1:length(pvs),
                set(pvs(m),'Ydata',[imag(ps(m)),2*pi*f(k)]) ;
            end
            set(wmark,'Ydata',2*pi*f(k)) ;
            set(mag,'Xdata',f(k),'Ydata',abs(frc(k))) ;
            set(pha,'Xdata',f(k),'Ydata',angle(frc(k))) ;
            drawnow ;
        end
    else   %   Discrete-time case
        if ~isempty(fbs.W), %   If the freq. resp. vector is not empty
            %   Get poles, zeros and gain of overall system and select axes
            [zs,ps,A] = zpkdata(fbs.Hd,'v') ; axes(h.fbsHax) ;
            %   Initialize vector of zero symbol and vector of pole symbol pointers
            %   Animation frequency range is -pi to +pi
            zvs = [] ; pvs = [] ; Wmn = min(fbs.W) ;
            %   Set up initial graphic vectors from poles and zeros to unit circle
            for m = 1:length(zs),
                ptr = line([real(zs(m)),cos(Wmn)],[imag(zs(m)),sin(Wmn)]) ;
                set(ptr,'Color','b','LineWidth',2) ; zvs = [zvs,ptr] ;
            end
            for m = 1:length(ps),
                ptr = line([real(ps(m)),cos(Wmn)],[imag(ps(m)),sin(Wmn)]) ;
                set(ptr,'Color','r','LineWidth',2) ; pvs = [pvs,ptr] ;
            end
            %   Initialize a green dot on pole-zero diagram and on frequency
            %   response graphs to indicate progress of frequency during 
            %   animation
            hold on ; wmark = plot(cos(Wmn),sin(Wmn),'g.') ; set(wmark,'MarkerSize',18) ; 
            axes(h.fbsMagax) ; hold on ;
            mag = plot(Wmn,abs(fbs.frd(1)),'g.') ; set(mag,'MarkerSize',18) ;
            axes(h.fbsPhaax) ; hold on ;
            pha = plot(Wmn,angle(fbs.frd(1)),'g.') ; set(pha,'MarkerSize',18) ;
        end
        %   Go through the full frequency response range moving the vectors and
        %   the frequency green dot synchronously
        for k = 2:4:length(fbs.W),
            for m = 1:length(zvs),
                set(zvs(m),'Xdata',[real(zs(m)),cos(fbs.W(k))],'Ydata',...
                        [imag(zs(m)),sin(fbs.W(k))]) ;
            end
            for m = 1:length(pvs),
                set(pvs(m),'Xdata',[real(ps(m)),cos(fbs.W(k))],'Ydata',...
                        [imag(ps(m)),sin(fbs.W(k))]) ;
            end
            set(wmark,'Xdata',cos(fbs.W(k)),'Ydata',sin(fbs.W(k))) ;
            set(mag,'Xdata',fbs.W(k),'Ydata',abs(fbs.frd(k))) ;
            set(pha,'Xdata',fbs.W(k),'Ydata',angle(fbs.frd(k))) ;
            drawnow ;
        end
    end
    %   Make vectors, pole symbols and zero symbols all invisible
    set(zvs,'Visible','off') ; set(pvs,'Visible','off') ;
    set(mag,'Visible','off') ; set(pha,'Visible','off') ;
    set(wmark,'Visible','off') ;

%>>>>>>>>>>>>>>>>>>>>>Beginning of Sampling Window<<<<<<<<<<<<<<<<<<<<<<<<<<<<
%   sam  All parameters for the sampling window
%       .ho    A button to return to the home window
%       .par   Parameters describing the analog input signal
%           .name Signal type name
%           .ptr  Pointer to text object containing name of signal
%           .A    Amplitude
%           .w    Width parameter
%           .t0   Delay 
%           .f0   Fundamental frequency
%       .xai The analog input signal
%           .t    Vector of times for graphing
%           .x    Vector of x values for graphing
%           .f    Vector of cyclic frequencies for graphing continuous CTFT of x (X)
%           .X    Vector of X values
%           .fi   Vector of cyclic frequencies for graphing impulse CTFT of x (X)
%           .Xi   Vector of X impulse strengths
%       .fs    Sampling rate in samples/second
%       .xdi   The digital input signal
%           .n    Vector of times
%           .x    Vector of values
%           .W    Vector of radian frequencies for graphing continuous DTFT of x (X)
%           .X    Vector of X values
%           .Wi   Vector of radian frequencies for graphing impulse DTFT of x (X)
%           .Xi   Vector of X impulse strengths
%       .df   The digital filter
%           .typ   Filter type (None or Butterworth)
%           .ord   Filter order (1-6)
%           .act   Filter action (lowpass, highpass, bandpass or bandstop)
%           .WLo   Lower cutoff frequency in radians
%           .Whi   Upper cutoff frequency in radians
%       .xdo    The digital output signal
%           .n    Vector of times
%           .x    Vector of values
%           .W    Vector of radian frequencies for graphing continuous DTFT of x (X)
%           .X    Vector of X values
%           .Wi   Vector of radian frequencies for graphing impulse DTFT of x (X)
%           .Xi   Vector of X impulse strengths
%       .in    The interpolator (ideal sinc, ZOH or FOH)
%       .xint    The interpolated analog signal
%           .t    Vector of times for graphing
%           .x    Vector of x values for graphing
%           .f    Vector of cyclic frequencies for graphing continuous CTFT of x (X)
%           .X    Vector of X values
%           .fi   Vector of cyclic frequencies for graphing impulse CTFT of x (X)
%           .Xi   Vector of X impulse strengths
%       .af   The analog filter
%           .typ    Filter type (None or Butterworth)
%           .ord    Filter order (1-6)
%           .act    Filter action (lowpass, highpass, bandpass or bandstop)
%           .fLo    Lower cutoff frequency in Hz
%           .fHi    Upper cutoff frequency in Hz
%       .xao    The analog output signal formed by filtering xint
%           .t    Vector of times for graphing
%           .x    Vector of x values for graphing
%           .f    Vector of cyclic frequencies for graphing continuous CTFT of x (X)
%           .X    Vector of X values
%           .fi   Vector of cyclic frequencies for graphing impulse CTFT of x (X)
%           .Xi   Vector of X impulse strengths
%
%   User Interface object tags:
%       Signal menu               samSigMenu
%       Signal parameter sliders and editable text
%           Amplitude             samASl        samAEt
%           Time delay            samt0Sl       samt0Et
%           Width (or Tau)        samwSl        samwEt
%           Frequency             samf0Sl       samf0Et
%       Digital filter menu       samDfMenu
%           Filter type menu      samDfTyp
%               None label          samDfTypNone
%               Butterworth label   samDfTypBw
%           Filter action menu    samDfAct
%               Lowpass label       samDfActLP
%               Highpass label      samDfActHP
%               Bandpass label      samDfActBP
%               Bandstop label      samDfActBS
%           Filter order menu     samDfOrd
%               Order 1 label       samDfOrd1
%               Order 2 label       samDfOrd2
%                   .                   .
%                   .                   .
%               Order 6 label       samDfOrd10
%       Digital filter type text    samDfTypTx
%       Digital filter action text  samDfActTx
%       Digital filter order text   samDfOrdTx
%       Digital filter freq sliders and editable text
%           Low corner              samDfWLoSl        samDfWLoEt
%           High corner             samDfWHiSl        samDfWHiEt
%       Interpolation menu        samInMenu
%           Ideal (Sinc) label      samInSinc
%           Zero-order hold label   samInZOH
%           First-order hold label  samInFOH
%       Analog filter menu       samAfMenu
%           Filter type menu      samAfTyp
%               None label          samAfTypNone
%               Butterworth label   samAfTypBw
%           Filter action menu    samAfAct
%               Lowpass label       samAfActLP
%               Highpass label      samAfActHP
%               Bandpass label      samAfActBP
%               Bandstop label      samAfActBS
%           Filter order menu     samAfOrd
%               Order 1 label       samAfOrd1
%               Order 2 label       samAfOrd2
%                   .                   .
%                   .                   .
%               Order 6 label      samAfOrd10
%       Analog filter type text    samAfTypTx
%       Analog filter action text  samAfActTx
%       Analog filter order text   samAfOrdTx
%       Analog filter freq sliders and editable text
%           Low corner              samAfWLoSl        samAfWLoEt
%           High corner             samAfWHiSl        samAfWHiEt
%       Graphing axes for signals and transforms
%           Analog x in             samxaiAx    samXaiMagAx    samXaiPhaAx
%           Digital x in            samxdiAx    samXdiMagAx    samXdiPhaAx
%           Digital x out           samxdoAx    samXdoMagAx    samXdoPhaAx
%           Analog x interp.        samxaintAx  samXaintMagAx  samXaintPhaAx
%           Analog x out            samxaoAx    samXaoMagx     samXaoPhaAx
%>>>>>>>>>>>>>>>>>>>>>End of Sampling Window<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

function sam = initSampWind(f)
    %   Define background and foreground colors
    bkClr = [1,0.9,0.8] ; fgClr = 0.8*bkClr ;
    %   Create the window
    figure('Units','Normalized','Position',...
        [0.05,0.05,0.9,0.9],'NumberTitle','off','Name','Sampling','Color',...
        bkClr,'Visible','off','ToolBar','none','Tag','sam','Menubar','none') ;
    h = guihandles(f) ;
    %   Store in the associated button on the home window a pointer
    %   to this window
    axes('Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
    set(h.sam,'UserData',gcf) ;
    %   Create all the user-interface elements in the window
    sam = samUI(f) ;
    guidata(gcf,sam) ;
    
function disableMenus(h)
    set(h.samSigMenu,'Enable','off') ;
    set(h.samDfMenu,'Enable','off') ;
    set(h.samInMenu,'Enable','off') ;
    set(h.samAfMenu,'Enable','off') ;
    
function enableMenus(h)
    set(h.samSigMenu,'Enable','on') ;
    set(h.samDfMenu,'Enable','on') ;
    set(h.samInMenu,'Enable','on') ;
    set(h.samAfMenu,'Enable','on') ;
    
function sam = samUI(f)
    %   Add a button to transfer control back to the home window
    sam.ho = uicontrol('Style','Pushbutton',...
        'Units','Normalized','Position',[0.91,0.01,0.08,0.03],'String',...
        'Home','FontName','Utopia','FontUnits','Normalized','FontSize',...
        0.6,'Callback',@goHome,'ForeGroundColor','k','Tag','sfnho',...
        'UserData',f,'Interruptible','off','BusyAction','cancel') ;
%   Names of signal types to be used as analog signals in
    names = {'Exponential','Rectangle','Triangle','Sinc','Sine','Cosine',...
            'Rectangular Wave','Triangular Wave'} ;
    %   Create a uimenu of signal names
    sigMenu = uimenu('Position',1,'Label','Signal Type','Tag','samSigMenu') ;
    for n = 1:length(names),
        st = ['uimenu(sigMenu,''Label'',''',names{n},...
                ''',''Callback'',@samSigName) ;'] ;
        eval(st) ;
    end
    sam.par.name = 'Exponential' ;  %   Initial signal choice
    ch = get(sigMenu,'Children') ; 
    set(ch(end),'Checked','on') ;   %   Check mark for initial choice Exponential
    %   Create a menu of digital filter parameter choices
    samDfMenu = uimenu('Position',2,'Label','Digital Filter','Tag','samDfMenu') ;
        %   Filter types None, Ideal, Butterworth, Chebyshev I and II and Elliptic
        uimenu(samDfMenu,'Label','Filter Type','Tag','samDfTyp') ; 
        sam.df.typ = 'None' ; %   Initial filter type
        %   Filter actions, lowpass, highpass, bandpass and bandstop
        uimenu(samDfMenu,'Label','Filter Action','Tag','samDfAct') ;
        sam.df.act = 'Lowpass' ;    %   Initialize filter action to lowpass
        %   Filter orders 1 through 10
        uimenu(samDfMenu,'Label','Filter Order','Tag','samDfOrd') ;
        sam.df.ord = 1 ;    %   Initialize filter order to 1
        %   The sequence of children is #1 at the BOTTOM of the menu list as it 
        %   appears on the screen and the last one at the TOP of the list
        ch = get(samDfMenu,'Children') ;
            %   Put the 6 filter orders in a submenu
            for n = 1:6,
                st = ['uimenu(ch(1),''Label'',''',num2str(n),...
                    ''',''Callback'',@samDfOrd,''Tag'',''samDfOrd',...
                    num2str(n),''',''Enable'',''off'') ;'] ;
                eval(st) ; 
            end
            h = guihandles(gcf) ; set(h.samDfOrd1,'Checked','on') ;
            %   Put the four filter actions in a submenu
            uimenu(ch(2),'Label','Lowpass','Callback',@samDfAct,'Tag',...
                            'samDfActLP','Checked','on','Enable','off') ;
            uimenu(ch(2),'Label','Highpass','Callback',@samDfAct,'Tag',...
                            'samDfActHP','Enable','off') ;
            uimenu(ch(2),'Label','Bandpass','Callback',@samDfAct,'Tag',...
                            'samDfActBP','Enable','off') ;
            uimenu(ch(2),'Label','Bandstop','Callback',@samDfAct,'Tag',...
                            'samDfActBS','Enable','off') ;
            %   Put the two filter types in a submenu
            uimenu(ch(3),'Label','None','Callback',@samDfTyp,'Tag',...
                            'samDfTypNone','Checked','on') ;
            uimenu(ch(3),'Label','Butterworth','Callback',@samDfTyp,'Tag','samDfypBw') ;
    %   Create a menu of interpolation choices
    samInMenu = uimenu('Position',3,'Label','Interpolation','Tag','samInMenu') ;
        uimenu(samInMenu,'Label','Ideal (Sinc)','Callback',@samInTyp,'Checked','on') ;
        sam.in.typ = 'Ideal (Sinc)' ; %   Initial interpolation choice
        uimenu(samInMenu,'Label','Zero-Order Hold','Callback',@samInTyp) ;
        uimenu(samInMenu,'Label','First-Order Hold','Callback',@samInTyp) ;
        sam.in = 'Ideal (Sinc)' ; 
    %   Create a menu of analog filter parameter choices
    samAfMenu = uimenu('Position',4,'Label','Analog Filter','Tag','samAfMenu') ;
        %   Filter types None, Ideal, Butterworth, Chebyshev I and II and Elliptic
        uimenu(samAfMenu,'Label','Filter Type','Tag','samAfTyp') ;
        sam.af.typ = 'None' ;   %   Initial filter type choice
        %   Filter actions, lowpass, highpass, bandpass and bandstop
        uimenu(samAfMenu,'Label','Filter Action','Tag','samAfAct') ;
        sam.af.act = 'Lowpass' ;
        %   Filter orders 1 through 10
        uimenu(samAfMenu,'Label','Filter Order','Tag','samAfOrd') ;
        sam.af.ord = 1 ;
        ch = get(samAfMenu,'Children') ;
            %   Put the 6 filter orders in a submenu
            for n = 1:6,
                st = ['uimenu(ch(1),''Label'',''',num2str(n),...
                    ''',''Callback'',@samAfOrd,''Tag'',''samAfOrd',...
                    num2str(n),''',''Enable'',''off'') ;'] ;
                eval(st) ; 
            end
            h = guihandles(gcf) ; set(h.samAfOrd1,'Checked','on') ;
            %   Put the four filter actions in a submenu
            uimenu(ch(2),'Label','Lowpass','Callback',@samAfAct,'Tag',...
                            'samAfActLP','Checked','on','Enable','off') ;
            uimenu(ch(2),'Label','Highpass','Callback',@samAfAct,'Tag',...
                            'samAfActHP','Enable','off') ;
            uimenu(ch(2),'Label','Bandpass','Callback',@samAfAct,'Tag',...
                            'samAfActBP','Enable','off') ;
            uimenu(ch(2),'Label','Bandstop','Callback',@samAfAct,'Tag',...
                            'samAfActBS','Enable','off') ;
            %   Put the five filter types in a submenu
            uimenu(ch(3),'Label','None','Callback',@samAfTyp,'Tag',...
                        'samAfTypNone','Checked','on') ;
            uimenu(ch(3),'Label','Butterworth','Callback',@samAfTyp,'Tag','samAfTypBw') ;
    %   Set the foreground and background colors
    bkClr = [1,0.9,0.8] ; fgClr = 0.4*bkClr ;
    %   Set the analog and digital foreground and background colors
    abkClr = [165,195,239]/255 ; aFgClr = [9,89,204]/255 ;
    dbkClr = [242,129,148]/255 ; dFgClr = [168,7,34]/255 ;
    %   Set up the parameter control panel
    paramPanel = uipanel('Units','Normalized','Position',[0,0.7,1,0.3],...
                'BackgroundColor',bkClr,'FontName','Utopia','FontUnits',...
                'Normalized','FontSize',0.05,'BorderType','line','Tag',...
                'samParamPanel','BorderWidth',5,'HighlightColor',fgClr) ;
            axes('Parent',paramPanel,'Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
%             I = find(double(lo)>30) ; lo(I) = 0 ; 
%             contrastFactor = 0.4 ;
%             pattern = granite(lo,[0.9,0.85,0.6;1,1,1],contrastFactor) ;
%             rc = size(pattern) ; rows = round(rc(1)*0.3) ;
%             image(pattern(1:rows,:,:)) ;
            set(gca,'Visible','off') ;
            %   Set up a signal parameter sub-panel inside the parameter panel
            sigPanel = uipanel(paramPanel,'Units','Normalized','Position',...
                [0.005,0.56,0.23,0.42],'BackgroundColor',abkClr,'BorderType',...
                'line','Tag','samsigPanel','BorderWidth',3,'HighlightColor','b','Title',...
                'Signal Parameters','FontUnits','Normalized','TitlePosition',...
                'centertop','FontSize',0.2,'ForegroundColor',aFgClr) ;
            uicontrol(sigPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.05,0.45,0.4,0.2],'Max',1,'Min',-1,...
                    'SliderStep',[0.05,0.25],'Value',1,'Tag','samASl','Callback',...
                     @samASl,'Enable','on','Visible','on','Interruptible','off',...
                     'BusyAction','Cancel') ;
            uicontrol(sigPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.05,0.65,0.4,0.25],'String','Amplitude = 1',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samAEt','Callback',@samAEt,'Interruptible','off',...
                    'BusyAction','cancel') ;
            sam.par.A = 1 ;
            uicontrol(sigPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.55,0.45,0.4,0.2],'Max',1,'Min',0.1,...
                    'SliderStep',[1/9,3/9],'Value',0.5,'Tag','samwSl','Callback',...
                     @samwSl,'Enable','on','Visible','on','Interruptible','off',...
                    'BusyAction','Cancel') ;
            uicontrol(sigPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.55,0.65,0.4,0.25],'String','Tau = 0.5',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samwEt','Callback',@samwEt,'Interruptible','off',...
                    'BusyAction','cancel') ;
            sam.par.w = 0.5 ;
            uicontrol(sigPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.05,0.05,0.4,0.2],'Max',1,'Min',-1,...
                    'SliderStep',[0.05/2,0.25/2],'Value',0,'Tag','samt0Sl','Callback',...
                     @samt0Sl,'Enable','on','Visible','on','Interruptible','off',...
                    'BusyAction','Cancel') ;
            uicontrol(sigPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.05,0.25,0.4,0.25],'String','Time Delay = 0',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samt0Et','Callback',@samt0Et,'Interruptible','off',...
                    'BusyAction','cancel') ;
            sam.par.t0 = 0 ;
            uicontrol(sigPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.55,0.05,0.4,0.2],'Max',10,'Min',1,...
                    'SliderStep',[1/9,3/9],'Value',1,'Tag','samf0Sl','Callback',...
                     @samf0Sl,'Enable','off','Visible','off','Interruptible','off',...
                    'BusyAction','Cancel') ;
            uicontrol(sigPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.55,0.25,0.4,0.25],'String','Frequency = 1 Hz',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samf0Et','Enable','off','Visible','off','Callback',...
                    @samf0Et,'Interruptible','off','BusyAction','cancel') ;
            sam.par.f0 = 1 ;
            sysAx = axes('Units','Normalized','Position',[0,0,1,1],'Visible',...
                        'off','Parent',paramPanel,'FontUnits','Normalized','Tag',...
                        'samSysPanelAx') ;
            axis([0,1,0,1]) ;
            ptr = text(0.088,0.3,'x_{\itai}({\itt})','FontName','Times','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','right',...
                'VerticalAlignment','baseline','Color',aFgClr) ;
            sam.par.ptr = text(0.058,0.22,sam.par.name,'FontName','Times','FontUnits',...
                'Normalized','FontSize',0.08,'HorizontalAlignment','center',...
                'VerticalAlignment','top','Color',aFgClr) ;
            ptr = sysArrow(0.11,0.33,aFgClr) ;
            dClr = dbkClr - abkClr ; hdClr = dFgClr - aFgClr ;
            for n = 1:110,
                x = [0.11+n/1000;0.11+n/1000] ; y = [0.06;0.46] ;
                clr = abkClr + dClr*n/110 ; ptr = line(x,y) ; 
                set(ptr,'Color',clr,'LineWidth',2) ;
                yhi = [0.45;0.46] ;
                hclr = aFgClr + hdClr*n/110 ; hptr = line(x,yhi) ; 
                set(hptr,'Color',hclr,'LineWidth',2) ;
                ylo = [0.06;0.07] ; lptr = line(x,ylo) ; 
                set(lptr,'Color',hclr,'LineWidth',2) ;
                if n < 4, set(ptr,'Color',aFgClr) ; end
                if n > 108, set(ptr,'Color',dFgClr) ; end
            end
            ptr = text(0.165,0.3,'Sampler','FontName','Utopia','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','center',...
                'VerticalAlignment','bottom','Color',fgClr) ;
            uicontrol(paramPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.118,0.08,0.1,0.06],'Max',100,'Min',1,...
                    'SliderStep',[1/99,9/99],'Value',10,'Tag','samfsSl','Callback',...
                     @samfsSl,'Interruptible','off','BusyAction','Cancel') ;
            uicontrol(paramPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.118,0.15,0.1,0.1],'String','10 samples/second',...
                    'BackgroundColor',bkClr,'ForegroundColor',fgClr,'Tag','samfsEt',...
                    'Callback',@samfsEt,'Interruptible','off','BusyAction','cancel') ;
            sam.fs = 10 ;
            ptr = text(0.30,0.3,'x_{\itdi}[{\itn}]','FontName','Times','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','right',...
                'VerticalAlignment','baseline','Color',dFgClr) ;
            ptr = sysArrow(0.24,0.33,dFgClr) ; ptr = sysArrow(0.33,0.33,dFgClr) ;
            DfPanel = uipanel(paramPanel,'Units','Normalized','Position',...
                [0.33,0.02,0.112,0.96],'BackgroundColor',dbkClr,'BorderType',...
                'line','Tag','samDfPanel','BorderWidth',3,'HighlightColor',dFgClr,'Title',...
                'Digital Filter','FontUnits','Normalized','TitlePosition',...
                'centertop','FontSize',0.1,'ForegroundColor',dFgClr) ;
            uicontrol(DfPanel,'Style','Text','Units','Normalized',...
                    'Position',[0.1,0.8,0.8,0.1],'String','Type: None',...
                    'BackgroundColor',dbkClr,'ForegroundColor',dFgClr,'Tag',...
                    'samDfTypTx') ;
            uicontrol(DfPanel,'Style','Text','Units','Normalized',...
                    'Position',[0.1,0.7,0.8,0.1],'String','Action: N/A',...
                    'BackgroundColor',dbkClr,'ForegroundColor',dFgClr,'Tag',...
                    'samDfActTx') ;
            uicontrol(DfPanel,'Style','Text','Units','Normalized',...
                    'Position',[0.1,0.6,0.8,0.1],'String','Order: N/A',...
                    'BackgroundColor',dbkClr,'ForegroundColor',dFgClr,'Tag',...
                    'samDfOrdTx') ;
            uicontrol(DfPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.1,0.3,0.8,0.1],'Max',3,'Min',0.1,...
                    'SliderStep',[0.1/2.9,0.5/2.9],'Value',0.1,'Tag','samDfWLoSl',...
                    'Callback',@samDfWLoSl,'Enable','off','Visible','off',...
                    'Interruptible','off','BusyAction','Cancel') ;
            uicontrol(DfPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.1,0.4,0.8,0.1],'String','Low Corner: 0.1 rad',...
                    'BackgroundColor',dbkClr,'ForegroundColor',dFgClr,'Tag',...
                    'samDfWLoEt','Callback',@samDfWLoEt,'Enable','off',...
                    'Visible','off','Interruptible','off','BusyAction','cancel') ;
            uicontrol(DfPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.1,0.1,0.8,0.1],'Max',3.1,'Min',0.2,...
                    'SliderStep',[0.1/2.9,0.5/2.9],'Value',3.1,'Tag','samDfWHiSl',...
                    'Callback',@samDfWHiSl,'Enable','off','Visible','off',...
                    'Interruptible','off','BusyAction','Cancel') ;
            uicontrol(DfPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.1,0.2,0.8,0.1],'String','High Corner: 3.1 rad',...
                    'BackgroundColor',dbkClr,'ForegroundColor',dFgClr,'Tag',...
                    'samDfWHiEt','Callback',@samDfWHiEt,'Enable','off',...
                    'Visible','off','Interruptible','off','BusyAction','cancel') ;
            sam.df.WLo = 0.1 ; sam.df.WHi = 3.1 ;
            axes(sysAx) ; 
            set(gcf,'Visible','off') ;
            axis([0,1,0,1]) ;
            ptr = sysArrow(0.46,0.33,dFgClr) ; ptr = sysArrow(0.535,0.33,dFgClr) ;
            ptr = text(0.514,0.3,'x_{\itdo}[{\itn}]','FontName','Times','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','right',...
                'VerticalAlignment','baseline','Color',dFgClr) ;
            for n = 1:115,
                x = [0.535+n/1000;0.535+n/1000] ; y = [0.18;0.54] ;
                clr = dbkClr - dClr*n/110 ; ptr = line(x,y) ; 
                set(ptr,'Color',clr,'LineWidth',2) ;
                yhi = [0.53;0.54] ;
                hclr = dFgClr - hdClr*n/115 ; hptr = line(x,yhi) ; 
                set(hptr,'Color',hclr,'LineWidth',2) ;
                ylo = [0.18;0.19] ; lptr = line(x,ylo) ; 
                set(lptr,'Color',hclr,'LineWidth',2) ;
                if n < 4, set(ptr,'Color',dFgClr) ; end
                if n > 113, set(ptr,'Color',aFgClr) ; end
            end
            ptr = text(0.595,0.4,'Interpolator','FontName','Utopia','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','center',...
                'VerticalAlignment','bottom','Color',fgClr) ;
            uicontrol(paramPanel,'Style','Text','Units','Normalized',...
                'Position',[0.543,0.23,0.1,0.06],'String','Ideal (Sinc)',...
                'BackgroundColor',bkClr,'ForegroundColor',fgClr,'Tag','samInTx') ;
            ptr = text(0.727,0.3,'x_{\itin}({\itt})','FontName','Times','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','right',...
                'VerticalAlignment','baseline','Color',aFgClr) ;
            ptr = sysArrow(0.67,0.33,aFgClr) ; ptr = sysArrow(0.755,0.33,aFgClr) ;
            AfPanel = uipanel(paramPanel,'Units','Normalized','Position',...
                [0.755,0.02,0.112,0.96],'BackgroundColor',abkClr,'BorderType',...
                'line','Tag','samAfPanel','BorderWidth',3,'HighlightColor',aFgClr,'Title',...
                'Analog Filter','FontUnits','Normalized','TitlePosition',...
                'centertop','FontSize',0.08,'ForegroundColor',...
                aFgClr) ;
            uicontrol(AfPanel,'Style','Text','Units','Normalized',...
                    'Position',[0.1,0.8,0.8,0.1],'String','Type: None',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samAfTypTx') ;
            uicontrol(AfPanel,'Style','Text','Units','Normalized',...
                    'Position',[0.1,0.7,0.8,0.1],'String','Action: N/A',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samAfActTx') ;
            uicontrol(AfPanel,'Style','Text','Units','Normalized',...
                    'Position',[0.1,0.6,0.8,0.1],'String','Order: N/A',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samAfOrdTx') ;
            uicontrol(AfPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.1,0.3,0.8,0.1],'Max',48,'Min',1,...
                    'SliderStep',[1/47,10/47],'Value',1,'Tag','samAffLoSl',...
                    'Callback',@samAffLoSl,'Enable','off','Visible','off',...
                    'Interruptible','off','BusyAction','Cancel') ;
            uicontrol(AfPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.1,0.4,0.8,0.1],'String','Low Corner: 1 Hz',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samAffLoEt','Callback',@samAffLoEt,'Enable','off',...
                    'Visible','off','Interruptible','off','BusyAction','cancel') ;
            uicontrol(AfPanel,'Style','Slider','Units','Normalized',...
                    'Position',[0.1,0.1,0.8,0.1],'Max',49,'Min',2,...
                    'SliderStep',[1/47,10/47],'Value',49,'Tag','samAffHiSl',...
                    'Callback',@samAffHiSl,'Enable','off','Visible','off',...
                    'Interruptible','off','BusyAction','Cancel') ;
            uicontrol(AfPanel,'Style','Edit','Units','Normalized',...
                    'Position',[0.1,0.2,0.8,0.1],'String','High Corner: 49 Hz',...
                    'BackgroundColor',abkClr,'ForegroundColor',aFgClr,'Tag',...
                    'samAffHiEt','Callback',@samAffHiEt,'Enable','off',...
                    'Visible','off','Interruptible','off','BusyAction','cancel') ;
            sam.af.fLo = 1 ; sam.af.fHi = 49 ;
            ptr = text(0.94,0.3,'x_{\itao}({\itt})','FontName','Times','FontUnits',...
                'Normalized','FontSize',0.1,'HorizontalAlignment','right',...
                'VerticalAlignment','baseline','Color',aFgClr) ;
            ptr = sysArrow(0.885,0.33,aFgClr) ;
    graphPanel = uipanel('Units','Normalized','Position',[0,0,1,0.7],...
                'BackgroundColor',bkClr,'FontName','Utopia','FontUnits',...
                'Normalized','FontSize',0.05,'BorderType','line','Tag',...
                'samGraphPanel','BorderWidth',5,'HighlightColor',fgClr) ;
            axes('Parent',graphPanel,'Units','Normalized','Visible','off','Position',[0 0 1 1]) ;
%             rc = size(pattern) ; rows = round(rc(1)*0.3) ;
%             image(pattern(rows:rc(1),:,:)) ;
            set(gca,'Visible','off') ;
            %   Set the widths and heights of the graph axes
            wd = 0.18 ; ht = 0.327 ; 
            %   Set the initial corners of the graphs
            lt = [0.01,0.21,0.41,0.61,0.81] ; 
            bt = [0.01,0.327,0.66] ;
            %   Assign axes for xai and its CTFT
            axes('Units','Normalized','Position',[lt(1),bt(3),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samxaiAx') ;
            axes('Units','Normalized','Position',[lt(1),bt(2),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXaiMagAx') ;
            axes('Units','Normalized','Position',[lt(1),bt(1),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXaiPhaAx') ;
            %   Assign axes for xdi and its DTFT
            axes('Units','Normalized','Position',[lt(2),bt(3),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samxdiAx') ;
            axes('Units','Normalized','Position',[lt(2),bt(2),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXdiMagAx') ;
            axes('Units','Normalized','Position',[lt(2),bt(1),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXdiPhaAx') ;
            %   Assign axes for xdo and its DTFT
            axes('Units','Normalized','Position',[lt(3),bt(3),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samxdoAx') ;
            axes('Units','Normalized','Position',[lt(3),bt(2),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXdoMagAx') ;
            axes('Units','Normalized','Position',[lt(3),bt(1),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXdoPhaAx') ;
            %   Assign axes for xin and its CTFT
            axes('Units','Normalized','Position',[lt(4),bt(3),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samxinAx') ;
            axes('Units','Normalized','Position',[lt(4),bt(2),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXinMagAx') ;
            axes('Units','Normalized','Position',[lt(4),bt(1),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXinPhaAx') ;
            %   Assign axes for xao and its CTFT
            axes('Units','Normalized','Position',[lt(5),bt(3),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samxaoAx') ;
            axes('Units','Normalized','Position',[lt(5),bt(2),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXaoMagAx') ;
            axes('Units','Normalized','Position',[lt(5),bt(1),wd,ht],...
                'Visible','off','Parent',graphPanel,'FontUnits','Normalized',...
                'Tag','samXaoPhaAx') ;

function ptr = sysArrow(x,y,aFgClr)
    xl = x - [0.02,0] ; yl = [y,y] ;
    ptr = line(xl,yl) ; set(ptr,'Color',aFgClr) ;
    xa = x - [0.006,0,0.006] ; ya = y + [-0.01,0,0.015] ; 
    ptr = patch(xa,ya,aFgClr) ; set(ptr,'EdgeColor',aFgClr) ;

function samSigName(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.par.name = get(obj,'Label') ; moveMenuCheckMark(obj) ;
    axes(h.samSysPanelAx) ; set(sam.par.ptr,'String',sam.par.name) ;
    updateSliderAndEdit(sam,h) ;
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    
function updateSliderAndEdit(sam,h)
    if strcmp(sam.par.name,'Exponential') | strcmp(sam.par.name,'Rectangle') | ...
        strcmp(sam.par.name,'Triangle') | strcmp(sam.par.name,'Sinc'),
        set(h.samf0Sl,'Enable','off','Visible','off') ;
        set(h.samf0Et,'Enable','off','Visible','off') ;
        set(h.samwSl,'Enable','on','Visible','on') ;
        set(h.samwEt,'Enable','on','Visible','on') ;
    end
    if strcmp(sam.par.name,'Sine') | strcmp(sam.par.name,'Cosine'),
        set(h.samf0Sl,'Enable','on','Visible','on') ;
        set(h.samf0Et,'Enable','on','Visible','on') ;
        set(h.samwSl,'Enable','off','Visible','off') ;
        set(h.samwEt,'Enable','off','Visible','off') ;
    end
    if strcmp(sam.par.name,'Rectangular Wave') | strcmp(sam.par.name,'Triangular Wave'),
        set(h.samf0Sl,'Enable','on','Visible','on') ;
        set(h.samf0Et,'Enable','on','Visible','on') ;
        set(h.samwSl,'Enable','on','Visible','on') ;
        set(h.samwEt,'Enable','on','Visible','on') ;
    end
    if strcmp(sam.par.name,'Exponential'),
        set(h.samwEt,'String',['Tau = ',num2str(sam.par.w)]) ;
    else
        set(h.samwEt,'String',['Width = ',num2str(sam.par.w)]) ;
    end
    
function sam = NewSamplingGraphs(sig1,sam,h)
%     disableControls(h) ; 
    disableMenus(h) ;
    sam = computeSignal(sig1,sam) ;
    sigs = {'ai','di','do','in','ao'} ;
    names = {sam.par.name,'Sampled','Digitally Filtered','Interpolated',...
                'Analog Filtered'} ;
    g1 = 1 ; while ~strcmp(sigs{g1},sig1) & g1 < 5, g1 = g1 + 1 ; end
    for g = g1:5, 
        if g < 2 | g > 3,
            analogSigGraph(sigs{g},names{g},sam,h) ;
        else
            digitalSigGraph(sigs{g},names{g},sam,h) ;
        end
    end
%     enableControls(h) ; 
    enableMenus(h) ;
    
function analogSigGraph(ss,name,sam,h)
    st = ['tAx = h.samx',ss,'Ax ;'] ; eval(st) ;
    st = ['magAx = h.samX',ss,'MagAx ;'] ; eval(st) ;
    st = ['phaAx = h.samX',ss,'PhaAx ;'] ; eval(st) ;
    st = ['xa = sam.x',ss,' ;'] ; eval(st) ;
    xmn = min(min(xa.x),0) ; xmx = max(max(xa.x),0) ; 
    axes(tAx) ;
    ptr = xyplot(xa.t,xa.x,[xa.t(1),xa.t(end),xmn,xmx],'\itt',['x_{\it',ss,'}({\itt})'],...
                'Times',0.1,'Times',0.08,name,'Times',0.12,'n','c',...
                [9,89,204]/255) ;
    if ~isempty(xa.f),
        if strcmp(ss,'in') | strcmp(ss,'ao'),
            [xa.f,xa.X] = DFTShift(xa.f,xa.X) ;    
            I = find(abs(xa.f) <= 2*max(sam.xai.f)) ; xa.f = xa.f(I) ; xa.X = xa.X(I) ;
        end
        axes(magAx) ; 
        ptr = xyplot(xa.f,abs(xa.X),[min(xa.f),max(xa.f),0,max(abs(xa.X))],' \itf ',['|X_{\it',ss,'}( {\itf} )|'],...
                    'Times',0.1,'Times',0.08,'CTFT','Times',0.12,'n','c',[9,89,204]/255) ;
        axes(phaAx) ;
        Xpha = angle(xa.X) ; N = length(xa.f) ; 
        I = find(abs(abs(Xpha)-pi) < pi/1000) ; Xpha(I) = pi ;
        I = find(xa.f < 0) ; 
        Xpha(I) = -Xpha(N:-1:N-length(I)+1) ;
        I = find(abs(xa.X) < 1e-13) ; Xpha(I) = NaN ;
        I = find(abs(xa.X) < max(abs(xa.X))/1000) ; Xpha(I) = NaN ;
        ptr = xyplot(xa.f,Xpha,[min(xa.f),max(xa.f),-pi,pi],' \itf ',['\<X_{\it',ss,'}( {\itf} )'],...
                    'Times',0.1,'Times',0.08,'','Times',0.12,'n','c',[9,89,204]/255) ;
%         drawAngleSign(ptr.an.y.lab,0.1) ;
    end
    if ~isempty(xa.fi),
        if strcmp(ss,'in') | strcmp(ss,'ao'),
            [xa.fi,xa.Xi] = DFTShift(xa.fi,xa.Xi) ;    
            I = find(abs(xa.fi) <= 2*max(sam.xai.fi)) ; xa.fi = xa.fi(I) ; xa.Xi = xa.Xi(I) ;
        end
        axes(magAx) ; 
        ptr = xyplot({xa.fi,[min(xa.fi);max(xa.fi)]},{abs(xa.Xi),[0;0]},[min(xa.fi),max(xa.fi),0,...
                max(abs(xa.Xi))],' \itf ',['|X_{\it',ss,'}( {\itf} )|'],...
                'Times',0.1,'Times',0.08,'CTFT','Times',0.12,'n',{'i','c'},[9,89,204]/255) ;

        axes(phaAx) ;
        Xipha = angle(xa.Xi) ; N = length(xa.fi) ; 
        I = find(abs(abs(Xipha)-pi) < pi/1000) ; Xipha(I) = pi ;
        I = find(xa.fi < 0) ; 
        Xipha(I) = -Xipha(N:-1:N-length(I)+1) ;
        I = find(abs(xa.Xi) < 1e-13) ; Xipha(I) = NaN ;
        I = find(abs(xa.Xi) < max(abs(xa.Xi))/1000) ; Xipha(I) = NaN ;
        ptr = xyplot(xa.fi,Xipha,[min(xa.fi),max(xa.fi),-pi,pi],' \itf ',['\<X_{\it',ss,'}( {\itf} )'],...
                    'Times',0.1,'Times',0.08,'','Times',0.12,'n','s',[9,89,204]/255) ;
        ch = get(ptr.cv{1},'Children') ; set(ch,'MarkerSize',4) ;
%         drawAngleSign(ptr.an.y.lab,0.1) ;
    end
    
function digitalSigGraph(ss,name,sam,h)
    st = ['nAx = h.samx',ss,'Ax ;'] ; eval(st) ;
    st = ['magAx = h.samX',ss,'MagAx ;'] ; eval(st) ;
    st = ['phaAx = h.samX',ss,'PhaAx ;'] ; eval(st) ;
    st = ['xd = sam.x',ss,' ;'] ; eval(st) ;
    xmn = min(min(xd.x),0) ; xmx = max(max(xd.x),0) ; 
    axes(nAx) ;
    ptr = xyplot(xd.n,xd.x,[xd.n(1),xd.n(end),xmn,xmx],'\itn',['x_{\it',ss,'}[{\itn}]'],...
                'Times',0.1,'Times',0.08,name,'Times',0.12,'n','d',...
                [168,7,34]/255) ;
    if ~isempty(xd.W),
        [xd.W,xd.X] = DFTShift(xd.W,xd.X) ;    
        axes(magAx) ; 
        I = find(xd.W >= -2*pi & xd.W <= 2*pi) ; 
        xd.W = xd.W(I) ; xd.X = xd.X(I) ;
        ptr = xyplot(xd.W,abs(xd.X),[-pi,pi,0,max(abs(xd.X))],'\Omega',['|X_{\it',ss,'}({\ite}^{ {\itj}{\Omega}})|'],...
                    'Times',0.1,'Times',0.08,'DTFT','Times',0.12,'n','c',[168,7,34]/255) ;
        Xpha = angle(xd.X) ; N = length(xd.W) ; 
        I = find(abs(abs(Xpha)-pi) < pi/1000) ; Xpha(I) = pi ;
        I = find(xd.W < 0) ; 
        I = I(2:end) ; Xpha(I) = -Xpha(N:-1:N-length(I)+1) ;
        I = find(abs(xd.X) < max(abs(xd.X))/1000) ; Xpha(I) = NaN ;
        I = find(abs(xd.X) < 1e-13) ; Xpha(I) = NaN ;
        axes(phaAx) ;
        ptr = xyplot(xd.W,Xpha,[-pi,pi,-pi,pi],'\Omega',['\<X_{\it',ss,'}({\ite}^{ {\itj}{\Omega}})'],...
                    'Times',0.1,'Times',0.08,'','Times',0.12,'n','c',[168,7,34]/255) ;
%         drawAngleSign(ptr.an.y.lab,0.1) ;
    end
    if ~isempty(xd.Wi),
        [xd.Wi,xd.Xi] = DFTShift(xd.Wi,xd.Xi) ;    
        axes(magAx) ; 
        I = find(xd.Wi >= -2*pi & xd.Wi <= 2*pi) ; 
        xd.Wi = xd.Wi(I) ; xd.Xi = xd.Xi(I) ;
        ptr = xyplot({xd.Wi,[-pi;pi]},{abs(xd.Xi),[0;0]},[-pi,pi,0,max(abs(xd.Xi))],...
                '\Omega',['|X_{\it',ss,'}({\ite}^{ {\itj}{\Omega}})|'],...
                    'Times',0.1,'Times',0.08,'DTFT','Times',0.12,'n',{'i','c'},[168,7,34]/255) ;
        axes(phaAx) ;
        Xipha = angle(xd.Xi) ; N = length(xd.Wi) ; 
        I = find(abs(abs(Xipha)-pi) < pi/1000) ; Xipha(I) = pi ;
        I = find(xd.Wi < 0) ; 
        I = I(2:end) ; Xipha(I) = -Xipha(N:-1:N-length(I)+1) ;
        I = find(abs(xd.Xi) < max(abs(xd.Xi))/1000) ; Xipha(I) = NaN ;
        I = find(abs(xd.Xi) < 1e-13) ; Xipha(I) = NaN ;
        ptr = xyplot(xd.Wi,Xipha,[-pi,pi,-pi,pi],'\Omega',['\<X_{\it',ss,'}({\ite}^{ {\itj}{\Omega}})'],...
                    'Times',0.1,'Times',0.08,'','Times',0.12,'n','s',[168,7,34]/255) ;
        ch = get(ptr.cv{1},'Children') ; set(ch,'MarkerSize',4) ;
%         drawAngleSign(ptr.an.y.lab,0.1) ;
    end
    
function sam = computeSignal(sig1,sam)
    if strcmp(sig1,'ai'), 
        sam = computexai(sam) ; sam = computexdi(sam) ; sam = computexdo(sam) ;
        sam = computexin(sam) ; 
        sam = computexao(sam) ;
    end
    if strcmp(sig1,'di'),
        sam = computexdi(sam) ; sam = computexdo(sam) ;
        sam = computexin(sam) ; sam = computexao(sam) ;
    end
    if strcmp(sig1,'do'),
        sam = computexdo(sam) ; sam = computexin(sam) ; 
        sam = computexao(sam) ;
    end
    if strcmp(sig1,'in'),
        sam = computexin(sam) ; sam = computexao(sam) ;
    else
        sam = computexao(sam) ;
    end
    
function sam = computexai(sam)
    ep = 10*eps ;
    %   Get the function parameters
    A = sam.par.A ; t0 = sam.par.t0 ; w = sam.par.w ; f0 = sam.par.f0 ;
    T0 = 1/f0 ; tau = sam.par.w ;
    %   Get the sampling rate and set the maximum time for energy signals 
    %   based on the analog and digital filter bandwidths
    fs = sam.fs ; Ts = 1/fs ; 
    [dBW,aBW] = getBWs(sam) ;   %   Get the digital and analog bandwidths
    dtmax = (4*pi*Ts/dBW)*(1+sam.df.ord/10) ; atmax = (4/aBW)*(1+sam.af.ord/10) ;
    tmax = max(dtmax,atmax) ;
    %   Find the period of a sampled power signal
    if ~isempty(f0), ; xdiN0 = fs/gcd(f0,fs) ; else xdiN0 = [] ; end
    switch sam.par.name,
        case 'Exponential', sam.xai = compxaiExp(A,t0,tau,tmax) ;
        case 'Rectangle', sam.xai = compxaiRect(A,t0,w,tmax) ;
        case 'Triangle', sam.xai = compxaiTri(A,t0,w,tmax) ;
        case 'Sinc', sam.xai = compxaiSinc(A,t0,w,tmax) ;
        case 'Sine', sam.xai = compxaiSin(A,t0,f0) ;
        case 'Cosine', sam.xai = compxaiCos(A,t0,f0) ;
        case 'Rectangular Wave', sam.xai = compxaiRwav(A,t0,w,f0) ;
        case 'Triangular Wave', sam.xai = compxaiTwav(A,t0,w,f0) ;
    end
        
function xai = compxaiExp(A,t0,tau,tmax)
    ep = 100*eps ; tmin = -2*tau ; tmax = max(tmax,10*tau) ; dt = tau/10 ;
    xai.t = [tmin;-ep;ep;[dt:dt:tmax]'] ; 
    xai.t = t0 + xai.t ; xai.t = sort([xai.t;0]) ;
    xai.x = A*exp(-(xai.t-t0)/tau).*us(xai.t-t0) ;
    w0 = 1/tau ; w = [-5*w0:w0/50:5*w0]' ; xai.f = w/(2*pi) ;
    xai.X = A*exp(-j*w*t0)./(j*w + w0) ; xai.fi = [] ; xai.Xi = [] ;

function xai = compxaiRect(A,t0,w,tmax)
    ep = 100*eps ; tmin = -2*w ; tmax = max(tmax,2*w) ;
    xai.t = [tmin;-w/2-ep;-w/2+ep;+w/2-ep;+w/2+ep;tmax] ; 
    xai.t = t0 + xai.t ; xai.t = sort([xai.t;0]) ; xai.x = A*rect(-(xai.t-t0)/w) ;
    fnull = 1/w ; df = fnull/50 ; xai.f = [ep,df:df:fnull-df,fnull-ep]' ;
    xai.f = [xai.f-4*fnull;xai.f-3*fnull;xai.f-2*fnull;xai.f-fnull;xai.f;...
            xai.f+fnull;xai.f+2*fnull;xai.f+3*fnull] ;
    xai.X = A*w*sinc(w*xai.f).*exp(-j*2*pi*xai.f*t0) ; xai.fi = [] ; xai.Xi = [] ;
    
function xai = compxaiTri(A,t0,w,tmax)
    ep = 100*eps ; tmin = -2*w ; tmax = max(tmax,2*w) ; xai.t = [tmin;-w;0;w;tmax] ;
    xai.t = t0 + xai.t ;  xai.t = sort([xai.t;0]) ; xai.x = A*tri(-(xai.t-t0)/w) ;
    fnull = 1/w ; df = fnull/50 ; xai.f = [ep,df:df:fnull-df,fnull-ep]' ;
    xai.f = [xai.f-4*fnull;xai.f-3*fnull;xai.f-2*fnull;xai.f-fnull;xai.f;...
            xai.f+fnull;xai.f+2*fnull;xai.f+3*fnull] ;
    xai.X = A*w*sinc(w*xai.f).^2.*exp(-j*2*pi*xai.f*t0) ; xai.fi = [] ; xai.Xi = [] ;
    
function xai = compxaiSinc(A,t0,w,tmax)
    ep = 100*eps ; tmin = min(-tmax,-6*w) ; tmax = max(tmax,6*w) ; 
    dt = w/8 ; xai.t = [tmin:dt:tmax]' ; 
    xai.t = t0 + xai.t ;  xai.t = sort([xai.t;0]) ; xai.x = A*sinc(-(xai.t-t0)/w) ;
    df = (1/w)/50 ; xai.f = [-2/w:df:2/w]' ; 
    xai.f = sort([xai.f;-1/(2*w)-ep;-1/(2*w)+ep;1/(2*w)-ep;1/(2*w)+ep]) ;
    xai.X = A*w*rect(w*xai.f).^2.*exp(-j*2*pi*xai.f*t0) ; xai.fi = [] ; xai.Xi = [] ;
    
function xai = compxaiSin(A,t0,f0)
    npts = 128 ; T0 = 1/f0 ; dt = 4*T0/npts ; xai.t = dt*[0:npts-1]' ;
    xai.x = A*sin(2*pi*f0*(xai.t-t0)) ;
    xai.fi = [-f0,f0]' ; xai.Xi = ([j,-j].').*(A/2).*exp(-j*2*pi*xai.fi*t0) ;
    xai.f = [] ; xai.X = [] ;
    
function xai = compxaiCos(A,t0,f0)
    npts = 128 ; T0 = 1/f0 ; dt = 4*T0/npts ; xai.t = dt*[0:npts-1]' ;
    xai.x = A*cos(2*pi*f0*(xai.t-t0)) ;
    xai.fi = [-f0,f0]' ; xai.Xi = ([1,1].').*(A/2).*exp(-j*2*pi*xai.fi*t0) ;
    xai.f = [] ; xai.X = [] ;
    
function  xai = compxaiRwav(A,t0,w,f0)
    ep = 100*eps ; T0 = 1/f0 ; xai.t = [0;w/2-ep;w/2+ep;T0-w/2-ep;T0-w/2+ep;T0] ; 
    xai.t = sort(t0+[xai.t-T0;xai.t;xai.t+T0;xai.t+2*T0]) ; 
    xai.x = rectwave(xai.t,T0,t0,w,0,A) ;
    nH = ceil(4/(w*f0)) ; xai.fi = [-nH*f0:f0:nH*f0]' ; 
    xai.Xi = (A*w/T0)*sinc(w*xai.fi).*exp(-j*2*pi*xai.fi*t0) ; 
    xai.f = [] ; xai.X = [] ;
    
function xai = compxaiTwav(A,t0,w,f0)
    T0 = 1/f0 ; xai.t = [0;w;T0-w;T0] ; 
    kmin = floor(-2*w/T0) ; kmax = ceil(2*w/T0) ;
    for k = kmin:kmax, xai.t = [xai.t+k*T0;xai.t] ; end
    xai.t = sort(t0 + xai.t) ; xai.x = triwave(xai.t,T0,t0,w,0,A) ;
    nH = ceil(4/(w*f0)) ; xai.fi = [-nH*f0:f0:nH*f0]' ; 
    xai.Xi = (A*w/T0)*sinc(w*xai.fi).^2.*exp(-j*2*pi*xai.fi*t0) ; 
    xai.f = [] ; xai.X = [] ;
    
function sam = computexdi(sam)
    ep = 10*eps ;
    %   Get the function parameters
    A = sam.par.A ; t0 = sam.par.t0 ; w = sam.par.w ; f0 = sam.par.f0 ;
    T0 = 1/f0 ; tau = sam.par.w ;
    %   Get the sampling rate and set the maximum time for energy signals 
    %   based on the analog and digital filter bandwidths
    fs = sam.fs ; Ts = 1/fs ; 
    [dBW,aBW] = getBWs(sam) ;   %   Get the digital and analog bandwidths
    dtmax = (4*pi*Ts/dBW)*(1+sam.df.ord/10) ; atmax = (4/aBW)*(1+sam.af.ord/10) ;
    tmax = max(dtmax,atmax) ;
    %   Find the period of a sampled power signal
    if ~isempty(f0), xdiN0 = fs/gcd(f0,fs) ; else xdiN0 = [] ; end
    %   Handle the case in which fs = f0.  Graph enough points to see the
    %   shape of the sampled signal xdi
    while xdiN0 < 8, xdiN0 = 2*xdiN0 ; end
    switch sam.par.name,
        case 'Exponential', sam.xdi = compxdiExp(A,t0,tau,tmax,Ts,sam.xai) ;
        case 'Rectangle', sam.xdi = compxdiRect(A,t0,w,tmax,Ts,sam.xai) ;
        case 'Triangle', sam.xdi = compxdiTri(A,t0,w,tmax,Ts,sam.xai) ;
        case 'Sinc', sam.xdi = compxdiSinc(A,t0,w,tmax,Ts,sam.xai) ;
        case 'Sine', sam.xdi = compxdiSin(A,t0,f0,xdiN0,Ts) ;
        case 'Cosine', sam.xdi = compxdiCos(A,t0,f0,xdiN0,Ts) ;
        case 'Rectangular Wave', sam.xdi = compxdiRwav(A,t0,w,f0,xdiN0,Ts) ;
        case 'Triangular Wave', sam.xdi = compxdiTwav(A,t0,w,f0,xdiN0,Ts) ;
    end
                
function xdi = compxdiExp(A,t0,tau,tmax,Ts,xai)
    xdi = setDTEnergy(xai.t,Ts) ; N = length(xdi.n) ;
    xdi.x = A*exp(-(xdi.n*Ts-t0)/tau).*us(xdi.n*Ts-t0) ;
    xdi = setDTFTEnergy(xdi) ;

function xdi = setDTEnergy(t,Ts)
    n1 = round(t(1)/Ts) ; n2 = round(t(end)/Ts) ; 
    N = n2 - n1 ; xdi.n = n1 + [0:N-1]' ;

function xdi = setDTFTEnergy(xdi)
    %   Zero pad for greater frequency resolution
    N = length(xdi.x) ; x = [xdi.x;zeros(7*N,1)] ;
    [xdi.W,xdi.X] = DTFT(xdi.n(1),x,'e','r') ;
    xdi.Wi = [] ; xdi.Xi =[]  ;

function xdi = compxdiRect(A,t0,w,tmax,Ts,xai)
    xdi = setDTEnergy(xai.t,Ts) ; N = length(xdi.n) ;
    xdi.x = A*rect((xdi.n*Ts-t0)/w) ; 
    xdi = setDTFTEnergy(xdi) ;
    
function xdi = compxdiTri(A,t0,w,tmax,Ts,xai)
    xdi = setDTEnergy(xai.t,Ts) ; N = length(xdi.n) ;
    xdi.x = A*tri((xdi.n*Ts-t0)/w) ;
    xdi = setDTFTEnergy(xdi) ;
    
function xdi = compxdiSinc(A,t0,w,tmax,Ts,xai)
    xdi = setDTEnergy(xai.t,Ts) ; N = length(xdi.n) ;
    xdi.x = A*sinc((xdi.n*Ts-t0)/w) ; 
    xdi = setDTFTEnergy(xdi) ;
    
function xdi = compxdiSin(A,t0,f0,N,Ts)
    xdi.n = [0:N-1]' ; xdi.x = A*sin(2*pi*f0*(xdi.n*Ts-t0)) ;
    [xdi.Wi,xdi.Xi] = DTFT(xdi.n(1),xdi.x,'p','r') ;
    xdi.W = [] ; xdi.X =[]  ;
    
function xdi = compxdiCos(A,t0,f0,N,Ts)
    xdi.n = [0:N-1]' ; xdi.x = A*cos(2*pi*f0*(xdi.n*Ts-t0)) ; 
    [xdi.Wi,xdi.Xi] = DTFT(xdi.n(1),xdi.x,'p','r') ;
    xdi.W = [] ; xdi.X =[]  ;
    
function  xdi = compxdiRwav(A,t0,w,f0,N,Ts)
    xdi.n = [0:N-1]' ; T0 = 1/f0 ; xdi.x = rectwave(xdi.n*Ts,T0,t0,w,0,A) ; 
    [xdi.Wi,xdi.Xi] = DTFT(xdi.n(1),xdi.x,'p','r') ;
    xdi.W = [] ; xdi.X =[]  ;
    
function xdi = compxdiTwav(A,t0,w,f0,N,Ts)
    xdi.n = [0:N-1]' ; T0 = 1/f0 ; xdi.x = triwave(xdi.n*Ts,T0,t0,w,0,A) ; 
    [xdi.Wi,xdi.Xi] = DTFT(xdi.n(1),xdi.x,'p','r') ;
    xdi.W = [] ; xdi.X =[]  ;

function sam = computexdo(sam)
    %   Digitally filter the digital signal
    if strcmp(sam.par.name,'Exponential') | strcmp(sam.par.name,'Rectangle') | ...
            strcmp(sam.par.name,'Triangle') | strcmp(sam.par.name,'Sinc')
        ep = 'e' ;
    else
        ep = 'p' ;
    end
    sam.xdo = digitalFilter(sam.xdi,ep,sam.df) ;
    
function sam = computexin(sam)
    fs = sam.fs ; Ts = 1/fs ; xdo = sam.xdo ; xdi = sam.xdi ;
    if strcmp(sam.par.name,'Exponential') | strcmp(sam.par.name,'Rectangle') | ...
            strcmp(sam.par.name,'Triangle') | strcmp(sam.par.name,'Sinc')
        %   Return to original frequency resolution
        [xdo.W,xdo.X] = DTFT(xdo.n(1),xdo.x,'e','r') ;
        %   Form one period of the CTFT of the impulse-sampled signal
        Ximp1 = xdo.X ; fimp1 = xdo.W*fs/(2*pi) ;
        %   Form the CTFT of the impulse-sampled signal from the DTFT of the 
        %   sampled signal.  Make the aliases extend to beyond 500 Hz so the
        %   digital filtering that simulates analog filtering will look right.
        Na = 2*ceil(500/fs) ;     %   Number of periods of DTFT used to form CTFT
        %   Replicate the CTFT period of the impulse-sampled signal to form the 
        %   CTFT from 0 to fs*Na-fs/N where N is the length of the DTFT
        [fimp,Ximp] = alias(fimp1,Ximp1,Na) ;
        xin.f = fimp ;
        [timp,ximp] = ICTFT(fimp,Ximp,'e','c',xdi.n(1)*Ts) ;
        Tsin = timp(2) - timp(1) ; fsin = 1/Tsin ;
        switch sam.in,
            case 'Ideal (Sinc)',
                H = Ts*rect(fimp/fs) ; H = H + [0;H(end:-1:2)] ;
                dum = conjsym(H,1e-10) ;
                xin.X = H.*Ximp ;
                [xin.t,xin.x] = ICTFT(xin.f,xin.X,'e','c',xdi.n(1)*Ts) ;
            case 'Zero-Order Hold',
                h = rect((timp-Ts/2)/Ts) ; 
                [f,H] = CTFT(timp,h,'e','c',fimp) ;
                xin.X = H.*Ximp ;
                [xin.t,xin.x] = ICTFT(xin.f,xin.X,'e','c',xdi.n(1)*Ts) ;
            case 'First-Order Hold', 
                h = tri((timp-Ts)/Ts) ; 
                [f,H] = CTFT(timp,h,'e','c',fimp) ;
                xin.X = H.*Ximp ;
                [xin.t,xin.x] = ICTFT(xin.f,xin.X,'e','c',xdi.n(1)*Ts) ;
        end
        xin.x = real(xin.x) ; xin.fi = [] ; xin.Xi = [] ; sam.xin = xin ;
    else
        Ximp1 = fs*xdo.Xi/(2*pi) ; fimp1 = xdo.Wi*fs/(2*pi) ;
        %   Form the CTFT of the impulse-sampled signal from the DTFT of the 
        %   sampled signal.  Make the aliases extend to beyond 500 Hz so the
        %   digital filtering that simulates analog filtering will look right.
        Na = 2*ceil(500/fs) ;     %   Number of periods of DTFT used to form CTFT
        %   Replicate the CTFT period of the impulse-sampled signal to form the 
        %   CTFT from 0 to Na*fs
        [fimp,Ximp] = alias(fimp1,Ximp1,Na) ;
        xin.fi = fimp ;
        [timp,ximp] = ICTFT(fimp,Ximp,'p','c',xdi.n(1)*Ts) ;
        Tsin = timp(2) - timp(1) ; fsin = 1/Tsin ;
        switch sam.in,
            case 'Ideal (Sinc)',
                H = Ts*rect(fimp/fs) ; H = H + [0;H(end:-1:2)] ;
                xin.Xi = H.*Ximp ;
                [xin.t,xin.x] = ICTFT(xin.fi,xin.Xi,'p','c',xdi.n(1)*Ts) ;
            case 'Zero-Order Hold',
                h = rect((timp-Ts/2)/Ts) ; 
                [f,H] = CTFT(timp,h,'e','c',fimp) ;
                xin.Xi = H.*Ximp ;
                [xin.t,xin.x] = ICTFT(xin.fi,xin.Xi,'p','c',xdi.n(1)*Ts) ;
            case 'First-Order Hold',
                h = tri((timp-Ts)/Ts) ; 
                [f,H] = CTFT(timp,h,'e','c',fimp) ;
                xin.Xi = H.*Ximp ;
                [xin.t,xin.x] = ICTFT(xin.fi,xin.Xi,'p','c',xdi.n(1)*Ts) ;
        end
        xin.x = real(xin.x) ; xin.f = [] ; xin.X = [] ; sam.xin = xin ;
    end 
    
function sam = computexao(sam)
    %   Simulate analog filtering of the interpolated signal
    if strcmp(sam.par.name,'Exponential') | strcmp(sam.par.name,'Rectangle') | ...
            strcmp(sam.par.name,'Triangle') | strcmp(sam.par.name,'Sinc')
        dfin = sam.xin.f(2) - sam.xin.f(1) ; Na = length(sam.xin.f) ;
        fsin = Na*dfin ;
        ep = 'e' ;
    else
        dfin = sam.xin.fi(2) - sam.xin.fi(1) ; Na = length(sam.xin.fi) ;
        fsin = Na*dfin ;
        ep = 'p' ;
    end
    sam.xao = analogFilter(sam.xin,ep,sam.af,fsin) ;
        
function [dBW,aBW] = getBWs(sam)
    if strcmp(sam.df.typ,'None'), 
        dBW = inf ;
    else
        switch sam.df.act,
            case 'Lowpass', dBW = sam.df.WHi ;
            case 'Highpass', dBW = pi - sam.df.WLo ;
            case 'Bandpass', dBW = sam.df.WHi - sam.df.WLo ;
            case 'Bandstop', dBW = pi - (sam.df.WHi - sam.df.WLo) ;
        end
    end
    if strcmp(sam.af.typ,'None'), 
        aBW = inf ;
    else
        switch sam.af.act,
            case 'Lowpass', aBW = sam.af.fHi ;
            case 'Highpass', aBW = pi - sam.af.fLo ;
            otherwise aBW = sam.af.fHi - sam.af.fLo ;
        end
    end
    
function xdo = digitalFilter(xdi,ep,df)
    xdo = xdi ; if strcmp(df.typ,'None'), return ; end
    ord = df.ord ; WLo = df.WLo ; WHi = df.WHi ;
    switch df.act,
        case 'Lowpass',  [b,a] = butter(ord,WHi/pi) ;
        case 'Highpass', [b,a] = butter(ord,WLo/pi,'high') ;
        case 'Bandpass', [b,a] = butter(ord,[WLo,WHi]/pi) ;
        case 'Bandstop', [b,a] = butter(ord,[WLo,WHi]/pi,'stop') ; 
    end
    if ep == 'e',
        H = freqz(b,a,xdo.W) ; xdo.X = xdo.X.*H ; xdo.x = filter(b,a,xdi.x) ;
    else
        H = freqz(b,a,xdo.Wi) ; xdo.Xi = xdi.Xi.*H ; xdo.x = real(ifft(xdo.Xi)) ;
    end

function xao = analogFilter(xin,ep,af,fs)
    xao = xin ; if strcmp(af.typ,'None'), return ; end
    ord = af.ord ; fLo = af.fLo ; fHi = af.fHi ;
    switch af.act,
        case 'Lowpass',  [b,a] = butter(ord,fHi/(fs/2)) ;
        case 'Highpass', [b,a] = butter(ord,fLo/(fs/2),'high') ;
        case 'Bandpass', [b,a] = butter(ord,[fLo,fHi]/(fs/2)) ;
        case 'Bandstop', [b,a] = butter(ord,[fLo,fHi]/(fs/2),'stop') ; 
    end
    if ep == 'e',
        H = freqz(b,a,2*pi*xao.f/fs) ; 
        xao.X = xao.X.*H ; xao.x = filter(b,a,xin.x) ;
    else
        H = freqz(b,a,2*pi*xao.fi/fs) ; 
        xao.Xi = xin.Xi.*H ; 
        [xao.t,xao.x] = ICTFT(xao.fi,xao.Xi,'p','c') ;
        xao.x = real(xao.x) ;
    end

function samDfTyp(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.df.typ = get(obj,'Label') ; moveMenuCheckMark(obj) ;    
    set(h.samDfTypTx,'String',['Type: ',sam.df.typ]) ;
    switch sam.df.typ,
        case 'None',
            disableDfActs(sam,h) ;  %   Disable all digital filter actions
            disableDfOrds(sam,h) ;  %   Disable digital filter order selection
            disableDfCorners(sam,h) ;   %   Disable digital filter corner freq selection
        otherwise,
            enableDfActs(sam,h) ;   %   Enable all digital filter actions
            enableDfOrds(sam,h) ;   %   Enable all digital filter order selection
            enableDfCorners(sam,h) ;    %   Enable digital filter corner freq selection
    end
%     guidata(f,sam) ;
    sam = NewSamplingGraphs('di',sam,h) ;
    guidata(f,sam) ;
    
function disableDfActs(sam,h)
    sam.df.WLo = get(h.samDfWLoSl,'Min') ; 
    sam.df.WHi = get(h.samDfWHiSl,'Max') ;
    set(h.samDfWLoSl,'Value',sam.df.WLo) ; 
    set(h.samDfWHiSl,'Value',sam.df.WHi) ;
    set(h.samDfActLP,'Enable','off') ; set(h.samDfActHP,'Enable','off') ;
    set(h.samDfActBP,'Enable','off') ; set(h.samDfActBS,'Enable','off') ;
    set(h.samDfWLoSl,'Enable','off') ; set(h.samDfWHiSl,'Enable','off') ;
    set(h.samDfActTx,'String','Action: N/A') ;
    disableDfOrds(sam,h) ;
    
function enableDfActs(sam,h)
    set(h.samDfActLP,'Enable','on') ; set(h.samDfActHP,'Enable','on') ;
    set(h.samDfActBP,'Enable','on') ; set(h.samDfActBS,'Enable','on') ;
    set(h.samDfActTx,'String',['Action: ',sam.df.act]) ;
    set(h.samDfOrdTx,'String',['Order: ',num2str(sam.df.ord)]) ;
    
function disableDfOrds(sam,h) ;
    for n = 1:6,
        st = ['set(h.samDfOrd',num2str(n),',''Enable'',''off'') ;'] ;
        eval(st) ;
    end
    set(h.samDfOrdTx,'String','Order: N/A') ;
    
function enableDfOrds(sam,h) ;
    for n = 1:6,
        st = ['set(h.samDfOrd',num2str(n),',''Enable'',''on'') ;'] ;
        eval(st) ;
    end
    
function disableDfCorners(sam,h)
    set(h.samDfWLoSl,'Enable','off','Visible','off') ; 
    set(h.samDfWLoEt,'Enable','off','Visible','off') ;
    set(h.samDfWHiSl,'Enable','off','Visible','off') ; 
    set(h.samDfWHiEt,'Enable','off','Visible','off') ;
    
function enableDfCorners(sam,h)
    switch sam.df.act,
        case 'Lowpass', 
            set(h.samDfWLoSl,'Enable','off','Visible','off') ;
            set(h.samDfWLoEt,'Enable','off','Visible','off') ;
            set(h.samDfWHiSl,'Enable','on','Visible','on') ;
            set(h.samDfWHiEt,'Enable','on','Visible','on') ;
        case 'Highpass',
            set(h.samDfWLoSl,'Enable','on','Visible','on') ;
            set(h.samDfWLoEt,'Enable','on','Visible','on') ;
            set(h.samDfWHiSl,'Enable','off','Visible','off') ;
            set(h.samDfWHiEt,'Enable','off','Visible','off') ;
        otherwise
            set(h.samDfWHiSl,'Enable','on','Visible','on') ;
            set(h.samDfWHiEt,'Enable','on','Visible','on') ;
            set(h.samDfWLoSl,'Enable','on','Visible','on') ;
            set(h.samDfWLoEt,'Enable','on','Visible','on') ;
    end
    set(h.samDfWLoSl,'Value',sam.df.WLo) ; 
    set(h.samDfWHiSl,'Value',sam.df.WHi) ; 
    
function samDfAct(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.df.act = get(obj,'Label') ; moveMenuCheckMark(obj) ;
    set(h.samDfActTx,'String',['Action: ',sam.df.act]) ;
    sam = NewSamplingGraphs('do',sam,h) ;
    enableDfCorners(sam,h) ;
    guidata(f,sam) ;
    
function samDfOrd(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.df.ord = str2num(get(obj,'Label')) ; moveMenuCheckMark(obj) ;    
    set(h.samDfOrdTx,'String',['Order: ',num2str(sam.df.ord)]) ;
    sam = NewSamplingGraphs('do',sam,h) ;
    guidata(f,sam) ;
    
function samInTyp(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.in = get(obj,'Label') ; moveMenuCheckMark(obj) ;
    set(h.samInTx,'String',sam.in) ;
    sam = NewSamplingGraphs('in',sam,h) ;
    guidata(f,sam) ;
    
function moveMenuCheckMark(obj)
    pa = get(obj,'Parent') ; set(obj,'Checked','on') ; ch = get(pa,'Children') ; 
    for n = 1:length(ch),
        if ch(n) ~= obj, set(ch(n),'Checked','off') ; end
    end

function samAfTyp(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.af.typ = get(obj,'Label') ; moveMenuCheckMark(obj) ;
    set(h.samAfTypTx,'String',['Type: ',sam.af.typ]) ;
    switch sam.af.typ,
        case 'None',
            disableAfActs(sam,h) ;  %   Disable all analog filter actions
            disableAfOrds(sam,h) ;  %   Disable analog filter order selection
            disableAfCorners(sam,h) ; % Disable analog filter corner freq selection
        otherwise,
            enableAfActs(sam,h) ;   %   Enable all analog filter actions
            enableAfOrds(sam,h) ;   %   Enable all analog filter order selection
            enableAfCorners(sam,h) ; %  Enable analog filter corner freq selection
    end
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;
    
function disableAfActs(sam,h)
    sam.af.fLo = get(h.samAffLoSl,'Min') ; 
    sam.af.fHi = get(h.samAffHiSl,'Max') ;
    set(h.samAffLoSl,'Value',sam.af.fLo) ; 
    set(h.samAffHiSl,'Value',sam.af.fHi) ;
    set(h.samAfActLP,'Enable','off') ; set(h.samAfActHP,'Enable','off') ;
    set(h.samAfActBP,'Enable','off') ; set(h.samAfActBS,'Enable','off') ;
    set(h.samAffLoSl,'Enable','off') ; set(h.samAffHiSl,'Enable','off') ;
    set(h.samAfActTx,'String','Action: N/A') ;
    disableAfOrds(sam,h) ;
    
function enableAfActs(sam,h)
    set(h.samAfActLP,'Enable','on') ; set(h.samAfActHP,'Enable','on') ;
    set(h.samAfActBP,'Enable','on') ; set(h.samAfActBS,'Enable','on') ;
    set(h.samAfActTx,'String',['Action: ',sam.af.act]) ;
    set(h.samAfOrdTx,'String',['Order: ',num2str(sam.af.ord)]) ;
    
function disableAfOrds(sam,h) ;
    for n = 1:6,
        st = ['set(h.samAfOrd',num2str(n),',''Enable'',''off'') ;'] ;
        eval(st) ;
    end
    set(h.samAfOrdTx,'String','Order: N/A') ;
    
function enableAfOrds(sam,h) ;
    for n = 1:6,
        st = ['set(h.samAfOrd',num2str(n),',''Enable'',''on'') ;'] ;
        eval(st) ;
    end
    
function disableAfCorners(sam,h)
    set(h.samAffLoSl,'Enable','off','Visible','off') ; 
    set(h.samAffLoEt,'Enable','off','Visible','off') ;
    set(h.samAffHiSl,'Enable','off','Visible','off') ; 
    set(h.samAffHiEt,'Enable','off','Visible','off') ;
    
function enableAfCorners(sam,h)
    switch sam.af.act,
        case 'Lowpass', 
            set(h.samAffLoSl,'Enable','off','Visible','off') ;
            set(h.samAffLoEt,'Enable','off','Visible','off') ;
            set(h.samAffHiSl,'Enable','on','Visible','on') ;
            set(h.samAffHiEt,'Enable','on','Visible','on') ;
        case 'Highpass',
            set(h.samAffLoSl,'Enable','on','Visible','on') ;
            set(h.samAffLoEt,'Enable','on','Visible','on') ;
            set(h.samAffHiSl,'Enable','off','Visible','off') ;
            set(h.samAffHiEt,'Enable','off','Visible','off') ;
        otherwise
            set(h.samAffHiSl,'Enable','on','Visible','on') ;
            set(h.samAffHiEt,'Enable','on','Visible','on') ;
            set(h.samAffLoSl,'Enable','on','Visible','on') ;
            set(h.samAffLoEt,'Enable','on','Visible','on') ;
    end
    set(h.samAffLoSl,'Value',sam.af.fLo) ; 
    set(h.samAffHiSl,'Value',sam.af.fHi) ; 
    
function samAfAct(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.af.act = get(obj,'Label') ; moveMenuCheckMark(obj) ;
    set(h.samAfActTx,'String',['Action: ',sam.af.act]) ;
    enableAfCorners(sam,h) ;
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;

function samAfOrd(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    sam.af.ord = str2num(get(obj,'Label')) ; moveMenuCheckMark(obj) ;
    set(h.samAfOrdTx,'String',['Order: ',num2str(sam.af.ord)]) ;
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;
    
function samASl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    val = updateSlider(obj) ; sam.par.A = val ;  
    set(h.samAEt,'String',['Amplitude = ',num2str(sam.par.A)]) ;
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    
function val = updateSlider(obj)
    mx = get(obj,'Max') ; mn = get(obj,'Min') ; span = mx - mn ; 
    q = get(obj,'SliderStep') ; q = q(1)*span ;
    val = get(obj,'Value') ; val = round(val/q)*q ; 
    val = max(val,mn) ; val = min(val,mx) ; 
    set(obj,'Value',val) ; 

function samAEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; A = str2num(st) ; 
    A = max(A,get(h.samASl,'Min')) ; A = min(A,get(h.samASl,'Max')) ;
    if ~isempty(A),
        sam.par.A = round(A*10)/10 ;
        set(h.samASl,'Value',sam.par.A) ;
        set(h.samAEt,'String',['Amplitude = ',num2str(sam.samp.A)]) ;
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in amplitude edit text as a number') ;
        sam.samp.A = NaN ;
        set(obj,'String','Amplitude = ???') ;
    end
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    
function samwSl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    val = updateSlider(obj) ; sam.par.w = val ;
    switch sam.par.name,
        case 'Exponential', 
            set(h.samwEt,'String',['Tau = ',num2str(sam.par.w)]) ;
        otherwise, set(h.samwEt,'String',['Width = ',num2str(sam.par.w)]) ;
    end
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    drawnow ;

function samwEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    qw = get(obj,'SliderStep') ; qw = qw(2) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; w = str2num(st) ; 
    w = max(w,get(h.samwSl,'Min')) ; w = min(w,get(h.samwSl,'Max')) ;
    st = get(h.samwEt,'String') ; [t,r] = strtok(st,'=') ;
    t = [t,'= '] ; 
    if ~isempty(w),
        sam.par.w = round(w/qw)*qw ;
        set(h.samwSl,'Value',sam.par.w) ;
        set(h.samwEt,'String',[t,num2str(sam.par.w)]) ;
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in width edit text as a number') ;
        sam.samp.w = NaN ;
        set(obj,'String',[t,'???']) ;
    end
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    
function samt0Sl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    val = updateSlider(obj) ; sam.par.t0 = val ;
    set(h.samt0Et,'String',['Delay = ',num2str(sam.par.t0)]) ;
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    drawnow ;
    
function samt0Et(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    qt0 = get(obj,'SliderStep') ; qt0 = qt0(2) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; t0 = str2num(st) ; 
    t0 = max(t0,get(h.samt0Sl,'Min')) ; t0 = min(t0,get(h.samt0Sl,'Max')) ;
    st = get(h.samt0Et,'String') ; [t,r] = strtok(st,'=') ;
    t = [t,'= '] ; 
    if ~isempty(t0),
        sam.par.t0 = round(t0/qt0)*qt0 ;
        set(h.samt0Sl,'Value',sam.par.t0) ;
        set(h.samt0Et,'String',[t,num2str(sam.par.t0)]) ;
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in delay edit text as a number') ;
        sam.samp.t0 = NaN ;
        set(obj,'String',[t,'???']) ;
    end
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    
function samf0Sl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ; 
    val = updateSlider(obj) ; sam.par.f0 = val ;
    set(h.samf0Et,'String',['Frequency = ',num2str(sam.par.f0)]) ;
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    drawnow ;

function samf0Et(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    qf0 = get(obj,'SliderStep') ; qf0 = qf0(2) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; f0 = str2num(st) ; 
    f0 = max(f0,get(h.samf0Sl,'Min')) ; f0 = min(f0,get(h.samf0Sl,'Max')) ;
    st = get(h.samf0Et,'String') ; [t,r] = strtok(st,'=') ;
    t = [t,'= '] ; 
    if ~isempty(f0),
        sam.par.f0 = round(f0/qf0)*qf0 ;
        set(h.samf0Sl,'Value',sam.par.f0) ;
        set(h.samf0Et,'String',[t,num2str(sam.par.f0)]) ;
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in frequency edit text as a number') ;
        sam.samp.f0 = NaN ;
        set(obj,'String',[t,'???']) ;
    end
    sam = NewSamplingGraphs('ai',sam,h) ;
    guidata(f,sam) ;
    
function samfsSl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    val = updateSlider(obj) ; sam.fs = val ;
    set(h.samfsEt,'String',[num2str(sam.fs),' samples/second']) ;
    sam = NewSamplingGraphs('di',sam,h) ;
    guidata(f,sam) ;

function samfsEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; fs = str2num(st) ; 
    fs = max(fs,get(h.samfsSl,'Min')) ; fs = min(fs,get(h.samfsSl,'Max')) ;
    if ~isempty(fs),
        sam.fs = round(fs) ;
        set(h.samfsSl,'Value',sam.fs) ;
        if fs == 1, st = ' sample/second' ; else st = ' samples/second' ; end
        set(h.samfsEt,'String',[num2str(sam.fs),st]) ;
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in sampling rate edit text as a number') ;
        sam.samp.fs = NaN ;
        set(obj,'String','??? samples/second') ;
    end
    sam = NewSamplingGraphs('di',sam,h) ;
    guidata(f,sam) ;
    
function samDfWLoSl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    val = updateSlider(obj) ; sam.df.WLo = val ;
    set(h.samDfWLoEt,'String',['Low Corner: ',num2str(sam.df.WLo),' rad']) ;
    WHi = max(get(h.samDfWHiSl,'Value'),sam.df.WLo+0.1) ;
    set(h.samDfWHiSl,'Value',WHi) ; sam.df.WHi = WHi ;
    set(h.samDfWHiEt,'String',['High Corner: ',num2str(sam.df.WHi),' rad']) ;,
    sam = NewSamplingGraphs('do',sam,h) ;
    guidata(f,sam) ;

function samDfWLoEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; WLo = str2num(st) ; 
    if ~isempty(WLo),
        WLo = max(WLo,get(h.samDfWLoSl,'Min')) ; 
        WLo = min(WLo,get(h.samDfWLoSl,'Max')) ;
        WLo = round(WLo*10)/10 ;
        sam.df.WLo = WLo ;
        set(h.samDfWLoSl,'Value',sam.df.WLo) ;
        set(h.samDfWLoEt,'String',['Low Corner: ',num2str(sam.df.WLo),' rad']) ;
        WHi = max(get(h.samDfWHiSl,'Value'),sam.df.WLo+0.1) ;
        set(h.samDfWHiSl,'Value',WHi) ; sam.df.WHi = WHi ;
        set(h.samDfWHiEt,'String',['High Corner: ',num2str(sam.df.WHi),' rad']) ;,
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in minimum frequency edit text as a number') ;
        sam.df.WLo = NaN ;
        set(obj,'String','Low Corner: ??? radians') ;
    end
    sam = NewSamplingGraphs('do',sam,h) ;
    guidata(f,sam) ;
    
function samDfWHiSl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    val = updateSlider(obj) ; sam.df.WHi = val ;
    set(h.samDfWHiEt,'String',['High Corner: ',num2str(sam.df.WHi),' rad']) ;
    WLo = min(get(h.samDfWLoSl,'Value'),sam.df.WHi-0.1) ;
    set(h.samDfWLoSl,'Value',WLo) ; sam.df.WLo = WLo ;
    set(h.samDfWLoEt,'String',['Low Corner: ',num2str(sam.df.WLo),' rad']) ;
    sam = NewSamplingGraphs('do',sam,h) ;
    guidata(f,sam) ;

function samDfWHiEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; WHi = str2num(st) ; 
    if ~isempty(WHi),
        WHi = max(WHi,get(h.samDfWHiSl,'Min')) ; 
        WHi = min(WHi,get(h.samDfWHiSl,'Max')) ;
        WHi = round(WHi*10)/10 ;
        sam.df.WHi = WHi ;
        set(h.samDfWHiSl,'Value',sam.df.WHi) ;
        set(h.samDfWHiEt,'String',['High Corner: ',num2str(sam.df.WHi),' rad']) ;
        WLo = min(get(h.samDfWLoSl,'Value'),sam.df.WHi-0.1) ;
        set(h.samDfWLoSl,'Value',WLo) ; sam.df.WLo = WLo ;
        set(h.samDfWLoEt,'String',['Low Corner: ',num2str(sam.df.WLo),' rad']) ;,
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in maximum frequency edit text as a number') ;
        sam.df.WHi = NaN ;
        set(obj,'String','High Corner: ??? radians') ;
    end
    sam = NewSamplingGraphs('do',sam,h) ;
    guidata(f,sam) ;

function samAffLoSl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    val = updateSlider(obj) ; sam.af.fLo = val ;
    set(h.samAffLoEt,'String',['Low Corner: ',num2str(sam.af.fLo),' Hz']) ;
    fHi = max(get(h.samAffHiSl,'Value'),sam.af.fLo+1) ;
    set(h.samAffHiSl,'Value',fHi) ; sam.af.fHi = fHi ;
    set(h.samAffHiEt,'String',['High Corner: ',num2str(sam.af.fHi),' Hz']) ;,
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;

function samAffLoEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    st = get(obj,'String') ; 
    I = (st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+' ;
    st = st(I) ; fLo = str2num(st) ; 
    if ~isempty(fLo),
        fLo = max(fLo,get(h.samAffLoSl,'Min')) ; 
        fLo = min(fLo,get(h.samAffLoSl,'Max')) ;
        fLo = round(fLo) ;
        sam.af.fLo = fLo ;
        set(h.samAffLoSl,'Value',sam.af.fLo) ;
        set(h.samAffLoEt,'String',['Low Corner: ',num2str(sam.af.fLo),' Hz']) ;
        fLo = max(get(h.samAffLoSl,'Value'),sam.af.fHi-1) ;
        set(h.samAffLoSl,'Value',fLo) ; sam.af.fLo = fLo ;
        set(h.samAffLoEt,'String',['High Corner: ',num2str(sam.af.fLo),' Hz']) ;
        guidata(f,sam) ;
    else
        disp('Cannot parse string in minimum frequency edit text as a number') ;
        sam.df.fLo = NaN ;
        set(obj,'String','Low Corner: ??? Hz') ;
    end
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;
    
function samAffHiSl(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    val = updateSlider(obj) ; sam.af.fHi = val ;
    set(h.samAffHiEt,'String',['High Corner: ',num2str(sam.af.fHi),' Hz']) ;
    fLo = min(get(h.samAffLoSl,'Value'),sam.af.fHi-1) ;
    set(h.samAffLoSl,'Value',fLo) ; sam.af.fLo = fLo ;
    set(h.samAffLoEt,'String',['Low Corner: ',num2str(sam.af.fLo),' Hz']) ;
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;

function samAffHiEt(hObject,eventdata)
    [obj,f] = gcbo ; h = guihandles(f) ; sam = guidata(f) ;
    st = get(obj,'String') ; 
    I = find((st >= '0' & st <= '9') | st == '.' | st == '-' | st == '+') ;
    st = st(I) ; fHi = str2num(st) ; 
    if ~isempty(fHi),
        fHi = max(fHi,get(h.samAffHiSl,'Min')) ; 
        fHi = min(fHi,get(h.samAffHiSl,'Max')) ;
        fHi = round(fHi) ;
        sam.af.fHi = fHi ;
        set(h.samAffHiSl,'Value',sam.af.fHi) ;
        set(h.samAffHiEt,'String',['High Corner: ',num2str(sam.af.fHi),' Hz']) ;
        fLo = min(get(h.samAffLoSl,'Value'),sam.af.fHi-1) ;
        set(h.samAffLoSl,'Value',fLo) ; sam.af.fLo = fLo ;
        set(h.samAffLoEt,'String',['Low Corner: ',num2str(sam.af.fLo),' Hz']) ;
        guidata(f,sam) ;    
    else
        disp('Cannot parse string in maximum frequency edit text as a number') ;
        sam.df.fHi = NaN ;
        set(obj,'String','High Corner: ??? Hz') ;
    end
    sam = NewSamplingGraphs('ao',sam,h) ;
    guidata(f,sam) ;

function y = us(x)
        y = (sign(x)+1)/2 ;
        x0 = abs(x) < 20*eps ;
        y = y.*(1-x0) + 0.5.*x0 ; 
        
function y = rect(x)
    y = us(x+1/2) - us(x-1/2) ;
    
function y = rectwave(t,T0,t0,w,mn,mx)
    y = t*0 ; tmn = min(t) ; tmx = max(t) ;
    kmin = floor(tmn-w/2+t0)/T0 ; kmax = ceil(tmx+w/2+t0)/T0 ;
    for k = kmin:kmax,
        y = y + rect((t-k*T0-t0)/w) ;
    end

function y = triwave(t,T0,t0,w,mn,mx)
    y = t*0 ; tmn = min(t) ; tmx = max(t) ;
    kmin = floor((tmn-2*w+t0)/T0) ; kmax = ceil((tmx+2*w+t0)/T0) ;
    for k = kmin:kmax,
        y = y + tri((t-k*T0-t0)/w) ;
    end
    
 %	Function to graph an "x" and a "y" on two axes with arrowheads and
%	labels
%	x	-	if one-dimensional cell array of vectors, each row or column of each cell is plotted
%	y	-	if one-dimensional cell array of vectors, each row or column of each cell is plotted
%	lims -	an array of limits for the plot, including all annotations. If empty, automatic scaling 
%           is done. If not empty, but containing "NaN" as a value, that value alone is automatically
%           set but the others remain as specified.
%	xl	-	x-axis label
%	yl	-	y-axis label
%	lfn	-	label font name, if empty, "Times" is the default font for the labels
%	lfs -	label font size, if empty, a font size is chosen consistent with the graph size
%	sfn	-	scale font name, if empty, "Times' is the default font for the scale
%	sfs -	scale font size, if empty, a font size is chosen consistent with the graph size
%	ttl	-	title
%	tfn -	title font name, if empty, "Times" is the default font for the title
%	tfs - 	title font size, if empty, a font size is chosen consistent with the graph size
%
%           For all fonts, if the font size is greater than one it is taken as a 
%           point number and the font size is fixed.  If it is less than one it 
%           is taken as a fraction of the axes limits and is normalized and will
%           change as the figure is resized.
%
%	fill -	flag to indicate whether the area under the curve should be shaded, 
%           1 to fill and 0 to not fill.  If there is a cell array of x and y values this
%           variable should also be a cell array of the same size containing flags or the 
%           empty vector (no fill is the default)
%	pt  -	flag to indicate whether a plot is a continuous-time (c), 
%			discrete-time (d) function, scatter plot (s), stairs plot (t)
%			or impulse plot (i). If this flag is any other single character a set
%			of axes is plotted but no graph.  If this flag is empty, (c) is the default.
%           If there is a cell array of x and y values this variable should also be a cell 
%           array of the same size containing flags or the empty vector (c is the default)
%	clr		color(s) of the plot(s), if this argument is omitted or empty all plots
%			are black.  If there is a cell array of x and y values this variable should also 
%           be a cell array of the same size containing colors or the empty vector (black is the
%           default
%	ann		annotation control, cell array, first cell contains a code for the
%			x axis, second cell for the y axis, code is a four-character string
%			'a' to draw the axis, 'h' to draw the arrowhead on the axis, 't' to
%			put tick marks on the axis, 's' to put a scale on the axis, 'g' to put
%           a grid on the plot, 'l' to put full length lines at each limit, 'c' to
%           truncate (chop) the data at the axis limits.  The chop feature does not
%           affect impulse or discrete plots, only continuous, scatter and stairs plots.
%           Characters can be in any order, if this argument is left out or empty 'ahts' is assumed
%	p		a structure containing handles to all the graphic elements, axes,
%			arrowheads, labels, tic marks, scales, title and curves
%		p.an	all annotation graphic elements
%			p.an.x		all x-axis graphic elements
%				p.an.x.ax		x axis
%				p.an.x.ah		x-axis arrowhead
%				p.an.x.lab		x-axis label
%				p.an.x.mintic	tic mark at minimum x-axis scale value
%				p.an.x.maxtic	tic mark at maximum x-axis scale value
%				p.an.x.minsc	scale indication at minimum x-axis scale value
%				p.an.x.maxsc	scale indication at maximum x-axis scale value
%			p.an.y		all y-axis graphic elements
%				p.an.y.ax		y axis
%				p.an.y.ah		y-axis arrowhead
%				p.an.y.lab		y-axis label
%				p.an.y.mintic	tic mark at minimum y-axis scale value
%				p.an.y.maxtic	tic mark at maximum y-axis scale value
%				p.an.y.minsc	scale indication at minimum y-axis scale value
%				p.an.y.maxsc	scale indication at maximum y-axis scale value
%		p.cv	all curve elements for all curves (stems for impulses)
%			p.cv(1)		the points plotted (the dot locations for a stem plot)
%			p.cv(2)		the stems to the points (in a stem plot)
%       p.as    Impulse arrows (patches)
%       p.fl    filling patch for filled-area plots
%		p.t		plot title
%		p.all	An array containing handles for all graphic elements so they
%				can be manipulated as a group if desired
%
%       p.xDataPerPixel The ratio of the axis x coordinates to the pixels in the x direction
%       p.yDataPerPixel The ratio of the axis y coordinates to the pixels in the y direction
%       These two data can be used to properly re-scale plots outside of this function
%
%       The entire plot, including annotations, fits inside the axis limits which are in effect when
%       the function is invoked.
%
%       function p  = xyplot(x,y,lims,xl,yl,lfn,lfs,sfn,sfs,ttl,tfn,tfs,fill,pt,clr,ann)
%
%       The figure created consists of a title, x and y axis labels, x and y axes, x and y tick marks
%       and the plot (curve or curves) itself.
%

function p = xyplot(x,y,lims,xl,yl,lfn,lfs,sfn,sfs,ttl,tfn,tfs,fill,pt,clr,ann)

%   Initialize to empty all pointers to all graphic elements

	p.an.x.ax = [] ; p.an.x.ah = [] ; p.an.x.lab = [] ; p.an.x.mintic = [] ; p.an.x.maxtic = [] ;
	p.an.x.minsc = [] ; p.an.x.maxsc = [] ;
	p.an.y.ax = [] ; p.an.y.ah = [] ; p.an.y.lab = [] ; p.an.y.mintic = [] ; p.an.y.maxtic = [] ;
	p.an.y.minsc = [] ; p.an.y.maxsc = [] ;
	p.cv = [] ; p.as = [] ; p.t = [] ; p.all = [] ;
    
%   Initialize to empty the x and y scale/pixel factors

    p.xDataPerPixel = [] ; p.yDataPerPixel = [] ;

    if isempty(lims), lims = [NaN,NaN,NaN,NaN] ; end
    
%   For backward compatibility with previous versions if "fill" has y's or Y's or '1''s and n's or N's 
%   or '0''s instead of 1's and 0's, set all y's or Y's to 1's and all n's or N's to 0's

    fill = initFill(fill,x) ;
    
%   Default pt to 'c' if it is not already specified.  Also if pt is not a cell array and x is, make
%   pt a cell array of the same size

    pt = initPt(pt,x) ;
    
%   Get the sizes of the axes in pixels and return the axes units to their original value

	un = get(gca,'Units') ; set(gca,'Units','pixels') ; as = get(gca,'Position') ; 
    ax = as(3) ; ay = as(4) ; set(gca,'Units',un) ;
    
%	Handle case in which color is not specified either by being empty or omitted.  It defaults to 'k'.

    clr = initClr(clr,x,nargin) ;

%	Handle case in which annotation-control cell array is not specified by being either empty or omitted

	if nargin < 16 | (nargin == 16 & isempty(ann)), ann = {'ahts','ahts'} ; end

	p.all = [] ;
    
	if iscell(x) & iscell(y),
	
		%	Handle multiple plots in this section
		%	Find the number of cells in a cell array
	
		if length(x) == length(y),	%	Check whether cell arrays are of the same size
            for n = 1:length(x), x{n} = x{n}(:) ; y{n} = y{n}(:) ; end
        else
			disp('Input cell arrays to xyplot are different sizes') ; return ;
        end
		[xmn,xmx,xspn,dx,ymn,ymx,yspn,dy] = cellLimits(x,y,lims) ;
		lims = [xmn, xmx, ymn, ymx] ;	%	Plotting limits
	else
        x = x(:) ; y = y(:) ;   %   Make all vectors column vectors
        if length(x) ~= length(y),
            disp('x and y vectors are different lengths') ; return ;
        end
		[xmn,xmx,xspn,dx,ymn,ymx,yspn,dy] = limits(x,y,lims) ;
		lims = [xmn, xmx, ymn, ymx] ;
    end
	xspn = xmx - xmn ; yspn = ymx - ymn ;
	if xspn == 0, xmn = xmn - 1 ; xmx = xmx + 1 ; end
	if yspn == 0, ymn = ymn - 1 ; ymx = ymx + 1 ; end
	lims = [xmn, xmx, ymn, ymx] ;
	if xmn <= 0 & xmx >=0, xmnp = 0 ; else xmnp = xmn ; end
	if ymn <= 0 & ymx >=0, ymnp = 0 ; else ymnp = ymn ; end
%
%       ---------------------------------------------------------------------------------------- lim(4) = ygmx
%       |                                       Title ____ ttlbt                               |
%       |                                             _____ ylbtp                              |
%       |                                       Ylabel ____ ylbbt                              |
%       |                                           _____ yaxmx                                |
%       |                                          ^                                           |
%       |                                          |                                           |
%       |                                   ymx   --- y-tick                                   |
%       |                                          |                                           |
%       |                                          |                                           |
%       |                                          |                                           |
%       |                                          |                                           |
%       |     x-tick                               |                           x-tick          |
%       |--------|---------------------------------------------------------------|---->  Xlabel|
%       |        |                                 |                             |    |        |
%       |        |                                 |                             |  xaxmx      |
%       |       xmn                                |                            xmx            |
%       |                                          |                                           |
%       |                                          |                                           |
%       |                                          |                                           |
%       |                                          |                                           |
%       |                                   ymn   --- y-tick                                   |
%       |                                          |                                           |
%       ---------------------------------------------------------------------------------------- lim(3) = ygmn
%  lim(1) = xgmn                                                                         xgmx = lim(2)
%
    if isempty(lfn), lfn = 'Times' ; end
    if isempty(sfn), sfn = 'Times' ; end
    if isempty(tfn), tfn = 'Times' ; end
    
%   Set the label font sizes

%   First check xl, yl and ttl for the presence of a leading angle sign code
%   If it is there, remove it and restore it later before annotating
    angI = strfind(xl,'\<') ;
    if ~isempty(angI) & angI(1) == 1, xang = '\<' ; xl = xl(3:end) ; else xang = [] ; end
    angI = strfind(yl,'\<') ;
    if ~isempty(angI) & angI(1) == 1, yang = '\<' ; yl = yl(3:end) ; else yang = [] ; end
    angI = strfind(ttl,'\<') ;
    if ~isempty(angI) & angI(1) == 1, tang = '\<' ; ttl = ttl(3:end) ; else tang = [] ; end
    fss = [72,48,36,30,24,18,14,12,10,9,8,6] ;  %   Font sizes
    set(gca,'Units','Pixels') ; plim = get(gca,'Position') ; axis([0,plim(3),0,plim(4)]) ; cla(gca) ;
    [xlfs,xlexpx] = setFontSize(lfs,lfn,fss,xl,plim(3)*0.2,plim(4)*0.1) ;
    [ylfs,ylexpx] = setFontSize(lfs,lfn,fss,yl,plim(3),plim(4)*0.1) ;
    lfs = min(xlfs,ylfs) ;
    if lfs > 1, fontUnits = 'Points' ; else fontUnits = 'Normalized' ; end
    pxl = text(0,0,xl,'HorizontalAlignment','left','VerticalAlignment','bottom',...
            'FontUnits',fontUnits,'FontSize',lfs,'FontName',lfn,'Units','Pixels') ;
    pyl = text(plim(3),plim(4),yl,'HorizontalAlignment','right','VerticalAlignment',...
            'top','FontUnits',fontUnits,'FontSize',lfs,'FontName',lfn,'Units','Pixels') ;
    xlexpx = get(pxl,'Extent') ; ylexpx = get(pyl,'Extent') ; cla(gca) ;
    
%   Set the title font size

    [tfs,texpx] = setFontSize(tfs,tfn,fss,ttl,plim(3),plim(4)*0.1) ;

%   Set the scale font size

    xmxtxt = setScaleText(xmx) ; 
    [xmxfs,xmxexpx] = setFontSize(sfs,sfn,fss,xmxtxt,plim(3)*0.12,plim(4)*0.075) ;
    xmntxt = setScaleText(xmn) ; 
    [xmnfs,xmnexpx] = setFontSize(sfs,sfn,fss,xmntxt,plim(3)*0.12,plim(4)*0.075) ;
    ymxtxt = setScaleText(ymx) ; 
    [ymxfs,ymxexpx] = setFontSize(sfs,sfn,fss,ymxtxt,plim(3)*0.12,plim(4)*0.075) ;
    ymntxt = setScaleText(ymn) ; 
    [ymnfs,ymnexpx] = setFontSize(sfs,sfn,fss,ymntxt,plim(3)*0.12,plim(4)*0.075) ;
    sfs = min([xmxfs,xmnfs,ymxfs,ymnfs]) ;
    pxmx = text(0,0,xmxtxt,'HorizontalAlignment','left','VerticalAlignment',...
            'bottom','FontUnits',fontUnits,'FontSize',sfs,'FontName',sfn,'Units',...
            'Pixels') ; 
    xmxexpx = get(pxmx,'Extent') ;
    pxmn = text(0,0,xmntxt,'HorizontalAlignment','left','VerticalAlignment',...
            'bottom','FontUnits',fontUnits,'FontSize',sfs,'FontName',sfn,'Units',...
            'Pixels') ; 
    xmnexpx = get(pxmn,'Extent') ;
    pymx = text(0,0,ymxtxt,'HorizontalAlignment','left','VerticalAlignment',...
            'bottom','FontUnits',fontUnits,'FontSize',sfs,'FontName',sfn,'Units',...
            'Pixels') ; 
    ymxexpx = get(pymx,'Extent') ;
    pymn = text(0,0,ymntxt,'HorizontalAlignment','left','VerticalAlignment',...
            'bottom','FontUnits',fontUnits,'FontSize',sfs,'FontName',sfn,'Units',...
            'Pixels') ; 
    ymnexpx = get(pymn,'Extent') ;
    cla(gca) ;

%   Set all plotting limits and scale factors

    xspnpx = plim(3)  - 4 - xlexpx(3) ;
    if findstr(ann{1},'s'),
        xspnpx = xspnpx - max(xmxexpx(3),18) - xmnexpx(3) ;
    else
        xspnpx = xspnpx - 23 ;  %   Leave room for the arrowhead and a small extension on the left
    end
    yspnpx = plim(4) - 2 - texpx(4) - 2 - ylexpx(4) - 2 ; 
    if findstr(ann{2},'s'), 
        yspnpx = yspnpx - ymxexpx(4) - ymnexpx(4) ;
    else
        yspnpx = yspnpx - 23 ;  %   Leave room for the arrowhead
    end
    xDataPerPixel = xspn/xspnpx ; yDataPerPixel = yspn/yspnpx ;
    p.xDataPerPixel = xDataPerPixel ; p.yDataPerPixel = yDataPerPixel ;
    xgmn = xmn ;
    if findstr(ann{1},'s'), 
        xgmn = xgmn - xDataPerPixel*xmnexpx(3) ; 
    else
        xgmn = xgmn - xDataPerPixel*5 ;   %   Let the x-axis extend slightly beyond the minimum value
    end
    xaxmx = xmx ;
    if findstr(ann{1},'s'), 
        xaxmx = xaxmx + max(xmxexpx(3),18)*xDataPerPixel ; 
    else
        xaxmx = xaxmx + xDataPerPixel*18 ; 
    end
    xlblt = xaxmx + 4*xDataPerPixel ; xgmx = xlblt + (2 + xlexpx(3))*xDataPerPixel ;
    ygmn = ymn ;
    if findstr(ann{2},'s'), 
        ygmn = ygmn - yDataPerPixel*ymnexpx(4) ; 
    else
        ygmn = ygmn - yDataPerPixel*5 ; %  Let the y-axis extend slightly below the minimum value
    end
    yaxmx = ymx ;
    if findstr(ann{2},'s') 
        yaxmx = yaxmx + ymxexpx(4)*yDataPerPixel ; 
    else
        yaxmx = yaxmx + yDataPerPixel*18 ; 
    end
    ylbbt = yaxmx + 2*yDataPerPixel ; ttlbt = ylbbt + (2 + ylexpx(4))*yDataPerPixel ;
    ygmx = ttlbt + (2 + texpx(4))*yDataPerPixel ;
    set(gca,'Units','Normalized') ; axis([xgmn,xgmx,ygmn,ygmx]) ;
    
%   Restore leading angle sign indicator if present
    xl = [xang,xl] ; yl = [yang,yl] ; ttl = [tang,ttl] ;
    
%   Annotate the x axis

    p = xAxisAnn(p,ann,xmn,xmx,xspn,dx,xlblt,ymnp,ymn,ymx,xgmn,xgmx,xaxmx,yspn,xDataPerPixel,...
                        yDataPerPixel,xl,sfn,sfs,lfn,lfs,clr) ;
%   Annotate the y axis

    p = yAxisAnn(p,ann,ymn,ymx,yspn,dy,ygmn,yaxmx,ylbbt,ttlbt,xgmn,xgmx,xmn,xmx,xspn,xmnp,...
                xDataPerPixel,yDataPerPixel,ttl,tfn,tfs,yl,sfn,sfs,lfn,lfs,clr) ;
	hold on ;
	
	if iscell(x) & iscell(y),
	
		%	Handle multiple plots in this section
		%	Find the number of elements in the cell arrays, x and y
	
		for n = 1:length(x),
			xa = x{n} ; ya = y{n} ;
			filla = fill{n} ; pta = pt{n} ; clra = clr{n} ;
            if ~isempty(findstr([ann{1},ann{2}],'c')) & xspn > 0 & isempty(findstr(pta,'di')),
                [xa,ya] = interpolate(xa,ya,xmn,xmx,ymn,ymx) ;
            end
            if ~isempty(findstr(ann{1},'c')) & xspn > 0 %& isempty(findstr(pta,'di')),
                I = find(xa > xmx) ; if filla, xa(I) = xmx ; else xa(I) = NaN ; end
                I = find(xa < xmn) ; if filla, xa(I) = xmn ; else xa(I) = NaN ; end
            end
            if ~isempty(findstr(ann{2},'c')) & yspn > 0 %& isempty(findstr(pta,'di')),
                I = find(ya > ymx) ; if filla, ya(I) = ymx ; else ya(I) = NaN ; end
                I = find(ya < ymn) ; if filla, ya(I) = ymn ; else ya(I) = NaN ; end
            end
			if length(xa) == length(ya),
				[cv,as,fl] = allPlots(xa,ya,pta,filla,xDataPerPixel,yDataPerPixel,ymn,ymx,clra) ;
                p.cv{n} = cv ; p.as{n} = as ; p.fl{n} = fl ;
				p.all = [p.all;p.cv{n};p.as{n};p.fl{n}] ;
			else
				disp('Input arrays to xyplot are different sizes') ; return ;
			end
		end
	else
		if length(x) == length(y),
            if ~isempty(findstr([ann{1},ann{2}],'c')) & xspn > 0 & isempty(findstr(pt,'di')),
                [x,y] = interpolate(x,y,xmn,xmx,ymn,ymx) ;
            end
            if findstr(ann{1},'c') & xspn > 0 %& isempty(findstr(pt,'di')),
                I = find(x > xmx) ; if fill, x(I) = xmx ; else x(I) = NaN ; end
                I = find(x < xmn) ; if fill, x(I) = xmn ; else x(I) = NaN ; end
            end
            if findstr(ann{2},'c') & yspn > 0 %& isempty(findstr(pt,'di')),
                I = find(y > ymx) ; if fill, y(I) = ymx ; else y(I) = NaN ; end
                I = find(y < ymn) ; if fill, y(I) = ymn ; else y(I) = NaN ; end
            end
			[cv,as,fl] = allPlots(x,y,pt,fill,xDataPerPixel,yDataPerPixel,ymn,ymx,clr) ;
            p.cv{1} = cv ; p.as{1} = as ; p.fl{1} = fl ;
			p.all = [p.all;p.cv{1};p.as{1};p.fl{1}] ;
		else
			disp('Input arrays to xyplot are different sizes') ; return ;
		end
	end
	set(gca,'Visible','off') ;
	hold off ;

%   Initialize the 'fill' parameter with not filled as the default

function fill = initFill(fill,x)
    if isempty(fill),
        if iscell(x), 
            for n = 1:length(x), fill{n} = 0 ; end
        else
            fill = 0 ;
        end
    else
        if iscell(fill)
            for n = 1:length(fill),
                if fill{n} == 'y' | fill{n} == 'Y' | fill{n} == '1',
                    fill{n} = 1 ; 
                else 
                    fill{n} = 0 ;
                end
            end
        else
            if iscell(x),
                dum = fill ; 
                if dum == 'y' | dum == 'Y' | dum == '1', dum = 1 ; else dum = 0 ; end
                fill = [] ; for n = 1:length(x), fill{n} = dum ; end
            else
                if fill == 'y' | fill == 'Y' | fill == '1', fill = 1 ; else fill = 0 ; end
            end
        end
    end

%   Initialize the 'pt' (plot type) parameter with 'c' (continuous) as the default

function pt = initPt(pt,x)
    if isempty(pt),
        if iscell(x), 
            for n = 1:length(x), pt{n} = 'c' ; end
        else
            pt = 'c' ;
        end
    else
        if iscell(pt),
            for n = 1:length(pt),
                if isempty(pt{n}), pt{n} = 'c' ; end
            end
        else
            if iscell(x),
                dum = pt ; pt = [] ;
                for n = 1:length(x), pt{n} = dum ; end
            end
        end
    end

%   Initialize the 'clr' (color) parameter with 'k' (black) as the default

function clr = initClr(clr,x,narg)
	if narg < 15,
        if iscell(x), 
        	for n = 1:length(x), clr{n} = 'k' ; end
        else
            clr = 'k' ;
        end
    end
    if narg >= 15,
        if isempty(clr),
            if iscell(x), 
                for n = 1:length(x), clr{n} = 'k' ; end
            else
                clr = 'k' ;
            end
        else
            if iscell(clr),
                for n = 1:length(clr),
                    if isempty(clr{n}), clr{n} = 'k' ; end
                end
            else
                if iscell(x),
                    dum = clr ; clr = [] ;
                    for n = 1:length(x), clr{n} = dum ; end
                end
            end
        end
	end

%   Set a font size that will fit into the x and y limits

function [fs,expx] = setFontSize(fs,fn,fss,txt,xlim,ylim)
    if isempty(fs),
        fs = fss(1) ;
        pl = text(0,0,txt,'HorizontalAlignment','left','VerticalAlignment',...
                'bottom','FontSize',fs,'FontName',fn,'Units','Pixels') ;
        expx = get(pl,'Extent') ; ssfss = 1 ;
        while ((expx(3) > xlim) | (expx(4) > ylim)) & (fs > fss(end)), 
            ssfss = ssfss + 1 ; fs = fss(ssfss) ; 
            set(pl,'FontSize',fs) ; expx = get(pl,'Extent') ; 
        end
    else
        if fs > 1, fontUnits = 'Points' ; else fontUnits = 'Normalized' ; end
%         angI = strfind(txt,'\<') ;
%         %   Detect angle sign indicator and remove it if present
%         if ~isempty(angI) & angI(1) == 1, txt = txt(3:end) ; end
        pl = text(0,0,txt,'HorizontalAlignment','left','VerticalAlignment',...
                'bottom','FontUnits',fontUnits,'FontSize',fs,'FontName',fn,...
                'Units','Pixels') ;
        expx = get(pl,'Extent') ;
    end
    cla(gca) ;

%   Set plotting limits if the data are in cell arrays.  If they are not specified (by being NaN) 
%   set them automatically.  Otherwise leave them as specified except quantize them to simple numbers 
%   to make the scale annotation simpler.

function [xmn,xmx,xspn,dx,ymn,ymx,yspn,dy] = cellLimits(x,y,lims)
    if isnan(lims(1)), 
        xmn = inf ; for n = 1:length(x), xmn = min(min(x{n}),xmn) ; end
    else
        xmn = lims(1) ;
    end
	if isnan(lims(2)), 
        xmx = -inf ; for n = 1:length(x), xmx = max(max(x{n}),xmx) ; end
    else
        xmx = lims(2) ;
    end
    if isnan(lims(3)), 
        ymn = inf ; for n = 1:length(y), ymn = min(min(y{n}),ymn) ; end
    else
        ymn = lims(3) ;
    end
	if isnan(lims(4)), 
        ymx = -inf ; for n = 1:length(y), ymx = max(max(y{n}),ymx) ; end
    else
        ymx = lims(4) ;
    end
    [xmn,xmx,dx] = niceLimits(xmn,xmx,8) ; [ymn,ymx,dy] = niceLimits(ymn,ymx,8) ;
    xspn = xmx - xmn ; yspn = ymx - ymn ;
	
%   Set plotting limits.  If they are not specified (by being NaN) set them automatically.  Otherwise 
%   leave them as specified except quantize them to simple numbers to make the scale annotation simpler.

function [xmn,xmx,xspn,dx,ymn,ymx,yspn,dy] = limits(x,y,lims)
    if isnan(lims(1)), xmn = min(x) ; else xmn = lims(1) ; end
	if isnan(lims(1)), xmx = max(x) ; else xmx = lims(2) ; end
    if isnan(lims(3)), ymn = min(y) ; else ymn = lims(3) ; end
    if isnan(lims(4)), ymx = max(y) ; else ymx = lims(4) ; end
    [xmn,xmx,dx] = niceLimits(xmn,xmx,8) ; [ymn,ymx,dy] = niceLimits(ymn,ymx,8) ;
    xspn = xmx - xmn ; yspn = ymx - ymn ;
    
%   Set limits that are quantized and simple for plot annotation.  If a limit is an integer
%   multiple of pi recognize that and leave it as is.

function [mn,mx,d] = niceLimits(mn,mx,N)
    sp = mx - mn ;
    if abs(sp) < 1000*eps, mx = round(mx + 1) ; mn = round(mn - 1) ; sp = mx - mn ; end
    d = 10^(floor(log10(sp)) - ceil(log10(N))) ; 
    while sp/d > N,
        d = d*2 ;
        if sp/d > N, d = d*2.5 ; end
        if sp/d > N, d = d*2 ; end
    end
	if abs(mn/pi-round(mn/pi)) > 0.001 | abs(mn) < pi/10, mn = floor(mn/d)*d ; end
	if abs(mx/pi-round(mx/pi)) > 0.001 | abs(mx) < pi/10, mx = ceil(mx/d)*d ; end

%   If a plot goes off the screen, interpolate to make the last point before leaving the screen be a
%   boundary point and the first point upon re-entering the screen also be a boundary point

function [x,y] = interpolate(x,y,xmn,xmx,ymn,ymx)
    xb = x ; I = find(xb > xmx) ; xb(I) = NaN ; xb = isnan(xb) ; xd = diff(xb) ; Ix = find(xd ~= 0) ;
    for n = length(Ix):-1:1,
        slope = (y(Ix(n)+1) - y(Ix(n)))/(x(Ix(n)+1) - x(Ix(n))) ; newx = xmx - 100*eps ;
        newy = y(Ix(n)) + slope*(newx - x(Ix(n))) ;
        x = [x(1:Ix(n));newx;x(Ix(n)+1:end)] ; y = [y(1:Ix(n));newy;y(Ix(n)+1:end)] ;
    end
    xb = x ; I = find(xb < xmn) ; xb(I) = NaN ; xb = isnan(xb) ; xd = diff(xb) ; Ix = find(xd ~= 0) ;
    for n = length(Ix):-1:1,
        slope = (y(Ix(n)+1) - y(Ix(n)))/(x(Ix(n)+1) - x(Ix(n))) ; newx = xmn + 100*eps ;
        newy = y(Ix(n)) + slope*(newx - x(Ix(n))) ;
        x = [x(1:Ix(n));newx;x(Ix(n)+1:end)] ; y = [y(1:Ix(n));newy;y(Ix(n)+1:end)] ;
    end
    yb = y ; I = find(yb > ymx) ; yb(I) = NaN ; yb = isnan(yb) ; yd = diff(yb) ; Iy = find(yd ~= 0) ;
    for n = length(Iy):-1:1,
        slope = (y(Iy(n)+1) - y(Iy(n)))/(x(Iy(n)+1) - x(Iy(n))) ; newy = ymx - 100*eps ;
        newx = (newy - y(Iy(n)))/slope + x(Iy(n)) ;
        x = [x(1:Iy(n));newx;x(Iy(n)+1:end)] ; y = [y(1:Iy(n));newy;y(Iy(n)+1:end)] ;
    end
    yb = y ; I = find(yb < ymn) ; yb(I) = NaN ; yb = isnan(yb) ; yd = diff(yb) ; Iy = find(yd ~= 0) ;
    for n = length(Iy):-1:1,
        slope = (y(Iy(n)+1) - y(Iy(n)))/(x(Iy(n)+1) - x(Iy(n))) ; newy = ymn + 100*eps ;
        newx = (newy - y(Iy(n)))/slope + x(Iy(n)) ;
        x = [x(1:Iy(n));newx;x(Iy(n)+1:end)] ; y = [y(1:Iy(n));newy;y(Iy(n)+1:end)] ;
    end

%   Plot all the data

function [cv,as,fl] = allPlots(x,y,pt,fill,xDataPerPixel,yDataPerPixel,ymn,ymx,clr)
	cv = [] ; as = [] ; fl = [] ;
	if pt == 'c' | pt == 'C', cv = contPlot(x,y,clr) ; end
	if pt == 'd' | pt == 'D', cv = discPlot(x,y,ymn,ymx,clr,xDataPerPixel) ; end
	if pt == 's' | pt == 'S', cv = scatterPlot(x,y,clr,xDataPerPixel) ; end
	if pt == 't' | pt == 'T', cv = stairs(x,y,'k') ; set(cv,'LineWidth',2,'Color',clr) ; end
	if fill, fl = fillPlot(x,y,clr) ; end
	if pt == 'i' | pt == 'I', as = impPlot(x,y,xDataPerPixel,yDataPerPixel,clr) ; end
	hold on ;
    set(cv,'Clipping','off') ;

%   Continuous plots

function p = contPlot(x,y,clr)
	p = plot(x,y) ; set(p,'LineWidth',2,'Color',clr,'Clipping','off') ;
    
%   Stem plots

function p = discPlot(x,y,ymn,ymx,clr,xDataPerPixel)
    xspmn = 7 ;
    if length(x) > 1, 
        xdiff = diff(sort(x)) ; I = find(xdiff >= 100*eps) ; 
        xspmn = mean(xdiff(I)) ; 
    end
    stwid = floor(xspmn/(3*xDataPerPixel)) ; 
    stwid = max(stwid,1) ; stwid = min(stwid,2) ;
	p = stem(x,y,'filled') ; set(p,'Clipping','off','ShowBaseLine','off') ;
    set(p,'MarkerEdgeColor',clr,'MarkerFaceColor',clr,'MarkerSize',stwid*2,...
        'LineWidth',stwid,'Color',clr) ;
    
function p = scatterPlot(x,y,clr,xDataPerPixel)
    xspmn = 7 ;
    if length(x) > 1, xdiff = diff(sort(x)) ; I = find(xdiff >= 100*eps) ; xspmn = mean(xdiff(I)) ; end
    mkrsize = floor(2*xspmn/xDataPerPixel) ; mkrsize = max(mkrsize,3) ; mkrsize = min(mkrsize,15) ;
    p = scatter(x,y,mkrsize,clr,'filled') ;
    
%   Fill plot

function p = fillPlot(x,y,clr)
	p = [] ; pvx = [x(1);x;x(length(x));x(1)] ; pvy = [0;y;0;0] ; p = [p;patch(pvx,pvy,clr)] ;
    set(p,'EdgeColor',clr) ;

%   Impulse plots

function as = impPlot(x,y,xDataPerPixel,yDataPerPixel,clr)
    as = [] ;
    
    xspmn = findMeanXSpacing(x,y) ;     %   Find the mean space between significant impulses
    
    [xpixvs,ypixvs] = setArrowSize(xspmn,xDataPerPixel) ;   %   Set the arrow size
    
%   Generate an array of patch objects that draw the arrows using homogeneous coordinates pixvs and
%   a scaling matrix scale

    pixvs = [xpixvs;ypixvs;ones(1,length(xpixvs))] ;
	scale = [xDataPerPixel,0,0 ; 0,yDataPerPixel,0 ; 0,0,1] ; datvs = scale*pixvs ;
    datx = datvs(1,:) ; datx = datx' ; daty = datvs(2,:) ; daty = daty' ;
    [ax,ay] = setArrowPatchArray(length(xpixvs),xDataPerPixel,yDataPerPixel,datx,daty,x,y) ;
    
%   Draw the arrows

    as = patch(ax,ay,clr) ; set(as,'EdgeColor',clr) ;

function xspmn = findMeanXSpacing(x,y)
    if length(x) > 1 & sum(abs(y)) > 0,
        I = find(abs(y) > max(abs(y))/50) ;
        if length(I) > 1,
            xdiff = diff(sort(x(I))) ; 
            I = find(xdiff >= 100*eps) ;
            xspmn = mean(xdiff(I)) ;
        else
            xspmn = inf ;
        end
    else
        xspmn = inf ;
    end

function [xpixvs,ypixvs] = setArrowSize(xspmn,xDataPerPixel)
    if xspmn > 6*xDataPerPixel,
        xpixvs = [1,3,0,-3,-1] ;
        ypixvs = [-12,-12,0,-12,-12] ;
    else
        if xspmn > 4*xDataPerPixel,
            xpixvs = [1,3,0,-3,-1]*2/3 ;
            ypixvs = [-12,-12,0,-12,-12]*2/3 ;
        else
            xpixvs = [1,3,0,-3,-1]/3 ;
            ypixvs = [-12,-12,0,-12,-12]/3 ;
        end
    end

function [ax,ay] = setArrowPatchArray(Npix,xDataPerPixel,yDataPerPixel,datx,daty,x,y)
    xm = repmat(x',Npix,1) ; ym = repmat(y',Npix,1) ;
    ax = repmat(datx,1,length(x)) ; ay = repmat(daty,1,length(y)) ;
    afac = min(abs(y),yDataPerPixel*12)./(yDataPerPixel*12) ;
    ax = ax.*repmat(afac',Npix,1) ;
    ay = ay.*repmat(afac',Npix,1).*repmat(sign(y'),Npix,1) ;
    ax = xm + ax ; ay = ym + ay ;
    ax = [ax(1,:) ; ax ; ax(end,:)] ;
    ay = [zeros(1,length(y)) ; ay ; zeros(1,length(y))] ;

function p = xAxisAnn(p,ann,xmn,xmx,xspn,dx,xlblt,ymnp,ymn,ymx,xgmn,xgmx,xaxmx,yspn,xDataPerPixel,...
                        yDataPerPixel,xl,sfn,sfs,lfn,lfs,clr)
	if ~isempty(findstr(ann{1},'a')),
		xaxp = line([xgmn,xaxmx],[ymnp,ymnp]) ;
		set(xaxp,'Color','k','LineWidth',0.5) ;
		p.an.x.ax = xaxp ; p.all = [p.all;xaxp] ;
	else
		p.an.x.ax = [] ;
	end
	if ~isempty(findstr(ann{1},'h')),
		ah = arrowHead(xaxmx,ymnp,0,12,'k') ;
		p.an.x.ah = ah ; p.all = [p.all;ah] ;
	else
		p.an.x.ah = [] ;
    end
    if lfs > 1, fontUnits = 'Points' ; else fontUnits = 'Normalized' ; end
    angI = strfind(xl,'\<') ;
    if ~isempty(angI) & angI(1) == 1,
        xl = xl(3:end) ;
        xlp = angText(xlblt,ymnp,xl,'left','middle',lfn,fontUnits,lfs) ;
    else
        xlp = text(xlblt,ymnp,xl,'HorizontalAlignment','left','VerticalAlignment',...
            'middle','FontName',lfn,'FontUnits',fontUnits,'FontSize',lfs) ;
    end
	p.an.x.lab = xlp ; p.all = [p.all;xlp] ;
	if ~isempty(findstr(ann{1},'t')),
        xtic = [] ;
        tic = line([xmn,xmn],[ymnp-yDataPerPixel*3,ymnp+yDataPerPixel*3]) ; 
        set(tic,'Color','k','LineWidth',0.5) ;
        xtic = [xtic ; tic] ;
        tic = line([xmx,xmx],[ymnp-yDataPerPixel*5,ymnp+yDataPerPixel*5]) ; set(tic,'Color','k','LineWidth',0.5) ;
        xtic = [xtic ; tic] ;
        n1 = ceil(xmn/dx) ; n2 = floor(xmx/dx) ;
        for n = n1:n2,
            x = n*dx ; tic = line([x,x],[ymnp-yDataPerPixel*3,ymnp+yDataPerPixel*3]) ;
			set(tic,'Color','k','LineWidth',0.5) ; xtic = [xtic ; tic] ;
        end
		p.an.x.tic = xtic ; p.all = [p.all;xtic] ;
	else
		p.an.x.tic = [] ;
	end
	if ~isempty(findstr(ann{1},'s')),
        xmntxt = setScaleText(xmn) ; ptxt = text(xmn,ymnp-yspn/20,xmntxt) ;
		set(ptxt,'HorizontalAlignment','center','VerticalAlignment','top',...
                'FontName',sfn,'FontUnits',fontUnits,'FontSize',sfs) ;
		if xmn == 0, set(ptxt,'Visible','off') ; end
		p.an.x.minsc = ptxt ; p.all = [p.all;ptxt] ;
        xmxtxt = setScaleText(xmx) ; ptxt = text(xmx+3*xDataPerPixel,ymnp-yspn/20,xmxtxt) ;
		set(ptxt,'HorizontalAlignment','center','VerticalAlignment','top',...
                'FontName',sfn,'FontUnits',fontUnits,'FontSize',sfs) ;
		if xmx == 0, set(ptxt,'Visible','off') ; end
		p.an.x.maxsc = ptxt ; p.all = [p.all;ptxt] ;
	else
		p.an.x.minsc = [] ; p.an.x.maxsc = [] ;
	end
    if ~isempty(findstr(ann{1},'g')) & xspn > 0,
        n = floor(xmn/dx) ; xg = n*dx ; cnt = 1 ; xgr = [] ;
        while n*dx <= xmx + 100*eps,
            if n*dx >= xmn, 
                xgr = [xgr,line([n*dx,n*dx],[ymn,ymx])] ; set(xgr(cnt),'LineWidth',0.5,'Color','k') ;
                cnt = cnt + 1 ;
            end
            n = n + 1 ;
        end
        p.an.x.xgr = xgr ;
    end
    if ~isempty(findstr(ann{1},'l')) & xspn > 0,
        xl1 = line([xmn,xmn],[ymn,ymx]) ; set(xl1,'Color','k') ;
        xl2 = line([xmx,xmx],[ymn,ymx]) ; set(xl2,'Color','k') ;
        xl = [xl1,xl2] ; p.an.x.xl = xl ;
    end
        
function txt = setScaleText(val)
	if abs(val/pi-round(val/pi)) < 0.001 & abs(val) > pi/10,
		mul = round(val/pi) ; 
		if abs(mul) ~= 1, 
			multxt = num2str(mul) ; 
		else 
			if mul>0, multxt = '' ; else multxt = '-' ; end
		end
		txt = [multxt,'\pi'] ;
	else
		txt = num2str(val) ;
	end
    
function p = yAxisAnn(p,ann,ymn,ymx,yspn,dy,ygmn,yaxmx,ylbbt,ttlbt,xgmn,xgmx,xmn,xmx,xspn,xmnp,...
                    xDataPerPixel,yDataPerPixel,ttl,tfn,tfs,yl,sfn,sfs,lfn,lfs,clr)
	if ~isempty(findstr(ann{2},'a')),
		yaxp = line([xmnp,xmnp],[ygmn,yaxmx]) ; 
		set(yaxp,'Color','k','LineWidth',0.5) ;
		p.an.y.ax = yaxp ; p.all = [p.all;yaxp] ;
	else
		p.an.y.ax = [] ;
	end
	if ~isempty(findstr(ann{2},'h')),
		ah = arrowHead(xmnp,yaxmx,pi/2,12,'k') ;
		p.an.y.ah = ah ; p.all = [p.all;ah] ;
	else
		p.an.y.ah = [] ;
    end
    if lfs > 1, fontUnits = 'Points' ; else fontUnits = 'Normalized' ; end
    angI = strfind(yl,'\<') ;
    if ~isempty(angI) & angI(1) == 1,
        yl = yl(3:end) ;
        ylp = angText(xmnp,ylbbt,yl,'center','bottom',lfn,fontUnits,lfs) ;
    else
        ylp = text(xmnp,ylbbt,yl,'VerticalAlignment','bottom','HorizontalAlignment',...
            'center','FontName',lfn,'FontUnits',fontUnits,'FontSize',lfs) ;
    end
	p.an.y.lab = ylp ; p.all = [p.all;ylp] ;
	if ~isempty(findstr(ann{2},'t')),
        ytic = [] ;
        tic = line([xmnp-xDataPerPixel*3,xmnp+xDataPerPixel*3],[ymn,ymn]) ; 
        set(tic,'Color','k','LineWidth',0.5) ;
        ytic = [ytic ; tic] ;
        tic = line([xmnp-xDataPerPixel*3,xmnp+xDataPerPixel*3],[ymx,ymx]) ; 
        set(tic,'Color','k','LineWidth',0.5) ;
        ytic = [ytic ; tic] ;
        n1 = ceil(ymn/dy) ; n2 = floor(ymx/dy) ;
        for n = n1:n2,
            y = n*dy ; tic = line([xmnp-xDataPerPixel*3,xmnp+xDataPerPixel*3],[y,y]) ;
			set(tic,'Color','k','LineWidth',0.5) ; ytic = [ytic ; tic] ;
        end
		p.an.y.tic = ytic ; p.all = [p.all;ytic] ;
	else
		p.an.y.tic = [] ;
	end
	if ~isempty(findstr(ann{2},'s')),
        ymntxt = setScaleText(ymn) ; ptxt = text(xmnp-xspn/40,ymn,ymntxt) ;
		set(ptxt,'HorizontalAlignment','right','VerticalAlignment','middle',...
                'FontName',sfn,'FontUnits',fontUnits,'FontSize',sfs) ;
		if ymn == 0, set(ptxt,'Visible','off') ; end
        ymxtxt = setScaleText(ymx) ; ptxt = text(xmnp-xspn/40,ymx,ymxtxt) ;
		set(ptxt,'HorizontalAlignment','right','VerticalAlignment','middle',...
                'FontName',sfn,'FontUnits',fontUnits,'FontSize',sfs) ;
		if ymx == 0, set(ptxt,'Visible','off') ; end
		p.an.y.maxsc = ptxt ; p.all = [p.all;ptxt] ; p.an.y.minsc = ptxt ; p.all = [p.all;ptxt] ;
	else
		p.an.y.minsc = [] ; p.an.y.maxsc = [] ;
	end
    if ~isempty(findstr(ann{2},'g')) & yspn > 0,
        n = floor(ymn/dy) ; yg = n*dy ; cnt = 1 ; ygr = [] ;
        while n*dy <= ymx + 100*eps,
            if n*dy >= ymn, 
                ygr = [ygr,line([xmn,xmx],[n*dy,n*dy])] ; set(ygr(cnt),'LineWidth',0.5,'Color','k') ;
                cnt = cnt + 1 ;
            end
            n = n + 1 ;
        end
        p.an.y.ygr = ygr ;
    end
	tp = text((xgmx + xgmn)/2,ttlbt,ttl,'VerticalAlignment','bottom',...
                'HorizontalAlignment','center','FontName',tfn,'FontUnits',...
                fontUnits,'FontSize',tfs) ;
	p.t = tp ; p.all = [p.all;tp] ;

    if ~isempty(findstr(ann{2},'l')) & yspn > 0,
        yl1 = line([xmn,xmx],[ymn,ymn]) ; set(yl1,'Color','k') ;
        yl2 = line([xmn,xmx],[ymx,ymx]) ; set(yl2,'Color','k') ;
        yl = [yl1,yl2] ; p.an.y.yl = yl ;
    end

%	Function to draw a single arrow head at a specified location and angle
%	with a specified length in pixels on the current axes in the current 
%	window.  A "standard" arrow has a length of 8 pixels.
%
%	x		x location in current axes units
%	y		y location in current axes units
%	theta	orientation angle in ccw radians (zero is pointing to the right)
%	pixlen	length of the arrow in pixels
%	clr		color of the arrowhead
%   dpp     x and y data per pixel, length 2 vector (optional)
%
%	function p = arrowHead(x,y,theta,pixlen,clr)

function p = arrowHead(x,y,theta,pixlen,clr,dpp)
    aunits = get(gca,'Units') ; set(gca,'Units','pixels') ;
	as = get(gca,'Position') ; ax = as(3) ; ay = as(4) ;
	lims = axis ; dx = lims(2) - lims(1) ; dy = lims(4) - lims(3) ;
	xpixvs = [-8,0,-8,-8,0] ; ypixvs = [4,0,-4,4,0]/2 ;
% 	xpixvs = [-8,-6.6,-4.93,-2.9,-2,-1,0,-1,-2,-2.9,-4.93,-6.6,-8] ;
% 	ypixvs = [4,3,2,1,0.6,0.25,0,-0.25,-0.6,-1,-2,-3,-4]/2 ;
	xpixvs = xpixvs*pixlen/8 ; ypixvs = ypixvs*pixlen/8 ;
	pixvs = round([xpixvs ; ypixvs ; ones(1,5)]) ;
    if nargin < 6, 
        xdpp = dx/ax ; ydpp = dy/ay ;
    else
        xdpp = dpp(1) ; ydpp = dpp(2) ;
    end
	scale = [xdpp,0,0 ; 0,ydpp,0 ; 0,0,1] ;
	rot = [cos(theta),-sin(theta),0 ; sin(theta),cos(theta),0 ; 0,0,1] ;
	trans = [1,0,x ; 0,1,y ; 0,0,1] ;
	datvs = trans*scale*rot*pixvs ;
	p = patch(datvs(1,:),datvs(2,:),clr) ; set(p,'EdgeColor',clr) ;
    set(gca,'Units',aunits) ;

function xlp = angText(x,y,l,h,v,lfn,fontUnits,lfs)
    xlp = text(x,y,l,'HorizontalAlignment',h,'VerticalAlignment',...
            'baseline','FontName',lfn,'FontUnits',fontUnits,'FontSize',lfs) ;
    temp = text(0,0,'M','HorizontalAlignment',h,'VerticalAlignment',...
            'baseline','FontName',lfn,'FontUnits',fontUnits,'FontSize',lfs) ;
    Mex = get(temp,'Extent') ; set(temp,'Visible','off') ; clear temp ;
    ht = Mex(4)*0.5 ; wd = Mex(3)*2/3 ;
    ex = get(xlp,'Extent') ;
    bt = y ; lt = ex(1) ; 
    set(xlp,'Position',[x + wd,y]) ;
    if strcmp(v,'bottom'),
        set(xlp,'Position',[x + wd,y + Mex(4)*0.3]) ; bt = bt + Mex(4)*0.3 ;
    end
    if strcmp(v,'top'),
        set(xlp,'Position',[x + wd,y - Mex(4)*0.7]) ; bt = bt + Mex(4)*0.7 ;
    end
    p = line([lt+wd,lt,lt+wd],[bt,bt,bt+ht]) ;
    set(p,'Color','k','LineWidth',1) ;
    xrad = 0.7*wd ; yrad = 0.6*ht ; xc = lt ; yc = bt ; angs = [-pi/16:pi/64:7*pi/16]' ;
    p = line(xc+xrad*cos(angs),yc+yrad*sin(angs)) ; 
    set(p,'Color','k','LineWidth',1) ; 
    
%	Function to generate the discrete-time impulse function defined as
%	one for input integer arguments equal to zero and zero otherwise. 
%	Returns "NaN" for non-integer arguments.  Works for vectors and
%	scalars equally well.
%
%	function y = impD(n)

function y = impD(n)
	y = double(n == 0) ;		%	Impulse is one where argument 
								%	is zero and zero otherwise
	ss = find(round(n) ~= n) ;	%   Find all non-integer "n's"
    y(ss) = NaN ;               %   Replace the corresponding values with NaN's
    
%	Unit sequence function defined as 0 for input integer argument 
%	values less than zero, and 1 for input integer argument values 
%	equal to or greater than zero.  Returns "NaN" for non-integer 
%	arguments.
%
%	function y = usD(n)
%
function y = usD(n)
	y = double(n >= 0) ;		%  Set output to one for non-
                                %  negative arguments
	I = find(round(n) ~= n) ;	%  Index non-integer values of n
	y(I) = NaN ;                %  Set those return values to NaN

%	Function to compute values of the Dirichlet function of the form,
%
%	x = sin(N*pi*t)/(N*sin(pi*t))
%
%	function x = drcl(t,N)
%
function x = drcl(t,N)
	x = diric(2*pi*t,N) ;
    
%	Function to compute the triangle function.  Uses the definition
%	of the triangle function in terms of the ramp function.  Works
%	for vectors and scalars equally well.

function y=tri(x)
	y=ramp(x+1)-2*ramp(x)+ramp(x-1) ;
    
%	Function to compute the ramp function defined as 0 for 
%	values of the argument less than zero and the value of 
%	the argument for arguments greater than or equal to zero.
%	Uses the unit-step function.
%
%	function y = ramp(x)
%
function y = ramp(x)
	y = x.*us(x) ;

%	Discrete-time periodic impulse function defined as 1 for input integer argument 
%	values equal to integer multiples of "N0" and 0 otherwise.  "N0" must be an
%	integer. Returns "NaN" for non-integer input values.  Works for vectors 
%	and scalars equally well.
%
%	function y = impND(N0,n)

function y = impND(N0,n)
	if N0 == round(N0),
		y = n/N0 == round(n/N0) ;	%	Set output to one for all n's which
									%	are integer multiples of N0 and zero
									%	otherwise
		I = find(round(n)==n) ;		%   Find all integer "n's"
	    NaNs = NaN + 0*y ;    		%   Create an array of NaN's the same 
									%   	size as y
	    NaNs(I) = 0 ;           	%   Replace NaN with 0 where the 
									%   	function result is defined
	    y = y + NaNs ;          	%   "Un-define" the values of y 
									%   	computed for non-integer 
									%   	arguments
	else
		disp('Error:  In impND, period parameter, N0, is not an integer') ;
    end

%   Function to find the overall system transfer function of a feedback system
%   with H1 in the forward path and H2 in the feedback path.  Works equally well
%   for continuous-time and discrete-time systems.
%   Avoids some problems that can occur using the MATLAB "feedback" function.
%
function H = fbsys(H1,H2)
    Ts = H1.Ts ;
    [num1,den1] = tfdata(H1,'v') ; [num2,den2] = tfdata(H2,'v') ;
    P1 = tf(num1,1,Ts) ; Q1 = tf(den1,1,Ts) ;
    P2 = tf(num2,1,Ts) ; Q2 = tf(den2,1,Ts) ;
    H = P1*Q2/(Q1*Q2 + P1*P2) ;

%   Function to extend a CTFT by aliasing
%   fwi is the input frequency vector
%   Xi is the input CTFT
%   fwo is the output frequency vector
%   Xo is the output CTFT
%   Na is the number of aliases in Xo (including the original)
%       That is, Na = 1 leaves the CTFT unchanged

function [fwo,Xo] = alias(fwi,Xi,Na)
    fwo = [] ; Xo = [] ; N = length(fwi) ; 
    if N > 1,
        df = fwi(2) - fwi(1) ; fsi = N*df ;
    else
        fsi = 1 ;
    end
    for na = 1:Na,
        fwo = [fwo;fwi+(na-1)*fsi] ; Xo = [Xo;Xi] ;
    end
    
%   Function to convert a frequency vector and corresponding CTFT
%   vector from a frequency range of 0 to fs (or 0 to 2*pi*fs) to a 
%   range of -fs/2 to fs/2 or (-pi*fs to pi*fs) putting the zero
%   frequency component at the center of the vectors
%
%   fwi is the input frequency vector
%   Xi is the input CTFT vector
%   fwo is the output frequency vector
%   Xo is the output CTFT vector
%
%   This function can be used in the same way for DTFT's also
%
%   function [fwo,Xo] = DFTShift(fwi,Xi)

function [fwo,Xo] = DFTShift(fwi,Xi)
    N = length(fwi) ; 
    if N > 1, 
        df = fwi(2) - fwi(1) ; fs = N*df ;
    else
        fs = 1 ;
    end
    if round(N/2)*2 == N,
        fwo = [fwi(N/2+1:N)-fs;fwi(1:N/2)] ;
    else
        fwo = [fwi((N+3)/2:N)-fs;fwi(1:(N+1)/2)] ;
    end
    Xo = fftshift(Xi) ;
    
%	Function to perform a DT convolution on two signals and return
%	their convolution at specified discrete times.  The two 
%	signals are in column vectors, x1 and x2, and their times 
%	are in column vectors, n1 and n2.  The discrete times at which 
%	the convolution is desired are in the column , n12.  The 
%	returned convolution is in column vector, x12, and its 
%	time is in column vector, n12.  If n12 is not included 
%	in the function call it is generated in the function as the 
%	total time determined by the individual time vectors
%
%	[x12,n12] = convD(x1,n1,x2,n2,n12)

function [x12,n12] = convD(x1,n1,x2,n2,n12)

%     Convolve the two vectors using the MATLAB conv command

	xtmp = conv(x1,x2) ;
 
%     Set a temporary vector of times for the convolution 
%     based on the input time vectors

	ntmp = n1(1) + n2(1) + [0:length(n1)+length(n2)-2]' ;

%     Set the first and last times in temporary vector

	nmin = ntmp(1) ; nmax = ntmp(length(ntmp)) ;    	

if nargin < 5,  %   If no input time vector is specified use ntmp
		x12 = xtmp ; n12 = ntmp ;

	else        
%   		If an input time vector is specified, compute the 
%		convolution at those times
		x12 = 0*n12 ;   %   Initialize output convolution to zero

%   		Find the indices of the desired times which are between 
%		the minimum and maximum of the temporary time vector

		I12intmp = find(n12 >= nmin & n12 <= nmax) ; 

%   		Translate them to the indices in the temporary time vector

		Itmp = (n12(I12intmp) - nmin) + 1 ;

%   		Replace the convolution values for those times 
%		in the desired time vector

		x12(I12intmp) = xtmp(Itmp) ;
end
    
%	Function to compute sinc(x) defined as sin(pi*x)/(pi*x).
%	Works for vectors or scalars equally well.

function y=sinc(x)
	zro=(x==0) ;	% This vector indicates the locations of
					% zeros in the input vector.
	%	Compute a numerator and denominator separately to avoid
	%	the division-by-zero problem.  If an element of the input
	%	vector is zero, set the numerator and denominator both
	%	to one.  If it is not zero, compute the numerator and
	%	denominator according to the definition of the sinc
	%	function.
    
	num=(~zro).*sin(pi*x)+zro ; den=(~zro).*(pi*x)+zro ;
	y=num./den ;
