MATLAB中的循环缓冲区,**无**复制旧数据

时间:2014-01-02 19:16:03

标签: matlab optimization buffer circular-buffer processing-efficiency

这里有一些关于如何在MATLAB中创建循环缓冲区的好帖子(例如this one)。然而,通过查看它们,我不相信它们适合我的应用程序,因为我所寻求的是MATLAB中的循环缓冲解决方案,它不涉及任何旧数据的复制。

使用一个简单的例子,让我们说我一次处理50个样本,每次迭代我读取10个样本。我将首先完成5次迭代,填充我的缓冲区,最后处理我的50个样本。所以我的缓冲区将是

[B1 B2 B3 B4 B5]

,其中每个'B'是10个样本的块。

现在,我读了接下来的10个样本,称之为B6。我希望我的缓冲区现在看起来像:

[B2 B3 B4 B5 B6]

问题就是这个 - 我不想每次复制旧数据,B2,B3,B4,B5,因为它在时间上变得昂贵。 (我有非常大的数据集)。

我想知道是否有办法在不复制“旧”数据的情况下执行此操作。谢谢。

3 个答案:

答案 0 :(得分:5)

快速实现循环缓冲区的一种方法是使用模数绕回到前面。这将稍微修改您指定的数据的顺序,但如果您只是用最新的数据替换最旧的数据而不是

,则可能更快且等效
[B2 B3 B4 B5 B6]

你得到了

[B6 B2 B3 B4 B5]

使用这样的代码:

bufferSize = 5;

data = nan(bufferSize,1)';

for ind = 1:bufferSize+2  

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

end

这适用于任意大小的数据。

如果您不熟悉模数,mod函数会有效地返回除法运算的剩余部分。因此mod(3,5)会返回3mod(6,5)会返回1mod(7,5)会返回2,依此类推,直到您达到等于0的mod(10,5)为止再次。这允许我们通过在每次到达结束时回到起点来“环绕”向量。代码中的+1-1是因为MATLAB将矢量索引设置为1而不是0,因此为了使数学计算正确,您必须在执行mod之前删除1将其添加回来以获得正确的索引。结果是当你尝试将第6个元素写入向量时,将其写入向量中的第1个位置。

答案 1 :(得分:1)

我的想法是使用一个包含5个条目的单元格数组,并使用一个变量来索引应该在下一步中覆盖的子数组。例如。

之类的东西
 a = {ones(10),2*ones(10),3*ones(10),4*ones(10),5*ones(10)};
 index = 1;

在下一步中,您可以写入子数组:

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

并像

一样增加索引
index = index+1

显然,某种限制:

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

那会是给你的吗?

编辑:要看的另一件事是条目的分类,因此总是会被某些条目转移,但取决于您如何继续使用数据,您可以例如根据变量index移动数据的使用。

EDIT2 :我有另一个想法:在MATLAB中使用类怎么样?您可以使用句柄类来保存数据,因此使用缓冲区仅引用数据。这个可能使它更快一些,具体取决于您拥有的数据(数据集的大小等)以及您在代码中将有多少班次。参见例如在这里:Matlab -- handle objects

您可以使用简单的句柄类:

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

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

将数据存储在其中:

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

然后只将对象引用存储在循环缓冲区中。在发布的链接中,答案显示作业bar = foo不会复制对象,但实际上只保留了引用:

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

但如上所述,由于OOP开销,我不知道这是否会更快。这可能取决于您的数据......以及有关它的更多信息:http://www.matlabtips.com/how-to-point-at-in-matlab/

答案 2 :(得分:0)

我刚上传了我的解决方案,用于快速循环缓冲区,不会复制旧数据

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

这种循环缓冲区的主要思想是持续快速的性能 在程序中使用缓冲区时避免复制操作:

% 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));

检查截图,看看如果缓冲区很大,这个循环缓冲区有优势,但每次附加的数据大小很小,因为circVBuf的性能不依赖于缓冲区大小,与简单的副本相比缓冲液中。

双缓冲可以根据要在任何情况下附加的数据来确定追加的预测时间。将来这个课程会给你一个双重缓冲的选择是或否 - 如果你不需要保证时间,事情就会加速。 enter image description here