2011-09-14 13 views
6

Sto raccogliendo dati e tracciare tali dati in tempo reale. I dati sono prodotti da un sistema di motion capture. Ho una classe DynamicDataset che è solo un wrapper attorno a una matrice a 2 colonne (sebbene sia più sfumata di quella) con un notificatore di eventi per i nuovi dati aggiunti; un'altra classe DynamicPlotter che ascolta l'evento con aggiunta di dati e aggiorna la trama in modo dinamico. frammenti di codice appropriato:MATLAB: il modo migliore per aggiornare dinamicamente una linea gestisce XData e YData?

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 

sulla base del profilo codice MATLAB, il comando set in updatePlot() è piuttosto costoso. Mi chiedo se c'è un modo migliore per tracciare i singoli punti man mano che arrivano? Idealmente, spingere il punto singolo in XData e YData e disegnare solo quel punto, ma non so se è possibile.

Si prega di notare che possono esserci più oggetti lineeries (cioè più grafici sullo stesso grafico); plot() accetta un argomento come argomento, quindi non considererebbe le proprietà degli handle di linea precedentemente disegnati (o c'è un modo per farlo?); Ho pensato di fare solo plot(x,y);hold all; ma questo mi avrebbe dato maniglie di linea separate ogni volta, ciascuna corrispondente ad un singolo punto.

Potrebbe essere che non c'è modo di tracciare i punti in arrivo più velocemente, ma ho pensato che avrei chiesto.

MODIFICA: OP aggiornato con il codice effettivo con cui sto lavorando, piuttosto che utilizzare un esempio generico valido per errori di interpretazione.

+0

Non so se avete visto questo, ma dare un'occhiata a http://stackoverflow.com/questions/1693429/matlab-oop-is-it-slow-or-am- I-doing-something-wrong. Fondamentalmente usando le classi in MATLAB generalmente si ottiene una prestazione scadente – Marm0t

+0

grazie, l'ho già visto prima. Il mio progetto richiede l'uso di classi per motivi per cui non entrerò, quindi non c'è modo di aggirare il problema ... ma la chiamata al 'set' sarebbe lenta semplicemente perché è chiamata all'interno di un metodo? –

+0

@ strictrude27: è necessario correggere la riga addlistener come: 'addlistener (oggetto (props {i}), 'DataAdded', @ (src, ev) obj.updatePlot (i));'. Si potrebbe anche voler aggiungere 'drawnow' alla fine della funzione' updatePlot' – Amro

risposta

4

La quantità di dati che stai manipolazione in ogni aggiornamento, è di grandi dimensioni (anche se solo un singolo punto sta effettivamente cambiando), rendendo il vostro codice di O (N^2).

Utilizzando una seconda linea per creare un ampio gruppo di dati, è possibile alternare l'aggiunta di ogni punto a una breve linea "attiva" e l'aggiunta di blocchi di grandi dimensioni alle linee principali principali. Sebbene ciò non eviti esattamente O (N^2), ti consente di ridurre significativamente la costante.

Se si esegue questa operazione, ricordare di sovrapporre le "vecchie" linee e le linee "attive" di un punto, in modo che si connettano.

In sostanza:

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 
+0

questo ha drasticamente ridotto il tempo di trama! se hai altre idee per ridurre ulteriormente il tempo, fammi sapere .. –

1

Parte del motivo per cui il codice potrebbe richiedere molto tempo per essere eseguito è perché si utilizza un ciclo for per assegnare le variabili. A seconda della versione di Matlab che stai usando, questo rallenterà significativamente il tuo processo. Propongo di usare vettorializzazione per assegnare valori al tuo x e y come questo:

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

È quindi possibile assegnare i primi punti nei dati.

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

Quando si stampa, assegnare XDataSource e YDataSource.

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

Ora, quando si esegue un ciclo di modificare i valori, utilizzare il RefreshData per aggiornare i valori XDATA e YData. Usa la funzione drawnow per aggiornare la finestra delle figure.

for k = 2:1000, 
xi = x(1:k); 
yi = y(1:k); 
refreshdata(h, 'caller') 
drawnow; 
end 
+0

Questo purtroppo non funzionerà per i miei bisogni: i miei dati non sono effettivamente generati in un ciclo for, ma sono prodotti da un sistema di motion capture in tempo reale. Lo snippet di codice sopra dimostra solo che sto tracciando dinamicamente i miei dati. Aggiornerò l'OP per riflettere il mio caso specifico; Stavo cercando di essere più generale, ma il mio esempio era chiaramente fuorviante. –

1

il codice è lento, perché si sta tracciare nuovamente tutti i valori ogni volta che si chiama updatePlot. Vorrei quindi solo tracciare l'ultimo punto in updatePlot (Questo è anche il problema che hai dichiarato: Idealmente avrei spinto il singolo punto in XData e YData e disegnato solo quel punto, ma non so se questo è possibile.)

  1. aggiungere proprietà 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. modificare 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 
    
+0

Questo potrebbe funzionare - Sono sicuro che dover ricopiare le proprietà non sarebbe la cosa più costosa al mondo. Tuttavia, mi domando su come questo interferirà con il manico degli assi principali che ho? Io aggiusto manualmente la finestra del grafico e gli altri assi gestiscono le proprietà, quindi scrivere costantemente questo potrebbe non essere l'opzione migliore. –

+1

il codice non sta ricopiando alcuna proprietà. Tutto ciò che fa è aggiungere il nuovo handle alla lista di handle: questa è un'operazione molto economica. La regolazione manuale dell'asse è un problema separato e non hai pubblicato il codice per questo. – memyself

Problemi correlati