Real time plotting slow: FigureController.flushCoalescer needs a lot of memory and cpu time
    7 views (last 30 days)
  
       Show older comments
    
Dear all,
I'm trying to plot data points from a serial device as fast as possible and I think, almost all best practices have been followed. The plot concept is approx like this (it's much more complicated, because it's part of a gui in reality)
classdef SensorPlots < handle
    properties
        HFig
        AxesHandles
        LineHandles
        Data = nan(300,4) % preallocate 300 samples, 4 different plots
        Time = nan(300,4)
        ToBePlottedIdx = false(300,4) % indicator, which data needs to be plotted
        LastPlottedIdx = repmat({nan},4,1) % idx to avoid dynamic growth of XData/YData
    end
    methods
        function obj = SensorPlots
           % load pre configured figure
           file = "pathToFig/fig.fig";
           obj.HFig = openfig(file);
           hh = findobj(obj.HFig,'type','axes');
           obj.AxesHandles = hh; % in reality, there are multiple axes
           obj.LineHandles = plot(obj.AxesHandles, obj.Time, obj.Data, '.');
           % first performance tweaks
           hh = obj.AxesHandles;
           disableDefaultInteractivity(hh);
           hh.Toolbar.Visible = 'off';
           hh.Toolbar = [];
           hh.Interactions = [];
           hh.XAxis.LimitsMode = 'manual';
           % timer to periodically update plots
           obj.plotTimer = timer('ExecutionMode', 'fixedRate', 'Period', 0.05, 'StartDelay', 0.5, 'TimerFcn', @obj.plotData, 'ErrorFcn', @obj.errorTimer, 'StopFcn', @obj.stopPlotTimer);
        end
        %% Cache the data in properties Data and Time
        % Is called by a Model in MVP context, based on an C# event class. 
        % gets called every ~40 ms
        % dataPack is a struct with fields accX, accY, accZ, temp
        function addData(obj, dataPack) 
            fn = fieldnames(dataPack);
            for k = 1:length(fn)
                len = length(dataPack.(fn{k}).value);
                freeIdx = find(~obj.ToBePlotted(:,k),len,'first');
                if isempty(freeIdx)
                    %                     disp('plot too slow')
                end
                obj.Data(freeIdx,k) = cat(1, dataPack.(fn{k}).value);
                obj.Time(freeIdx,k) = cat(1, dataPack.(fn{k}).lastUpdate);
                obj.ToBePlotted(freeIdx,k) = true;
            end
        end
        %% PlotData callback. 
        function plotData(obj, sender, evnt)
            for iDat = 1:size(obj.Data,2) % 4 cols -> 4 lines plots
                plotIdx = find(obj.ToBePlotted(:,iAng));
                if isempty(plotIdx)
                    continue;
                end
                len = nnz(plotIdx);             
                try
                    currLastPlottedIdx = obj.LastPlottedIdx{iDat};
                    % currLastPlottedIdx not initialized yet?
                    if any(isnan(currLastPlottedIdx))
                        currLastPlottedIdx = 1:len;
                    else
                        currLastPlottedIdx = currLastPlottedIdx(end) + 1:len;
                    end
                    % restrict indices not to be greater than preallocated XData
                    if(currLastPlottedIdx > size(obj.Data,1))
                        currLastPlottedIdx = currLastPlottedIdx - min(currLastPlottedIdx) + 1;
                    end
                    % plot data
                    obj.LineHandles(iData).XData(currLastPlottedIdx) = obj.Time(plotIdx,iDat)';
                    obj.LineHandles(iData).YData(currLastPlottedIdx) = obj.Data(plotIdx,iDat)';
                    maxTime = max(obj.Time(plotIdx,iDat)');
                    obj.LastPlottedIdx{iDat} = currLastPlottedIdx;
                catch e
                    e
                end
                obj.ToBePlotted(plotIdx,iAng) = false;
                meanAng(iAng) = mean(obj.Data(plotIdx,iAng));
            end       
            % try not to update the axes limits all the time, but each 500 ms
            currentToc = toc(obj.StartTic);
            if (currentToc - obj.LastLimitSetTime) > 0.5
                for hh = each(obj.AxesHandles)
                    hh.XAxis.Limits = [maxTime-10,maxTime+5];
                end
                drawnow limitrate
                obj.LastLimitSetTime = currentToc;
            end 
        end
    end
end
Do you see any obvious problems with that code? I tried to avoid high level functions an preallocate everything.
The profiler shows that output:

plotData takes the most time here:

Which seems reasonable, it's a lot of data. But what happens to the FigureController? Look at the memory + cpu time

Could anybody help me out with that? Why is this happening?
Thank you all very much!
6 Comments
Answers (0)
See Also
Categories
				Find more on Graphics Performance in Help Center and File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


