Советы по повышению эффективности кода построения последовательных данных в реальном времени - PullRequest
1 голос
/ 01 ноября 2019

Я ищу предложения о том, как улучшить свой код, чтобы он мог работать более эффективно в режиме реального времени. Я потратил немало времени, пытаясь выяснить, как векторизовать мой товар и уменьшить количество циклов, а также улучшить графики в реальном времени (используя Matlab R2019a)

Буду признателен за предложения по

1) Векторизация кода

2) Попытка выяснить, как использовать удержание с субплотом. В настоящее время я инициализирую свой субплот и график перед тем, как войти в процедуру последовательных данных. Однако вместо того, чтобы добавлять каждую точку данных на график, я многократно строю все свои XData и YData от начала до текущей точки на каждой итерации, используя команду set, что я считаю бесполезным.

3)Любые другие предложения по эффективности

4) f.stop - это функция, которая создает кнопку, позволяющую мне запускать и останавливать процедуру. Если есть лучший способ сделать это, например, использовать дескрипторы сюжета таким образом, что процедура закрывается, когда я закрываю график, это также будет оценено.

Кодовый фон

Код последовательно считывает и выводит на экран мультиплексированные данные о емкости с пользовательской печатной платы, которая управляется Arduino. Печатная плата опрашивает массив конденсаторных ячеек 3х3, где каждая ячейка имеет 4 сигнала дифференциальной емкости - всего 36 сигналов. Это строится на 3x3, 4 сигнала на каждом графике. Данные представляют собой просто поток чисел, и я использую 29069 и 29070 в качестве маркеров, чтобы сообщить мне, когда плата начнет запускать и заканчивать опрос всех каналов возбуждения. Поток данных читается путем последовательного просмотра всех 12 сигналов канала возбуждения и объединения его в наборы по 4, перехода к следующему каналу емкости, повторения всего процесса 3 раза (операторы регистра).

%% Serial Data Acquisition from Arduino to Matlab
clc
clear all
close all
%Preallocate Arrays
c1 = zeros(4,1000);
c2 = zeros(4,1000);
c3 = zeros(4,1000);
c4 = zeros(4,1000);
c5 = zeros(4,1000);
c6 = zeros(4,1000);
c7 = zeros(4,1000);
c8 = zeros(4,1000);
c9 = zeros(4,1000);
c1_timer = zeros(5,1000);
incoming_data_1 = zeros(4,8)
incoming_data_2 = zeros(4,8)
incoming_data_3 = zeros(4,8)
arduino=serial('COM5','BaudRate',38400);
count = 1;
flag = 0;
f = stoploop
plot_count_1 = 1;
plot_count_2 = 1;
plot_count_3 = 1;
data_count = 1;
exc_ch_number = 1;
total_exc_ch_number = 13;
cin_ch_number = 1;
total_cin_ch_number = 3;
% Setup the Initial Plot
figure(1)
subplot(3,3,1)
plotGraph1 = plot(1:plot_count_1,c1(:,1:plot_count_1));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,2)
plotGraph2 = plot(1:plot_count_1,c2(:,1:plot_count_1));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,3)
plotGraph3 = plot(1:plot_count_2,c3(:,1:plot_count_1));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,4)
plotGraph4 = plot(1:plot_count_2,c4(:,1:plot_count_2));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,5)
plotGraph5 = plot(1:plot_count_2,c5(:,1:plot_count_2));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,6)
plotGraph6 = plot(1:plot_count_2,c6(:,1:plot_count_2));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,7)
plotGraph7 = plot(1:plot_count_3,c7(:,1:plot_count_3));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,8)
plotGraph8 = plot(1:plot_count_3,c8(:,1:plot_count_3));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
subplot(3,3,9)
plotGraph9 = plot(1:plot_count_3,c9(:,1:plot_count_3));
xtickangle(90)
legend('Top Left', 'Bot Left', 'Bot Right', 'Top Right', 'Location','southwest');
fopen(arduino)
timer_value = tic;
% Start the Serial Data read routine
while (~f.Stop())

    data = fscanf(arduino, '%d')


     if(data == 29069)
        flag = 1;
        continue

     elseif(data == 29070)
         flag = 0;
         data_count = 1;
         exc_ch_number =  exc_ch_number+1;


         if(exc_ch_number>total_exc_ch_number)
             exc_ch_number = 1

             switch cin_ch_number
             case 1
             c1(1:4,plot_count_1) = ((incoming_data_1(3,1:4)'./16777215).*8.192)-4.096;
             c1_timer(5,plot_count_1) = round(toc(timer_value));
             c2(1:4,plot_count_1) = ((incoming_data_1(3,[5 6 7 8])'./16777215).*8.192)-4.096;
             c3(1:4,plot_count_1) = ((incoming_data_1(3,9:12)'./16777215).*8.192)-4.096;

             set(plotGraph1,'XData',c1_timer(5,1:plot_count_1),{'YData'},num2cell(c1(:,1:plot_count_1),2));

             set(plotGraph2,'XData',c1_timer(5,1:plot_count_1),{'YData'},num2cell(c2(:,1:plot_count_1),2));

             set(plotGraph3,'XData',c1_timer(5,1:plot_count_1),{'YData'},num2cell(c3(:,1:plot_count_1),2));

             plot_count_1 = plot_count_1+1;

             case 2
             c4(1:4,plot_count_2) = ((incoming_data_2(3,1:4)'./16777215).*8.192)-4.096;
             c5(1:4,plot_count_2) = ((incoming_data_2(3,[5 6 7 8])'./16777215).*8.192)-4.096;
             c6(1:4,plot_count_2) = ((incoming_data_2(3,9:12)'./16777215).*8.192)-4.096;

             set(plotGraph4,'XData',c1_timer(5,1:plot_count_2),{'YData'},num2cell(c4(:,1:plot_count_2),2));

             set(plotGraph5,'XData',c1_timer(5,1:plot_count_2),{'YData'},num2cell(c5(:,1:plot_count_2),2));

             set(plotGraph6,'XData',c1_timer(5,1:plot_count_2),{'YData'},num2cell(c6(:,1:plot_count_2),2));

             plot_count_2 = plot_count_2+1;


             case 3
             c7(1:4,plot_count_3) = ((incoming_data_3(3,1:4)'./16777215).*8.192)-4.096;
             c8(1:4,plot_count_3) = ((incoming_data_3(3,[5 6 7 8])'./16777215).*8.192)-4.096;
             c9(1:4,plot_count_3) = ((incoming_data_3(3,9:12)'./16777215).*8.192)-4.096;

             set(plotGraph7,'XData',c1_timer(5,1:plot_count_3),{'YData'},num2cell(c7(:,1:plot_count_3),2));

             set(plotGraph8,'XData',c1_timer(5,1:plot_count_3),{'YData'},num2cell(c8(:,1:plot_count_3),2));

             set(plotGraph9,'XData',c1_timer(5,1:plot_count_3),{'YData'},num2cell(c9(:,1:plot_count_3),2));

             plot_count_3 = plot_count_3+1;

             end

             cin_ch_number = cin_ch_number+1;


             if(cin_ch_number>total_cin_ch_number)
                 cin_ch_number = 1;
             end
         end
     end


     if(flag==1)
         switch cin_ch_number
             case 1
                 incoming_data_1(data_count,exc_ch_number) = data;

             case 2
                 incoming_data_2(data_count,exc_ch_number) = data;

             case 3
                 incoming_data_3(data_count,exc_ch_number) = data;
         end

         data_count = data_count+1;
     end



end
delete(arduino)
clear arduino

Ответы [ 3 ]

0 голосов
/ 03 ноября 2019

Вы предварительно выделяете массивы данных для 1000 элементов, но нет никакой гарантии, что вы не будете использовать больше. Таким образом, вы, вероятно, будете расширять эти массивы, что стоит времени.

Далее, в следующих выражениях:

set(plotGraph1,'XData',c1_timer(5,1:plot_count_1),{'YData'},num2cell(c1(:,1:plot_count_1),2));

вы копируете данные путем индексации и копируете снова, чтобы преобразовать в ячейкумассив для каждой итерации цикла. То есть num2cell(c1(:,1:plot_count_1),2) вызывает две копии всех записанных данных. Это намного дороже, чем добавление в массив *. Я бы просто добавил к свойствам XData и YData, чтобы избежать дублирования и копирования данных постоянно:

c1 = ((incoming_data_1(3,1:4)'./16777215).*8.192)-4.096;
c1_timer = round(toc(timer_value));
% ...
for ii=1:4
   plotGraph1(ii).XData(end+1) = c1_timer;
   plotGraph1(ii).YData(end+1) = c1(ii);
end

* Обратите внимание, что MATLAB при добавлении удваивает внутреннее хранилище длямассив при необходимости, такой, что многократное добавление n элементов в массив стоит O ( n log n ), а не O ( n ²). См. этот другой вопрос и ответ для демонстрации.


Минимальный воспроизводимый пример:

figure(1)
timer_value = tic;
plotGraph1 = plot(0,zeros(4,1),'.-');
while true
   c1 = randn(4,1);
   c1_timer = toc(timer_value);
   % ...
   for ii=1:4
      plotGraph1(ii).XData(end+1) = c1_timer;
      plotGraph1(ii).YData(end+1) = c1(ii);
   end
   drawnow
   pause(0.1)
end
0 голосов
/ 08 ноября 2019

Возможно, вы захотите использовать анимированную функцию . Он заботится о многих оптимизациях, о которых вам нужно беспокоиться в этом случае.

0 голосов
/ 03 ноября 2019

Я не пробовал запускать ваш код, так как было бы трудно обойтись без отсутствующей функции или аппаратного обеспечения arduino. Вам следует взглянуть на документацию для предоставления минимального воспроизводимого примера: https://stackoverflow.com/help/minimal-reproducible-example Однако я определенно могу предложить несколько советов:

Во-первых, вы пытались использовать профилировщик Matlab? Из редактора вы можете использовать кнопку «Run and Time». Вы также можете запустить его из командной строки следующим образом:

profile on; my_func_here; profile viewer

Способ обновления графика имеет смысл для меня. Вот что я бы сделал: Обновление свойств XData / YData. Независимо от того, переписываете ли вы весь вектор или обновляете одну позицию, на самом деле это не имеет значения. В качестве другого подхода вы можете попробовать вызвать plot, чтобы каждый раз отображать одну новую точку;но я подозреваю, что это будет медленнее. Это то, что вы можете легко попробовать разные подходы, профилировать каждый, и посмотреть, который является наиболее эффективным.

Что касается остановки сюжета, ваш подход кажется нормальным. Если вы хотите остановить его, когда закроете график, он, вероятно, сделает это без какого-либо дополнительного кода, потому что он выдаст ошибку, когда рисунок и графики исчезнут. Если вам нужно более точное решение, вы можете сначала получить указатель на фигуру:

f = figure(1);

Затем в цикле while убедитесь, что фигура верна:

while isvalid(f)

Конечновы все равно можете получить код, выдающий ошибку, потому что вы можете закрыть цифру между проверкой isvalid и вызовом одной из функций plot. Таким образом, чтобы избежать этого, вы можете обернуть свои вызовы, чтобы изменить сюжет в try / catch.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...