Das lässt sich in Python+Psyco noch ein klein wenig steigern bzw. mit Pyrex erheblich beschleunigen.
Deine Funktion auf eine ca. 40 sekündige WAV Datei angesetzt gab bei mir folgende Zeiten:
23.829282999 (Python)
7.06526303291 (Python+Psyco)
Deine Funktion benötigt aber ziemlich viel Speicher. Zum einen weil unnötige Kopien angelegt werden und weil die Daten in `rawd` und im Ergebnis zusätzlich in ein Tupel und eine Liste mit `int` bzw. `float` Objekten kopiert wird. Da werden pro Sample nicht 2-Byte sondern wesentlich mehr belegt. Das sind 12 Bytes für jedes `int` und 16 Bytes für jedes `float` plus dem Zeiger in der Liste auf das jeweilige Objekt. Aus meiner 4MB Testdatei werden da im Speicher mindestens 75MB.
Und bei der Berechnung von `lenraw` wird der gesamte Sampleteil der Daten einmal unnötig kopiert. Besser wäre es von der Länge der Wave-Daten 44 abzuziehen und das dann durch 2 zu teilen.
Man kann eine Menge Speicher sparen, wenn man die Samples einzeln umwandelt. Dazu ist das Modul `array` besser geeignet als `struct`.
Code: Alles auswählen
from __future__ import division
from array import array
def lp_filter2(wave):
result = array('h')
result.fromstring(wave[:44])
rawd = array('h')
rawd.fromstring(wave)
del rawd[:22]
xv = [0,0,0,0,0]
yv = [0,0,0,0,0]
for sample in rawd:
del xv[0]
del yv[0]
xv.append(sample / 1.132343779e+03)
yv.append( xv[0]
+ xv[4]
+ 4 * (xv[1] + xv[3])
+ 6 * xv[2]
+ -0.8143381742 * yv[0]
+ 3.1524314324 * yv[1]
+ -4.8358600552 * yv[2]
+ 3.4836368126 * yv[3])
tmp = int(yv[4])
if tmp < -32767:
result.append(-32767)
elif tmp > 32766:
result.append(32766)
else:
result.append(tmp)
return result
Der Speicherverbrauch ist wesentlich niedriger und schwankt nicht so stark wie bei der ursprünglichen Version. Ohne Psyco läuft es leider ein ganz klein wenig langsamer, mit Psyco aber etwas schneller als das Orignal:
24.1125090122 (Python)
5.48418307304 (Python+Psyco)
Die Rechnung finde ich so übrigens etwas übersichtlicher formatiert. Die ``\`` zum Fortsetzen von einer Zeile braucht man nicht solange noch Klammern geöffnet sind.
Erheblich schneller wird es wenn man Pyrex benutzt:
Code: Alles auswählen
from array import array
def lp_filter3(wave):
cdef signed int i, j, size, tmp
cdef signed short *data, sample
cdef double xv[5], yv[5]
wave_array = array('h')
wave_array.fromstring(wave)
for i from 0 <= i < 5:
xv[i] = yv[i] = 0
info = wave_array.buffer_info()
tmp = info[0]
data = <signed short*> tmp
size = info[1]
for i from 22 <= i < size:
sample = data[i]
for j from 0 <= j < 4:
xv[j] = xv[j + 1]
yv[j] = yv[j + 1]
xv[4] = sample / 1.132343779e+03
yv[4] = ( xv[0]
+ xv[4]
+ 4 * (xv[1] + xv[3])
+ 6 * xv[2]
+ -0.8143381742 * yv[0]
+ 3.1524314324 * yv[1]
+ -4.8358600552 * yv[2]
+ 3.4836368126 * yv[3])
if yv[4] < -32767:
sample = -32767
elif yv[4] > 32766:
sample = 32766
else:
sample = <signed int> yv[4]
data[i] = sample
return wave_array
Damit kommt man unter eine Sekunde und braucht noch weniger Speicher weil hier nur
ein `array` Objekt "in place" verändert wird.
0.28432393074 (Pyrex)