Circular buffer in MATLAB, **without** copying old data

夙愿已清 提交于 2020-01-03 17:17:06

问题


There are some good posts on here (such as this one) on how to make a circular buffer in MATLAB. However from looking at them, I do not believe they fit my application, because what I am seeking, is a circular buffer solution in MATLAB, that does NOT involve any copying of old data.

To use a simple example, let us say that I am processing 50 samples at a time, and I read in 10 samples each iteration. I would first run through 5 iterations, fill up my buffer, and in the end, process my 50 samples. So my buffer will be

[B1 B2 B3 B4 B5]

, where each 'B' is a block of 10 samples.

Now, I read in the next 10 samples, call them B6. I want my buffer to now look like:

[B2 B3 B4 B5 B6]

The catch is this - I do NOT want to copy the old data, B2, B3, B4, B5 everytime, because it becomes expensive in time. (I have very large data sets).

I am wondering if there is a way to do this without any copying of 'old' data. Thank you.


回答1:


One way to quickly implement a circular buffer is to use modulus to circle back around to the front. This will slightly modify the order of the data from what you specified but may be faster and equivalent if you simply replace the oldest data with the newest so instead of

[B2 B3 B4 B5 B6]

You get

[B6 B2 B3 B4 B5]

By using code like this:

bufferSize = 5;

data = nan(bufferSize,1)';

for ind = 1:bufferSize+2  

    data(mod(ind-1, bufferSize)+1) = ind

end

and this works for arbitrary sized data.

If you're not familiar with modulo, the mod function returns effectively the remainder of a division operation. So mod(3,5) returns3, mod(6,5) returns 1, mod(7,5) returns 2 and so on until you reach mod(10,5) which equals 0 again. This allows us to 'wrap around' the vector by moving back to the start every time we reach the end. The +1 and -1 in the code is because MATLAB starts its vector indices at 1 rather than 0 so to get the math to work out right you have to remove 1 before doing the mod then add it back in to get the right index. The result is that when you try and write the 6th element to your vector is goes and writes it to the 1st position in the vector.




回答2:


My idea would be to use a cell-array with 5 entries and use a variable to index the sub-array which should be overwritten in the next step. E.g. something like

 a = {ones(10),2*ones(10),3*ones(10),4*ones(10),5*ones(10)};
 index = 1;

in the next step you could then write into the sub-array:

 a{index} = 6*ones(10);

and increase the index like

index = index+1

Obviously, some sort of limitation:

if(index > 5) % FIXED TYPO!!
   index = 1;
end

Would that be for you?

EDIT: One more thing to look at would be the sortation of the entries which would therefore always be shifted by some entries but depending on how you keep on using the data, you could e.g. shift the usage of the data depending on the variable index.

EDIT2: I've got another idea: What about using classes in MATLAB. You could use a handle-class to hold your data thus using the buffer to only reference to the data. This might make it a bit faster, depending on what data (how large the datasets are etc) you hold and how many shifts you'll have in your code. See e.g. here: Matlab -- handle objects

You could use a simple handle class:

classdef Foo < handle   
    properties (SetAccess = public, GetAccess = public)
        x
    end

    methods
        function obj = foo(x)
            % constructor
            obj.x = x;
        end 
    end       
end

Store the data in it:

data = [1 2 3 4];
foo = Foo(data);  % handle object

and then only store the object-reference in the circular buffer. In the posted link the answer shows that the assignment bar = foo doesn't copy the object but really only helds the reference:

foo.x = [3 4]
disp(bar.x)      % would be [3 4]

but as stated, I don't know if that will be faster because of the OOP-overhead. It might be depending on your data... And here some more information about it: http://www.matlabtips.com/how-to-point-at-in-matlab/




回答3:


I just uploaded my solution for a fast circular buffer to which does not copy old data

http://www.mathworks.com/matlabcentral/fileexchange/47025-circvbuf-m

The main idea of this circular buffer is constant and fast performance and avoiding copy operations when using the buffer in a program:

% create a circular vector buffer
    bufferSz = 1000;
    vectorLen= 7;
    cvbuf = circVBuf(int64(bufferSz),int64(vectorLen));

% fill buffer with 99 vectors
    vecs = zeros(99,vectorLen,'double');
    cvbuf.append(vecs);

% loop over lastly appended vectors of the circVBuf:
    new = cvbuf.new;
    lst = cvbuf.lst;
    for ix=new:lst
       vec(:) = cvbuf.raw(:,ix);
    end

% or direct array operation on lastly appended vectors in the buffer (no copy => fast)
    new = cvbuf.new;
    lst = cvbuf.lst;
    mean = mean(cvbuf.raw(3:7,new:lst));

Check the screenshot to see, that this circular buffer has advantages if the buffer is large, but the size of data to append each time is small as the performance of circVBuf does NOT depend on the buffer size, compared to a simple copy buffer.

The double buffering garanties a predictive time for an append depending on the data to append in any situation. In future this class shall give you a choice for double buffering yes or no - things will speedup, if you do not need the garantied time.



来源:https://stackoverflow.com/questions/20890128/circular-buffer-in-matlab-without-copying-old-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!