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
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"
Auf einem DSP Schleifen in C zu schreiben ist schon mal ungünstig. Warum
verwendest du keine Bibliotheksfunktionen für Faltung oder
Vektormultiplikation?
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
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.
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...
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 :(
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.
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):
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.
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 !
&&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.
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)?
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!!!! :)