6

私はデータを収集し、そのデータをリアルタイムでプロットしています。データはモーションキャプチャシステムによって生成されます。新しいデータのイベント通知機能が追加された、2列の行列の単なるラッパーであるクラスが1つDynamicDatasetあります(ただし、それよりも微妙な違いがあります)。DynamicPlotterデータが追加されたイベントをリッスンし、プロットを動的に更新する別のクラス。適切なコードスニペット:

classdef DynamicDataset < handle
    properties
        newestData = [];
        data = []
    end
    events
        DataAdded
    end
    methods
        function append(obj, val)
            obj.data(end+1,:) = val;
            obj.newestData = val;
            notify(obj, 'DataAdded');
        end
    end
end

classdef DynamicPlotter < dynamicprops
    properties
        FH %# figure handle
        AH %# axes handle
        LH %# array of line handles - may have multiple lines on the plot

        dynProps = {} %# cell array of dynamic property names - 
                      %# use to access individual datasets
    end
    methods
        function obj = DynamicPlotter(props) %# props is a cell array of dynamic 
                                             %# properties to store information
            for i = 1:length(props) 
                addprop(obj, props{i});
                obj.(props{i}) = DynamicDataset;
                obj.dynProps = [obj.dynProps props{i}];

                addlistener(obj.(props{i}), 'DataAdded', @obj.updatePlot(i));
            end
            obj.createBlankPlot();
        end

        function createBlankPlot(obj)
            obj.FH = figure;
            obj.AH = axes;

            hold all;

            for i = 1:length(obj.dynProps)
                obj.LH(i) = plot(nan); %# only used to produce a line handle
                    set(obj.LH(i), 'XData', [], 'YData', []);
            end
        end

        function updatePlot(obj, propNum)
            X = get(obj.LH(propNum), 'XData');
            Y = get(obj.LH(propNum), 'YData');

            X(end+1) = obj.(dynProps{propNum}).newestData(1);
            Y(end+1) = obj.(dynProps{propNum}).newestData(2);

            set(obj.LH(propNum), 'XData', X, 'YData', Y);
        end
    end
end

MATLABコードプロファイルに基づくと、のsetコマンドupdatePlot()はかなり高価です。個々のポイントが来たときにプロットするためのより良い方法があるかどうか疑問に思っていますか?理想的には、単一のポイントを押し込んXDataYDataそのポイントのみを描画しますが、これが可能かどうかはわかりません。

複数の線列オブジェクト(つまり、同じプロット上に複数のグラフ)が存在する場合があることに注意してください。plot()引数としてAxesハンドルを受け取るため、以前に描画されたラインハンドルのプロパティは考慮されません(またはそうする方法はありますか?)。私はただやろうと思っていplot(x,y);hold all;ましたが、それは毎回別々のラインハンドルを与え、それぞれが単一のポイントに対応します。

入ってくるポイントのプロットをこれ以上速くする方法がないかもしれませんが、私は尋ねると思いました。

編集:誤解されやすい一般的な例を使用するのではなく、私が使用している実際のコードでOPを更新しました。

4

3 に答える 3

4

各更新で処理するデータの量は多く(実際には1つのポイントのみが変更されますが)、コードはO(N ^ 2)になります。

2番目のラインシリーズを使用してデータの大きなグループを構築することにより、すべてのポイントを短い「アクティブな」ラインに追加することと、まれに大きなブロックをメインのラインシリーズに追加することを交互に行うことができます。これはO(N ^ 2)を正確に回避するわけではありませんが、定数を大幅に減らすことができます。

これを行う場合は、「古い」ラインシリーズと「アクティブな」ラインシリーズを1ポイントオーバーラップさせて、それらが接続されるようにしてください。

基本的に:

    function updatePlot(obj, propNum)
        X = get(obj.LHactive(propNum), 'XData');
        Y = get(obj.LHactive(propNum), 'YData');

        X(end+1) = obj.(dynProps{propNum}).newestData(1);
        Y(end+1) = obj.(dynProps{propNum}).newestData(2);

        if numel(X) > 100
            Xold = [get(obj.LH(propNum), 'XData'); X(2:end)];
            Yold = [get(obj.LH(propNum), 'YData'); Y(2:end)];
            set(obj.LH(propNum), 'XData', Xold, 'YData', Yold);

            X = X(end);
            Y = Y(end);
        end

        set(obj.LHactive(propNum), 'XData', X, 'YData', Y);
    end
于 2011-09-17T22:39:52.070 に答える
1

コードの実行に時間がかかる理由の1つは、forループを使用して変数を割り当てるためです。使用しているMatlabのバージョンによっては、プロセスが大幅に遅くなります。次のように、ベクトル化を使用してxとyに値を割り当てることをお勧めします。

x = 1:1000;
y = cosd(x);

次に、データの最初のポイントを割り当てることができます。

xi = x(1);
yi = y(1);

プロットするときは、XDataSourceとYDataSourceを割り当てます。

h = plot(xi, yi, 'YDataSource', 'yi', 'XDataSource', 'xi');

ループして値を変更するときは、refreshdataを使用してXdata値とYdata値を更新します。drawow関数を使用して、Figureウィンドウを更新します。

for k = 2:1000,
xi = x(1:k);
yi = y(1:k);
refreshdata(h, 'caller')
drawnow;
end
于 2011-09-14T14:22:37.247 に答える
1

updatePlotを呼び出すたびにすべての値を再プロットするため、コードは低速です。したがって、updatePlotで最新のポイントのみをプロットします(これは、あなたが述べた問題でもあります。理想的には、単一のポイントをXDataとYDataにプッシュし、そのポイントのみを描画しますが、これが可能かどうかはわかりません。)。

  1. プロパティLH_point_counterを追加します

    classdef DynamicPlotter < dynamicprops
       properties
          FH %# figure handle
          AH %# axes handle
          LH %# cell array of line handles - may have multiple lines on the plot
    
          % counter that counts home many points we have for each dynProps
          LH_point_counter = [];
    
          dynProps = {} %# cell array of dynamic property names - 
                  %# use to access individual datasets
       end
    
  2. updatePlotを変更します

    function updatePlot(obj, propNum)
        % plot new point
        new_x = obj.(dynProps{propNum}).newestData(1);
        new_y = obj.(dynProps{propNum}).newestData(2);
        new_handle = plot(new_x, new_y);
    
        % add new handle to list of handles of this property
        counter_this_prop = obj.LH_point_counter(propNum);
        counter_this_prop = counter_this_prop + 1;
        obj.LH{propNum}(counter_this_prop) = new_handle;
    
        % save new counter value
        obj.LH_point_counter(propNum) = counter_this_prop;
    end
    
于 2011-09-23T18:50:17.620 に答える