Matlab GUI с использованием GUIDE: хотите динамически обновлять графики - PullRequest
8 голосов
/ 06 января 2012

Я написал скрипт Matlab, который считывает данные с использованием виртуального порта COMM в в режиме реального времени . Я сделал значительное количество обработки сигналов в mfile.

Затем я почувствовал необходимость в компактном графическом интерфейсе, который отображает информацию в виде сводки.

Я только недавно начал копать и читать больше встроенного в Matlab инструмента GUI GUIDE. Я выполнил несколько уроков и успешно смог отобразить мои графики на моем графическом интерфейсе после нажатия кнопки .

Однако я хочу, чтобы графический интерфейс обновлялся в режиме реального времени . Мой вектор данных постоянно обновляется (чтение данных из порта COMM). Я хочу, чтобы графический интерфейс пользователя обновлял графики новыми данными, в отличие от нажатия кнопки для обновления. Может кто-нибудь указать мне правильное направление для фонового обновления?

Вот соответствующий код в настоящее время для GUI:

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global data
global time

% Time domain plot
axes(handles.timeDomainPlot);
cla;
plot (time, data);

РЕДАКТИРОВАТЬ Измененный код:

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

%Setting it to display something when it ends
% t = timer('TimerFcn', 'timerOn=false; disp(''Updating GUI!'')',... 
t = timer(... 
            'TasksToExecute', 10, ... % Number of times to run the timer object
            'Period', 3, ...                
            'TimerFcn', GUIUpdate()); 

%Starting the timer
start(t)

function GUIUpdate()
global data
global time
%Parameters below axes
    global min
    global max 
      % Time domain plot
    axes(handles.timeDomainPlot);
    cla;
    plot (time, data);
    %Other parameters:
    set(handles.mean, 'String', mean);
    set(handles.max, 'String', max);

Я получаю ошибку:

??? Error using ==> GUI_Learning>GUIUpdate
Too many output arguments.

Error in ==>
@(hObject,eventdata)GUI_Learning('pushbutton1_Callback',hObject,eventdata,guidata(hObject))


??? Error while evaluating uicontrol Callback

Ответы [ 4 ]

10 голосов
/ 08 января 2012

Вот пример использования таймера с обратным вызовом timerFcn. Я сделал простой графический интерфейс с 1 осями и 1 кнопкой.

В функции открытия я инициализирую график и создаю таймер. При обратном вызове кнопки запуска я запускаю таймер и начинаю манипулировать данными. Функция обратного вызова таймера просто обновляет y-данные строки через ее дескриптор. Ниже приведены соответствующие функции из M-файла графического интерфейса пользователя (разрезанный раздел init и вывод fcn.

function testTimer_OpeningFcn(hObject, eventdata, handles, varargin)
global y x
x = 0:.1:3*pi; % Make up some data and plot
y = sin(x);
handles.plot = plot(handles.axes1,x,y);
handles.timer = timer('ExecutionMode','fixedRate',...
                    'Period', 0.5,...
                    'TimerFcn', {@GUIUpdate,handles});
handles.output = hObject;
guidata(hObject, handles);

% --- Executes on button press in startButton.
function startButton_Callback(hObject, eventdata, handles)
global y x
start(handles.timer)
for i =1:30
   y = sin(x+i/10); 
   pause(1) 
end

function GUIUpdate(obj,event,handles)
global y 
set(handles.plot,'ydata',y);

Возможно, вы захотите, чтобы кнопка «Стоп» остановила таймер в зависимости от структуры вашего графического интерфейса и от того, как / как обновляются данные.

Edit: Basic обрабатывает информацию, кое-что из этого довольно простое, и вы, возможно, уже знаете это:

Отдельный дескриптор объекта содержит набор свойств, которые вы можете прочитать с помощью функции get () или установить с помощью функции set (). Так, например, может быть, я захотел изменить текст startButton по какой-то причине в моем графическом интерфейсе.

set(handles.startButton,'String','Something Other Than Start');

Возможно, вы просто захотите установить точку останова в своем коде где-нибудь (возможно, нажатием кнопки) и поэкспериментировать со структурой дескрипторов. Выполнение get() команд на различных объектах для изучения их свойств.

Теперь структура дескрипторов содержит все ... umm ... дескрипторы объектов вашего GUI, а также любые пользовательские элементы, которые могут быть удобны для хранения там. Большинство обратных вызовов GUI автоматически передаются через структуру дескрипторов, поэтому у вас есть легкий доступ ко всем частям GUI.

Ex. Обратный вызов startButton был автоматически передан handles. Так что у меня был легкий доступ к объекту таймера через handles.timer.

Что заставляет меня вставлять нестандартные вещи в handles. В функции открытия я добавил новый элемент в структуру дескрипторов handles.timer и handles.plot, потому что я знал, что они будут полезны для других обратных вызовов (таких как нажатие кнопки и обратный вызов timerFcn).

Однако для постоянного хранения этих вещей вам необходимо использовать функцию «guidata». Эта функция в основном либо сохраняет измененную структуру handles, либо получает копию handles в зависимости от того, как вы ее называете. Поэтому следующая строка в функции открытия сохраняет измененную структуру дескрипторов (добавлены .timer и .plot) в основной графический интерфейс.

guidata(hObject,handles);

Как правило, каждый раз, когда вы добавляете что-то в handles, у вас должна быть эта строка, чтобы сделать изменение постоянным.

Теперь другой метод вызова:

handles = guidata(hObject); %hObject can be any handle who is a child of the main GUI.

При этом будет получена структура дескрипторов для графического интерфейса.

И последний handles.output = hObject - это просто вывод по умолчанию при запуске вашего графического интерфейса. Если вы вызываете свой графический интерфейс через командную строку Matlab, как это h = myGUI;, он должен вернуть дескриптор в ваш графический интерфейс.

1 голос
/ 06 января 2012

Взгляните на Создание графиков, чувствительных к связыванию данных и команду linkdata .

Если одна и та же переменная отображается на графиках на нескольких рисунках,Вы можете связать любой из графиков с переменной.Вы можете использовать связанные графики в сочетании с разметкой графиков с помощью Data Brushing, но также и самостоятельно.Связывание графиков позволяет вам

  • Заставлять графики реагировать на изменения переменных в базовой рабочей области или в функции
  • Заставлять графы реагировать при изменении переменных в Редакторе переменных и Командной строке
  • Изменение переменных с помощью чистки данных, которые влияют на различные графические представления их одновременно
  • Создание графических "окон наблюдения" для целей отладки

Просмотр окон полезен, если вы программируете вязык MATLAB.Например, при уточнении алгоритма обработки данных для пошагового выполнения кода вы можете видеть графики, реагирующие на изменения переменных, когда функция выполняет операторы.

Я сделал быстрый и грязный тест, показанный ниже, и яЯ не уверен, как это будет работать в GUI стихи функции, но может сделать свое дело.

Примечание 1: Мне пришлось добавить точку останова в моей подпрограмме, где она изменяет глобальный y, чтобы фактически увидеть автоматическое обновление графика.Вам может понадобиться комбинация drawnow, pause или таймера, если данные быстро меняются.

function testLinking()
global x y
%Links failed if the global did not also exist in the base workspace
evalin('base','global x y');
x = 0:.1:3*pi; % Make up some data and plot
y = sin(x);

h = plot(x,y,'ydatasource','y','xdatasource','x');
linkdata on
testSub

function testSub()
%Test to see if a sub can make a linked global refresh
global x y
for i = 1:10
    %This should automatically update the plot.
    y = sin(x+i/10); 
end

Редактировать: могут быть способы обойти глобальные переменные в зависимости от структуры ваших функций ...но у меня нет времени копаться в этом.

1 голос
/ 06 января 2012

Вам необходимо использовать объект таймера . Установите функцию обратного вызова для функции, которая обновляет графики.

0 голосов
/ 06 января 2012

Вы можете добавить обратный вызов для последовательного объекта, который выполняет функцию построения.Вы должны прикрепить обратный вызов к событию «BytesAvailableFcn» на объекте (см. this для получения дополнительной информации о свойствах объекта com).

По существу, когда вcom порт, вы указываете Matlab запускать определенную функцию.В вашем случае это будет функция обновления GUI.Если вам сначала нужно обработать входящие данные, тогда ваша функция обратного вызова сначала выполнит обработку сигнала, а затем выполнит команды построения графика.

...