Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ring buffer with numpy/ctypes

I'm developing a client which will receive the [EEG] data over tcp and write it to the ring buffer. I thought it can be very convenient to have the buffer as a ctypes or numpy array because it's possible to create a numpy 'view' to any location of such buffer and read/write/process the data without any copying operations. Or is it a bad idea in general?

However, I don't see how to implement a circular buffer of a fixed size this way. Suppose I have created a buffer object which is contiguous in memory. What is the best way to write the data when the end of the buffer is reached?

One possible way is to start overwriting the (already old) bytes from the begining when the write pointer reaches the end of the buffer array. Near the boundaries, however, the numpy view of some chunk (for processing) can't be created (or can it?) in this case, because some of it can still be located in the end of the buffer array while another already in its begining. I've read it's impossible to create such circular slices. How to solve this?

UPD: Thanks everybody for the answers. In case somebody also faces the same problem, here's the final code I've got.

like image 750
dmytro Avatar asked Jan 18 '12 11:01

dmytro


2 Answers

If you need a window of N bytes, make your buffer 2*N bytes and write all input to two locations: i % N and i % N + N, where i is a byte counter. That way you always have N consecutive bytes in the buffer.

data = 'Data to buffer'
N = 4
buf = 2*N*['\00']

for i,c in enumerate(data):
    j = i % N
    buf[j] = c
    buf[j+N] = c
    if i >= N-1:
        print ''.join(buf[j+1:j+N+1]) 

prints

Data
ata 
ta t
a to
 to 
to b
o bu
 buf
buff
uffe
ffer
like image 62
Janne Karila Avatar answered Sep 26 '22 12:09

Janne Karila


One possible way is to start overwriting the (already old) bytes from the begining when the write pointer reaches the end of the buffer array.

That's the only option in a fixed-size ring buffer.

I've read it's impossible to create such circular slices.

Which is why I wouldn't do this with a Numpy view. You can create a class wrapper around an ndarray instead, holding the buffer/array, the capacity and a pointer (index) to the insertion point. If you want to get the contents as a Numpy array, you'll have to make a copy like so:

buf = np.array([1,2,3,4])
indices = [3,0,1,2]
contents = buf[indices]    # copy

You can still set elements' values in-place if you implement __setitem__ and __setslice__.

like image 34
Fred Foo Avatar answered Sep 25 '22 12:09

Fred Foo