MATLAB Answers

0

How to plot a real time signal with axes automatically updating

Asked by Alessandro Russo on 14 May 2016
Latest activity Commented on by Geoff Hayes
on 10 Aug 2016
Hi all, i have an analog signal coming from the usb port of my PC, and i save it in Matlab using fread(serial...); i want to plot them in real time as soon as i acquire them, of course updating the time axis (seconds vs volts). How can i do this? Note that i get a sample every 100 ms! Thanks.

  2 Comments

Alessandro - how are you reading the data from your USB port? Do you have a timer that periodically (every 100 ms) polls the port for new data? Have you created a GUI that initiates this process and will attempt to update an axes within that GUI? Please provide more context and a sample of your code so that we can get an idea of how to best fit the solution for your needs.
Ok sorry i will contextualize better: i have a bluetooth development board that receives values from a sensor, every 100 ms (temporized by a timer counter of the source of the signal); as soon as it receives a value, it sends it to the PC via usb. In Matlab, i developed a GUI with a plot in it, the code that i implemented for a first use, sets the parameters for the function "serial", that is for example to stay opened for 1 second and receive a buffer of 8 bits (which is the dimension of the signle datum). After this, in a while loop i plot the value with a "pause" of 100 ms between one cycle and the next one. But i don't think that this method is efficient at all, and i would like to have a more expert advice :) Thanks!
Sample of the code (whole GUI, look at the function "start"):
function varargout = provauart(varargin)
% PROVAUART MATLAB code for provauart.fig
% PROVAUART, by itself, creates a new PROVAUART or raises the existing
% singleton*.
%
% H = PROVAUART returns the handle to a new PROVAUART or the handle to
% the existing singleton*.
%
% PROVAUART('CALLBACK',hObject,eventData,handles,...) calls the local
% function named CALLBACK in PROVAUART.M with the given input arguments.
%
% PROVAUART('Property','Value',...) creates a new PROVAUART or raises the
% existing singleton*. Starting from the left, property value pairs are
% applied to the GUI before provauart_OpeningFcn gets called. An
% unrecognized property name or invalid value makes property application
% stop. All inputs are passed to provauart_OpeningFcn via varargin.
%
% *See GUI Options on GUIDE's Tools menu. Choose "GUI allows only one
% instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES
% Edit the above text to modify the response to help provauart
% Last Modified by GUIDE v2.5 08-Apr-2016 10:40:11
% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @provauart_OpeningFcn, ...
'gui_OutputFcn', @provauart_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT
% --- Executes just before provauart is made visible.
function provauart_OpeningFcn(hObject, eventdata, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% varargin command line arguments to provauart (see VARARGIN)
% Choose default command line output for provauart
handles.output = hObject;
setappdata(0,'hgui',gcf);
% Update handles structure
guidata(hObject, handles);
% UIWAIT makes provauart wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = provauart_OutputFcn(hObject, eventdata, handles)
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes on button press in start.
function start_Callback(hObject, eventdata, handles) %START FUNCTION HERE!!!!
% hObject handle to start (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
hgui=getappdata(0,'hgui');
setappdata(hgui,'start',1);
priorPorts = instrfind;
delete(priorPorts);
s=serial ('COM3');
set(s,'BaudRate', 38400, 'DataBits', 8, 'Parity', 'none','StopBits', 1, 'FlowControl', 'none');
set(s, 'InputBufferSize', 4);
set(s, 'Timeout',0.1);
set(s, 'Terminator', 'CR/LF');
fopen(s);
setappdata(hgui,'s',s);
i=0;
array=[];
T=0;
while getappdata(hgui,'start')==1
i=i+1;
a=fread(s);
array(i)=a(1)*3/255;
if i>1
T=[T T(end)+0.1];
end
plot(T,array(1:i)),grid on,ylim([-1 4]),xlabel('Time [s]'),ylabel('Voltage [V]')
pause(0.1)
end
fclose(s);
guidata(hObject, handles)
% --- Executes on button press in stop.
function stop_Callback(hObject, eventdata, handles)
% hObject handle to stop (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
hgui=getappdata(0,'hgui');
setappdata(hgui,'start',0);
fclose(getappdata(hgui,'s'));
guidata(hObject, handles)

Sign in to comment.

Tags

2 Answers

Answer by Geoff Hayes
on 14 May 2016
Edited by Geoff Hayes
on 17 May 2016
 Accepted Answer

Alessandro - you could use a timer started from within your GUI that would, every 100 milliseconds, read from the bluetooth development board. You can set up your timer in such a way that it can access the handles object of the GUI so that if data has been read, it can be drawn on your axes.
For example, suppose that your timer starts when you press the start button in your GUI. The pushbutton callback would look something like
function start_Callback(hObject, eventdata, handles)
handles.timer = timer('Name','MyTimer', ...
'Period',0.1, ...
'StartDelay',0, ...
'TasksToExecute',inf, ...
'ExecutionMode','fixedSpacing', ...
'TimerFcn',{@timerCallback,handles.figure1});
guidata(hObject,handles);
start(handles.timer);
The above timer will fire (roughly) every 100 milliseconds. Note how we pass the GUI figure handle as an input to the timerCallback function. This is necessary so that we can access the handles structure (from there) to (potentially) update the axes with new data. The callback can be defined as
function [] = timerCallback(~,~,guiHandle)
if ~isempty(guiHandle)
% get the handles
handles = guidata(guiHandle);
if ~isempty(handles)
% query your bluetooth board using your code from the while loop
% if new data, then update the axes
end
end
In the above, we get the handles structure using guihandles so that we can get the current set of data in the axes control. In your stop button callback, you would then stop the timer
function stop_Callback(hObject, eventdata, handles)
if isfield(handles, 'timer')
stop(handles.timer);
end
When it comes to the code to update the plot with the new data, you can continue as before but bear in mind that every time you call plot you are creating a new graphics object. Which is a lot given that you do this ten times a second. An alternative is to plot once and update it's x and y data every time you have something to plot. In your start_Callback, create the object as
function start_Callback(hObject, eventdata, handles)
handles.timer - ...;
handles.hPlot = plot(NaN,NaN); % creates the graphics object with no data
guidata(hObject,handles);
start(handles.timer);
Then in the timer callback, update this plot as
xdata = [get(handles.hPlot,'XData') handles.T(end)];
ydata = [get(handles.hPlot,'YData') handles.array(end)];
set(handles.hPlot,'XData',xdata,'YData',data);
The above assumes that you are saving your updated T and array data to handles with the new data.
Try implementing the above and see what happens!
EDIT In the above, I replaced the
% get the handles
handles = guihandles(guiHandle);
with
% get the handles
handles = guidata(guiHandle);
so that we get back both the handles to the objects and any user-defined data.

  8 Comments

Hi, i'm trying t use your code to create a GUI to connect a bluetooth device for read data and plot in real time in the GUI but i have a problem with this code, can you help me Geoff Hayes????
Mauricio - please create a new question and describe what your code is doing and what the problem is.

Sign in to comment.


Answer by Shivaputra Narke on 14 May 2016

Hi,
Using loops is not good idea in your case.
You can use the BytesAvailableFcn callback to update the plot with new set of bytes received.

  1 Comment

Ok, can you provide an example of code using this function that also update the time axis in real time? Thanks!

Sign in to comment.