I think you need to take a step back from the mental style of C. Updating the ringbuffer for each individual insert will never be effective. The ring buffer is fundamentally different from the adjacent memory block interface, which requires numpy arrays; including the fft you are talking about want to do.
The natural solution is to sacrifice some memory for performance. For example, if the number of elements to keep in your buffer is N, select an array of N + 1024 (or some reasonable number). Then you only need to move N elements around every 1024 inserts, and you should always have a continuous view of N elements for direct access.
EDIT: here is a piece of code that implements the above, and should give good performance. Please note, however, that you will be advised to add to pieces, not per item. Otherwise, the benefits of using numpy are quickly nullified, regardless of how you implement your ringbuffer.
import numpy as np class RingBuffer(object): def __init__(self, size, padding=None): self.size = size self.padding = size if padding is None else padding self.buffer = np.zeros(self.size+self.padding) self.counter = 0 def append(self, data): """this is an O(n) operation""" data = data[-self.padding:] n = len(data) if self.remaining < n: self.compact() self.buffer[self.counter+self.size:][:n] = data self.counter += n @property def remaining(self): return self.padding-self.counter @property def view(self): """this is always an O(1) operation""" return self.buffer[self.counter:][:self.size] def compact(self): """ note: only when this function is called, is an O(size) performance hit incurred, and this cost is amortized over the whole padding space """ print 'compacting' self.buffer[:self.size] = self.view self.counter = 0 rb = RingBuffer(10) for i in range(4): rb.append([1,2,3]) print rb.view rb.append(np.arange(15)) print rb.view
source share