2

My FPGA is sending UDP packets on network using 100 mbps ethernet and a have written a MATLAB code to capture the data. The problem is i am getting very low speed in MATLAB around 50 kbps during reception. FPGA kit is connected to a gbps switch and then to PC. No internet cable in the switch. I am pasting the matlab code below. If i try to increase the speed by increasing buffer size, the packets are dropped. current settings are through hit and trial on which i receive all data successfully. IS there any way to increase data reception speed in MATLAB?

Code:: (UDP from FPGA to Matlab) clc clear all close all

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;

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

A MODIFIED VERSION OF THE ABOVE CODE (EASE OF UNDERSTANDING) + IMAGE Showing the PROBLEM

also: An image showing Data Variable with a buffer size of 20 Packets (18 bytes / Packet). Data must not be all zero as pointed in the image. It represents missed packets. /////////////////////////////////////////////////////////

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

An image showing Data Variable with a buffer size of 20 Packets (18 bytes / Packet). Data must not be all zero as pointed in the image. It represents missed packets

  • It is possible that your code is too slow to catch all packets. Problems exist like not initializing `data`, causing aggregating delays over loops. You can put `t(:,ii) = toc` inside the loop, so later you can know the actual excecuting time for each iteration. Another problem with your code is that you read the buffer **only** when it's full - most likely that could be the reason - when you are reading the buffer it actually cannot receive any more. – Yvon Aug 13 '14 at 05:06
  • ....Or, if I'm getting on the right point, `if (count == buffer_size) ` says you store the data **only** when the buffer is full. That may be a problem when the data is shorter than the buffer length?? – Yvon Aug 13 '14 at 05:08
  • Could you add to `if (count == buffer_size) ` an `else` condition, in which you just `disp('hi! missed packet')`? Thing seems like after `data(:,2) = something` it jumps to `data(:,6) = something other`. – Yvon Aug 13 '14 at 07:14
  • I actually had two points. Anyway, it can't be that Matlab skips 3 columns because it's "slow", and continue on the 6th column. If it is slow, then those 3 zero columns should not appear; instead the 4th col will be "3;3;3;3;3....". So more likely it's the buffer reading code. – Yvon Aug 13 '14 at 09:38
  • Thank you for your interest. The problem seems to be as you have pointed out. The FPGA is sending Data at a very fast rate around 50-60 Mbps but Matlab is receiving it at a lower rate. But i dont understand why data is being dropped. If slow reception was the issue then initial packets should also have been affected but that is not the case and increasing buffer size should have solved this. And why do i get timeouts if the sender is fast, changing timeouts also doesnt help. And this almost always happens when fread() is called in the loop never in between packets. – SameedSohail92 Aug 13 '14 at 09:41
  • How do i solve this buffer reading issue??? I also tried buffer size = 3*buffer_size_old while reading only fread(u,buffer_size_old) this also doesnt help. – SameedSohail92 Aug 13 '14 at 09:43
  • Why do you want to wait until the buffer is full before reading it? A buffer is not defined that way. – Yvon Aug 13 '14 at 09:45
  • I need high UDP reception speed (>1Mbps) for my project. I have somewhat solved the issue of dropped data packets at expense of reduction in speed(70kbps). By waiting for u.BytesAvailable == Buffer_size & then reading the buffer. But this is not meeting my projects requirements. – SameedSohail92 Aug 13 '14 at 09:49
  • It is not essential that i read the buffer when its full but as i mentioned earlier reading even buffer_size/2 doesnt help solve the issue?? – SameedSohail92 Aug 13 '14 at 09:52
  • The two issues have tangled together. You wait until the buffer is full, so you _miss_ packets, and those packets do not appear in `data` at all; the next time you read the buffer, it is not full, so you _drop_ those ones, putting zeros in `data`. Seems you'll need to solve both problems - keep the buffer available at any time; AND make your code fast. – Yvon Aug 13 '14 at 09:55
  • Yes. That seems to be the most plausible conclusion. Also when i change the Timeout period, it doesn't seem to have any considerable effect on speed of reception. If i double the timeout (say) the number of failed reads should reduce but it doesnot appear to be this way. – SameedSohail92 Aug 13 '14 at 10:42

2 Answers2

1

I looked at your code and found some basic corrections, let me know if it speed up your code.

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;
m_power
  • 3,156
  • 5
  • 33
  • 54
  • Thank you for your interest. But the issue isnt about execution speed. The tips you provided do not produce a significant effect on UDP reception speed. The issue lies in fread() command if i increase the buffer size to acquire many packets simultaneously where each packet is of 18Bytes, i start to lose some packets whereas speed of UDP reception goes up . I have tried different methodologies but nothing. I have also put a modified version of the original code in the thread for easy understanding of the problem. – SameedSohail92 Aug 13 '14 at 04:14
0

Let me summarize my comments.

Low code efficiency

  1. As @m_power has pointed out, using i and j slows down your code by a bit. See this for more information. In Matlab, you should always use ii and jj instead.

  2. You didn't initialize data. See how Mathworks explain this. If #1 "slows by a bit", #2 then slows a lot.

Since your code is slow, it's not guaranteed that each time FPGA sends a packet, your PC is able to find any available buffer to receive the packet.

Full buffer

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

So if the packet is smaller than the buffer, data(:,i) = nothing? That is the most possible reason why you are getting zeros in column 3,4,and 5.

Empty buffer

Zeros in column 3, 4 and 5 may also originate from an empty buffer, if you have done the previous changes. The buffer is not guaranteed to carry something when Matlab reads it, so some for iterations may catch zero-length contents, data(:,ii) = 0.

Use a while loop to solve this issue. Only count for non-empty buffer readings.

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

....incomplete packets?

You wait for a full buffer, because each time you want to read an entire packet? I suddenly realized it; how stupid I was!

But what you have done is keeping reading the buffer, and throwing away the data as long as it's shorter than the buffer length.

Instead, you'll need aggregate the data in each loop.

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

Test - I changed fread to a random integer generator with ii remembering how many times the buffer is read.

clear all;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)

The result is

    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

As you can see, each time the length of fread output is either equal to or less than the buffer size. But it only jumps to the next column when the current one has been completely received.

Community
  • 1
  • 1
Yvon
  • 2,903
  • 1
  • 14
  • 36
  • That's also the problem. In case of first miss in buffer size, count is zero. No other packets are read from the buffer if first packet is dropped.data(:, ii) = [a;zeros(buffer_size-count,1)]; – SameedSohail92 Aug 13 '14 at 10:54
  • Use while loop instead of for. Only increase the counter if the buffer is not empty. – Yvon Aug 13 '14 at 10:58
  • @SameedSohail92 I updated my answer. what did you mean by "first miss in buffer size"? – Yvon Aug 13 '14 at 16:19
  • Thank you for ur help Yvon. Your answer seems to be the most correct one. That indeed when I read the buffer I also block it fom receiving UDP packets at that point. If you see the data.png image the data columns where there are 0's are 3 in total which is also the number of packets dropped by MAtlab. Just to clarify a few things – SameedSohail92 Aug 14 '14 at 15:50
  • 1
    1) I read full buffer not because I want to read full packet (packet is of 18 bytes) but I do need to read in multiples of 18 to get complete packets as done in buffer-size calculation. By reading a large number of packets, I am minimizing the number of fread calls to improve the udp reception speed – SameedSohail92 Aug 14 '14 at 15:58
  • 1
    2) I dont think that while loop code will also solve the issue, the reason being what you pointed out in your earlier comment that if I read a buffer I block udp reception so even If I do read only when there is some data, some packets will be dropped. Which is not acceptable for my project. Even though I will be getting higher speed, I will not be getting all packets. Need to solve this packet drop issue associated with fread ( ). – SameedSohail92 Aug 14 '14 at 16:04
  • What I mean by ,"first miss" is that if even one packet is dropped the entire buffer is returned empty. Not sure yet why?? Although FPGA is transmitting packets at high speed. – SameedSohail92 Aug 14 '14 at 16:07
  • @SameedSohail92 It might be useful if you include your explanations into your question, which may attract more people into your problem. Now I think I can realize your problem is that Matlab isn't reading the buffer at an ideal speed, so the buffer can be easily filled up, blocking succeeding packets. It really needs some fine tune to your program :) – Yvon Aug 14 '14 at 16:55