【问题标题】:Slow speed of UDP reception in MatlabMatlab中UDP接收速度慢
【发布时间】:2014-08-14 00:26:47
【问题描述】:

我的 FPGA 正在使用 100 mbps 以太网在网络上发送 UDP 数据包,并且我编写了一个 MATLAB 代码来捕获数据。问题是我在接收期间在 MATLAB 中的速度非常低,大约为 50 kbps。 FPGA 套件连接到 gbps 交换机,然后连接到 PC。交换机中没有网线。 我正在粘贴下面的matlab代码。如果我尝试通过增加缓冲区大小来提高速度,则会丢弃数据包。当前设置是通过点击和试用,我成功接收到所有数据。有什么办法可以提高MATLAB中的数据接收速度?

代码:: (从 FPGA 到 Matlab 的 UDP) clc 清除所有 全部关闭

u=udp('192.168.0.100','RemotePort',4660,'Localport',4661);
set(u,'DatagramTerminateMode','off');
set(u, 'InputBufferSize', 18);
set(u,'Timeout',0.1);

fopen(u);
x=tic;
for i =1:1000
  a(:,i) = fread(u,18);
end
fclose(u);
delete(u);
t=toc(x);
bw = (1000*18*8)/t;

/////////////////////////////////////// //////////

上述代码的修改版本(易于理解)+显示问题的图像

也:显示数据变量的图像,缓冲区大小为 20 个数据包(18 个字节/数据包)。如图所示,数据不得全为零。它代表丢失的数据包。 ///////////////////////////////////////// ///////

clc
clear all
close all

packet_size = 18;                % Size of 1 Packet
buffer_size = 1*packet_size;     % Buffer to store 1024 packets each of Packet_Size
buffer_read_count = 10;          % How many times the buffer must be read 

u=udp('192.168.0.100','RemotePort',4660,'Localport',4661);

set(u,'DatagramTerminateMode','off');   
set(u, 'InputBufferSize', buffer_size);     
set(u,'Timeout',0.5); 

fopen(u);
x=tic;

for i =1:buffer_read_count
    [a, count] = fread(u,buffer_size);  % Read the complete buffer in one Fread()
    if (count == buffer_size) 
        data(:, i) = a;           %If Read_BYtes(Count) == BufferSize Store in Data
    end
end

fclose(u);
delete(u);

t=toc(x);

bw = (buffer_read_count*buffer_size*8)/t; %Speed / BW of UDP Reception

【问题讨论】:

  • 您的代码可能太慢而无法捕获所有数据包。存在诸如未初始化 data 等问题,从而导致循环聚合延迟。您可以将t(:,ii) = toc 放入循环中,以便稍后您可以知道每次迭代的实际执行时间。您的代码的另一个问题是,当缓冲区已满时,您 才读取该缓冲区 - 这很可能是原因 - 当您读取缓冲区时,它实际上无法再接收。
  • ....或者,如果我说得对,if (count == buffer_size) 说您在缓冲区已满时存储数据。当数据短于缓冲区长度时,这可能是一个问题??
  • 您能否在if (count == buffer_size) 中添加一个else 条件,其中您只是disp('hi! missed packet')?事情似乎在data(:,2) = something 之后跳转到data(:,6) = something other
  • 我其实有两点。无论如何,Matlab不可能因为“慢”而跳过3列,并在第6列继续。如果它很慢,那么这 3 个零列不应该出现;相反,第 4 列将是“3;3;3;3;3....”。所以更有可能是缓冲区读取代码。
  • 感谢您的关注。问题似乎正如您所指出的那样。 FPGA 以 50-60 Mbps 左右的非常快的速率发送数据,但 Matlab 以较低的速率接收数据。但我不明白为什么数据被丢弃。如果接收速度慢是问题,那么初始数据包也应该受到影响,但事实并非如此,增加缓冲区大小应该可以解决这个问题。如果发件人速度很快,为什么我会超时,更改超时也无济于事。这几乎总是在循环中调用 fread() 时发生,而不是在数据包之间。

标签: matlab udp fpga


【解决方案1】:

我查看了您的代码并发现了一些基本的更正,如果它加快了您的代码速度,请告诉我。

u=udp('192.168.0.100','RemotePort',4660,'Localport',4661);
set(u,'DatagramTerminateMode','off', ...
      'InputBufferSize', 18, ...
      'Timeout',0.1); % I think only one call of set is needed here

fopen(u);
x=tic;
% The variable a is not pre-allocated before the loop
a = zeros(YourNumberOfLine, 1000)
for ii =1:1000 % Always use ii and jj and not i and j
  a(:,ii) = fread(u,18);
end
fclose(u);
delete(u);
t=toc(x);
bw = (1000*18*8)/t;

【讨论】:

  • 感谢您的关注。但问题不在于执行速度。您提供的提示不会对 UDP 接收速度产生显着影响。问题在于 fread() 命令,如果我增加缓冲区大小以同时获取许多数据包,其中每个数据包为 18 字节,我开始丢失一些数据包,而 UDP 接收速度上升。我尝试了不同的方法,但没有。为了便于理解问题,我还在线程中放了原代码的修改版。
【解决方案2】:

让我总结一下我的cmets。

代码效率低

  1. 正如@m_power 所指出的,使用ij 会稍微减慢您的代码速度。请参阅this 了解更多信息。在 Matlab 中,您应该始终使用 iijj

  2. 你没有初始化data。看看Mathworks 是如何解释这个的。如果#1“慢了一点”,那么#2就会慢很多。

由于您的代码很慢,因此无法保证每次 FPGA 发送数据包时,您的 PC 都能找到任何可用的缓冲区来接收数据包。

完整缓冲区

if (count == buffer_size) 
    data(:, i) = a;           %If Read_BYtes(Count) == BufferSize Store in Data
end

那么如果数据包小于缓冲区,data(:,i) = nothing?这是您在第 3、4 和 5 列中得到零的最可能原因。

空缓冲区

第 3、4 和 5 列中的零也可能源自空缓冲区,如果您已完成之前的更改。当 Matlab 读取缓冲区时,不能保证缓冲区携带某些内容,因此某些 for 迭代可能会捕获零长度内容,data(:,ii) = 0

使用while 循环来解决此问题。仅计算非空缓冲区读数。

ii = 0;

while (ii < buffer_read_count)
    [a, count] = fread(u, buffer_size);
    if count % non-empty reading
        ii = ii+1;
        data(1:count,ii) = a;
    end
end

....不完整的数据包?

你等待一个完整的缓冲区,因为每次你想读取一个完整的数据包?我突然意识到;我是多么愚蠢!

但是您所做的是继续读取缓冲区,并丢弃数据,只要它比缓冲区长度短。

相反,您需要汇总每个循环中的数据。

data = zeros(buffer_size, buffer_read_count);
total_size = buffer_read_count*buffer_size;
ptr = 1; % 1-D array index of data
while (ptr < total_size)
    [a, count] = fread(u, buffer_size);
    if count % non-empty reading
        if ( (ptr+count) > total_size )
            data(ptr:end) = a(1:(total_size-ptr+1));
            ptr = total_size;
        else
            data( ptr:(ptr+count-1) ) = a;
            ptr = ptr+count;
        end
    end
end

测试 - 我将 fread 更改为随机整数生成器,ii 记住读取缓冲区的次数。

全部清除;clc;

buffer_size = 18;
buffer_read_count = 10;
data = zeros(buffer_size, buffer_read_count);
total_size = buffer_read_count*buffer_size;
ptr = 1; % 1-D array index of data
ii = 1;
while (ptr < total_size)
    count = randi(buffer_size);
    a = randi(9, count, 1) + ii*10; % 10's show number of buffer readings
    ii = ii+1;
%     [a, count] = fread(u, buffer_size);
    if count % non-empty reading
        if ( (ptr+count) > total_size )
            data(ptr:end) = a(1:(total_size-ptr+1));
            ptr = total_size;
        else
            data( ptr:(ptr+count-1) ) = a;
            ptr = ptr+count;
        end
    end
end
disp(data)

结果是

    13    38    51    63    72    93   104   125   141   164
    12    35    53    63    73    96   101   123   148   168
    14    33    55    68    72    99   106   124   142   168
    14    37    51    69    77    91   109   127   145   165
    12    33    57    66    76    96   114   137   143   168
    14    39    56    63    72    94   117   139   144   169
    11    46    55    61    72    93   111   139   146   164
    16    42    58    68    75    93   119   135   153   164
    26    41    58    66    79   109   126   139   152   166
    33    43    58    69    75   102   122   132   152   177
    35    48    53    61    81   108   125   131   153   174
    36    49    55    66    95   102   125   133   165   177
    31    47    57    63    94   109   129   136   164   179
    35    47    51    72    98   108   128   135   162   175
    36    43    51    74    94   104   129   139   169   175
    32    46    53    74    95   107   127   144   164   173
    38    48    55    78    97   105   124   145   168   171
    39    44    59    77    98   108   129   147   166   172

如您所见,每次fread 输出的长度要么等于或小于缓冲区大小。但只有当当前的列已完全接收时,它才会跳转到下一列。

【讨论】:

  • 这也是问题所在。如果缓冲区大小首次未命中,则计数为零。如果第一个数据包被丢弃,则不会从缓冲区中读取其他数据包。data(:, ii) = [a;zeros(buffer_size-count,1)];
  • 使用 while 循环代替 for。仅当缓冲区不为空时才增加计数器。
  • @SameedSohail92 我更新了我的答案。 “第一次丢失缓冲区大小”是什么意思?
  • 1) 我读取完整的缓冲区不是因为我想读取完整的数据包(数据包为 18 字节),但我确实需要读取 18 的倍数才能获得完整的数据包,如缓冲区大小计算中所做的那样.通过读取大量数据包,我将 fread 调用次数降至最低,以提高 udp 接收速度
  • 2) 我不认为 while 循环代码也能解决问题,原因是你在之前的评论中指出,如果我读取缓冲区,我会阻止 udp 接收,所以即使我读了只有当有一些数据时,才会丢弃一些数据包。这对我的项目来说是不可接受的。即使我会得到更高的速度,我也不会得到所有的数据包。需要解决这个与 fread ( ) 相关的丢包问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-05-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-12-14
  • 2012-12-25
  • 2020-06-17
相关资源
最近更新 更多