2013-10-20 12 views
2

我已经写了一个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 
+0

在改变流数据的某些内容并在Matlab中看到它相当稳定或者随着时间的推移会变得更糟?在主循环中快速增长的'red_lowpass_data'可能是罪魁祸首。 – nkjt

+0

在特定的采样运行期间延迟是恒定的。更改图上显示的数据量确实会改变延迟的长度 - 显示10个数值的数据,延迟时间为10s。显示20s的数据,延迟时间为20s。这不是由于'red_lowpass_data'规模越来越大 - 所发生的一切就是现有数据正在被左移,以便为新数据腾出空间。 – RBE

回答

2

我前一段时间提出的原来的问题,而忽略了后期的答案时,我发现它 - 我们对此深感抱歉。对于那些有兴趣的人来说,结果是10秒的延迟是由于我设置我的轴​​的XLimXtick属性时出现错误而引起的。更换下面的代码片断:

set(red_subplot, 'XTickLabel',[],... 
    'XTick',1:cycle_count,... 
    'XGrid','on'); 
xlim(red_subplot,[1 cycle_count]); 
xlabel('1 sec/div'); 

有了这一个:

set(red_subplot,'XTickLabel',[],... 
    'XTick',(0:sample_rate:(sample_rate * cycle_count))',... 
    'XGrid','on'); 
xlim(red_subplot,[0 sample_rate * cycle_count]); 
xlabel('1 sec/div'); 

消除了10秒延迟。通常情况下,解决一个问题暴露出另一个更基本的问题。看来,MATLAB无法在不丢弃样本的情况下记录57600串行数据流。这种行为已经通过类似于上面发布的代码(即GUI代码)以及根本没有GUI的简化命令行版本进行了验证。每次运行的样本数量都有所不同,但是每分钟约有7个,即每3000个样本有7个。然后,我编写了一些LabVIEW代码来完成同样的任务,并且不会丢失任何一个样本,无论我将其运行多少小时。我从这一切中吸取的教训是,MATLAB对分析数据非常有用,但对于获取它不太好。这是LabVIEW或dSPACE的最佳任务。

相关问题