我已经写了一个m函数来捕捉和绘制一个50Hz的串行数据流。这可以按预期工作,禁止在数据流的任何更改反映在图中之前存在大量(大约10秒)延迟的事实。使用MATLAB来显示流串行数据
m函数使用serial data stream设计模式,并且该图被配置为类似于strip chart。已经遵循MATLAB推荐的optimizing graphics performance,YData使用get/set方法更新,而不是重新绘制数据。
现在,无论是我的代码有问题,还是我已经达到了MATLAB能够在不使用实时窗口目标的情况下完成的极限。任何人都可以发现我做错了什么吗?我正在考虑在嵌入式系统上实现一个USB接口,以传输MATLAB绘制的数据,但我不相信这会解决这个问题。
function [] = tiny_stream(file)
% TINY_STREAM Plot and record a live pulse oximeter data stream.
% [] = TINY_STREAM(file) plots a live pulse oximeter data stream, and also
% records it to file. The data stream must contain ten columns of data.
expected_column_count = 10;
%% Declare variables.
% The sample rate is currently set to 50Hz by the pulse oximeter firmware, and
% only the last 10 cycles are plotted. Declaring plot data beforehand makes it
% easier to configure the plot.
global MAIN_LOOP;
MAIN_LOOP = true;
sample_rate = 50;
cycle_count = 10;
red_lowpass_data = NaN(sample_rate * cycle_count,1);
%% Create and configure plot.
% The 'plot' command is not used to update the plot, as it is far too slow to
% handle data streaming at 50Hz. Instead, the existing plot data is updated.
close all;
strip_chart = figure('Renderer','painters');
set(strip_chart,'DoubleBuffer','on');
set(strip_chart,'KeyPressFcn',@stop_stream);
time = 1:(sample_rate * cycle_count);
% Configure red chart.
red_subplot = subplot(2,1,1);
red_lowpass_trace = plot(time,red_lowpass_data,'b');
set(red_subplot,'YTickLabel',...
{'-10,000','0','10,000','20,000','30,000','40,000'},...
'YTick',[-10000 0 10000 20000 30000 40000],...
'YGrid','on');
ylim(red_subplot,[-10000 40000]);
ylabel('count');
set(red_subplot, 'XTickLabel',[],...
'XTick',1:cycle_count,...
'XGrid','on');
xlim(red_subplot,[1 cycle_count]);
xlabel('1 sec/div');
set(red_subplot,'OuterPosition',[0 0.5 1 0.5]);
box(red_subplot,'on');
title('Red Data');
set(red_subplot,'ALimMode','manual',...
'CameraPositionMode','manual',...
'CameraTargetMode','manual',...
'CameraUpVectorMode','manual',...
'CLimMode','manual',...
'TickDirMode','manual',...
'XLimMode','manual','YLimMode','manual','ZLimMode','manual',...
'XTickMode','manual','YTickMode','manual','ZTickMode','manual',...
'XTickLabelMode','manual','YTickLabelMode','manual',...
'ZTickLabelMode','manual');
drawnow;
%% Create and configure the serial port object.
serial_object = serial('COM2');
serial_object.BaudRate = 57600;
serial_object.DataBits = 8;
serial_object.FlowControl = 'none';
serial_object.StopBits = 1;
%% Configure the data stream.
% Note the use of the callback function 'transfer_data'. This is called by
% MATLAB whenever it detects the specified terminator in the serial object
% buffer.
serial_object.Terminator = 'CR/LF';
serial_object.InputBufferSize = 2^18;
serial_object.BytesAvailableFcnMode = 'terminator';
serial_object.BytesAvailableFcn = {@transfer_data};
serial_object.UserData.string_data = [];
serial_object.UserData.is_new = false;
%% Open the serial port.
if strcmp(serial_object.Status,'closed')
fopen(serial_object);
end
%% Open the file.
data_file = fopen(file,'w');
%% Main program loop.
% There may be more than one row of source data in the serial input buffer at
% the start of the main program loop. Any of these rows may be incomplete, so
% the first thing the main program does is to check that the data contains the
% expected number of entries. If it does not, then the entire data chunk is
% discarded.
while MAIN_LOOP == true
if serial_object.UserData.is_new == true
chunk_string = serial_object.UserData.string_data;
serial_object.UserData.is_new = false;
chunk_numeric = sscanf(chunk_string,'%d');
chunk_length = length(chunk_numeric);
if mod(chunk_length, expected_column_count) == 0
data_column_count = chunk_length/expected_column_count;
data = reshape(chunk_numeric,expected_column_count,...
data_column_count);
fprintf(data_file,...
'%6d %6d %6d %6d %6d %6d %6d %6d %6d %6d\r\n',data);
% Update red subplot.
red_lowpass_data = get(red_lowpass_trace,'YData');
red_lowpass_data(1,1:end - data_column_count) =...
red_lowpass_data(1,data_column_count + 1:end);
red_lowpass_data(1,end - data_column_count + 1:end) =...
data(4,:);
set(red_lowpass_trace,'YData',red_lowpass_data);
drawnow;
end
end
pause(0.001);
end
fclose(data_file);
fclose(serial_object);
delete(serial_object);
clear serial_object;
return
%% Loop control.
function [] = stop_stream(source, event)
% STOP_STREAM Stop the pulse oximeter serial stream.
% STOP_STREAM(source, event) sets the MAIN_LOOP global variable to false
% whenever a key is pressed while plot has focus.
global MAIN_LOOP;
MAIN_LOOP = false;
return
%% Data transfer.
function [] = transfer_data(object, event)
% TRANSFER_DATA Transfer data between buffers.
% TRANSFER_DATA(object, event) transfers data between the serial object
% input buffer and the user data area of the serial object.
string_data = fgets(object);
if object.UserData.is_new == false
object.UserData.string_data = string_data;
object.UserData.is_new = true;
else
object.UserData.string_data = [object.UserData.string_data string_data];
end
return
在改变流数据的某些内容并在Matlab中看到它相当稳定或者随着时间的推移会变得更糟?在主循环中快速增长的'red_lowpass_data'可能是罪魁祸首。 – nkjt
在特定的采样运行期间延迟是恒定的。更改图上显示的数据量确实会改变延迟的长度 - 显示10个数值的数据,延迟时间为10s。显示20s的数据,延迟时间为20s。这不是由于'red_lowpass_data'规模越来越大 - 所发生的一切就是现有数据正在被左移,以便为新数据腾出空间。 – RBE