2011-09-14 62 views
6

Tôi đang thu thập dữ liệu và vẽ sơ đồ dữ liệu đó theo thời gian thực. Dữ liệu được tạo ra bởi một hệ thống chụp chuyển động. Tôi có một lớp DynamicDataset chỉ là một trình bao bọc xung quanh ma trận 2 cột (mặc dù nó có nhiều sắc thái hơn) với một trình thông báo sự kiện cho dữ liệu mới được thêm vào; một lớp khác DynamicPlotter lắng nghe sự kiện được thêm dữ liệu và cập nhật cốt truyện động. đoạn mã thích hợp:MATLAB - cách tốt nhất để tự động cập nhật một dòng xử lý 'XData và 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 

Dựa trên hồ sơ MATLAB Mã, lệnh set trong updatePlot() là khá tốn kém. Tôi tự hỏi nếu có một cách tốt hơn để âm mưu các điểm cá nhân khi họ đến? Lý tưởng nhất là tôi sẽ đẩy điểm duy nhất vào XDataYData và vẽ điểm đó, nhưng tôi không biết nếu điều này là có thể.

Xin lưu ý rằng có thể có nhiều đối tượng dòng (ví dụ: nhiều đồ thị trên cùng một ô); plot() mất một trục xử lý như một đối số, do đó, nó sẽ không xem xét các thuộc tính của xử lý dòng vẽ trước đó (hoặc là có một cách để làm cho nó làm như vậy?); Tôi nghĩ chỉ cần làm plot(x,y);hold all; nhưng điều đó sẽ cho tôi xử lý dòng riêng biệt mỗi lần, mỗi lần tương ứng với một điểm duy nhất.

Nó có thể là không có cách nào để làm cho âm mưu điểm đến nhanh hơn, nhưng tôi figured tôi muốn hỏi.

EDIT: Đã cập nhật OP bằng mã thực tế mà tôi đang làm việc, thay vì sử dụng ví dụ chung để giải thích sai.

+0

Tôi không biết nếu bạn đã nhìn thấy điều này, nhưng hãy nhìn vào http://stackoverflow.com/questions/1693429/matlab-oop-is-it-slow-or-am- tôi đang làm gì đó. Về cơ bản sử dụng các lớp học trong MATLAB thường kết quả trong hiệu suất kém – Marm0t

+0

cảm ơn, tôi đã thấy rằng trước đây. Dự án của tôi yêu cầu sử dụng các lớp vì lý do tôi sẽ không đi vào, vì vậy không có cách nào xung quanh đó .. nhưng cuộc gọi 'set' sẽ chậm lại đơn giản chỉ vì nó được gọi bên trong một phương thức? –

+0

@ strictrude27: bạn nên sửa dòng addlistener như: 'addlistener (obj. (Đạo cụ {i}), 'DataAdded', @ (src, ev) obj.updatePlot (i));'. Bạn cũng có thể muốn thêm 'drawow' vào cuối hàm' updatePlot' – Amro

Trả lời

4

Lượng dữ liệu bạn đang xử lý trong mỗi bản cập nhật là lớn (mặc dù chỉ có một điểm thực sự thay đổi), làm cho mã của bạn O (N^2).

Bằng cách sử dụng một dòng thứ hai để xây dựng một nhóm lớn dữ liệu, bạn có thể thay thế giữa việc thêm mọi điểm vào một dòng "hoạt động" ngắn và không thường xuyên thêm khối lớn vào dòng chính. Trong khi điều này không chính xác tránh O (N^2), nó cho phép bạn giảm đáng kể liên tục.

Nếu bạn thực hiện việc này, hãy nhớ chồng chéo các dòng lệnh "cũ" và "hoạt động" theo một điểm để chúng kết nối.

Về cơ bản:

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

điều này làm giảm đáng kể thời gian âm mưu! nếu bạn có thêm ý tưởng để giảm thêm thời gian, hãy cho tôi biết .. –

1

Một phần lý do khiến mã của bạn có thể mất nhiều thời gian để chạy là vì bạn đang sử dụng vòng lặp for để gán biến của mình. Tùy thuộc vào phiên bản của Matlab bạn đang sử dụng, điều này sẽ làm chậm quá trình của bạn xuống đáng kể. Tôi khuyên bạn nên sử dụng vectơ để gán các giá trị cho x và y của bạn như sau:

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

Sau đó bạn có thể chỉ định các điểm đầu tiên trong dữ liệu của mình.

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

Khi bạn vẽ, hãy chỉ định XDataSource và YDataSource.

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

Bây giờ khi bạn lặp lại để thay đổi giá trị, hãy sử dụng hàm làm mới để cập nhật giá trị Xdata và Ydata. Sử dụng hàm rút gọn để cập nhật cửa sổ hình.

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

Điều này không may sẽ không hoạt động cho nhu cầu của tôi - dữ liệu của tôi không thực sự được tạo ra trong vòng lặp, nhưng được tạo bởi hệ thống chụp chuyển động trong thời gian thực. Đoạn mã trên chỉ chứng minh rằng tôi đang vẽ dữ liệu động của mình. Tôi sẽ cập nhật OP để phản ánh trường hợp cụ thể của tôi; Tôi đã cố gắng tổng quát hơn nhưng ví dụ của tôi rõ ràng là gây hiểu nhầm. –

1

Mã của bạn là chậm, bởi vì bạn đang replotting tất cả các giá trị mỗi lần mà bạn gọi updatePlot. Do đó tôi sẽ chỉ vẽ điểm mới nhất trong updatePlot (Đây cũng là vấn đề bạn đã nêu: Lý tưởng nhất là tôi sẽ đẩy điểm duy nhất vào XData và YData và vẽ điểm đó, nhưng tôi không biết điều này là có thể.)

  1. thêm tài sản 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. sửa đổi 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

Điều này có thể làm việc - Tôi chắc chắn phải recopy trên tài sản sẽ không phải là điều tốn kém nhất trên thế giới. Tuy nhiên, tôi tự hỏi làm thế nào điều này sẽ can thiệp với các trục chính xử lý tôi có? Tôi tự điều chỉnh cửa sổ lô và các trục khác xử lý các thuộc tính, vì vậy việc viết liên tục điều này có thể không phải là tùy chọn tốt nhất. –

+1

mã không được sao chép bất kỳ thuộc tính nào. Tất cả nó làm là thêm xử lý mới nhất vào danh sách xử lý - đây là một hoạt động rất rẻ. Điều chỉnh trục thủ công của bạn là một vấn đề riêng biệt và bạn chưa đăng mã cho điều đó. – memyself

Các vấn đề liên quan