image thumbnail

Simple Plot, Zoom and FFT GUI

by

 

03 Dec 2007 (Updated )

GUI to select a Simulink output file or workspace variable, m-file outputs or oscilloscope data. Zo

GetData_v13(varargin)
function varargout = GetData_v13(varargin)
%====================================================================
% - FFT PROGRAM - GetData_vxx.m  
%====================================================================
% - Load an input vector from a:
% 
%        - Workspace variable generated in the command window or from or
%          *.m file. The voltage (y-axis) data can be in a single row or column. 
%          Except for the *.mat files the data should be ascii.
%
%        - A Simulink generated 'To File' (*.mat file) or 'To Workspace' ('Array',
%          'Structure', 'Structure With Time') 
%
% - Input the sample rate and zoom into a selected time range for 
%   performing the FFT.  
%
 % - Workspace and *.mat data from Simulink must be sampled using
 %   zero-order-hold if the remaining data is variable-step or use the sample
 %   parameter in the save-to-workspace or save-to-file block.  
%  
% - No input parameter is required to start the program - Loaded from the 
%    GUI (GetData_vx)
%
% - The sample rate is used to construct the time vectors because outputs from
%    the different data files, scopes and Excel have various line formats. The 
%    types tried here had either no time vector column (row) or the Y (voltage) 
%    vector values are always located at the end of the line (trimmed) after a
%    final blank, tab or comma. Having  to enter the sample rate allows more 
%    formats to run without special handling for each format type.  
% 
% - On the FFT GUI there are options to apply a WINDOW or to down sample the
%   data.  The windowing does not appear useful either because the FFT range
%   is selected  visually in plotZoom_vxx.m or possibly because the window
%   length is always the same size as the data vector?
% 
% - For file input, if there are less than 10 lines of data, an ERROR is flagged 
%   and the routine goes back to the start-up screen for a different (new) WS 
%   variable or file selection.  Each Workspace input variable data is checked 
%   for length when loaded at program startup and if less than 10 lines they
%   are not shown in the WS variable selection scroll box on the GUI. 
%   
% - If there are less than 30 lines of data a WARNING is flagged with the option
%   for a new selection  or to continue with  the given data.
% 
% -The programs are a mix of nested functions and GUIDE developed. 
%  Suggestions are requested for details on better optimization, program 
%  organization, data handling...etc.
%  
% - The data lines to be plotted must have only numeric data following the last 
%   comma, space or tab in the line or the whole line must be numeric. This 
%   allows for the Excel (.cvs extension) and ASCII data from the HP and 
%   Tektronix oscilloscopes used in our lab.    
% 
% - Limited error trapping. On most errors the program attempts to start over
%    by putting back up the GetData window for different (new) data input.
%	 
% - Developed on WINDOWS OS using a 1280 x 800 screen, but works
%   OK down to 1024 x 768 resolution. Screens set at any_width x 600 do not
%   work. OTHER: Gateway MX6453 laptop. Windows XP Professional Service
%   Pack 2, Dual-Core AMD (1.596 Mhz).
%
%                FILE NAME                              FIGURE                          DESCRIPTION   
%  ___________________________________________________________________
%  |  GetData_vxx      | GetData_vxx.fig           | Select WS or File data to
%  |                              |                                        | plot. Input sample frequency
%  |  plotZoom_vxx   | plotZoomGUI_vxx.fig | Select portion of input data for FFT
%  |  plotFFT_vxx      | plotFFTGUI_vxx.fig     | Show the FFT and allow 
%  |                             |                                         | various changes
%  |                             |   ---small_plot_xx.fig    | Smaller plots of input data, FFT 
%  |                             |                                         |   (udB) and phase shift 
%  |_ _____________|__________________ __|_______________________________
%
% FUTURE:
%        - Calculate sample rate data from input time data, if available.
%          Simulink *.mat files already do this.
%
%   	J. Fallon                      Staff Engineer GE Aerospace 11-23-07   
%  	937-237-8215               silverrock@ameritech.net        
% 	937-898-5881 x 325     jim.fallon@ge.com	<-- Work info.  Presently out 
%                                                                                   on disability. 
%=====================================================================
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @GetData_v13_OpeningFcn, ...
                   'gui_OutputFcn',  @GetData_v13_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end                                            % End initialization code - DO NOT EDIT

% --- Executes just before GetData_v13 is made visible.
function GetData_v13_OpeningFcn(hObject, eventdata, handles, varargin)
                                                                 
 % Choose default command line output for GetData_v13 
handles.output = hObject; 
vars = evalin('base','who');  % load WS variables
%=========================================================
% Load up workspace variables. Show  '-'  If less than 10 elements
%  or more than 1 dimension
%==========================================================
     numberInputVar = length(vars);              % get # of WS variables
     varOut = vars;                                             % start with original data
     for icnt = 1:1:numberInputVar                  % check for vectors < 10 characters  
       indexSelected = icnt;                                     % ... or > 2 dimensions
       varName = vars{indexSelected(1)};               % get variable name 
       varGet = evalin('base',varName);                   % bring date into program
  
      if isstruct(varGet)                                     % handle stucture
             try                                                        % catch if structure and 
               varGet = varGet.signals.values;     % skip  if no signal value parameters
             catch
             end
       end   
  
       [varDimOne  varDimTwo]  = size(varGet);       % get variable size
       if (varDimOne == 1) && (varDimTwo > 1)         % transpose input Data = [a b] 
             varGet = varGet';                                          % ...  with a = 1 and b > 1
             [varDimOne  varDimTwo]  = size(varGet);  % get new variable size    
       end
       
       if (varDimOne < 10) || (varDimTwo ~= 1)  ||                ... % eliminate small vectors
                        ischar(varGet)                 % ,,,or multi-dim  if not correct data
          varName = '-';                                  % ...type or <  10 lines
       end
       varOut{icnt(1)} = varName;                     % update variable out table    
     end
     vars = varOut;
     set(handles.listWS,'String',vars);         % save new list. keep non-visible 
                                                                          % ...on GUI
      screenSize = get(0,'MonitorPosition');    % get screen size
      % scale for new resolution different from designed 1280 x 800 screen
      % example: original designed lower right point = 451 pixels
      %                   point scale = (451 / 1200) x present screen width  
      %                                       = 0.3523 x present screen width
      positionX = 0.0811 * screenSize(1,3);  positionY = 0.0491 * screenSize(1,4);
      positionW = 0.0572 * screenSize(1,3); positionH = 0.0219 * screenSize(1,4);
      % set new figure position
      set(gcf,'Position',[positionX  positionY   positionW  positionH] );       

                                                                         
     %=================================================================
      % Initialize - possible that some variables or constants that are 
     %  no longer used
      %=================================================================
     
      handles.errorString3 = 'Bad WS variable';
      warnStringa = 'Data length appears short  [< 40 ]? Select  new WS variable';
      warnStringb =  ' or continue with the PLOT!!';
      handles.warnString = strcat(warnStringa, warnStringb);

      handles.fs = 1e6;           % the assumed sample frequency in KHz
       
      handles.to = [];              % future output time vector (also below?)
      handles.fs_calc = []; 
      handles.fs_flag = false;              
      handles.length_calc = 0;
 
      % Data to be saved before jumping to view+zoom 
      % GUI when 'Plot' button is selected  
      handles.GUI_info.fs = handles.fs;   % sample freq - initialize others to empty 
      handles.GUI_info.volt = [];               %  voltage (or y) data
      handles.GUI_info.time = [];              % time vector
      handles.GUI_info.volt_past = [];     % space used for replots when running
      handles.GUI_info.time_past = [];     % ....plot GUI

      handles.DataLength = 0;
 
      % Update handles structure
      guidata(hObject, handles);

% --- Outputs from this function are returned to the command line.
function varargout = GetData_v13_OutputFcn(hObject, eventdata, handles) 
 
% Get default command line output from handles structure
varargout{1} = handles.output;
 
%===============================================================
% Panel pushbutton selecting WS input
%===============================================================  
% --- Executes on button press in buttonSelWS.
function buttonSelWS_Callback(hObject, eventdata, handles)
    handles = guidata(gcbo);                              % get handles 
    set( gcf,'SelectionType','open')   
    cleanUP(hObject, eventdata, handles);   % standard initialization of  all panels
    set(handles.panelWS,'Visible','on');       % Show WS variables     
    set(handles.panelWSname,'Visible','on');  % Show var name - start with 'NONE' 
    guidata(hObject, handles);                           % save changed or new handle set    
  
% --- Executes on selection change in listWS.
%===================================================================
% get WS variable when a variable name from the GUI WS panel list is
% selected.
%===================================================================  
function listWS_Callback(hObject, eventdata, handles)
try
    handles = guidata(gcbo);                                % get handles      
    [handles.GUI_info.volt   dataOKflag] = getWorkspaceData(...
                            hObject, eventdata, handles);   % get the selected input var data    
    handles.DataLength = length(handles.GUI_info.volt);   % get the data length
    set(handles.txtLength,'string', handles.DataLength);    %  data length to GUI
    set(handles.panelInfo, 'Visible','on');       % set data length panel visible        
    set(handles.panelPlot, 'Visible','on');       % show the fft plot button on GUI
    set(handles.txtPath,'string', pwd);            % show data source location on GUI
    if dataOKflag == false                                  % pwd = display current directory
          % warning less than 100 data points 
           msgbox(handles.errorString3,'! ERROR !', 'error');  
           cleanUP(hObject, eventdata, handles);                      % clean up
           handles.fs = 0; to = [];                                                   %...and return
           return
    else                                                     % request sample freq from user and 
           guidata(hObject, handles);      %... return with calculated time vector
           [fileStatus] = lineCountCheck(hObject, eventdata, ...
                                    handles, handles.DataLength);       
           
           if fileStatus(1) == 'C'                                % check on getting freq-time inf9
                 [handles.GUI_info.fs   handles.GUI_info.time] =...
                              inputSampleFrequemcy(hObject, eventdata, handles);  
           else
                cleanUP(hObject, eventdata, handles);  % clean up 
                 return
           end
    end
catch
    errorString = lasterror;                                  % get the last error  
    WSloadError = 'Unknown ERROR Loading Workspace Variable...';
    WSError = strcat(WSloadError, errorString.message,'...',errorString.identifier); 
    msgbox(WSError,'! ERROR !','error');       %Error - WS' 
    cleanUP(hObject, eventdata, handles);     % clean up - initialize all panels
end
    guidata(hObject, handles);                          % save changed or new handle set  

%=====================================================================
% Called for selecting workspace variable 
%=====================================================================        
function [selectedVariableData   dataOK] = getWorkspaceData(hObject,...
                                                      eventdata, handles)
    handles = guidata(gcbo);                                      % get handles  
    
    dataOK = true;
    % Returns the data of the selected variable to plot. The list was
    % preloaded at startup                                           % get names of  WS 
    entryList = get(handles.listWS,'String');            %  ... variables from panel list
   % get index of selected variable(var) name          
    indexSelected = get(handles.listWS,'Value');                             
    selectedVariableName = entryList{indexSelected(1)}; % get selected var name
    set(handles.textWS,'string',selectedVariableName);  % write the name to GUI
    vars = evalin('base','who');                                         % Get WS var string names  
    indexWSvariable = strmatch(selectedVariableName,...
                        vars,'exact');                                      %  point to WS var index 
    if ~isempty(indexWSvariable)                              % if the data is found
          % load WS var for return
           selectedVariableData = evalin('base',vars{indexWSvariable}); 
           if isstruct( selectedVariableData)
                 selectedVariableData = selectedVariableData.signals.values;
           end
   else
            selectedVariableData = 1;                            % default data = 1 for return
            dataOK = false;                                              % set return flag as false     
    end
    guidata(hObject, handles);                                  % save handles  
  
%================================================================
% LOAD File Data - Pushbutton selecting file data  input. 
% File extensions:   *.cvs --> Excel data and other data types (.dat and .txt 
% - ascii)
% From scopes? -   some Tektonix and HP data types 
%================================================================   
% --- Executes on button press in buttonSelFile.
function buttonSelFile_Callback(hObject, eventdata, handles)
    handles = guidata(gcbo);                           % get handles   
    
    fileStatus = 'CONTINUE';                      % assume 'QUIT' is not selected    
    dataCount = 0;                                       % init total data line counter
    handles.fs_flag = false;                         % pre-set  flag for not *.mat file 
    done = false;     lineOutChar = '0';       % init more local data                 
     handles.GUI_info.volt = [];                                        % initialize output vector
try 
    % init all panels at start (redundant?) 
    cleanUP(hObject, eventdata, handles);   
    set(handles.panelFileName,'Visible','on'); % show the file name panel on GUI
    set(handles.panelPlot,'Visible','on');          % show the fft 'Plot' button on GUI 
    set(handles.panelInfo,'Visible','on');         % show panel for input vector length
    
    [filename,  pathname] =  uigetfile({'*.txt; *dat;*.csv ;*.mat'},...
                                          'File Selector');              % Get user selected file name   
    if filename == 0                                                     % if  no selection
        cleanUP(hObject, eventdata, handles);        % cleanup all panels
        %  do again due to 'uigetfile' command
        set(handles.panelFileName,'Visible','on');  
        set(handles.textFile,'string','None Selected');  %  writefile name on GUI
    else                                                                               % process file
        set(handles.textFile,'string',filename);               % write the filename to GUI
        set(handles.txtPath,'string',pathname);             % write pathname to GUI
     
%===================================================================
% FILE_handler
%  The individual lines require numeric data after ths last tab or space. Commas 
%  are replaced  with spaces before check.
%===================================================================   
         %  check if Simulik  *.mat file. This will be a structure
       if strfind(lower(filename),'.mat')                       
              getStructure = load(filename);                % get the structure
              getField = cell(fieldnames(getStructure)); % check name of structure
              getData = getStructure.(getField{ 1} )';      % get all data    
               handles.GUI_info.volt = getData(: , 2);      % get data vector column                            
              timeVector = getData(:,1);                             % get time vector  
    
              % calculate sample freq and time      
              dt =  timeVector(2) - timeVector(1);             % sample time
              handles.fs_flag = true;                                 % set the flag for following
              handles.GUI_info.fs = 1 / dt;                       % calculate sample frequency
               % calculate  # of points          
              handles.DataLength = length( handles.GUI_info.volt);    
              handles.GUI_info.time = (1:1:length(handles.GUI_info.volt))*dt;
              set(handles.textFs,'string',handles.GUI_info.fs / 1000);  % write to GUI
              set(handles.panelFreqSample,'Visible','on');           
      else      
              fid = fopen(filename,'r') ;                  % Open input file.for read
              while done == false                                % start processing file lines.
                  line = fgets(fid);                                  % read a line from file 
                  if line == -1;                                         % look  for EOF
                       done = true;                                   % set done flag true if EOF
                  else
                      handles.DataLength =  handles.DataLength + 1;       % increment the total line counter     
                      line = strtrim(line);                         % trim leading and trailing blanks
                      line = strrep(line,',', ' ');                 % replace commas with spaces
                      findNoBlank = strfind(isspace(line),true);  % look for spaces, tabs 
                      if  findNoBlank > 0
                         lineOutChar = line( findNoBlank(length(findNoBlank))... % if     
                                        + 1:length(line));           % ... found get line end data (data 
                      else                                                    % ...after last space)(
                          lineOutChar = line;                      % if none just  grab data line  
                      end
                     % convert to number (required?) 
                      lineOutData = str2double(lineOutChar); 
                      if  isnan(lineOutData) 
                        % check for corrupt data (NotANumber)        
                         handles.DataLength = handles.DataLength - 1;   
                      else
                         % add valid data to output vector      
                          handles.GUI_info.volt(handles.DataLength) = lineOutData;  
                      end                                                                                         
                  end         
              end
         fclose(fid);                                                % close the data file after while loop
       end
       
       [fileStatus] = lineCountCheck(hObject, eventdata,...
                                       handles, handles.DataLength);        % check line count
       if fileStatus(1) ~=  'C'                                     % if QUIT selected in 'fileStatus'
              cleanUP(hObject, eventdata, handles);%... initialize all panels 
              return                                                         % ... go back to initial GUI
       end
    
       set(handles.txtLength,'string',...                                          
                              length(handles.GUI_info.volt));  %  Write length to GUI
        if handles.fs_flag == false                                  % if not a *.mat file 
               guidata(hObject, handles);                         % get fs and time vector 
               [handles.GUI_info.fs   handles.GUI_info.time] = ...
                                 inputSampleFrequemcy(hObject, eventdata, handles); 
        end
    end  
     
catch     %  IF an error)  
     errorString = lasterror;            % get the last error  and put  message together  
     buildErrorLine = strcat('GUI - ERROR -  While loading file data?....',...   
                                       errorString.message,'...',errorString.identifier);      
     showErrorMessage = msgbox(buildErrorLine ,...
                                    'ERROR ATTEMPTING TO LOAD FILE DATA','error');                    
    uiwait (showErrorMessage)                          % wait for user response %   
    cleanUP(hObject, eventdata, handles);      %  initialization of  all panels
end
     guidata(hObject, handles);                             % save any changed handles
 
%=====================================================================
% Check # of data length
%=====================================================================
function [fileStatus] = lineCountCheck(hObject, eventdata, handles, dataCount)
 
          fileStatus = 'CONTINUE';                              %  set default
         if  dataCount < 10
            String1 = 'Not Enough Data ( # lines < 10 )';  
            msgbox(String1,'! ERROR !','error');        % 'Not Enough Data!' 
            cleanUP(hObject, eventdata, handles);    % clean up - init all panels
            fileStatus = 'QUIT';
            return
        elseif   dataCount < 30                                    % Warning - 'Data length short ?
            dialogText = 'Possibly not enough data.  CONTINUE?';
            dialogTitle = 'Number of Data Lines < 30 ';
            dialogAnswer = QuestionDialog_v01( 'Title',dialogTitle,... % in separate .m 
                                          'String',dialogText );                                  %.... file   
            if dialogAnswer(1) == 'N'             % check answer (NO if a problem )
                  fileStatus = 'QUIT';                % ... send status to caller
            end
         end
  
%===============================================================
% Cleanup GUI open panels etc.
%===============================================================  
%Called as subroutine
function cleanUP(hObject, eventdata, handles)
    handles = guidata(gcbo);                            % get handles 

    set(handles.txtPath,'string','');                   % clean up GUI panels and flags
    set(handles.textFile,'string','NONE');
    set(handles.textWS,'string','NONE');
    set(handles.txtLength,'string','');
    set(handles.panelInfo,'Visible','off');
    set(handles.panelWS,'Visible','off');
    set(handles.panelFreqSample,'Visible','off');
    set(handles.textFs,'string','NONE');
    set(handles.panelPlot,'Visible','off');
    set(handles.panelWSname,'Visible','off');
    set(handles.panelFileName,'Visible','off');
    set(handles.txtPath,'string','');  
 
    guidata(hObject, handles);                        % save changed handles 

%===============================================================
% Pushbutton selecting time plot
%===============================================================      
    % --- Executes on button press in buttonTimePlot.
function buttonTimePlot_Callback(hObject, eventdata, handles)
    handles = guidata(gcbo);                                         % get handles
    delete(gcf)                                                                  % close the figure
    assignin('base','GUI_data',handles.GUI_info);     % send data to workspace 
 
    plotZoom_v02                                                % Plot input signal and setup                       
                                                                              % ... .for FFT   
%===============================================================
% Input sample frequency  
%===============================================================         
function [fs to] = inputSampleFrequemcy(hObject, eventdata, handles);    
      handles = guidata(gcbo);                             % get handles
      
      notANumber = true;                                     % preset as not a number
      while notANumber                                       % open window to input sample freq 
         prompt = {'KHz'};  windowTitle = 'Sample Frequency';   numberLines = 1;
         defaulSampleFreq = {'100'};                    % KHz
         sampleFrequencyInput = str2double(inputdlg(prompt, ...
                                  windowTitle, numberLines, defaulSampleFreq));
         % response = 1 if  no data present or cancel button,             
         promptResponse = isempty(sampleFrequencyInput);  
         % do one of the following
         if isnan(sampleFrequencyInput)                         % ans = 1 - if not number.  
              msgbox('Not a number','! ERROR !','error');  % put up dialog box and wait 
              uiwait(gcf);                                                          % ...for response                                                                             
         elseif   promptResponse == 1                     % for bracket reponse = 1 (cancel) 
              notANumber = false;                                % clean up for restart                                                   
              cleanUP(hObject, eventdata, handles);
              handles.fs = 0; to = [];
        else
             handles.fs = sampleFrequencyInput;         % frequency sample input ok
             dt = 1/(handles.fs*1000);                               % construct time vector with
             handles.to = (1:1:length(handles.GUI_info.volt))*dt;  % .. length = length  
             notANumber = false;                                                         %  ... of signal vector 
             set(handles.textFs,'string',handles.fs);                        % write to GUI
             set(handles.panelFreqSample,'Visible','on'); 
       end
      end
   %end
   fs = handles.fs*1000;                                % output parameters frequency & time
   to = handles.to;
    
   guidata(hObject, handles);                      % save any changed handles
  
%===============================================================
% Pushbutton selecting CLOSE GUI application
%===============================================================  
% --- Executes on button press in buttonClose.
function buttonClose_Callback(hObject, eventdata, handles)
    close
 
%===============================================================
% Required File Functions
%===============================================================     
function listWS_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'),...
                                          get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end
 
 

Contact us