function sgolaydemo(action);
%SGOLAYDEMO Demonstrates Savitzky-Golay filtering.
%   This demo shows the smoothing of an electrocardiogram (ECG) signal
%   by filtering the noisy ECG with a Savitzky-Golay FIR filter.
% 
%   Three plots are shown: The noisy ECG signal, the smoothed signal and
%   the noiseless signal.    
%
%   You can vary the noise level of the ECG signal to be filtered with the
%   slider control on the upper right of the GUI. The parameters of the
%   Savitzky-Golay filter can be changed through the two popup menus provided.
% 
%   Savitzky-Golay filters act as smoothers by performing a least squares
%   fitting of a frame of data to a polynomial of a given degree.
% 
%   The frame size indicates the number of samples you are using to perform
%   the smoothing for each data point. The degree is the order of the polynomial
%   to which each frame of data is fitted.
% 
%   The noiseless or ideal ECG is shown at the bottom of the figure for
%   comparison purposes
 
%   Author(s): R. Losada
%   Copyright 1988-2004 The MathWorks, Inc.
%   $Revision: 1.11.4.3 $  $Date: 2004/08/10 02:07:13 $
if nargin==0,
   action = 'initialize';
end

x1 = ecg(500).';
x = [x1;x1;x1;x1;x1;x1];
y = sgolayfilt(x,0,15); %noiseless signal

switch action, 
case 'initialize',
   % Initialize Graphics
   hfig = figure('NumberTitle','off',...
      'Name','Savitzky-Golay Filtering Demo'); 
  
  bgc = get(0,'DefaultUIControlBackgroundColor');
   % Frame for the all uicontrols
   framepos = [.74 .05 .25 .85];
   uicontrol( ...
      'Style','frame',...
      'Units','normalized',...
      'BackgroundColor',bgc,...
      'Position',framepos);   
   % Frame for the parameters section
   framepos2 = [.75 .36 .23 .23];
   uicontrol( ...
      'Style','frame',...
      'Units','normalized',...
      'ForegroundColor','black',...
      'Position',framepos2);   
  % Savitzky-Golay Filter Parameters Text
  titlepos = [.76 .57 .17 .03];
  titlelabel = ' Filter Parameters';
  uicontrol( ...
      'String',titlelabel,...
      'HorizontalAlignment','left',...
      'Style','text',...
      'Units','normalized',...
      'BackgroundColor',bgc,...
      'ForegroundColor','black',...
      'Position',titlepos); 
  % SG degree menu
   menuname1 = 'Polynomial Degree';
   tposition1 = [.77 .5 .2 .05];
   uicontrol( ...
      'String',menuname1,...
      'HorizontalAlignment','left',...
      'Style','text',...
      'Units','normalized',...
      'ForegroundColor','black',...
      'Position',tposition1);
   mposition1 = [.77 .46 .1 .05];
   popstr1 = {'0','1','2','3','4'};
   degreehndl = uicontrol('String',popstr1,...
      'Style','Popup',...
      'Tag','degreepopup',...
      'Units','normalized',...
      'Backgroundcolor','white',...
      'Position',mposition1,...
      'UserData',str2double(popstr1),...
      'CallBack','sgolaydemo(''recal'')'); 
   % SG frame size menu
   menuname2 = 'Frame Size';
   tposition2 = [.77 .4 .2 .05];
   uicontrol( ...
      'String',menuname2,...
      'Style','text',...
      'HorizontalAlignment','left',...
      'Units','normalized',...
      'ForegroundColor','black',...
      'Position',tposition2);
   mposition2 = [.77 .37 .1 .05];
   popstr2 = {'5','15','25','55'};
   framehndl = uicontrol('String',popstr2,...
      'Style','Popup',...
      'Tag','framepopup',...
      'Backgroundcolor','white',...
      'Units','normalized',...
      'Position',mposition2,...
      'UserData',str2double(popstr2),...
      'CallBack','sgolaydemo(''recal'')');
   % Noise variance slider
   sliname1 = 'Noise Level';
   tposition4 = [.76 .8 .21 .05];
   uicontrol(...
      'String',sliname1,...
      'Style','text',...
      'Units','normalized',...
      'BackgroundColor',bgc,...
      'ForegroundColor','black',...
      'Position',tposition4);
   mposition4 = [.76 .75 .21 .05];
   sliderhndl = uicontrol('Style','slider',...
      'Tag','noiseslider',...
      'Units','normalized',...
      'Value',0.7,...
      'Min',0,'Max',1.4,...
      'Position',mposition4,...
      'CallBack','sgolaydemo(''recal'')');
   slimin = 'Less';
   tposition5 = [.76 .68 .07 .07];
   uicontrol(...
      'String',slimin,...
      'Style','text',...
      'Units','normalized',...
      'HorizontalAlignment','left',...
      'ForegroundColor','black',...
      'BackgroundColor',bgc,...
      'Position',tposition5);
   slimax = 'More';
   tposition6 = [.9 .68 .07 .07];
   uicontrol(...
      'String',slimax,...
      'Style','text',...
      'Units','normalized',...
      'HorizontalAlignment','right',...
      'ForegroundColor','black',...
      'BackgroundColor',bgc,...
      'Position',tposition6);
   % Info and Close buttons
   tposition7 = [.77 .18 .19 .1];
   uicontrol(...
      'String','Info',...
      'Units','normalized',...
      'Position',tposition7,...
      'Callback','sgolaydemo(''info'')');
   tposition8 = [.77 .06 .19 .1];
   uicontrol(...
      'String','Close',...
      'Units','normalized',...
      'ForegroundColor','black',...
      'Position',tposition8,...
      'Callback','sgolaydemo(''done'')');
      
   % Initial values
   noise = 0.7;
   degree = 0;
   frame = 5;
   subplot('Position',[.07 .05 .65 .23]), plot(y)
   set(gca,'XTick',[])
   axis([0 3000 -.6 .8])
   title('Noiseless ECG')
   ha1 = subplot('Position',[.07 .67 .65 .23]); plot(y)
   set(gca,'XTick',[])
   axis([0 3000 -.6 .8])
   title('Noisy ECG')
   ha2 = subplot('Position',[.07 .36 .65 .23]); plot(y)
   set(gca,'XTick',[])
   axis([0 3000 -.6 .8])
   title('Filtered ECG')
   ud.handles.ax = [ha1 ha2];
   ud.handles.uis = [degreehndl framehndl sliderhndl];
   set(hfig,'UserData',ud);
   update_gui(y,noise,degree,frame)
   
case 'recal',
   hfig = gcf;
   ud = get(hfig,'UserData');
   hn = ud.handles.uis(3);
   hd = ud.handles.uis(1);
   hf = ud.handles.uis(2);
   
   noise = get(hn,'Value');
   degindx = get(hd,'Value');
   deg = get(hd,'UserData');
   degree = deg(degindx);
   
   frmindx = get(hf,'Value');
   frm = get(hf,'UserData');
   frame = frm(frmindx);
   update_gui(y,noise,degree,frame)
   
case 'info',
   ttlStr = 'Savitzky-Golay Filtering Demo'; 
   
   hlpStr1= ...                                              
      ['This demo shows the smoothing of an electrocardiogram (ECG) signal' sprintf('\n')...
         'by filtering the noisy ECG with a Savitzky-Golay FIR filter.' sprintf('\n')...
         'You can vary the noise level of the ECG signal to be filtered with the' sprintf('\n')...
         'slider control on the upper right of the GUI. The parameters of the' sprintf('\n')...
         'Savitzky-Golay filter can be changed through the two popup menus provided.' sprintf('\n')...
         '' sprintf('\n')...
         'Savitzky-Golay filters act as smoothers by performing a least squares' sprintf('\n')...
         'fitting of a frame of data to a polynomial of a given degree.' sprintf('\n')...
         '' sprintf('\n')...
         'The frame size indicates the number of samples you are using to perform'  sprintf('\n')...
         'the smoothing for each data point. The degree is the order of the polynomial' sprintf('\n')...
         'to which each frame of data is fitted.' sprintf('\n')...
         '' sprintf('\n')...
         'The noiseless or ideal ECG is shown at the bottom of the figure for' sprintf('\n')...
         'comparison purposes'];
             
   helpwin(hlpStr1, ttlStr);
   
case 'done',
   close(gcf);
end        

function [s,f] = update_signal(y,noise,degree,frame)
%UPDATE_SIGNAL Recalculates the noisy ECG and the filtered ECG signals.
v = 0.05*noise*randn(3000,1);    % noise
s = y + v;         % noisy ecg
f = sgolayfilt(s,degree,frame);

function update_gui(y,noise,degree,frame)
%UPDATE_GUI This function is called to update the GUI with the new values.
hfig = gcf;
[s,f] = update_signal(y,noise,degree,frame);
ud = get(hfig,'UserData');
axhdlnp = ud.handles.ax(1);
axhdlfp = ud.handles.ax(2);
hdn = get(axhdlnp,'Children');
hdf = get(axhdlfp,'Children');
set(hdn,'YData',s);
set(hdf,'YData',f);


