Given a large one-dimensional array, break it into blocks of contstant length and compute min and max for each block, the so-called "peaks data".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
from Numeric import * def peaks(data, step): n = len(data) - len(data)%step # ignore tail slices = [ data[i:n:step] for i in range(step) ] peak_max = reduce(maximum, slices) peak_min = reduce(minimum, slices) return transpose(array([peak_max, peak_min])) """example of use: >>> x = sin(arrayrange(0, 3.14, 1e-5)) >>> len(x) 314000 >>> peaks(x,10000) array([[ 0.09982347, 0. ], [ 0.19865953, 0.09983342], ... [ 0.23924933, 0.14112991], [ 0.14112001, 0.04159065]]) """
In a typical waveform display widget one needs to display a sampled sound of length ~1e6 in a GUI window of 800-1000 pixels width. Thus there are around 1024 samples for pixel, and it seems reasonable to draw both min and max values (there are alternatives, such as RMS energy).
Assuming the data is stored in a Numeric.array (numarray.array would work as well) of length n=m*step, the peaks() function returns (m,2)-shaped array containing min and max for each block of length step in data.
Note that the arrays created by slices = ... assignment do not copy the contents of data, so there is little (or no) memory allocation overhead.
The main disadvantage of the recipe is that it requires (steps-1) passes over the array and the CPU cache usage is non-optimal. The obvious one-pass algorithm should perform better, but i can't figure out how to write the one-pass algorithm in Numeric.