Forum: Digitale Signalverarbeitung / DSP / Machine Learning Faltung Optimieren


von Andre R. (ltisystem)


Lesenswert?

Hallo,

ich hatte vor längerem schon einmal ein paar "naive" Beiträge.

Ich bin dabei auf einem TMS320C6713 eine Faltung in Echtzeit 
durchzuführen.
Dabei nutze ich die Faltung im Zeitbereich, die Faltung im 
Frequenzbereich (mittels FFT, Multiplikation der Spektren, iFFT) ist 
nicht erwünscht. Die Abtastrate beträgt 16kHz.

Momentan bin ich in der Lage eine Faltung in Echtzeit durchzuführen, 
wobei die Impulsantwort eine maximale Länge von rund 2100 Samples 
betragen kann. Alles was darüber hinaus geht, hört sich klirrig an, der 
DSP kommt mit dem Rechnen dann eifnahc nicht mehr hinterher. Da ich an 
der Rechenoperation, außer eventuell mit Hand-Assembler-Optimierung, 
nichts mehr optimieren kann, bleibt mir nur noch das Tunen der 
Speicherverwaltung. Ich nutze zur Zeit die klassische Variante:
Pseudo-Code
1
x[size]; //INPUT
2
h[size]; //IMPULSANTWORT
3
y;
4
5
x[0]=INPUT;
6
7
FOR(0 bis size)
8
   y+=x[i]*h[i];
9
y>>15 //SKALIERUNG
10
11
CODEC_WRITE(y);
12
13
FOR(0 bis size)
14
   x[size]=x[size-1];

So ist die Frage: Habt ihr Ideen wie ich das eventuell noch etwas tunen 
kann? Ich hatte überlegt, dass man die Impulsanwort und den Input in 
einem Array speichert.
Das sieht dann so aus(Input=I, Impulsantwort=H):

I,H,I,H,I,H,I,H,I,H,...

Damit würde man vermeiden, dass man zwischen zwei Speicherbereichen 
immer hin und her switcht, was eventuell Rechenzeit einsparen könnte. 
Habs aber noch nicht geschafft zu testen.

Bin für jede Anregung offen.

Grüße Andre

von jens (Gast)


Lesenswert?

Warum ist die Faltung im Frequenzbereich nicht erwünscht?

von Andre R. (ltisystem)


Lesenswert?

jens schrieb:
> Warum ist die Faltung im Frequenzbereich nicht erwünscht?

weil ich es zeitlich nicht mehr hin bekommen würde, jetzt noch darauf 
"umzustellen"

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Auf einem DSP Schleifen in C zu schreiben ist schon mal ungünstig. Warum 
verwendest du keine Bibliotheksfunktionen für Faltung oder 
Vektormultiplikation?

von Andre R. (ltisystem)


Lesenswert?

Andreas Schwarz schrieb:
> Auf einem DSP Schleifen in C zu schreiben ist schon mal ungünstig. Warum
> verwendest du keine Bibliotheksfunktionen für Faltung oder
> Vektormultiplikation?

weil die bibliotheksfunktion (DSPLIB) nicht in-place rechnet. wenn ich 
"off-place" rechne, ist das wieder mit so vielen speicherzugriffen 
verbunden. das c-äquivalent dieser DSPLIB-funktion ist quasi genau diese 
schleife. ich habe keine idee, wie es ohne schleifen funktionieren soll, 
irgendwie müssen doch die arrays durchgegangen werden.

wie ist das mit der vektormulitplikation gemeint? die arrays sind die 
beiden vektoren, ok. meines wissens nach berechnet man doch auch so ein 
vektorprodukt in C?!

grüße

von Andreas S. (andreas) (Admin) Benutzerseite


Lesenswert?

Normalerweise iteriert man nicht selbst über einzelne Samples, sondern 
nutzt die Funktionen die die Signalverarbeitungsbibliothek für das 
Rechnen mit Vektoren (=Arrays) anbietet. Gerade bei DSPs kannst du dich 
nämlich nicht darauf verlassen, dass der Compiler Schleifen in 
effizienten Maschinencode umsetzt.

von Andre R. (ltisystem)


Lesenswert?

Ja ok das leuchtet mir ein. auch wenn ich beim compiler 
optimierungslevel drei (-o3) gesetzt habe, wird das trotzdem nicht die 
selbe leistung wie die dsplib-funktion haben.

Aber wenn ich die Funktion benutze, dann habe ich wieder das Problem, 
dass ich Latenz drin habe, da ja erst eine bestimmte anzahl an samples 
gebuffert werden muss. noch mehr fällt dann das kopieren für das 
overlap-save ins gewicht, was ich für die synchronisation beim 
bufferwechsel benötige.

was ein graus, wie man es dreht und wendet...

von lalala (Gast)


Lesenswert?

Die letzten beiden Zeilen sehen arg problematisch aus. Ueber welche 
Variable läuft z.b. das FOR?

von Andre R. (ltisystem)


Lesenswert?

die for-schleife dient dazu um alle input-samples im fir-block um eine 
stelle zu verschieben. das heißt also, dass sie über die länge des 
koeffizientenblockes läuft, was gleich der länge gespeicherten sample 
ist.

input -->  x(n)   x(n-1) ....   x(2)   x(1)  x(0)
                                          *
           h(n)   h(n-1) ....   h(2)   h(1)  h(0)
            =      =             =     =      =
           val +  val +  .... + val + val +  val = y --> output

nach jeder rechnung kommt quasi ein neuer x-wert und somit müssen vorher 
alle anderen um eine stelle verschoben werden, der älteste wert wird 
verworfen.

ich persönlich finde die vorgehensweise mit buffern besser.
beispiel:

-2024 samples auf eingangsbuffer schreiben und gleichzeit 2024 samples 
aus ausgangsbuffer lesen.
-wenn buffer voll --> switch buffers --> ein- ung ausgangsvorgänge 
passieren jetzt auf anderen buffern
-in der zeit wo wieder 2024 samples gelesen werden führe eine 
fir-funktion aus, die die eben eingelesen eingangsamples als input nutzt 
und die ergebnisse auf den eben schon gelesenen ausgangsbuffer schreibt
-dabei muss die rechnung schneller sein als das einlesen der 2024 
samples dauert, denn dannkommt es wieder zum switchen

dabei sit allerdings das problem, dass ich eine latenz mit einer länge 
der buffer erzeuge und latenz ist bei echtzeit nicht erwünscht. bei 
einem filter mit wenig koeffizienten (ca 100) ist die latenz nicht 
hörbar. da es sich aber um eine impulsantwort mit z.b. 1 sekunde länge 
handelt, kommt diese herangehensweise nicht in frage :(

von ... (Gast)


Lesenswert?

Ringpuffer.... ganz ehrlich. Das Verschieben um eine Stelle ist eine 
katastrophe.

x[4096]; //INPUT
h[size]; //IMPULSANTWORT
y;
pos;

x[pos]=INPUT;
FOR(0 bis size)
   y+=x[(pos+i)%4096]*h[i];
y>>15 //SKALIERUNG
CODEC_WRITE(y);
pos = (pos+1)%4096


Modulo 4096 ist das gleiche wie AND 4095.
Geht also problemlos.

von Luther B. (luther-blissett)


Lesenswert?

Andre Richter schrieb:
> nach jeder rechnung kommt quasi ein neuer x-wert und somit müssen vorher
> alle anderen um eine stelle verschoben werden, der älteste wert wird
> verworfen.
>

Verschieben? Du musst doch nur einen Startindex für x ändern. 
(Ringspeicher):
1
xlow=0; 
2
[...]
3
k=0; 
4
for (i=xlow;i<size;i++) y+=x[i]*h[k++];
5
for (i=0;i<xlow;i++)    y+=x[i]*h[k++];
6
7
fertig(y); 
8
9
xlow++; if (xlow==size) xlow=0; 
10
11
// kein Verschieben mehr.

von ... (Gast)


Lesenswert?

hmmh. erspart das modulo. auch gut^^

von Andre R. (ltisystem)


Lesenswert?

ich hatte ne implementierung mit ringbuffer schon mal, weiß gar nicht 
warum ich das wieder verworfen habe...ich probiers nochmal und halte 
"euch" auf dem laufenden.

danke schon mal

[edit]: werde es allerdings mit der &&SIZE-variante versuchen, da ja 
andreas meinte das jede eigene for-schleife schon kritisch ist.

: Bearbeitet durch User
von MB (Gast)


Lesenswert?

Ich würde dir ebenfalls empfehlen die DSPLIB (es gibt auch noch andere 
Libs mit zusätzlichen Math funktionen) zu verwenden. Diese Libs bieten 
Hand-optimierte Funktionen die deinen DSP optimal ausnützen. Dein DSP 
bietet spezielle sehr schnelle Speicherzugriffsverfahren für die 
Operationen die du ausführen willst. Wenn du selbst etwas schnelleres 
proggen willst, wird das sehr schwierig / zeitaufwändig !

von ... (Gast)


Lesenswert?

&&SIZE ist eine boolsche Verundung. Gangz ehrlich: damit wirds nix.

Und ja, die Forschleife ist Kritisch. Aber jetzt hast zu 2 Schleifen, 
anstatt einer. Das ist der 3fache Datendurchsatz.
(Lesen, zum Rechnen, Lesen zum Verschieben, Schreiben zum Verschieben)
Das LOGISCHE und hingegen ist eine Instruktion und eine Konstante. Die 
Schleife hat sicherlich kein Registerdruck.

Du könntest deine Schleife aber durchaus händisch etwas optimieren. 
Zumal deine Impulsantwort ja eine konstante länge hat.
z.B. Pro iteration 4 multiplikationen machen, anstatt nur eine....  kann 
aber sein, dass der Compiler das eh schon so macht.

von lalala (Gast)


Lesenswert?

Ich bin hier vielleicht auch zu pingelig: das y=0 hast Du nur nicht 
geposted weil klar, oder?
Was für Variablentypen/Wertebereiche verwendest Du? Kann es sein, dass 
das 'klirre' durch einen Varianlenüberlauf zustande kommt (in y)?

von lalala (Gast)


Lesenswert?

Übrigens nochmal zum Verschieben. So:
X(i)=X(i-1)
in der Schleife kann es nicht gehen, ausser Du zaehlst abwaerts.

von ... (Gast)


Lesenswert?

Da spricht der Systemtheoretiker, der Programmierer lacht sich schlapp 
:-D

von Andre R. (ltisystem)


Lesenswert?

MB schrieb:
> Ich würde dir ebenfalls empfehlen die DSPLIB (es gibt auch noch andere
> Libs mit zusätzlichen Math funktionen) zu verwenden.

Es gibt auch noch andere? Ich weiß google ist mein freund, aber mir ist 
noch keine andere bekannt?!?

... schrieb:
> &&SIZE ist eine boolsche Verundung. Gangz ehrlich: damit wirds nix.

sry, verschrieben...meinte &SIZE (and)

... schrieb:
> z.B. Pro iteration 4 multiplikationen machen, anstatt nur eine....  kann
> aber sein, dass der Compiler das eh schon so macht.

so wie ich das aus dem TI forum raus lesen konnte, wird mit der level3 
optimierung schon gemacht, könnte ich aber auch nochmal probieren

lalala schrieb:
> Was für Variablentypen/Wertebereiche verwendest Du? Kann es sein, dass
> das 'klirre' durch einen Varianlenüberlauf zustande kommt (in y)?

das geklirre kommt durch meine interrupt basiertes programm, es kommt 
dann immer eher ein interrupt, eh meine rechnung fertig ist und somit 
werden zwischendurch ein paar samples verworfen.


vielen dank schon mal für die guten anregungen!!!! :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.