2012-01-05 10 views
7

He escrito un script de Matlab que lee datos usando un puerto COMM virtual en en tiempo real. He realizado una cantidad significativa de procesamiento de señal en un mfile.GUI de Matlab utilizando la GUÍA: Desea actualizar gráficamente los gráficos

A continuación, sentí la necesidad de tener una GUI compacta que muestre la información como un resumen.

Recientemente empecé a cavar y leer más de la herramienta GUI incorporada de Matlab, GUIDE. He seguido algunos tutoriales y puedo mostrar mis gráficos en mi GUI después de presionar un botón.

Sin embargo, quiero que la GUI se actualice en tiempo real. Mi vector de datos se actualiza constantemente (leyendo datos del puerto COMM). Quiero que la GUI mantenga actualizando los gráficos con los datos más nuevos, en lugar de confiar en un botón para actualizar. ¿Puede alguien señalarme en la dirección correcta para actualizar el fondo?

Este es el código relevante actualmente para la interfaz gráfica de usuario:

% --- 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); 

editar el código modificado: Se

% --- 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); 

El error que consigo es:

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

Posible duplicado: http://stackoverflow.com/questions/1007385/getting-matlab-timer-to-update-matlab-guide-gui – Nzbuu

+0

@ c0d3rz Echa un vistazo a este enlace sobre la definición de las devoluciones de llamada timerfcn http: // www. mathworks.com/help/techdoc/matlab_prog/f9-39541.html#f9-42494 Intenta configurar 'timerfcn' en @GUIUpdate y cambiando GUIUpdate para que tenga dos entradas 'GUIUpdate (obj, event)'. 'obj' será el manejador del objeto del temporizador y 'event' tendrá algunos detalles sobre cómo se llamó. Por defecto, las devoluciones de llamada a la función del temporizador se transmitirán al menos a esos dos argumentos. No estoy seguro de si esa es la causa exacta de su error, pero su muestra no parece correcta. Si tengo la oportunidad más tarde intentaré publicar un temporizador de ejemplo. –

Respuesta

10

Aquí hay un ejemplo que usa un temporizador con una devolución de llamada timerFcn. Hice una GUI simple con 1 eje y 1 botón.

En la función de apertura inicializo la gráfica y creo el temporizador. En la devolución de llamada del botón de inicio, comienzo el temporizador y comienzo a manipular los datos. La función de devolución de llamada del temporizador simplemente actualiza los datos y de la línea a través de su manejador. A continuación se presentan las funciones relevantes de M-archivo de la interfaz gráfica de usuario (sección init cortado con tijeras y FCN salida.

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); 

es posible que desee un botón de parada para detener el temporizador en función de cómo se estructura el GUI y eran/cómo los datos se . actualizado

Editar: Basic controla info algo de esto es bastante básico y es posible que ya lo saben:

un mango individuo a un objeto contiene un montón de propiedades que se pueden leer con la función get() o establecer con la función set() Así que, por ejemplo, tal vez quería cambiar el texto del startButton por alguna razón en mi GUI.

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

Es posible que desee establecer un punto de interrupción en su código en algún lugar (tal vez en un botón de presionar) y jugar con las manejas struct. Ejecutando comandos get() en varios objetos para conocer sus propiedades.

Ahora la estructura de las manijas contiene todos los ... umm ... maneja los objetos de su GUI así como también cualquier artículo personalizado que pueda ser conveniente para su almacenamiento allí. La mayoría de las devoluciones de llamada GUI pasan automáticamente a la estructura de manejadores para que tenga fácil acceso a todas las partes de la GUI.

Ej. La devolución de llamada 'startButton' se pasó automáticamente al handles. Así que tuve fácil acceso al objeto del temporizador a través del handles.timer.

Lo que me lleva a pegar cosas personalizadas en handles. En la función de apertura, agregué un nuevo elemento a la estructura de identificadores handles.timer y handles.plot porque sabía que serían útiles en otras devoluciones de llamada (como la pulsación de un botón y la devolución de llamada timerFcn).

Sin embargo, para almacenar estas cosas permanentemente necesita utilizar la función 'guidata'.Esta función, básicamente, almacena la estructura modificada o recupera una copia de dependiendo de cómo la llame. Por lo tanto, la siguiente línea en la función de apertura guarda la estructura de controles modificados (agregado .timer y .plot) en la GUI principal.

guidata(hObject,handles); 

Básicamente cualquier momento se agrega algo en handles que debería tener esa línea para hacer el cambio permanente.

Ahora otro método de llamar es:

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

Esto recuperará la estructura de asas para la interfaz gráfica de usuario.

Y la última handles.output = hObject es la salida predeterminada cuando inicia su GUI. SI llama a su GUI a través de la línea de comandos de Matlab como esta h = myGUI;, debe devolver el identificador a su GUI.

+0

Muchas gracias Aero Energy. Creo que tengo que trabajar como quería con la ayuda de tu código. Realmente aprecio la ayuda. Leí la ayuda del temporizador en el sitio web, pero no pude hacerlo bien, el fragmento de código realmente me ayudó. Me sorprende que hayas tomado el tiempo de escribir un código relevante para ayudarme. ¡Gracias de nuevo! – c0d3rz

+0

Podría complacer lo que hacen estas dos líneas de código: handleles.output = hObject; guidata (hObject, handle); – c0d3rz

+0

No estoy seguro de usar esta notación. *. Leí el archivo de ayuda de Matlab sobre el uso de Handles, pero no tenía demasiado sentido para mí. – c0d3rz

1

Es necesario utilizar a timer object. Establezca la devolución de llamada para que sea la función que actualiza los diagramas.

+0

¿Hay una alternativa? – c0d3rz

+0

No a lo mejor de mi conocimiento. ¿Hay alguna buena razón por la que no puedas hacerlo de esta manera? – Nzbuu

+0

¿Puedes echar un vistazo a mi edición? Parece que no puedo usar correctamente la función del temporizador. – c0d3rz

1

Eche un vistazo a Making Graphs Responsive with Data Linking y el comando linkdata.

Si la misma variable aparece en trazados en varias figuras, puede vincular cualquiera de los trazados a la variable. Puede usar diagramas vinculados en el concierto con Marcado de gráficos con cepillado de datos, pero también en su propio . La vinculación de las parcelas que permite

  • hacer gráficos responden a los cambios en las variables en el espacio de trabajo de base o dentro de una función
  • hacer gráficas responden al cambiar las variables en el Editor de variables y la línea de comandos
  • modificar las variables a través de cepillado de datos que afectan a diferentes representaciones gráficas de ellos a la vez
  • Crear gráficas "ventanas" de vigilancia para propósitos de depuración

reloj ventanas son útiles si programa en el lenguaje MATLAB. Para el ejemplo , al refinar un algoritmo de procesamiento de datos para pasar a través de su código, puede ver que los gráficos responden a los cambios en las variables ya que una función ejecuta sentencias.

Hice una prueba rápida y sucia que se muestra a continuación y no estoy seguro de cómo funcionará esto en una GUI en función de una función, pero puede hacer el truco.

Nota 1: Tuve que agregar un punto de interrupción en mi subrutina donde se modifica el global y para ver realmente la actualización automática de la gráfica. Es posible que necesite una combinación de drawow, pausa o un temporizador si los datos se cambian rápidamente.

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 

Editar: puede haber maneras de evitar el uso de variables globales dependiendo de cómo sus funciones se estructuran ... pero no tengo tiempo para cavar en él para mucho.

+0

Gracias Aero, sin embargo, no estaba claro en mi pregunta. Además de cambiar los gráficos, también tengo algunos cuadros de texto estáticos, que también quiero actualizar. Parece que el temporizador es el camino a seguir ... – c0d3rz

+0

@ c0d3rz Consulte Mi otra respuesta para obtener ayuda con el funcionamiento de su temporizador. –

0

Puede agregar una devolución de llamada en el objeto serie que ejecuta una función de trazado. Debe adjuntar la devolución de llamada al evento 'BytesAvailableFcn' en el objeto (consulte this para obtener más detalles sobre las propiedades del objeto com).

Básicamente, cuando hay bytes disponibles en el puerto COM, instruye a matlab para que ejecute una función específica. En su caso, será la función de actualización de la GUI. Si necesita procesar los datos entrantes primero, su función de devolución de llamada primero hará el procesamiento de la señal y luego realizará los comandos de trazado.

+0

Gracias Jorge, sin embargo, no estaba claro en mi pregunta. Además de cambiar los gráficos, también tengo algunos cuadros de texto estáticos, que también quiero actualizar. Parece que el temporizador es el camino a seguir ... – c0d3rz

+0

También puede actualizar los cuadros utilizando get/set. El caso es que no conozco la lógica de tu código. – Jorge

Cuestiones relacionadas