2

我编写了一个 m 函数来捕获和绘制 50Hz 串行数据流。这可以按预期工作,除非在数据流中的任何更改反映在绘图中之前存在很大的延迟(大约 10 秒)。

m-function 使用串行数据流设计模式,并且绘图被配置为类似于条形图。已遵循MATLAB优化图形性能的建议,使用 get/set 方法更新 YData,而不是重新绘制数据。

现在,要么我的代码有问题,要么我已经达到了 MATLAB 在不使用实时 windows 目标的情况下所能做的极限。谁能发现我做错了什么?我正在考虑在嵌入式系统上实现一个 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
4

2 回答 2

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 的任务。

于 2014-07-21T19:12:41.630 回答
0

我有类似的问题。对我来说,这是串行连接溢出引入的延迟。尝试降低采样率并提高波特率。看:

https://arduino.stackexchange.com/questions/3039/binary-serial-transmission-order-of-data

https://stackoverflow.com/questions/24368670/matlab-plot-serial-data-continously

于 2014-06-25T08:44:43.443 回答