Code covered by the BSD License  

Highlights from
CircuitTool (a Test and Measurement Demo)

image thumbnail

CircuitTool (a Test and Measurement Demo)

by

 

07 Sep 2004 (Updated )

A demonstration test and measurement application with system identification.

stripchart(varargin)
function varargout = stripchart(varargin)
% STRIPCHART Create a stripchart for real-time data display
%
% STRIPCHART makes it fairly easy to include a strip chart in your
% real-time data acquisition and analysis application.  You feed
% stripchart your data, and it updates the display.  It takes
% 2 steps to use STRIPCHART.  First, you initialize the stripchart with basic
% information needed for the FFT (sample rate, axis width, number of traces).
% After that, all you need to do is pass your data to the scope to update.
%
% This documentation starts with the simplest syntax for the two steps,
% then provides a few more advanced options.
%
% STEP 1: Initialize the stripchart
% STRIPCHART(FS,AXESWIDTH) initializes a stripchart in the current axes.
% This stripchart will display incoming data with a sample rate of FS Hz.
% The stripchart will display the most recent AXESWIDTH seconds of data.
%
% STEP 2: Update the scope
% STRIPCHART(S) updates the stripchart in the current axes with the
% data in vector S.  The scope should first be initialized as above with
% sample rate and axes width.  If not, the sample rate will be 1 Hz and the
% axes width will match the duration of S.  
%
% STRIPCHART(FS,AXESWIDTH,NTRACES) initializes a stripchart in the
% current axes with NTRACES traces.  A trace is a single line on the scope;
% typically one will display one trace per channel of data.  The default
% for NTRACES is 1. To update a stripchart with multiple traces,
% STRIPCHART(S) must specify a matrix S with shorter dimension length =
% NTRACES.  
%
% STRIPCHART(HAX, ...) defines the scope in specified axes HAX instead of GCA.  i.e.,
% STRIPCHART(HAX,FS,AXESWIDTH) initializes axes HAX as a stripchart, and
% STRIPCHART(HAX,S) updates axes HAX with vector S.
%
% HAX = STRIPCHART(...) returns a handle to the axes initialized by the
% stripchart.  This is useful if you allow STRIPCHART to create an
% axes for you, and want to be able to easily reference the axes for
% updates.  The lines created by STRIPCHART all have the tag
% 'StripChart'.  If you would like to manually modify the properties of
% these lines, their handles can be found by:
%
%        HAX = STRIPCHART(...);
%        HLINE = findobj(HAX,'Tag','StripChart');
%
% Example
% 		%% Create data
%       Fs = 1000;              % Sample rate
%       Ns = Fs*3;              % Make 5 seconds worth of data
%       t = (0:1:Ns-1)'/Fs;
%       A = sqrt(t);
%       A(1:Ns/2) = A(1:Ns/2);
%       A(end:-1:Ns/2+1) = A(1:Ns/2);
%       s = A.*sin(2*pi*t*1);
% 		
% 		%% Initialize scope
%       clf
%       AxesWidth = 2;          % Axes Width (s)
% 		stripchart(Fs,AxesWidth);
% 		
% 		%% Update scope
%       N = 50;
%       ind = 1:N:Ns;
% 
%       for ii = ind
%           stripchart(s(ii:ii+N-1,:));
%           drawnow;pause(.05);
%       end;

% Original version of StripChart written by Bob Bemis
% This modification was developed by Scott Hirsch to match syntax
%  of SpectrumScope
% Copyright 2003-2004 The MathWorks, Inc


%% Parse input arguments
% Decision tree:
% + Initialize or update?
%   o If update -> OK
%   o If initialize -> Axes specified, or use GCA?

error(nargchk(1,4,nargin))

%% Initialize or update?
% If first or second input argument is not a scalar, it must be data - i.e. we are
% updating

if numel(varargin{1}) > 1 || numel(varargin{2}) > 1 % Update
    action = 'update';
    
    if nargin==1                % Use current axes
        hAxes = gca;
        data = varargin{1};
    else
        hAxes = varargin{1};    % Axes was specified
        data = varargin{2};
    end;
    
    % If the user has not initialized this scope, do it for them
    parms = getappdata(hAxes,'StripChartParameters');
    
    % Ensure that scope has been initialized
    if isempty(parms)
        % Use default values
        Fs = 1;
        data = rowmajor(data);
        [Ns,NTraces] = size(data);
        AxesWidth = Ns*Fs;
        feval(mfilename,hAxes,Fs,AxesWidth,NTraces);       % This recursive call will initialize the scope
        % Get the new parameter structure
        parms = getappdata(hAxes,'StripChartParameters');
    end;
    
    
    
else                                    % Initialize  
    action = 'init';
    
    if ~isaxes(varargin{1})             % Easy mode, no handle passed in
        % Use current axes
        hAxes = gca;
        Fs = varargin{1};
        AxesWidth = varargin{2};
        Ns = AxesWidth*Fs;              % Number of samples across axes
        if nargin==3
            NTraces = varargin{3};
        else
            NTraces = 1;
        end;
        
    else                                % Expert mode, passed handle in
        hAxes = varargin{1};
        Fs = varargin{2};
        AxesWidth = varargin{3};
        Ns = AxesWidth*Fs;              % Number of samples across axes
        if nargin==4
            NTraces = varargin{4};
        else
            NTraces = 1;
        end;
    end;
end;


%% Dole out the work
% 
switch action
    case 'init'     % Initialize

        % Build structure to internally pass information
        parms.Fs = Fs;                      % Sample Rate
        parms.NTraces = NTraces;            % Number of lines in plot
        parms.hAxes = hAxes;                % Handle to axes
        parms.Ns = Ns;                      % Number of samples across axes
        parms.AxesWidth = AxesWidth;        % Requested Axes Width (s)
        
        % Store parameter structure
        setappdata(hAxes,'StripChartParameters',parms);
        
        localInitScope(parms)               % Initialize scope
        
    case 'update'   % Update
        parms = getappdata(hAxes,'StripChartParameters');

        % Error checking
        % Ensure that scope has been initialized.  This shouldn't slip
        % through to here.
        if isempty(parms)
            error(['The spectrum scope must first be initialized ' ...
                    'with the sample rate: stripchart(hAxes,Fs)']);
        end;
        
        % Force data to be in columns.  Allow for multiple columns.  This will
        % error if data actually has more channels than samples.
        data = rowmajor(data);

        % Check that the number of columns corresponds to the number of lines
        nc = size(data,2);      % Number of columns
        if nc ~= parms.NTraces
            error(['Size mismatch.  You initialized stripchart with ' num2str(parms.NTraces) ...
                    ' lines, but just passed in ' num2str(nc) ' channels of data.  These' ...
                    ' numbers must be the same.']);
        end;
        
        localUpdateScope(data,parms)            % Update the scope
end;

% Return appropriate output argument
if nargout
    varargout{1} = parms.hAxes;
end;        
            

% ***********************************************************************  
% Initialize the Scope
function localInitScope(parms)

% Set axes
t = (0:1:parms.Ns-1)'/parms.Fs;

% Add line(s)
parms.hLine = plot(t,NaN*ones(length(t),parms.NTraces), ...
    'Tag','StripChart', ...
    'Parent',parms.hAxes, ...
    'YDataSource','yData', ...
    'XDataMode','manual');
set(parms.hAxes,'XLim',[0 parms.AxesWidth]);
parms.yData = NaN*ones(length(t),parms.NTraces);
setappdata(parms.hAxes,'StripChartParameters',parms);

%% Get handle to the figure
% Turn doublebuffer on to eliminate flickering
hFig = get(parms.hAxes,'Parent');

% In R14, it's possible that hFig would return a handle to a panel, not a
% figure
vs = version;
if str2num(vs(1))>=7
    hFig = ancestor(parms.hAxes,'figure');
end;
% if ~strcmp(get(hFig,'Type'),'figure')
%     hFig = get(hFig,'Parent');
% end;

%%
% Format the axes 
% maintain X tick spacing
Ticks = get(parms.hAxes,'XTick');
dX = mean(diff(Ticks));

% enforce right justification for grid lines & remove X tick labels
Range = get(parms.hAxes,'XLim');
if Range(end)~=Ticks(end)
  Ticks = fliplr(Range(end):-dX:Range(1));
  set(parms.hAxes,'XTick',Ticks)
end
set(parms.hAxes,'XTickLabel',[],'XTickMode','Manual','XGrid','On','YGrid','On')

%%
% Label the plot.
% There's a bug in R13 when creating xlabel and ylabel with direct
% parenting - the alignment gets all messed up. Instead, make hAx current
% axes
% ca = gca;
set(hFig,'CurrentAxes',parms.hAxes);
xlabel(sprintf('%g%s/div',dX,'s'))
ylabel('Amplitude');
% set(hFig,'CurrentAxes',ca);

axis manual


%%
% Turn doublebuffer on to eliminate flickering
set(hFig,'DoubleBuffer','on');

% ***********************************************************************  
% Update the plot.
function localUpdateScope(data,parms)
% Callback function to update stripchart with new data

% Dynamically modify Magnitude axis as we go.  Expand, but don't shrink.  
% maxM=max(data(:));
% minM=min(data(:));
% yax2=get(parms.hAxes,'YLim');
% if minM<yax2(1),
%    yax2(1)=minM;
% end
% if maxM>yax2(2),
%    yax2(2)=maxM;
% end
% set(parms.hAxes,'YLim',yax2)


hLine = parms.hLine;

newPts = size(data);

% yData = zeros(parms.Ns,parms.NTraces);
yData = parms.yData;
% for ii=1:parms.NTraces
%     yData(:,ii) = get(hLine(ii),'YData');
% end;

% Shift and add data
parms.yData = [parms.yData(newPts+1:end,:) ; data];
% yData(1:end-newPts,:) = yData(newPts+1:end,:);      % shift old data left
% yData(end-newPts+1:end,:) = data;                 % new data goes on right
% set(hLine,{'YData'}, num2cell(yData,1)')
for ii=1:parms.NTraces
    set(hLine(ii),'YData',parms.yData(:,ii)) 
end;
% refreshdata(parms.hAxes,'caller');
setappdata(parms.hAxes,'StripChartParameters',parms);

% refreshdata(parms.hAxes,'caller');

% if NLines==1         %Special case for one line only
%     yData(1:end-newPts) = yData(newPts+1:end);      % shift old data left
%     yData(end-newPts+1:end) = data;                 % new data goes on right
% %     set(hLine,'YData',yData)                        % update plot
% else
%     for ii=1:NLines
%         yData{ii}(1:end-newPts) = yData{ii}(newPts+1:end);      % shift old data left
%         yData{ii}(end-newPts+1:end) = data(:,ii);              % new data goes on right
%     end;
% %     set(hLine,{'YData'},yData)                        % update plot
% end;
% refreshdata(parms.hAxes,'caller');

% ***********************************************************************  
% Utility - isaxes
function truefalse = isaxes(h)
% ISAXES(H)  True if H is a handle to a valid axes

truefalse = 0;      % Start false
if ishandle(h)
    if strcmp('axes',get(h,'Type'))
        truefalse = 1;
    end;
end;

% ***********************************************************************  
% Utility - rowmajor
function data = rowmajor(data)
% Force data to be row major. i.e. more rows than columns

[nr,nc] = size(data);
if nc>nr
    data = data';
end;



Contact us